feat: prioritize warnings for selected province
This commit is contained in:
@@ -1,17 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { Map, MapPinned } from "lucide-react";
|
||||
import { useWarnings } from "@/hooks/use-warnings";
|
||||
import { WarningCard } from "@/components/warnings/warning-card";
|
||||
import { PageLoadingSkeleton } from "@/components/states/loading-skeleton";
|
||||
import { EmptyState } from "@/components/states/empty-state";
|
||||
import { ErrorState } from "@/components/states/error-state";
|
||||
import { DEFAULT_STATION_ID } from "@/lib/constants";
|
||||
import { useI18n } from "@/lib/i18n";
|
||||
import { formatProvinceName, getProvinceForStation, normalizeProvinceName } from "@/lib/provinces";
|
||||
import { useWeatherStore } from "@/lib/store";
|
||||
import type { WeatherWarning } from "@/types/imgw";
|
||||
|
||||
function WarningGrid({ warnings, indexOffset = 0 }: { warnings: WeatherWarning[]; indexOffset?: number }) {
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{warnings.map((warning, index) => <WarningCard key={warning.id} warning={warning} index={index + indexOffset} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function WarningsPanel() {
|
||||
const { t } = useI18n();
|
||||
const { language, t } = useI18n();
|
||||
const { data: warnings, isPending, isError, refetch } = useWarnings();
|
||||
const selectedStationId = useWeatherStore((state) => state.selectedStationId);
|
||||
const selectedLocation = useWeatherStore((state) => state.selectedLocation);
|
||||
if (isPending) return <PageLoadingSkeleton />;
|
||||
if (isError) return <ErrorState onRetry={() => refetch()} description={t("warnings.error")} />;
|
||||
if (!warnings?.length) return <EmptyState title={t("warnings.emptyTitle")} description={t("warnings.emptyDescription")} />;
|
||||
return <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">{warnings.map((warning, index) => <WarningCard key={warning.id} warning={warning} index={index} />)}</div>;
|
||||
|
||||
const province = normalizeProvinceName(selectedLocation?.province)
|
||||
?? getProvinceForStation(selectedStationId ?? DEFAULT_STATION_ID);
|
||||
if (!province) return <WarningGrid warnings={warnings} />;
|
||||
|
||||
const provinceLabel = formatProvinceName(province, language);
|
||||
const localWarnings = warnings.filter((warning) => warning.provinces.includes(province));
|
||||
const otherWarnings = warnings.filter((warning) => !warning.provinces.includes(province));
|
||||
|
||||
return (
|
||||
<div className="space-y-9">
|
||||
<section className="space-y-4">
|
||||
<div>
|
||||
<p className="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-sky-700 dark:text-sky-300"><MapPinned className="size-4" />{t("warnings.myProvince")}</p>
|
||||
<h2 className="mt-2 text-2xl font-semibold capitalize tracking-tight">{provinceLabel}</h2>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-6 text-slate-600 dark:text-slate-300">{t("warnings.myProvinceDescription", { province: provinceLabel })}</p>
|
||||
</div>
|
||||
{localWarnings.length
|
||||
? <WarningGrid warnings={localWarnings} />
|
||||
: <EmptyState title={t("warnings.myProvinceEmptyTitle")} description={t("warnings.myProvinceEmptyDescription", { province: provinceLabel })} />}
|
||||
</section>
|
||||
|
||||
{otherWarnings.length > 0 && (
|
||||
<section className="space-y-4">
|
||||
<div>
|
||||
<p className="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400"><Map className="size-4" />{t("warnings.otherRegions")}</p>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-6 text-slate-600 dark:text-slate-300">{t("warnings.otherRegionsDescription")}</p>
|
||||
</div>
|
||||
<WarningGrid warnings={otherWarnings} indexOffset={localWarnings.length} />
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user