From 8448ea7985e5a1c693b5cda0a384e3ea1c455551 Mon Sep 17 00:00:00 2001 From: Nan Kyung Lee Date: Mon, 23 Mar 2026 11:12:11 +0900 Subject: [PATCH] =?UTF-8?q?fix(iran):=20=ED=95=B4=EC=99=B8=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=203=EB=8B=A8=EA=B3=84=20=EB=A0=88=EC=9D=B4=EC=96=B4?= =?UTF-8?q?=20=EB=B3=B5=EC=9B=90=20=E2=80=94=20overseasItems=20IIFE=20+=20?= =?UTF-8?q?count=20+=20=EC=9D=B4=EC=8A=A4=EB=9D=BC=EC=97=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 54 ++++++++++++++----- frontend/src/components/common/LayerPanel.tsx | 41 +++++++++++--- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index bdd8948..c5b36b6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next'; import LoginPage from './components/auth/LoginPage'; import CollectorMonitor from './components/common/CollectorMonitor'; import { FieldAnalysisModal } from './components/korea/FieldAnalysisModal'; +import { filterFacilities } from './data/meEnergyHazardFacilities'; // 정적 데이터 카운트용 import (이미 useStaticDeckLayers에서 번들 포함됨) import { EAST_ASIA_PORTS } from './data/ports'; import { KOREAN_AIRPORTS } from './services/airports'; @@ -83,7 +84,7 @@ function AuthenticatedApp({ user, onLogout }: AuthenticatedAppProps) { meFacilities: true, militaryOnly: false, overseasUS: false, - overseasUK: false, + overseasIsrael: false, overseasIran: false, overseasUAE: false, overseasSaudi: false, @@ -512,18 +513,45 @@ function AuthenticatedApp({ user, onLogout }: AuthenticatedAppProps) { { key: 'meFacilities', label: '주요시설/군사', color: '#ef4444', count: 35 }, { key: 'sensorCharts', label: t('layers.sensorCharts'), color: '#22c55e' }, ]} - overseasItems={[ - { key: 'overseasUS', label: '🇺🇸 미국', color: '#3b82f6' }, - { key: 'overseasUK', label: '🇬🇧 영국', color: '#dc2626' }, - { key: 'overseasIran', label: '🇮🇷 이란', color: '#22c55e' }, - { key: 'overseasUAE', label: '🇦🇪 UAE', color: '#f59e0b' }, - { key: 'overseasSaudi', label: '🇸🇦 사우디아라비아', color: '#84cc16' }, - { key: 'overseasOman', label: '🇴🇲 오만', color: '#e11d48' }, - { key: 'overseasQatar', label: '🇶🇦 카타르', color: '#8b5cf6' }, - { key: 'overseasKuwait', label: '🇰🇼 쿠웨이트', color: '#f97316' }, - { key: 'overseasIraq', label: '🇮🇶 이라크', color: '#65a30d' }, - { key: 'overseasBahrain', label: '🇧🇭 바레인', color: '#e11d48' }, - ]} + overseasItems={(() => { + const fc = (ck: string, st?: string) => filterFacilities(ck, st as never).length; + const energyChildren = (ck: string) => [ + { key: `${ck}Power`, label: '발전소', color: '#a855f7', count: fc(ck, 'power') }, + { key: `${ck}Wind`, label: '풍력단지', color: '#22d3ee', count: fc(ck, 'wind') }, + { key: `${ck}Nuclear`, label: '원자력발전소', color: '#f59e0b', count: fc(ck, 'nuclear') }, + { key: `${ck}Thermal`, label: '화력발전소', color: '#64748b', count: fc(ck, 'thermal') }, + ]; + const hazardChildren = (ck: string) => [ + { key: `${ck}Petrochem`, label: '석유화학단지', color: '#f97316', count: fc(ck, 'petrochem') }, + { key: `${ck}Lng`, label: 'LNG저장기지', color: '#0ea5e9', count: fc(ck, 'lng') }, + { key: `${ck}OilTank`, label: '유류저장탱크', color: '#eab308', count: fc(ck, 'oil_tank') }, + { key: `${ck}HazPort`, label: '위험물항만하역시설', color: '#dc2626', count: fc(ck, 'haz_port') }, + ]; + const fullCountry = (key: string, label: string, color: string, ck: string) => ({ + key, label, color, children: [ + { key: `${ck}Energy`, label: '에너지/발전시설', color: '#a855f7', children: energyChildren(ck) }, + { key: `${ck}Hazard`, label: '위험시설', color: '#ef4444', children: hazardChildren(ck) }, + ], + }); + const compactCountry = (key: string, label: string, color: string, ck: string) => ({ + key, label, color, children: [ + { key: `${ck}Energy`, label: '에너지/발전시설', color: '#a855f7', count: filterFacilities(ck).filter(f => f.category === 'energy').length }, + { key: `${ck}Hazard`, label: '위험시설', color: '#ef4444', count: filterFacilities(ck).filter(f => f.category === 'hazard').length }, + ], + }); + return [ + fullCountry('overseasUS', '🇺🇸 미국', '#3b82f6', 'us'), + fullCountry('overseasIsrael', '🇮🇱 이스라엘', '#0ea5e9', 'il'), + fullCountry('overseasIran', '🇮🇷 이란', '#22c55e', 'ir'), + fullCountry('overseasUAE', '🇦🇪 UAE', '#f59e0b', 'ae'), + fullCountry('overseasSaudi', '🇸🇦 사우디아라비아', '#84cc16', 'sa'), + compactCountry('overseasOman', '🇴🇲 오만', '#e11d48', 'om'), + compactCountry('overseasQatar', '🇶🇦 카타르', '#8b5cf6', 'qa'), + compactCountry('overseasKuwait', '🇰🇼 쿠웨이트', '#f97316', 'kw'), + compactCountry('overseasIraq', '🇮🇶 이라크', '#65a30d', 'iq'), + compactCountry('overseasBahrain', '🇧🇭 바레인', '#e11d48', 'bh'), + ]; + })()} hiddenAcCategories={hiddenAcCategories} hiddenShipCategories={hiddenShipCategories} onAcCategoryToggle={toggleAcCategory} diff --git a/frontend/src/components/common/LayerPanel.tsx b/frontend/src/components/common/LayerPanel.tsx index 0f4c3bf..f014358 100644 --- a/frontend/src/components/common/LayerPanel.tsx +++ b/frontend/src/components/common/LayerPanel.tsx @@ -129,6 +129,11 @@ interface OverseasItem { children?: OverseasItem[]; } +function countOverseasLeaves(item: OverseasItem): number { + if (!item.children?.length) return item.count ?? 0; + return item.children.reduce((sum, c) => sum + countOverseasLeaves(c), 0); +} + interface LayerPanelProps { layers: Record; onToggle: (key: string) => void; @@ -574,14 +579,34 @@ export function LayerPanel({ {item.children?.length && expanded.has(`overseas-${item.key}`) && (
{item.children.map(child => ( - onToggle(child.key)} - /> +
+ onToggle(child.key)} + onExpand={child.children?.length ? () => toggleExpand(`overseas-${child.key}`) : undefined} + /> + {child.children?.length && expanded.has(`overseas-${child.key}`) && ( +
+ {child.children.map(gc => ( + onToggle(gc.key)} + /> + ))} +
+ )} +
))}
)}