add react-toastify for notifications and implement weather fetching functionality

This commit is contained in:
2025-07-27 13:33:54 +02:00
parent a1f4de1a8b
commit 5f514d4578
8 changed files with 97 additions and 5 deletions

View File

@@ -12,6 +12,7 @@
"jscookie": "^1.1.0", "jscookie": "^1.1.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-toastify": "^11.0.5",
"toastify": "^2.0.1" "toastify": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
@@ -1945,6 +1946,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "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": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2997,6 +3007,19 @@
"node": ">=0.10.0" "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": { "node_modules/resolve-from": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",

View File

@@ -14,6 +14,7 @@
"jscookie": "^1.1.0", "jscookie": "^1.1.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-toastify": "^11.0.5",
"toastify": "^2.0.1" "toastify": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,4 +1,5 @@
import "./App.css"; import "./App.css";
import "react-toastify/dist/ReactToastify.css";
import Layout from "./Layout/Layout.tsx"; import Layout from "./Layout/Layout.tsx";
import WeatherCard from "./components/WeatherCard"; import WeatherCard from "./components/WeatherCard";

View File

@@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import Header from "../components/Header"; import Header from "../components/Header";
import { ToastContainer } from "react-toastify";
type LayoutProps = { type LayoutProps = {
children: React.ReactNode; children: React.ReactNode;
@@ -7,8 +8,9 @@ type LayoutProps = {
const Layout: React.FC<LayoutProps> = ({ children }) => { const Layout: React.FC<LayoutProps> = ({ children }) => {
return ( return (
<div className="flex flex-col min-h-screen bg-gradient-to-br from-blue-50 via-blue-100 to-blue-200 dark:from-gray-900 dark:via-gray-950 dark:to-gray-900"> <div>
<Header /> <Header />
<ToastContainer />
<main>{children}</main> <main>{children}</main>
</div> </div>
); );

View File

@@ -7,6 +7,7 @@ const Header: React.FC = () => {
if (apiKey) { if (apiKey) {
Cookies.set("apiKey", apiKey); Cookies.set("apiKey", apiKey);
} }
console.log(Cookies.get("apiKey"));
}; };
return ( return (
<header> <header>

View File

@@ -1,17 +1,40 @@
import React from "react"; 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<HTMLInputElement>) => {
setCity(event.target.value);
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
fetchWeather(city, apiKey);
};
const WeaatherCard: React.FC = () => {
return ( return (
<div> <div>
<h2>Weather Card</h2> <h2>Weather Card</h2>
<p>Current Weather will be displayed here</p> <p>Current Weather will be displayed here</p>
<form action="" method="post"> <form onSubmit={handleSubmit}>
<label htmlFor="city">Enter City:</label> <label htmlFor="city">Enter City:</label>
<input type="text" id="city" name="city" placeholder="City Name" /> <input
type="text"
id="city"
name="city"
onChange={handleCityChange}
value={city}
placeholder="City Name"
required
/>
<button type="submit">Get Weather</button> <button type="submit">Get Weather</button>
</form> </form>
</div> </div>
); );
}; };
export default WeaatherCard; export default WeatherCard;

View File

@@ -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");
};

View File

@@ -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);
};