finished meteorologia and main dashboard

This commit is contained in:
litoral05
2026-05-25 16:37:00 +01:00
parent b1bcf44f0f
commit d7ef36fc53
16 changed files with 2202 additions and 1167 deletions
@@ -0,0 +1,99 @@
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,
};
}