From f2501ce6d00485f042d1790936c8ddee8ac841d3 Mon Sep 17 00:00:00 2001 From: Anthony Ramos Date: Thu, 5 Jun 2025 08:44:02 -0700 Subject: [PATCH 1/2] eval final --- .env.local | 2 + .gitignore | 4 +- app/components/CityList.tsx | 193 ++++ app/components/ReduxProvider.tsx | 15 + app/components/WeatherChart.tsx | 28 + app/components/WeatherMap.tsx | 114 +++ app/components/searchBar.module.css | 41 + app/components/searchBar.tsx | 50 + app/globals.css | 207 +++-- app/layout.js | 17 - app/layout.tsx | 22 + app/page.js | 95 -- app/page.tsx | 220 +++++ app/store/configStore.ts | 13 + app/store/rootReducer.ts | 9 + app/store/slice/weatherSlice.ts | 144 +++ app/types/global.d.ts | 33 + app/types/weather.ts | 62 ++ jsconfig.json | 1 + next.config.js | 6 +- package-lock.json | 1305 +++++++++++++++++++++++---- package.json | 17 +- tsconfig.json | 40 + 23 files changed, 2239 insertions(+), 399 deletions(-) create mode 100644 .env.local create mode 100644 app/components/CityList.tsx create mode 100644 app/components/ReduxProvider.tsx create mode 100644 app/components/WeatherChart.tsx create mode 100644 app/components/WeatherMap.tsx create mode 100644 app/components/searchBar.module.css create mode 100644 app/components/searchBar.tsx delete mode 100644 app/layout.js create mode 100644 app/layout.tsx delete mode 100644 app/page.js create mode 100644 app/page.tsx create mode 100644 app/store/configStore.ts create mode 100644 app/store/rootReducer.ts create mode 100644 app/store/slice/weatherSlice.ts create mode 100644 app/types/global.d.ts create mode 100644 app/types/weather.ts create mode 100644 tsconfig.json diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..2cc1411 --- /dev/null +++ b/.env.local @@ -0,0 +1,2 @@ +NEXT_PUBLIC_OPENWEATHER_API_KEY=357ceb5b611074a4e9f82678df4ee1da +NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=AIzaSyC_FPwK88VMlBQ2ed44uwqZqZwM_MWHvTs \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8f322f0..e842897 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files -.env*.local +# .env*.local # vercel .vercel @@ -33,3 +33,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +app/layout.js +app/page.js diff --git a/app/components/CityList.tsx b/app/components/CityList.tsx new file mode 100644 index 0000000..3a12561 --- /dev/null +++ b/app/components/CityList.tsx @@ -0,0 +1,193 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { Sparklines, SparklinesLine, SparklinesReferenceLine } from 'react-sparklines'; +import { removeSearchedCity } from '../store/slice/weatherSlice'; +import { RootState } from '../store/rootReducer'; + +const CityList = () => { + const dispatch = useDispatch(); + const searchedCities = useSelector((state: RootState) => state.weather.searchedCities); + + const getChartData = (list: any[], field: string) => { + return list.map(item => item.main[field]); + }; + + const calculateAverage = (data: number[]) => { + const sum = data.reduce((a, b) => a + b, 0); + return Math.round(sum / data.length); + }; + + return ( +
+

Searched Cities

+ {searchedCities.map((cityData) => ( +
+
+
+

{cityData.city.name}

+ {cityData.city.country && ( + {cityData.city.country} + )} +
+ +
+ +
+
+

Temperature (°F)

+ + + + +
+ Average: {calculateAverage(getChartData(cityData.list, 'temp'))}°F +
+
+ +
+

Pressure (hPa)

+ + + + +
+ Average: {calculateAverage(getChartData(cityData.list, 'pressure'))} hPa +
+
+ +
+

Humidity (%)

+ + + + +
+ Average: {calculateAverage(getChartData(cityData.list, 'humidity'))}% +
+
+
+
+ ))} + + +
+ ); +}; + +export default CityList; diff --git a/app/components/ReduxProvider.tsx b/app/components/ReduxProvider.tsx new file mode 100644 index 0000000..ec582c3 --- /dev/null +++ b/app/components/ReduxProvider.tsx @@ -0,0 +1,15 @@ +'use client'; + +import React from 'react'; +import { Provider } from 'react-redux'; +import { store } from '../store/configStore'; + +interface ReduxProviderProps { + children: React.ReactNode; +} + +const ReduxProvider: React.FC = ({ children }) => { + return {children}; +}; + +export default ReduxProvider; diff --git a/app/components/WeatherChart.tsx b/app/components/WeatherChart.tsx new file mode 100644 index 0000000..c2128e0 --- /dev/null +++ b/app/components/WeatherChart.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Sparklines, SparklinesLine, SparklinesCurve, SparklinesReferenceLine } from 'react-sparklines'; + +interface WeatherChartProps { + data: number[]; + color: string; + unit: string; + title: string; +} + +const WeatherChart: React.FC = ({ data, color, unit, title }) => { + const average = data.reduce((sum, value) => sum + value, 0) / data.length; + + return ( +
+

{title}

+ + + + +
+ Average: {average.toFixed(2)} {unit} +
+
+ ); +}; + +export default WeatherChart; diff --git a/app/components/WeatherMap.tsx b/app/components/WeatherMap.tsx new file mode 100644 index 0000000..4b31483 --- /dev/null +++ b/app/components/WeatherMap.tsx @@ -0,0 +1,114 @@ +import React from 'react'; +import Image from 'next/image'; +import { useSelector, useDispatch } from 'react-redux'; +import { fetchWeatherData } from '../store/slice/weatherSlice'; +import { WeatherState } from '../types/weather'; +import { AppDispatch } from '../store/configStore'; + +interface WeatherMapProps { + lat: number; + lon: number; +} + +const WeatherMap: React.FC = ({ lat, lon }) => { + const dispatch = useDispatch(); + const { nearbyCities } = useSelector((state: { weather: WeatherState }) => state.weather); + + const handleCityClick = (cityName: string) => { + dispatch(fetchWeatherData(cityName)); + }; + + return ( +
+