diff --git a/frontend/components/dashboard/CitySidebar.tsx b/frontend/components/dashboard/CitySidebar.tsx index 4b5c440f..df198a28 100644 --- a/frontend/components/dashboard/CitySidebar.tsx +++ b/frontend/components/dashboard/CitySidebar.tsx @@ -1,20 +1,73 @@ "use client"; +import { useEffect, useMemo, useState } from "react"; import clsx from "clsx"; import { useDashboardStore } from "@/hooks/useDashboardStore"; import { useI18n } from "@/hooks/useI18n"; +import { CityListItem } from "@/lib/dashboard-types"; + +type RiskGroupKey = "high" | "medium" | "low" | "other"; + +function toRiskGroup(level?: string): RiskGroupKey { + if (level === "high" || level === "medium" || level === "low") return level; + return "other"; +} export function CitySidebar() { const store = useDashboardStore(); const { t } = useI18n(); - const sortedCities = [...store.cities].sort((a, b) => { - const order = { high: 0, medium: 1, low: 2 }; - return ( - (order[a.risk_level as keyof typeof order] ?? 3) - - (order[b.risk_level as keyof typeof order] ?? 3) - ); + const selectedCity = store.selectedCity; + const riskOrder = { high: 0, medium: 1, low: 2, other: 3 }; + const [expandedGroups, setExpandedGroups] = useState>({ + high: true, + medium: true, + low: false, + other: false, }); + const sortedCities = useMemo(() => [...store.cities].sort((a, b) => { + const aSelected = a.name === selectedCity; + const bSelected = b.name === selectedCity; + if (aSelected !== bSelected) return aSelected ? -1 : 1; + const aGroup = toRiskGroup(a.risk_level); + const bGroup = toRiskGroup(b.risk_level); + return ( + (riskOrder[aGroup] ?? 3) - + (riskOrder[bGroup] ?? 3) || + a.display_name.localeCompare(b.display_name) + ); + }), [store.cities, selectedCity]); + + const groupedCities = useMemo(() => { + const groups: Record = { + high: [], + medium: [], + low: [], + other: [], + }; + sortedCities.forEach((city) => { + groups[toRiskGroup(city.risk_level)].push(city); + }); + return groups; + }, [sortedCities]); + + useEffect(() => { + if (!selectedCity) return; + const selected = store.cities.find((city) => city.name === selectedCity); + if (!selected) return; + const groupKey = toRiskGroup(selected.risk_level); + setExpandedGroups((current) => + current[groupKey] ? current : { ...current, [groupKey]: true }, + ); + }, [selectedCity, store.cities]); + + const groupMeta: Array<{ key: RiskGroupKey; label: string }> = [ + { key: "high", label: t("sidebar.group.high") }, + { key: "medium", label: t("sidebar.group.medium") }, + { key: "low", label: t("sidebar.group.low") }, + { key: "other", label: t("sidebar.group.other") }, + ]; + return (