125 lines
5.5 KiB
TypeScript
125 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import { DEFAULT_STATION_NAME } from "@/lib/constants";
|
|
import { useWeatherStore } from "@/lib/store";
|
|
import { useWeatherStations } from "@/hooks/use-weather-stations";
|
|
import { WeatherHero } from "@/components/weather/weather-hero";
|
|
import { FavoritesSection } from "@/components/weather/favorites-section";
|
|
import { LocationSearch } from "@/components/weather/location-search";
|
|
import { FeaturedStationsSection } from "@/components/weather/featured-stations-section";
|
|
import { PageLoadingSkeleton } from "@/components/states/loading-skeleton";
|
|
import { ErrorState } from "@/components/states/error-state";
|
|
import { useI18n } from "@/lib/i18n";
|
|
import { useMeteoStationPositions } from "@/hooks/use-meteo-stations";
|
|
import { useCurrentWeather } from "@/hooks/use-current-weather";
|
|
import { useForecast } from "@/hooks/use-forecast";
|
|
import { ForecastPanel } from "@/components/forecast/forecast-panel";
|
|
import { getUpcomingHourlyForecast } from "@/lib/forecast-utils";
|
|
import { locateSynopStations } from "@/lib/location-utils";
|
|
import { DashboardWarnings } from "@/components/warnings/dashboard-warnings";
|
|
import { WeatherBriefCard } from "@/components/dashboard/weather-brief-card";
|
|
import type { SynopStation } from "@/types/imgw";
|
|
import {
|
|
normalizeDashboardSectionOrder,
|
|
normalizeDashboardSectionVisibility,
|
|
type DashboardSectionId,
|
|
} from "@/lib/dashboard-sections";
|
|
|
|
export function DashboardPage() {
|
|
const { t } = useI18n();
|
|
const { data: stations, isPending, isError, refetch } = useWeatherStations();
|
|
const { data: positions = [] } = useMeteoStationPositions();
|
|
const selectedStationId = useWeatherStore((state) => state.selectedStationId);
|
|
const selectedLocation = useWeatherStore((state) => state.selectedLocation);
|
|
const dashboardSections = normalizeDashboardSectionVisibility(useWeatherStore((state) => state.dashboardSections));
|
|
const dashboardSectionOrder = normalizeDashboardSectionOrder(useWeatherStore((state) => state.dashboardSectionOrder));
|
|
const selectedStation =
|
|
stations?.find((station) => station.id === selectedStationId) ??
|
|
stations?.find((station) => station.name === DEFAULT_STATION_NAME) ??
|
|
stations?.[0];
|
|
const activeLocation = selectedLocation;
|
|
const activeRegion = activeLocation?.region ?? "PL";
|
|
const stationPosition = selectedStation
|
|
? locateSynopStations(stations ?? [], positions).find((station) => station.id === selectedStation.id)
|
|
: null;
|
|
const hasActiveLocationCoordinates =
|
|
Number.isFinite(activeLocation?.latitude) && Number.isFinite(activeLocation?.longitude);
|
|
const forecastLatitude = hasActiveLocationCoordinates ? activeLocation?.latitude : stationPosition?.latitude;
|
|
const forecastLongitude = hasActiveLocationCoordinates ? activeLocation?.longitude : stationPosition?.longitude;
|
|
const forecastLocationName = hasActiveLocationCoordinates
|
|
? (activeLocation?.name ?? selectedStation?.name)
|
|
: selectedStation?.name;
|
|
const { data: currentWeather, isPending: isCurrentWeatherPending } = useCurrentWeather(
|
|
forecastLatitude,
|
|
forecastLongitude,
|
|
activeRegion,
|
|
);
|
|
const { data: forecast } = useForecast(forecastLatitude, forecastLongitude, activeRegion);
|
|
const currentForecastWeatherCode = forecast
|
|
? (getUpcomingHourlyForecast(forecast.hourly, 1)[0]?.weatherCode ?? null)
|
|
: null;
|
|
const isCurrentWeatherLoading =
|
|
Number.isFinite(forecastLatitude) && Number.isFinite(forecastLongitude) && isCurrentWeatherPending;
|
|
if (isPending) return <PageLoadingSkeleton />;
|
|
if (isError || !stations?.length || !selectedStation)
|
|
return <ErrorState onRetry={() => refetch()} description={t("dashboard.error")} />;
|
|
|
|
const heroStation: SynopStation =
|
|
activeLocation?.region === "GLOBAL"
|
|
? {
|
|
id: `global:${activeLocation.latitude},${activeLocation.longitude}`,
|
|
name: activeLocation.name,
|
|
measuredAt: null,
|
|
temperature: null,
|
|
windSpeed: null,
|
|
windDirection: null,
|
|
humidity: null,
|
|
rainfall: null,
|
|
pressure: null,
|
|
}
|
|
: selectedStation;
|
|
|
|
const renderDashboardSection = (sectionId: DashboardSectionId) => {
|
|
if (!dashboardSections[sectionId]) return null;
|
|
if (sectionId === "warnings") return <DashboardWarnings key={sectionId} />;
|
|
if (sectionId === "weatherBrief")
|
|
return (
|
|
<WeatherBriefCard
|
|
key={sectionId}
|
|
latitude={forecastLatitude}
|
|
longitude={forecastLongitude}
|
|
region={activeRegion}
|
|
locationName={forecastLocationName ?? selectedStation.name}
|
|
/>
|
|
);
|
|
if (sectionId === "forecast")
|
|
return (
|
|
<ForecastPanel
|
|
key={sectionId}
|
|
latitude={forecastLatitude}
|
|
longitude={forecastLongitude}
|
|
region={activeRegion}
|
|
locationName={forecastLocationName ?? selectedStation.name}
|
|
/>
|
|
);
|
|
if (sectionId === "favorites") return <FavoritesSection key={sectionId} stations={stations} />;
|
|
if (sectionId === "featuredStations") return <FeaturedStationsSection key={sectionId} stations={stations} />;
|
|
return null;
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-10">
|
|
<LocationSearch stations={stations} positions={positions} />
|
|
<WeatherHero
|
|
station={heroStation}
|
|
currentWeather={currentWeather}
|
|
currentWeatherLoading={isCurrentWeatherLoading}
|
|
currentForecastWeatherCode={currentForecastWeatherCode}
|
|
locationName={activeLocation?.name}
|
|
distanceKm={activeLocation?.distanceKm}
|
|
/>
|
|
{dashboardSectionOrder.map(renderDashboardSection)}
|
|
</div>
|
|
);
|
|
}
|