2025-11-17 17:54:32 +08:00
|
|
|
import { create } from 'zustand'
|
|
|
|
|
import {persist} from 'zustand/middleware'
|
|
|
|
|
const CACHE_EXPIRY = 10 * 60 * 1000;
|
|
|
|
|
|
|
|
|
|
export interface Location {
|
|
|
|
|
name: string;
|
|
|
|
|
country: string;
|
|
|
|
|
region: string;
|
|
|
|
|
lat: string;
|
|
|
|
|
lon: string;
|
|
|
|
|
timezone_id: string
|
|
|
|
|
localtime: string;
|
|
|
|
|
localtime_epoch: number;
|
|
|
|
|
utc_offset: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface Current {
|
|
|
|
|
observation_time: string;
|
|
|
|
|
temperature: number;
|
|
|
|
|
weather_code: number;
|
|
|
|
|
weather_icons: string[];
|
|
|
|
|
weather_descriptions: string[];
|
|
|
|
|
wind_speed: number;
|
|
|
|
|
wind_degree: number;
|
|
|
|
|
wind_dir: string;
|
|
|
|
|
pressure: number;
|
|
|
|
|
precip: number;
|
|
|
|
|
humidity: number;
|
|
|
|
|
cloudcover: number;
|
|
|
|
|
feelslike: number;
|
|
|
|
|
uv_index: number;
|
|
|
|
|
visibility: number;
|
|
|
|
|
is_day: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface WeatherData {
|
|
|
|
|
request?: {
|
|
|
|
|
type: string;
|
|
|
|
|
query: string;
|
|
|
|
|
language: string;
|
|
|
|
|
unit: string;
|
|
|
|
|
};
|
|
|
|
|
location: Location;
|
|
|
|
|
current: Current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface WeatherCache {
|
|
|
|
|
data: WeatherData;
|
|
|
|
|
timestamp: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export interface WeatherStore {
|
|
|
|
|
|
|
|
|
|
currentWeather: WeatherData | null;
|
|
|
|
|
weatherCache: Map<string, WeatherCache>;
|
|
|
|
|
isLoading: boolean;
|
|
|
|
|
error: string | null;
|
|
|
|
|
|
|
|
|
|
// Actions
|
|
|
|
|
setCurrentWeather: (weather: WeatherData | null) => void;
|
|
|
|
|
getWeatherFromCache: (city: string) => WeatherData | null;
|
|
|
|
|
cacheWeather: (city: string, weather: WeatherData) => void;
|
|
|
|
|
setLoading: (loading: boolean) => void;
|
|
|
|
|
setError: (error: string | null) => void;
|
|
|
|
|
reset: () => void;
|
|
|
|
|
|
|
|
|
|
// API Actions
|
|
|
|
|
searchWeather: (city: string) => Promise<void>;
|
|
|
|
|
refreshWeather: () => Promise<void>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const useWeatherStore = create<WeatherStore>()(persist((set,get)=>({currentWeather:null,weatherCache:new Map(),isLoading:false,error:null,
|
|
|
|
|
setCurrentWeather:(weather)=>set({currentWeather:weather}),
|
|
|
|
|
getWeatherFromCache:(city)=>{
|
|
|
|
|
const cashe = get().weatherCache.get(city.toLowerCase());
|
|
|
|
|
if(!cashe)return null;
|
|
|
|
|
const isExpired = Date.now()-cashe.timestamp>CACHE_EXPIRY;
|
|
|
|
|
return isExpired?null:cashe.data;
|
|
|
|
|
},
|
|
|
|
|
cacheWeather:(city,weather)=>set((state)=>{
|
|
|
|
|
const newCache = new Map(state.weatherCache);
|
|
|
|
|
newCache.set(city.toLowerCase(),{data:weather,timestamp:Date.now()});
|
|
|
|
|
return{weatherCache:newCache}
|
|
|
|
|
}),
|
|
|
|
|
setLoading:(loading)=>set({error})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|