From 5f514d457878010f9303e595822c9259b893889e Mon Sep 17 00:00:00 2001 From: "theis.gaedigk" Date: Sun, 27 Jul 2025 13:33:54 +0200 Subject: [PATCH] add react-toastify for notifications and implement weather fetching functionality --- frontend/package-lock.json | 23 ++++++++++++++++++ frontend/package.json | 1 + frontend/src/App.tsx | 1 + frontend/src/Layout/Layout.tsx | 4 +++- frontend/src/components/Header.tsx | 1 + frontend/src/components/WeatherCard.tsx | 31 +++++++++++++++++++++---- frontend/src/utils/apiFunc.ts | 24 +++++++++++++++++++ frontend/src/utils/toastify.ts | 17 ++++++++++++++ 8 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 frontend/src/utils/apiFunc.ts create mode 100644 frontend/src/utils/toastify.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4f8ccaf..7e7ce0e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "jscookie": "^1.1.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-toastify": "^11.0.5", "toastify": "^2.0.1" }, "devDependencies": { @@ -1945,6 +1946,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2997,6 +3007,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-toastify": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", + "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 08a6b75..1901f70 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "jscookie": "^1.1.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-toastify": "^11.0.5", "toastify": "^2.0.1" }, "devDependencies": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e8e0c99..ce55b8f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ import "./App.css"; +import "react-toastify/dist/ReactToastify.css"; import Layout from "./Layout/Layout.tsx"; import WeatherCard from "./components/WeatherCard"; diff --git a/frontend/src/Layout/Layout.tsx b/frontend/src/Layout/Layout.tsx index 0a3d02a..99548b9 100644 --- a/frontend/src/Layout/Layout.tsx +++ b/frontend/src/Layout/Layout.tsx @@ -1,5 +1,6 @@ import React from "react"; import Header from "../components/Header"; +import { ToastContainer } from "react-toastify"; type LayoutProps = { children: React.ReactNode; @@ -7,8 +8,9 @@ type LayoutProps = { const Layout: React.FC = ({ children }) => { return ( -
+
+
{children}
); diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 434b391..00ef2e2 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -7,6 +7,7 @@ const Header: React.FC = () => { if (apiKey) { Cookies.set("apiKey", apiKey); } + console.log(Cookies.get("apiKey")); }; return (
diff --git a/frontend/src/components/WeatherCard.tsx b/frontend/src/components/WeatherCard.tsx index 71ae0b3..cf682c1 100644 --- a/frontend/src/components/WeatherCard.tsx +++ b/frontend/src/components/WeatherCard.tsx @@ -1,17 +1,40 @@ import React from "react"; +import { useState } from "react"; +import { fetchWeather } from "../utils/apiFunc"; +import Cookies from "js-cookie"; + +const WeatherCard: React.FC = () => { + const [city, setCity] = useState(""); + const apiKey = Cookies.get("apiKey") || ""; + + const handleCityChange = (event: React.ChangeEvent) => { + setCity(event.target.value); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + fetchWeather(city, apiKey); + }; -const WeaatherCard: React.FC = () => { return (

Weather Card

Current Weather will be displayed here

-
+ - +
); }; -export default WeaatherCard; +export default WeatherCard; diff --git a/frontend/src/utils/apiFunc.ts b/frontend/src/utils/apiFunc.ts new file mode 100644 index 0000000..c4413b0 --- /dev/null +++ b/frontend/src/utils/apiFunc.ts @@ -0,0 +1,24 @@ +import { myToast } from "./toastify"; + +export const fetchWeather = async (city: string, apiKey: string) => { + // Get location data + const location = await fetch( + `http://api.openweathermap.org/geo/1.0/direct?q=${city}&appid=${apiKey}` + ).then((response) => { + if (response.status === 401) { + myToast("Request Failed! Check API key and city name.", "error"); + throw new Error("Network response was not ok"); + } else if (response.ok) { + return response.json(); + } + }); + const lat = location[0].lat; + const lon = location[0].lon; + + // Get weather data + const weather = await fetch( + `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}` + ).then((response) => response.json()); + console.log(weather); + myToast("Successfully fetched weather data", "success"); +}; diff --git a/frontend/src/utils/toastify.ts b/frontend/src/utils/toastify.ts new file mode 100644 index 0000000..3607ed8 --- /dev/null +++ b/frontend/src/utils/toastify.ts @@ -0,0 +1,17 @@ +import { toast, type ToastOptions } from "react-toastify"; + +export type ToastType = "success" | "error" | "info" | "warning"; + +export const myToast = (message: string, msgType: ToastType) => { + let config: ToastOptions = { + position: "top-right", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "dark", + }; + toast[msgType](message, config); +};