"use client"; import { useEffect, useMemo, useState } from "react"; import { AlertTriangle, Bot, Globe2, Languages, Radar, Signal, Waves, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { CityDetailPanel } from "@/components/city-detail-panel"; import { CityList } from "@/components/city-list"; import { MapView } from "@/components/map-view"; import { getCities, getCityDetail } from "@/lib/api"; import { copy, type Locale } from "@/lib/i18n"; import type { CityDetail, CitySummary } from "@/lib/types"; export function PolyWeatherDashboard() { const [locale, setLocale] = useState("zh"); const [cities, setCities] = useState([]); const [selectedCity, setSelectedCity] = useState(null); const [selectedDetail, setSelectedDetail] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const t = copy[locale]; useEffect(() => { let mounted = true; (async () => { try { setError(null); const data = await getCities(); if (!mounted) return; setCities(data); } catch (err) { if (!mounted) return; setError(String(err)); } })(); return () => { mounted = false; }; }, []); useEffect(() => { if (!selectedCity) return; let mounted = true; (async () => { try { setLoading(true); setError(null); const detail = await getCityDetail(selectedCity); if (!mounted) return; setSelectedDetail(detail); } catch (err) { if (!mounted) return; setError(String(err)); } finally { if (mounted) setLoading(false); } })(); return () => { mounted = false; }; }, [selectedCity]); const orderedCities = useMemo(() => { const order = { high: 0, medium: 1, low: 2 }; return [...cities].sort( (a, b) => (order[a.risk_level] ?? 99) - (order[b.risk_level] ?? 99), ); }, [cities]); const riskStats = useMemo(() => { return { high: cities.filter((c) => c.risk_level === "high").length, medium: cities.filter((c) => c.risk_level === "medium").length, low: cities.filter((c) => c.risk_level === "low").length, }; }, [cities]); async function refreshCurrentCity() { if (!selectedCity) return; setLoading(true); try { const detail = await getCityDetail(selectedCity, true); setSelectedDetail(detail); } catch (err) { setError(String(err)); } finally { setLoading(false); } } function localizeError(raw: string) { if (raw.includes("POLYWEATHER_API_BASE_URL")) { return t.backendConfigMissing; } if (raw.toLowerCase().includes("failed to load cities")) { return `${t.loadCitiesFailed}: ${raw}`; } if (raw.toLowerCase().includes("failed to load city detail")) { return `${t.loadCityDetailFailed}: ${raw}`; } return raw; } return (

PolyWeather

{t.brandSubtitle}
{t.live}
H {riskStats.high}
M {riskStats.medium}
L {riskStats.low}
{cities.length} {t.cities}
AI + DEB
{error ? (
{localizeError(error)}
) : null}
); }