58 lines
3.2 KiB
TypeScript
58 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { ArrowLeft, Heart, ShieldCheck } from "lucide-react";
|
|
import { useWeatherStation } from "@/hooks/use-weather-stations";
|
|
import { useWeatherStore } from "@/lib/store";
|
|
import { formatDateTime } from "@/lib/weather-utils";
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card } from "@/components/ui/card";
|
|
import { WeatherHero } from "@/components/weather/weather-hero";
|
|
import { WeatherDetailsGrid } from "@/components/weather/current-conditions-card";
|
|
import { SnapshotChart } from "@/components/charts/snapshot-chart";
|
|
import { PageLoadingSkeleton } from "@/components/states/loading-skeleton";
|
|
import { ErrorState } from "@/components/states/error-state";
|
|
import { useI18n } from "@/lib/i18n";
|
|
|
|
export function StationDetailPage({ id }: { id: string }) {
|
|
const { language, t } = useI18n();
|
|
const { data: station, isPending, isError, refetch } = useWeatherStation(id);
|
|
const favoriteIds = useWeatherStore((state) => state.favorites);
|
|
const toggleFavorite = useWeatherStore((state) => state.toggleFavorite);
|
|
if (isPending) return <PageLoadingSkeleton />;
|
|
if (isError || !station) return <ErrorState onRetry={() => refetch()} description={t("station.error")} />;
|
|
const favorite = favoriteIds.includes(station.id);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
<Link href="/" className="inline-flex items-center gap-2 rounded-control px-1 py-1 text-sm font-medium text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"><ArrowLeft className="size-4" />{t("station.all")}</Link>
|
|
<Button variant="glass" onClick={() => toggleFavorite(station.id)}>
|
|
<Heart className={cn("size-4", favorite && "fill-rose-500 text-rose-500")} />
|
|
{favorite ? t("favorites.remove") : t("favorites.add")}
|
|
</Button>
|
|
</div>
|
|
<WeatherHero station={station} />
|
|
<section>
|
|
<p className="section-kicker">{t("station.label", { name: station.name })}</p>
|
|
<h1 className="mt-2 text-2xl font-semibold tracking-tight">{t("station.parameters")}</h1>
|
|
<p className="mb-4 mt-1 text-sm leading-6 text-muted">{t("station.parametersDescription")}</p>
|
|
<WeatherDetailsGrid station={station} />
|
|
</section>
|
|
<div className="grid gap-4 lg:grid-cols-[1.3fr_0.7fr]">
|
|
<SnapshotChart station={station} />
|
|
<Card className="p-5">
|
|
<div className="section-kicker flex items-center gap-2"><ShieldCheck className="size-5" /><p>{t("station.quality")}</p></div>
|
|
<h2 className="mt-4 text-xl font-semibold tracking-tight">{t("station.lastMeasurementImgw")}</h2>
|
|
<p className="mt-2 text-sm leading-6 text-muted">{t("station.qualityDescription")}</p>
|
|
<dl className="mt-6 space-y-3 text-sm">
|
|
<div><dt className="text-muted">{t("station.lastMeasurement")}</dt><dd className="mt-0.5 font-medium">{formatDateTime(station.measuredAt, language)}</dd></div>
|
|
<div><dt className="text-muted">{t("station.source")}</dt><dd className="mt-0.5 font-medium">{t("station.publicApi")}</dd></div>
|
|
</dl>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|