108 lines
3.1 KiB
TypeScript
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,
|
|
});
|
|
}
|