-
Notifications
You must be signed in to change notification settings - Fork 36
Eval Submission #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Eval Submission #14
Changes from all commits
0f7e86c
9752ad2
f9ca0f1
6077b6c
5d48e18
a13623f
d3128a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const openWeatherApi = { | ||
| key: "47141b27ae5c4862c3e7faece74bb0ed", | ||
| rootUrl: "https://api.openweathermap.org/data/2.5" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| function Header() { | ||
| return ( | ||
| <div className="row justify-content-md-center"> | ||
| <div className="col col-8 text-center"> | ||
| <h1>Weather App</h1> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default Header; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||
| 'use client'; | ||||||
| import { useSelector } from "react-redux"; | ||||||
| import { Sparklines, SparklinesLine, SparklinesReferenceLine } from "react-sparklines"; | ||||||
|
|
||||||
|
|
||||||
| export const ForecastList = () => { | ||||||
|
|
||||||
| const forecastsListState = useSelector((state) => state.forecastsList.forecasts) | ||||||
|
|
||||||
| const getAverage = (array) => { | ||||||
| return array.reduce((a, b) => a + b) / array.length; | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| const columnHeader = | ||||||
| <div className="row justify-content-md-center text-center"> | ||||||
| <div className="col-3">City</div> | ||||||
| <div className="col-3">Temperature</div> | ||||||
| <div className="col-3">Pressure</div> | ||||||
| <div className="col-3">Humidity</div> | ||||||
| </div> | ||||||
|
|
||||||
| const forcasts = forecastsListState.map((forecast) => { | ||||||
|
|
||||||
| let { humidities, pressures, temperatures } = forecast; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const , not let. |
||||||
|
|
||||||
| return <div key={forecast.id} className="row justify-content-md-center text-center"> | ||||||
| <div className="col-3">{forecast.city}</div> | ||||||
| <div className="col-3"> | ||||||
| <Sparklines data={temperatures}> | ||||||
| <SparklinesLine color="#63CBDE" /> | ||||||
| <SparklinesReferenceLine type="avg" /> | ||||||
| </Sparklines> | ||||||
| {getAverage(temperatures)}</div> | ||||||
| <div className="col-3"> | ||||||
| <Sparklines data={pressures}> | ||||||
| <SparklinesLine color="green" /> | ||||||
| <SparklinesReferenceLine type="avg" /> | ||||||
| </Sparklines> | ||||||
| {getAverage(pressures)}</div> | ||||||
| <div className="col-3"> | ||||||
| <Sparklines data={humidities}> | ||||||
| <SparklinesLine color="#A627A4" /> | ||||||
| <SparklinesReferenceLine type="avg" /> | ||||||
| </Sparklines> | ||||||
| {getAverage(humidities)}</div> | ||||||
| </div> | ||||||
| }) | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| return ( | ||||||
| <> | ||||||
| <div>{columnHeader}</div> | ||||||
| <div>{forcasts}</div> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| </> | ||||||
| ) | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; | ||
| import { openWeatherApi } from "@/OpenWeatherAPI"; | ||
| import axios from "axios"; | ||
| import { parseFiveDayForecast } from "@/app/utilities/fiveDayForcastParser"; | ||
|
|
||
| const rootUrl = openWeatherApi.rootUrl | ||
|
|
||
| export const fetchFiveDayForecast = createAsyncThunk('data/fetchFiveDayForecast', async (locationId) => { | ||
| const singleForecastResponse = await axios.get(`${rootUrl}/weather?q=${locationId},us&units=imperial&appid=${openWeatherApi.key}`); | ||
| let { coord: { lon: longitude, lat: latitude } } = singleForecastResponse.data; | ||
|
|
||
| const fiveDayForecastResponse = await axios.get(`${rootUrl}/forecast?lat=${latitude}&lon=${longitude}&units=imperial&appid=${openWeatherApi.key}`) | ||
|
|
||
| return fiveDayForecastResponse.data | ||
| }) | ||
|
|
||
| const initialState = { | ||
| forecasts: [], | ||
| status: 'idle', // to track loading state | ||
| error: null, | ||
| } | ||
|
|
||
| export const forecastsListSlice = createSlice({ | ||
| name: "forecasts", | ||
| initialState, | ||
| reducers: { | ||
| addToForecastsList: (state) => { | ||
| state.list.shift(action.payload) | ||
| } | ||
| }, | ||
| extraReducers: (builder) => { | ||
| builder | ||
| .addCase(fetchFiveDayForecast.pending, (state) => { | ||
| state.status = 'loading'; | ||
| }) | ||
| .addCase(fetchFiveDayForecast.fulfilled, (state, action) => { | ||
| state.status = 'succeeded'; | ||
| state.forecasts.unshift(parseFiveDayForecast(action.payload)) | ||
| }) | ||
| .addCase(fetchFiveDayForecast.rejected, (state, action) => { | ||
| state.status = 'failed'; | ||
| state.error = action.error.message; | ||
| }); | ||
| }, | ||
| }) | ||
|
|
||
| export const { } = forecastsListSlice.actions; | ||
|
|
||
| export default forecastsListSlice.reducer; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| 'use client'; | ||
| import { useDispatch, useSelector } from "react-redux"; | ||
| import { setInputState, reset } from "./searchInputSlice"; | ||
| import { fetchFiveDayForecast, fetchSingleDayForcast } from "../forecastsList/forecastsListSlice"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. clean unused imports |
||
|
|
||
|
|
||
| function SearchInput() { | ||
| const string = useSelector((state) => state.searchInput.string) | ||
| const dispatch = useDispatch() | ||
|
|
||
| const handleEnterKey = (e) => { | ||
| let key = e.key | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bad use of let, this is a const |
||
|
|
||
| if (key === 'Enter') { | ||
| dispatch(fetchFiveDayForecast(string)) | ||
| dispatch(reset()) | ||
| } | ||
| } | ||
|
|
||
| return ( | ||
| <div className="row justify-content-md-center top-buffer"> | ||
| <div className="col col-12"> | ||
| <div className="input-group mb-3"> | ||
| <input | ||
| type="text" | ||
| className="form-control" | ||
| placeholder="Get a five-day forecast in your different cities" | ||
| defaultValue={string} | ||
| onChange={(e) => | ||
| dispatch(setInputState(e.target.value)) | ||
| } | ||
| onKeyDown={(e) => handleEnterKey(e)} | ||
| > | ||
| </input> | ||
| <div className="input-group-append"> | ||
| <button type="button" className="btn btn-primary" | ||
| onClick={() => { | ||
| dispatch(fetchFiveDayForecast(string)) | ||
| dispatch(reset()) | ||
| }}> | ||
| Search | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
Comment on lines
+21
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) | ||
| } | ||
|
|
||
| export default SearchInput; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { createSlice } from "@reduxjs/toolkit"; | ||
|
|
||
| const initialState = { | ||
| string: "", | ||
|
|
||
| } | ||
|
|
||
| export const searchInputSlice = createSlice({ | ||
| name: "searchInputSlice", | ||
| initialState, | ||
| reducers: { | ||
| setInputState: (state, action) => { | ||
| state.string = action.payload | ||
| }, | ||
| reset: (state) => { | ||
| state.string = "" | ||
| } | ||
| }, | ||
| }) | ||
|
|
||
| export const { setInputState, reset } = searchInputSlice.actions; | ||
|
|
||
| export default searchInputSlice.reducer; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,107 +1,19 @@ | ||
| :root { | ||
| --max-width: 1100px; | ||
| --border-radius: 12px; | ||
| --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', | ||
| 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', | ||
| 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; | ||
| /* h1 { | ||
| text-align: center; | ||
| } */ | ||
|
|
||
| --foreground-rgb: 0, 0, 0; | ||
| --background-start-rgb: 214, 219, 220; | ||
| --background-end-rgb: 255, 255, 255; | ||
|
|
||
| --primary-glow: conic-gradient( | ||
| from 180deg at 50% 50%, | ||
| #16abff33 0deg, | ||
| #0885ff33 55deg, | ||
| #54d6ff33 120deg, | ||
| #0071ff33 160deg, | ||
| transparent 360deg | ||
| ); | ||
| --secondary-glow: radial-gradient( | ||
| rgba(255, 255, 255, 1), | ||
| rgba(255, 255, 255, 0) | ||
| ); | ||
|
|
||
| --tile-start-rgb: 239, 245, 249; | ||
| --tile-end-rgb: 228, 232, 233; | ||
| --tile-border: conic-gradient( | ||
| #00000080, | ||
| #00000040, | ||
| #00000030, | ||
| #00000020, | ||
| #00000010, | ||
| #00000010, | ||
| #00000080 | ||
| ); | ||
|
|
||
| --callout-rgb: 238, 240, 241; | ||
| --callout-border-rgb: 172, 175, 176; | ||
| --card-rgb: 180, 185, 188; | ||
| --card-border-rgb: 131, 134, 135; | ||
| /* .container { | ||
| background: black; | ||
| } | ||
|
|
||
| @media (prefers-color-scheme: dark) { | ||
| :root { | ||
| --foreground-rgb: 255, 255, 255; | ||
| --background-start-rgb: 0, 0, 0; | ||
| --background-end-rgb: 0, 0, 0; | ||
|
|
||
| --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); | ||
| --secondary-glow: linear-gradient( | ||
| to bottom right, | ||
| rgba(1, 65, 255, 0), | ||
| rgba(1, 65, 255, 0), | ||
| rgba(1, 65, 255, 0.3) | ||
| ); | ||
|
|
||
| --tile-start-rgb: 2, 13, 46; | ||
| --tile-end-rgb: 2, 5, 19; | ||
| --tile-border: conic-gradient( | ||
| #ffffff80, | ||
| #ffffff40, | ||
| #ffffff30, | ||
| #ffffff20, | ||
| #ffffff10, | ||
| #ffffff10, | ||
| #ffffff80 | ||
| ); | ||
|
|
||
| --callout-rgb: 20, 20, 20; | ||
| --callout-border-rgb: 108, 108, 108; | ||
| --card-rgb: 100, 100, 100; | ||
| --card-border-rgb: 200, 200, 200; | ||
| } | ||
| .col { | ||
| background: gray; | ||
| } | ||
|
|
||
| * { | ||
| box-sizing: border-box; | ||
| padding: 0; | ||
| margin: 0; | ||
| .row { | ||
| background: lightgreen; | ||
| } | ||
|
|
||
| html, | ||
| body { | ||
| max-width: 100vw; | ||
| overflow-x: hidden; | ||
| } | ||
|
|
||
| body { | ||
| color: rgb(var(--foreground-rgb)); | ||
| background: linear-gradient( | ||
| to bottom, | ||
| transparent, | ||
| rgb(var(--background-end-rgb)) | ||
| ) | ||
| rgb(var(--background-start-rgb)); | ||
| } | ||
|
|
||
| a { | ||
| color: inherit; | ||
| text-decoration: none; | ||
| } | ||
|
|
||
| @media (prefers-color-scheme: dark) { | ||
| html { | ||
| color-scheme: dark; | ||
| } | ||
| } | ||
| .top-buffer { | ||
| margin-top: 20px; | ||
| } */ |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| 'use client' | ||
| import 'bootstrap/dist/css/bootstrap.css' | ||
| import 'react-bootstrap' | ||
| import './globals.css' | ||
| import { Inter } from 'next/font/google' | ||
| import { Provider } from 'react-redux' | ||
| import store from './store/store' | ||
|
|
||
| const inter = Inter({ subsets: ['latin'] }) | ||
|
|
||
| export default function RootLayout({ children }) { | ||
| return ( | ||
| <html lang="en"> | ||
| <Provider store={store}> | ||
| <body className={inter.className}>{children}</body> | ||
| </Provider> | ||
| </html> | ||
| ) | ||
| } |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DRY,
you could have done something like:
const columnTitles = ['city', 'Temperature', 'Pressure', 'Humidity']And then you map them