99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import type { WeatherForecastResponse } from "../../../types/weather";
|
|
|
|
const BACKEND_URL = "http://localhost:18450";
|
|
|
|
type LocationState = {
|
|
latitude: number;
|
|
longitude: number;
|
|
};
|
|
|
|
export function useWeatherForecast() {
|
|
const [forecast, setForecast] = useState<WeatherForecastResponse | null>(null);
|
|
const [location, setLocation] = useState<LocationState | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!navigator.geolocation) {
|
|
setError("Geolocalização não suportada.");
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
(position) => {
|
|
setLocation({
|
|
latitude: position.coords.latitude,
|
|
longitude: position.coords.longitude,
|
|
});
|
|
},
|
|
() => {
|
|
// Fallback Leiria
|
|
setLocation({
|
|
latitude: 39.75,
|
|
longitude: -8.8,
|
|
});
|
|
},
|
|
{
|
|
enableHighAccuracy: false,
|
|
timeout: 8000,
|
|
maximumAge: 1000 * 60 * 60 * 12,
|
|
},
|
|
);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!location) return;
|
|
|
|
const latitude = location.latitude;
|
|
const longitude = location.longitude;
|
|
|
|
const controller = new AbortController();
|
|
|
|
async function loadForecast() {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
const params = new URLSearchParams({
|
|
lat: String(latitude),
|
|
lon: String(longitude),
|
|
days: "7",
|
|
});
|
|
|
|
const response = await fetch(
|
|
`${BACKEND_URL}/api/weather/forecast?${params.toString()}`,
|
|
{ signal: controller.signal },
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to load weather forecast");
|
|
}
|
|
|
|
const payload = (await response.json()) as WeatherForecastResponse;
|
|
setForecast(payload);
|
|
} catch (error) {
|
|
if (controller.signal.aborted) return;
|
|
|
|
console.error("Failed to load weather forecast", error);
|
|
setError("Não foi possível carregar a previsão meteorológica.");
|
|
setForecast(null);
|
|
} finally {
|
|
if (!controller.signal.aborted) {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
loadForecast();
|
|
|
|
return () => controller.abort();
|
|
}, [location]);
|
|
|
|
return {
|
|
forecast,
|
|
loading,
|
|
error,
|
|
};
|
|
} |