add weather module

This commit is contained in:
2025-08-29 13:15:38 +02:00
parent b27be08b87
commit 69f46059e0
12 changed files with 527 additions and 9 deletions

389
src/store/weather.ts Normal file
View File

@@ -0,0 +1,389 @@
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import fetchWeatherData from "@/api/weather";
const iconNumberToPng = {
"0": {
day: {
description: "Sunny",
image: "http://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Clear",
image: "http://openweathermap.org/img/wn/01n@2x.png",
},
},
"1": {
day: {
description: "Mainly Sunny",
image: "http://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Mainly Clear",
image: "http://openweathermap.org/img/wn/01n@2x.png",
},
},
"2": {
day: {
description: "Partly Cloudy",
image: "http://openweathermap.org/img/wn/02d@2x.png",
},
night: {
description: "Partly Cloudy",
image: "http://openweathermap.org/img/wn/02n@2x.png",
},
},
"3": {
day: {
description: "Cloudy",
image: "http://openweathermap.org/img/wn/03d@2x.png",
},
night: {
description: "Cloudy",
image: "http://openweathermap.org/img/wn/03n@2x.png",
},
},
"45": {
day: {
description: "Foggy",
image: "http://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Foggy",
image: "http://openweathermap.org/img/wn/50n@2x.png",
},
},
"48": {
day: {
description: "Rime Fog",
image: "http://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Rime Fog",
image: "http://openweathermap.org/img/wn/50n@2x.png",
},
},
"51": {
day: {
description: "Light Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"53": {
day: {
description: "Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"55": {
day: {
description: "Heavy Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"56": {
day: {
description: "Light Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"57": {
day: {
description: "Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"61": {
day: {
description: "Light Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"63": {
day: {
description: "Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"65": {
day: {
description: "Heavy Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Heavy Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"66": {
day: {
description: "Light Freezing Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Freezing Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"67": {
day: {
description: "Freezing Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Freezing Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"71": {
day: {
description: "Light Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"73": {
day: {
description: "Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"75": {
day: {
description: "Heavy Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Heavy Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"77": {
day: {
description: "Snow Grains",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Grains",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"80": {
day: {
description: "Light Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"81": {
day: {
description: "Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"82": {
day: {
description: "Heavy Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"85": {
day: {
description: "Light Snow Showers",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow Showers",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"86": {
day: {
description: "Snow Showers",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Showers",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"95": {
day: {
description: "Thunderstorm",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
"96": {
day: {
description: "Light Thunderstorms With Hail",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Light Thunderstorms With Hail",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
"99": {
day: {
description: "Thunderstorm With Hail",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm With Hail",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
};
const useWeatherStore = create(
devtools(
(set) => ({
weatherData: {},
fetchWeatherData: async () => {
const data = await fetchWeatherData();
// Process first location. Add a for-loop for multiple locations or weather models
const response = data[0];
if (response === null) {
console.error("Failed to fetch weather data");
return;
}
// Attributes for timezone and location
const utcOffsetSeconds = response.utcOffsetSeconds();
const current = response.current();
const hourly = response.hourly();
const daily = response.daily();
if (!current || !hourly || !daily) {
console.error("Failed to fetch weather data");
return;
}
// Note: The order of weather variables in the URL query and the indices below need to match!
const weatherData = {
current: {
time: current.time(),
temperature_2m: current.variables(0)?.value(),
precipitation: current.variables(1)?.value(),
rain: current.variables(2)?.value(),
showers: current.variables(3)?.value(),
snowfall: current.variables(4)?.value(),
relative_humidity_2m: current.variables(5)?.value(),
apparent_temperature: current.variables(6)?.value(),
weather_code: current.variables(7)?.value(),
cloud_cover: current.variables(8)?.value(),
is_day: current.variables(9)?.value(),
},
hourly: {
time: [
...Array(
(Number(hourly.timeEnd()) -
Number(hourly.time())) /
hourly.interval(),
),
].map(
(_, i) =>
new Date(
(Number(hourly.time()) +
i * hourly.interval() +
utcOffsetSeconds) *
1000,
),
),
temperature_2m: hourly.variables(0)?.valuesArray(),
precipitation: hourly.variables(1)?.valuesArray(),
rain: hourly.variables(2)?.valuesArray(),
precipitation_probability: hourly
.variables(3)
?.valuesArray(),
},
daily: {
time: [
...Array(
(Number(daily.timeEnd()) -
Number(daily.time())) /
daily.interval(),
),
].map(
(_, i) =>
new Date(
(Number(daily.time()) +
i * daily.interval() +
utcOffsetSeconds) *
1000,
),
),
temperature_2m_max: daily.variables(0)?.valuesArray(),
temperature_2m_min: daily.variables(1)?.valuesArray(),
},
};
const isDay = weatherData.current.is_day === 1;
const weatherCode = weatherData.current.weather_code;
const url =
iconNumberToPng[weatherCode][isDay ? "day" : "night"].image;
weatherData.current = { ...weatherData.current, icon: url };
set({ weatherData });
},
}),
{
name: "weather-store",
},
),
);
export { useWeatherStore };