Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a20fac9
initial commit
JoeCarnahan42 Jan 13, 2025
d47b702
add txt file that stores free api key
JoeCarnahan42 Jan 13, 2025
9799fee
Install React-Sparklines. Initialize store. Add Provider to RootLayout.
JoeCarnahan42 Jan 14, 2025
2f17a35
Init components files.
JoeCarnahan42 Jan 14, 2025
b212f55
install TS. Begin writing table for data render.
JoeCarnahan42 Jan 14, 2025
db197a2
add table outline
JoeCarnahan42 Jan 14, 2025
6232df4
Install axios
JoeCarnahan42 Jan 14, 2025
8e3aa85
refactor. Basic boilerplate
JoeCarnahan42 Jan 14, 2025
17c8675
Add slice for search bar state
JoeCarnahan42 Jan 14, 2025
c3aaf8f
More refactor(condensed slices). Working api returns.
JoeCarnahan42 Jan 15, 2025
94e7116
Added slice for search history
JoeCarnahan42 Jan 17, 2025
62ad7d6
Remove historySlice.
JoeCarnahan42 Jan 18, 2025
c99d65f
Separate search bar into its own component
JoeCarnahan42 Jan 18, 2025
4904691
Chasing down exsessive render issue
JoeCarnahan42 Jan 18, 2025
7bf3cc2
removed useless component files
JoeCarnahan42 Jan 21, 2025
76e52d1
changed data flow
JoeCarnahan42 Jan 21, 2025
586d55a
restructure data(again)
JoeCarnahan42 Jan 21, 2025
ff02e53
Full render functionality. Form validation not implemented.
JoeCarnahan42 Jan 21, 2025
beaa75a
Install and implement React-Hook-Form and yup. Full functionality.
JoeCarnahan42 Jan 22, 2025
187a4db
removed TODO comment
JoeCarnahan42 Jan 22, 2025
42de4f9
Delete un-used TS file
JoeCarnahan42 Jan 22, 2025
1f10c38
Refactor, more DRY. Improve response mutation.
JoeCarnahan42 Jan 24, 2025
d2938a5
Update app/components/Table.js
JoeCarnahan42 Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions app/components/SearchBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";
import { getLatLong } from "../store/slices/apiSlice";
import { useDispatch } from "react-redux";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const SearchBar = () => {
const dispatch = useDispatch();

// Better validation?? //
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you dont need // at the end

const schema = yup.object({
input: yup
.string()
.transform(function (value) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not es6?

return value.toLowerCase(), value.trim(" ");
})
.required("City name is required."),
});

const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});

const submit = (data) => {
dispatch(getLatLong(data.input));
setValue("input", "");
};

return (
<div className="container">
<br />
<div className="input-group">
<input
{...register("input", { required: true })}
type="text"
className="form-control"
placeholder="Enter City Name:"
aria-describedby="basic-addon2"
/>
<div className="input-group-append">
<button
onClick={handleSubmit(submit)}
className="btn btn-outline-primary"
type="button"
>
Submit
</button>
</div>
</div>
{errors.input?.message && (
<div className="alert alert-danger">{errors.input?.message}</div>
)}
</div>
);
};

export default SearchBar;
125 changes: 125 additions & 0 deletions app/components/Table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"use client";
import { useDispatch, useSelector } from "react-redux";
import { getForecast } from "../store/slices/apiSlice";
import { useState, useEffect } from "react";
import {
Sparklines,
SparklinesReferenceLine,
SparklinesBars,
} from "react-sparklines";

export default function Table() {
const [weatherData, setWeatherData] = useState([]);
const dispatch = useDispatch();

const { latitude, longitude, weather } = useSelector(
(state) => state.weather
);

const data = (weather, dataPoint) => {
const arr = [3, 12, 20, 28, 36];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't be shy on naming consts for what they are, dont be too generic

return arr.map((number) => Math.floor(weather.list[number].main[dataPoint]);
);
};

const calcAvg = (numbers) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too generic argument name

const sum = numbers.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0
);

const avg = Math.floor(sum / numbers.length);

return avg;
};

useEffect(() => {
if (latitude && longitude) {
dispatch(getForecast({ latitude, longitude }));
}
}, [latitude, longitude, dispatch]);

useEffect(() => {
if (weather) {
const temp = data(weather, "temp");
const pressure = data(weather, "pressure");
const humidity = data(weather, "humidity");

const weatherObj = {
id: Math.random(Math.floor() * 10000),
cityName: weather.city.name,
temp: temp,
avgTemp: calcAvg(temp),
pressure: pressure,
avgPress: calcAvg(pressure),
humidity: humidity,
avgHum: calcAvg(humidity),
};
setWeatherData((weatherData) => {
return [weatherObj, ...weatherData];
});
}
}, [weather]);

return (
<div className="container">
{!weather ? <h1>Enter a city to get started</h1> : <h1></h1>}
<br />
<table className="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">City</th>
<th scope="col">Tempurature (F)</th>
<th scope="col">Pressure (hPa)</th>
<th scope="col">Humidity (%)</th>
</tr>
</thead>
{weatherData.length > 0 &&
weatherData.map((data) => {
if (data) {
return (
<tbody key={data.id}>
<tr className="align-middle">
<th scope="row">{data.cityName}</th>
<td className="align-middle">
<Sparklines data={data.temp}>
<SparklinesBars
style={{ fill: "orange", fillOpacity: ".5" }}
/>
<SparklinesReferenceLine type="avg" />
</Sparklines>
<p>
Average Temperature: <strong>{data.avgTemp} F</strong>
</p>
</td>
<td className="align-middle">
<Sparklines data={data.pressure}>
<SparklinesBars
style={{ fill: "orange", fillOpacity: ".5" }}
/>
<SparklinesReferenceLine type="avg" />
</Sparklines>
<p>
Average Pressure: <strong>{data.avgPress} hPa</strong>
</p>
</td>
<td className="align-middle">
<Sparklines data={data.humidity}>
<SparklinesBars
style={{ fill: "orange", fillOpacity: ".5" }}
/>
<SparklinesReferenceLine type="avg" />
</Sparklines>
<p>
Average Humidity: <strong>{data.avgHum} %</strong>
</p>
</td>
</tr>
</tbody>
);
}
})}
</table>
</div>
);
}
Binary file removed app/favicon.ico
Binary file not shown.
107 changes: 0 additions & 107 deletions app/globals.css

This file was deleted.

19 changes: 8 additions & 11 deletions app/layout.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import './globals.css'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
"use client";
import "bootstrap/dist/css/bootstrap.min.css";
import { Provider } from "react-redux";
import store from "./store/configureStore";

export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<Provider store={store}>
<body>{children}</body>
</Provider>
</html>
)
);
}
Loading