diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 42d545b..0807efa 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@tailwindcss/vite": "^4.1.11", + "bootstrap-icons": "^1.13.1", "js-cookie": "^3.0.5", "jscookie": "^1.1.0", "react": "^19.1.0", @@ -2064,6 +2065,22 @@ "dev": true, "license": "MIT" }, + "node_modules/bootstrap-icons": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.13.1.tgz", + "integrity": "sha512-ijombt4v6bv5CLeXvRWKy7CuM3TRTuPEuGaGKvTV5cz65rQSY8RQ2JcHt6b90cBBAC7s8fsf2EkQDldzCoXUjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", diff --git a/frontend/package.json b/frontend/package.json index b9262fc..c95ef22 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.11", + "bootstrap-icons": "^1.13.1", "js-cookie": "^3.0.5", "jscookie": "^1.1.0", "react": "^19.1.0", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ce55b8f..3145733 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,7 @@ import "./App.css"; import "react-toastify/dist/ReactToastify.css"; import Layout from "./Layout/Layout.tsx"; -import WeatherCard from "./components/WeatherCard"; +import WeatherCard from "./components/WeatherForm.tsx"; function App() { return ( diff --git a/frontend/src/assets/icons/sunrise-fill.svg b/frontend/src/assets/icons/sunrise-fill.svg new file mode 100644 index 0000000..c922d7c --- /dev/null +++ b/frontend/src/assets/icons/sunrise-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/icons/sunset-fill.svg b/frontend/src/assets/icons/sunset-fill.svg new file mode 100644 index 0000000..91a8d0e --- /dev/null +++ b/frontend/src/assets/icons/sunset-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/IsLoading.tsx b/frontend/src/components/IsLoading.tsx deleted file mode 100644 index 4e9155e..0000000 --- a/frontend/src/components/IsLoading.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; - -interface Props { - message: string; -} - -const IsLoading: React.FC = ({ message }) => { - return ( -
-

{message}

-
- ); -}; - -export default IsLoading; diff --git a/frontend/src/components/WeatherData.tsx b/frontend/src/components/WeatherData.tsx index 81a46d3..14f4609 100644 --- a/frontend/src/components/WeatherData.tsx +++ b/frontend/src/components/WeatherData.tsx @@ -1,10 +1,60 @@ import React from "react"; +import sunriseIcon from "../assets/icons/sunrise-fill.svg"; +import sunsetIcon from "../assets/icons/sunset-fill.svg"; const WeatherData: React.FC = () => { + const weatherRaw = localStorage.getItem("weather"); + const weatherData = JSON.parse(weatherRaw || "{}"); + + // OpenWeatherMap Icon-URL + const iconCode = weatherData?.weather?.[0]?.icon; + const iconUrl = iconCode + ? `https://openweathermap.org/img/wn/${iconCode}@4x.png` + : ""; + return ( - <> -

Weather

- +
+
+

{weatherData?.name}

+

{weatherData?.main?.temp} °C

+

+ {weatherData?.weather?.[0]?.description} +

+ {iconUrl && ( + {weatherData?.weather?.[0]?.description} + )} +
+
+ Sunrise Icon + + Sunrise:{" "} + {weatherData?.sys?.sunrise + ? new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString( + "de-DE", + { hour: "2-digit", minute: "2-digit" } + ) + : "--:--"} + +
+
+ Sunset Icon + + Sunset:{" "} + {weatherData?.sys?.sunset + ? new Date(weatherData.sys.sunset * 1000).toLocaleTimeString( + "de-DE", + { hour: "2-digit", minute: "2-digit" } + ) + : "--:--"} + +
+
+
+
); }; diff --git a/frontend/src/components/WeatherCard.tsx b/frontend/src/components/WeatherForm.tsx similarity index 97% rename from frontend/src/components/WeatherCard.tsx rename to frontend/src/components/WeatherForm.tsx index ba822e4..90744d4 100644 --- a/frontend/src/components/WeatherCard.tsx +++ b/frontend/src/components/WeatherForm.tsx @@ -21,7 +21,7 @@ const WeatherCard: React.FC = () => { event.preventDefault(); setLoading(true); toast - .promise(fetchWeather(city, getAPIKey()), { + .promise(fetchWeather(city, getAPIKey(), "metric"), { pending: "Fetching weather data...", success: "Weather data loaded successfully!", error: "Error loading weather data! (Check console for details)", diff --git a/frontend/src/utils/apiFunc.ts b/frontend/src/utils/apiFunc.ts index 6d2e1c5..5ca8aa8 100644 --- a/frontend/src/utils/apiFunc.ts +++ b/frontend/src/utils/apiFunc.ts @@ -1,4 +1,10 @@ -export const fetchWeather = async (city: string, apiKey: string) => { +export type units = "metric" | "imperial"; + +export const fetchWeather = async ( + city: string, + apiKey: string, + units: units +) => { // Get location data const location = await fetch( `http://api.openweathermap.org/geo/1.0/direct?q=${city}&appid=${apiKey}` @@ -18,7 +24,7 @@ export const fetchWeather = async (city: string, apiKey: string) => { // Get weather data const weather = await fetch( - `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}` + `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=${units}` ).then((response) => response.json()); localStorage.setItem("weather", JSON.stringify(weather)); };