SkateSpots/src/hooks/useSpotWeather.ts
2026-08-27 10:17:01 +07:00

108 lines
3.1 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import ngeohash from 'ngeohash';
import {
fetchWeather,
fetchAirQuality,
fetchWeatherForecast,
calculateSkateability,
type WeatherData,
type AirQualityData,
type WeatherForecast,
type SkateabilityScore,
} from '@/lib/weather';
export interface SpotWeatherData {
weather: WeatherData;
airQuality?: AirQualityData;
forecast?: WeatherForecast;
skateability: SkateabilityScore;
}
/**
* Fetch weather data for a single spot by geohash
*/
export function useSpotWeather(geohash: string | undefined, enabled: boolean = true) {
return useQuery({
queryKey: ['spot-weather', geohash],
queryFn: async () => {
if (!geohash) throw new Error('Geohash is required');
const { latitude, longitude } = ngeohash.decode(geohash);
// Fetch weather and air quality in parallel
const [weather, airQuality, forecast] = await Promise.all([
fetchWeather(latitude, longitude),
fetchAirQuality(latitude, longitude).catch(() => undefined), // Air quality might not be available everywhere
fetchWeatherForecast(latitude, longitude).catch(() => undefined),
]);
const skateability = calculateSkateability(weather, airQuality);
return {
weather,
airQuality,
forecast,
skateability,
} as SpotWeatherData;
},
enabled: enabled && !!geohash,
staleTime: 10 * 60 * 1000, // 10 minutes
gcTime: 30 * 60 * 1000, // 30 minutes
});
}
/**
* Fetch weather data for multiple spots
* Returns a map of geohash -> weather data
*/
export function useMultipleSpotWeather(geohashes: string[], enabled: boolean = true) {
return useQuery({
queryKey: ['multiple-spot-weather', geohashes.sort().join(',')],
queryFn: async () => {
// Deduplicate geohashes to avoid fetching the same location multiple times
const uniqueGeohashes = [...new Set(geohashes)];
// Fetch weather for all spots in parallel
const weatherDataPromises = uniqueGeohashes.map(async (geohash) => {
try {
const { latitude, longitude } = ngeohash.decode(geohash);
const [weather, airQuality] = await Promise.all([
fetchWeather(latitude, longitude),
fetchAirQuality(latitude, longitude).catch(() => undefined),
]);
const skateability = calculateSkateability(weather, airQuality);
return {
geohash,
data: {
weather,
airQuality,
skateability,
} as SpotWeatherData,
};
} catch (error) {
console.error(`Failed to fetch weather for ${geohash}:`, error);
return null;
}
});
const results = await Promise.all(weatherDataPromises);
// Convert array to map
const weatherMap = new Map<string, SpotWeatherData>();
results.forEach((result) => {
if (result) {
weatherMap.set(result.geohash, result.data);
}
});
return weatherMap;
},
enabled: enabled && geohashes.length > 0,
staleTime: 10 * 60 * 1000, // 10 minutes
gcTime: 30 * 60 * 1000, // 30 minutes
retry: 2,
});
}