chore: add prettier formatting
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m56s
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m56s
This commit is contained in:
@@ -27,44 +27,78 @@ export function DashboardPage() {
|
||||
const selectedStationId = useWeatherStore((state) => state.selectedStationId);
|
||||
const selectedLocation = useWeatherStore((state) => state.selectedLocation);
|
||||
const dashboardSections = useWeatherStore((state) => state.dashboardSections);
|
||||
const selectedStation = stations?.find((station) => station.id === selectedStationId)
|
||||
?? stations?.find((station) => station.name === DEFAULT_STATION_NAME)
|
||||
?? stations?.[0];
|
||||
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 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 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;
|
||||
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")} />;
|
||||
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 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;
|
||||
|
||||
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} />
|
||||
<WeatherHero
|
||||
station={heroStation}
|
||||
currentWeather={currentWeather}
|
||||
currentWeatherLoading={isCurrentWeatherLoading}
|
||||
currentForecastWeatherCode={currentForecastWeatherCode}
|
||||
locationName={activeLocation?.name}
|
||||
distanceKm={activeLocation?.distanceKm}
|
||||
/>
|
||||
<DashboardWarnings />
|
||||
{dashboardSections.weatherBrief && <WeatherBriefCard latitude={forecastLatitude} longitude={forecastLongitude} region={activeRegion} locationName={forecastLocationName ?? selectedStation.name} />}
|
||||
<ForecastPanel latitude={forecastLatitude} longitude={forecastLongitude} region={activeRegion} locationName={forecastLocationName ?? selectedStation.name} />
|
||||
{dashboardSections.weatherBrief && (
|
||||
<WeatherBriefCard
|
||||
latitude={forecastLatitude}
|
||||
longitude={forecastLongitude}
|
||||
region={activeRegion}
|
||||
locationName={forecastLocationName ?? selectedStation.name}
|
||||
/>
|
||||
)}
|
||||
<ForecastPanel
|
||||
latitude={forecastLatitude}
|
||||
longitude={forecastLongitude}
|
||||
region={activeRegion}
|
||||
locationName={forecastLocationName ?? selectedStation.name}
|
||||
/>
|
||||
<FavoritesSection stations={stations} />
|
||||
{dashboardSections.featuredStations && <FeaturedStationsSection stations={stations} />}
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,17 @@ import { useWeatherStore } from "@/lib/store";
|
||||
import { buildTomorrowWeatherBrief, buildWeatherBrief } from "@/lib/weather-brief";
|
||||
import type { WeatherRegion } from "@/types/weather-region";
|
||||
|
||||
export function WeatherBriefCard({ latitude, longitude, region = "PL", locationName }: { latitude?: number; longitude?: number; region?: WeatherRegion; locationName: string }) {
|
||||
export function WeatherBriefCard({
|
||||
latitude,
|
||||
longitude,
|
||||
region = "PL",
|
||||
locationName,
|
||||
}: {
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
region?: WeatherRegion;
|
||||
locationName: string;
|
||||
}) {
|
||||
const { language, t } = useI18n();
|
||||
const { data: forecast, isPending, isError, refetch } = useForecast(latitude, longitude, region);
|
||||
const { data: warnings = [] } = useWarnings();
|
||||
@@ -24,17 +34,57 @@ export function WeatherBriefCard({ latitude, longitude, region = "PL", locationN
|
||||
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
||||
const windSpeedUnit = useWeatherStore((state) => state.windSpeedUnit);
|
||||
const isGlobalLocation = region === "GLOBAL";
|
||||
const province = isGlobalLocation ? null : getProvinceForSelection(selectedLocation?.province, selectedStationId ?? DEFAULT_STATION_ID);
|
||||
const relevantWarnings = useMemo(() => isGlobalLocation ? [] : warnings, [isGlobalLocation, warnings]);
|
||||
const province = isGlobalLocation
|
||||
? null
|
||||
: getProvinceForSelection(selectedLocation?.province, selectedStationId ?? DEFAULT_STATION_ID);
|
||||
const relevantWarnings = useMemo(() => (isGlobalLocation ? [] : warnings), [isGlobalLocation, warnings]);
|
||||
|
||||
const brief = useMemo(() => {
|
||||
if (!forecast) return null;
|
||||
return buildWeatherBrief({ forecast, warnings: relevantWarnings, province, countyTeryt: isGlobalLocation ? null : selectedLocation?.countyTeryt, locationName, language, temperatureUnit, windSpeedUnit });
|
||||
}, [forecast, isGlobalLocation, language, locationName, province, relevantWarnings, selectedLocation?.countyTeryt, temperatureUnit, windSpeedUnit]);
|
||||
return buildWeatherBrief({
|
||||
forecast,
|
||||
warnings: relevantWarnings,
|
||||
province,
|
||||
countyTeryt: isGlobalLocation ? null : selectedLocation?.countyTeryt,
|
||||
locationName,
|
||||
language,
|
||||
temperatureUnit,
|
||||
windSpeedUnit,
|
||||
});
|
||||
}, [
|
||||
forecast,
|
||||
isGlobalLocation,
|
||||
language,
|
||||
locationName,
|
||||
province,
|
||||
relevantWarnings,
|
||||
selectedLocation?.countyTeryt,
|
||||
temperatureUnit,
|
||||
windSpeedUnit,
|
||||
]);
|
||||
const tomorrowBrief = useMemo(() => {
|
||||
if (!forecast) return null;
|
||||
return buildTomorrowWeatherBrief({ forecast, warnings: relevantWarnings, province, countyTeryt: isGlobalLocation ? null : selectedLocation?.countyTeryt, locationName, language, temperatureUnit, windSpeedUnit });
|
||||
}, [forecast, isGlobalLocation, language, locationName, province, relevantWarnings, selectedLocation?.countyTeryt, temperatureUnit, windSpeedUnit]);
|
||||
return buildTomorrowWeatherBrief({
|
||||
forecast,
|
||||
warnings: relevantWarnings,
|
||||
province,
|
||||
countyTeryt: isGlobalLocation ? null : selectedLocation?.countyTeryt,
|
||||
locationName,
|
||||
language,
|
||||
temperatureUnit,
|
||||
windSpeedUnit,
|
||||
});
|
||||
}, [
|
||||
forecast,
|
||||
isGlobalLocation,
|
||||
language,
|
||||
locationName,
|
||||
province,
|
||||
relevantWarnings,
|
||||
selectedLocation?.countyTeryt,
|
||||
temperatureUnit,
|
||||
windSpeedUnit,
|
||||
]);
|
||||
|
||||
if (!Number.isFinite(latitude) || !Number.isFinite(longitude) || isPending) {
|
||||
return <LoadingSkeleton className="h-48" />;
|
||||
@@ -61,11 +111,25 @@ export function WeatherBriefCard({ latitude, longitude, region = "PL", locationN
|
||||
return (
|
||||
<Card className="p-4 sm:p-5">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={isWarning ? "rounded-control border border-warning/30 bg-warning/10 p-2 text-warning" : "rounded-control border border-border/70 bg-surface-muted/70 p-2 text-accent"}>
|
||||
{isWarning ? <AlertTriangle className="size-4" aria-hidden="true" /> : <CloudSun className="size-4" aria-hidden="true" />}
|
||||
<div
|
||||
className={
|
||||
isWarning
|
||||
? "rounded-control border border-warning/30 bg-warning/10 p-2 text-warning"
|
||||
: "rounded-control border border-border/70 bg-surface-muted/70 p-2 text-accent"
|
||||
}
|
||||
>
|
||||
{isWarning ? (
|
||||
<AlertTriangle className="size-4" aria-hidden="true" />
|
||||
) : (
|
||||
<CloudSun className="size-4" aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className={isWarning ? "text-[0.68rem] font-semibold uppercase tracking-[0.16em] text-warning" : "section-kicker"}>
|
||||
<p
|
||||
className={
|
||||
isWarning ? "text-[0.68rem] font-semibold uppercase tracking-[0.16em] text-warning" : "section-kicker"
|
||||
}
|
||||
>
|
||||
{t("brief.label")}
|
||||
</p>
|
||||
<h2 className="mt-1 text-lg font-semibold tracking-tight">{brief.headline}</h2>
|
||||
@@ -75,7 +139,10 @@ export function WeatherBriefCard({ latitude, longitude, region = "PL", locationN
|
||||
|
||||
<ul className="mt-4 space-y-2">
|
||||
{brief.body.slice(0, 4).map((line) => (
|
||||
<li key={line} className="rounded-card border border-border/60 bg-surface-muted/45 px-3 py-2 text-sm leading-6">
|
||||
<li
|
||||
key={line}
|
||||
className="rounded-card border border-border/60 bg-surface-muted/45 px-3 py-2 text-sm leading-6"
|
||||
>
|
||||
{line}
|
||||
</li>
|
||||
))}
|
||||
@@ -87,7 +154,10 @@ export function WeatherBriefCard({ latitude, longitude, region = "PL", locationN
|
||||
<h3 className="mt-1 text-sm font-semibold">{tomorrowBrief.headline}</h3>
|
||||
<ul className="mt-3 space-y-2">
|
||||
{tomorrowBrief.body.slice(0, 3).map((line) => (
|
||||
<li key={line} className="rounded-card border border-border/60 bg-surface-muted/45 px-3 py-2 text-sm leading-6">
|
||||
<li
|
||||
key={line}
|
||||
className="rounded-card border border-border/60 bg-surface-muted/45 px-3 py-2 text-sm leading-6"
|
||||
>
|
||||
{line}
|
||||
</li>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user