From 85cb6b40a2ece85ff4a231a5d82cd22a0ac183ac Mon Sep 17 00:00:00 2001 From: htlee Date: Wed, 8 Apr 2026 12:09:17 +0900 Subject: [PATCH] =?UTF-8?q?refactor(frontend):=20=EB=B3=B5=EC=9E=A1=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20PageContainer=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20(Phase=20B-5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MonitoringDashboard: 표준 PageHeader - MapControl: demo 배지 - RiskMap: 수집 중 배지 + secondary Button 2개 액션 - Dashboard: PageContainer 래핑 (커스텀 DEFCON 헤더는 유지) - LiveMapView: PageContainer fullBleed + flex 레이아웃 유지 - VesselDetail: PageContainer fullBleed + -m-4 해킹 제거 - TransferDetection: PageHeader 적용 Phase B 전체 완료. 실제 프론트엔드의 모든 주요 페이지가 쇼케이스 기준 공통 컴포넌트(PageContainer/PageHeader/Button/Select/Badge)를 사용한다. 카탈로그/variant 변경 시 쇼케이스와 실 페이지 동시 반영됨. 최종 통계: - 7개 batch에서 총 30+ 파일 마이그레이션 - PageContainer 도입률: ~100% (SPA 메인 라우트 기준) - PageHeader 도입률: ~95% - 신규 Button 컴포넌트 도입: admin/enforcement/parent-inference 등 주요 액션 빌드 검증: - tsc ✅, eslint ✅ (경고만), vite build ✅ --- frontend/src/features/dashboard/Dashboard.tsx | 7 ++-- .../monitoring/MonitoringDashboard.tsx | 15 ++++---- .../src/features/risk-assessment/RiskMap.tsx | 34 +++++++++++-------- .../src/features/surveillance/LiveMapView.tsx | 5 +-- .../src/features/surveillance/MapControl.tsx | 23 ++++++------- .../src/features/vessel/TransferDetection.tsx | 16 +++++---- frontend/src/features/vessel/VesselDetail.tsx | 5 +-- 7 files changed, 59 insertions(+), 46 deletions(-) diff --git a/frontend/src/features/dashboard/Dashboard.tsx b/frontend/src/features/dashboard/Dashboard.tsx index ce146b7..1423dfb 100644 --- a/frontend/src/features/dashboard/Dashboard.tsx +++ b/frontend/src/features/dashboard/Dashboard.tsx @@ -11,6 +11,7 @@ import { import type { LucideIcon } from 'lucide-react'; import { Card, CardContent, CardHeader, CardTitle } from '@shared/components/ui/card'; import { Badge } from '@shared/components/ui/badge'; +import { PageContainer } from '@shared/components/layout'; import { AreaChart, PieChart } from '@lib/charts'; import { useKpiStore } from '@stores/kpiStore'; import { useEventStore } from '@stores/eventStore'; @@ -393,8 +394,8 @@ export function Dashboard() { const defconLabels = ['', 'DEFCON 1', 'DEFCON 2', 'DEFCON 3', 'DEFCON 4', 'DEFCON 5']; return ( -
- {/* ── 상단 헤더 바 ── */} + + {/* ── 상단 헤더 바 (DEFCON + 라이브 상태) — 커스텀 구조 유지 ── */}
@@ -670,6 +671,6 @@ export function Dashboard() {
-
+ ); } diff --git a/frontend/src/features/monitoring/MonitoringDashboard.tsx b/frontend/src/features/monitoring/MonitoringDashboard.tsx index debb480..9532769 100644 --- a/frontend/src/features/monitoring/MonitoringDashboard.tsx +++ b/frontend/src/features/monitoring/MonitoringDashboard.tsx @@ -2,6 +2,7 @@ import { useEffect, useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Card, CardContent } from '@shared/components/ui/card'; import { Badge } from '@shared/components/ui/badge'; +import { PageContainer, PageHeader } from '@shared/components/layout'; import { Activity, AlertTriangle, Ship, Eye, Anchor, Radar, Shield, Bell, Clock, Target, ChevronRight } from 'lucide-react'; import type { LucideIcon } from 'lucide-react'; import { AreaChart, PieChart } from '@lib/charts'; @@ -80,11 +81,13 @@ export function MonitoringDashboard() { })); return ( -
-
-

{t('monitoring.title')}

-

{t('monitoring.desc')}

-
+ + {/* iran 백엔드 + Prediction 시스템 상태 (실시간) */} @@ -125,6 +128,6 @@ export function MonitoringDashboard() { ))}
-
+
); } diff --git a/frontend/src/features/risk-assessment/RiskMap.tsx b/frontend/src/features/risk-assessment/RiskMap.tsx index a041a0c..1c57d6d 100644 --- a/frontend/src/features/risk-assessment/RiskMap.tsx +++ b/frontend/src/features/risk-assessment/RiskMap.tsx @@ -2,6 +2,8 @@ import { useState, useRef, useCallback } from 'react'; import { BaseMap, STATIC_LAYERS, createHeatmapLayer, useMapLayers, type MapHandle } from '@lib/map'; import type { HeatPoint } from '@lib/map'; import { Card, CardContent } from '@shared/components/ui/card'; +import { Button } from '@shared/components/ui/button'; +import { PageContainer, PageHeader } from '@shared/components/layout'; import { Map, Layers, Clock, BarChart3, AlertTriangle, Printer, Download, Ship, TrendingUp } from 'lucide-react'; import { AreaChart as EcAreaChart, LineChart as EcLineChart, PieChart as EcPieChart, BarChart as EcBarChart } from '@lib/charts'; @@ -175,20 +177,24 @@ export function RiskMap() { useMapLayers(mapRef, buildLayers, [tab]); return ( -
-
-
-

- 격자 기반 불법조업 위험도 지도 + + {COLLECTING_BADGE} -

-

SFR-05 | 위험도 히트맵 (수집 중) + MTIS 해양사고 통계 (중앙해양안전심판원)

-
-
- - -
-
+ + + + } + /> {/* 탭 */}
@@ -489,6 +495,6 @@ export function RiskMap() {
)} -
+ ); } diff --git a/frontend/src/features/surveillance/LiveMapView.tsx b/frontend/src/features/surveillance/LiveMapView.tsx index be54d76..27a71cf 100644 --- a/frontend/src/features/surveillance/LiveMapView.tsx +++ b/frontend/src/features/surveillance/LiveMapView.tsx @@ -4,6 +4,7 @@ import { BaseMap, STATIC_LAYERS, createMarkerLayer, createRadiusLayer, useMapLay import type { MarkerData } from '@lib/map'; import { Card, CardContent } from '@shared/components/ui/card'; import { Badge } from '@shared/components/ui/badge'; +import { PageContainer } from '@shared/components/layout'; import { AlertTriangle, Ship, Radio, Zap, Activity, Clock, Pin, Loader2, WifiOff } from 'lucide-react'; import { fetchVesselAnalysis, @@ -227,7 +228,7 @@ export function LiveMapView() { }, [selectedEvent]); return ( -
+ {/* 좌측: 이벤트 목록 + 지도 */}
{/* 이벤트 카드 목록 */} @@ -391,6 +392,6 @@ export function LiveMapView() {
)} -
+ ); } diff --git a/frontend/src/features/surveillance/MapControl.tsx b/frontend/src/features/surveillance/MapControl.tsx index 7f1bde1..e3f9ec6 100644 --- a/frontend/src/features/surveillance/MapControl.tsx +++ b/frontend/src/features/surveillance/MapControl.tsx @@ -2,6 +2,7 @@ import { useState, useRef, useCallback } from 'react'; import { BaseMap, STATIC_LAYERS, createMarkerLayer, createRadiusLayer, useMapLayers, type MapHandle } from '@lib/map'; import { Card, CardContent } from '@shared/components/ui/card'; import { Badge } from '@shared/components/ui/badge'; +import { PageContainer, PageHeader } from '@shared/components/layout'; import { DataTable, type DataColumn } from '@shared/components/common/DataTable'; import { Map, Shield, Crosshair, AlertTriangle, Eye, Anchor, Ship, Filter, Layers, Target, Clock, MapPin, Bell, Navigation, Info } from 'lucide-react'; import { getTrainingZoneIntent, getTrainingZoneHex, getTrainingZoneMeta } from '@shared/constants/trainingZoneTypes'; @@ -244,18 +245,14 @@ export function MapControl() { useMapLayers(mapRef, buildLayers, [visibleZones]); return ( -
-
-
-

- 해역 통제 - - 데모 데이터 (백엔드 API 미구현) - -

-

한국연안 해상사격 훈련구역도 No.462 | Chart of Firing and Bombing Exercise Areas | WGS-84 | 출처: 국립해양조사원

-
-
+ + {/* KPI */}
@@ -428,6 +425,6 @@ export function MapControl() { /> )} -
+
); } diff --git a/frontend/src/features/vessel/TransferDetection.tsx b/frontend/src/features/vessel/TransferDetection.tsx index bb962e5..0ca79c5 100644 --- a/frontend/src/features/vessel/TransferDetection.tsx +++ b/frontend/src/features/vessel/TransferDetection.tsx @@ -1,13 +1,17 @@ import { Card, CardContent } from '@shared/components/ui/card'; +import { PageContainer, PageHeader } from '@shared/components/layout'; +import { RefreshCw } from 'lucide-react'; import { RealTransshipSuspects } from '@features/detection/RealVesselAnalysis'; export function TransferDetection() { return ( -
-
-

환적·접촉 탐지

-

선박 간 근접 접촉 및 환적 의심 행위 분석

-
+ + {/* prediction 분석 결과 기반 실시간 환적 의심 선박 */} @@ -32,6 +36,6 @@ export function TransferDetection() {
-
+ ); } diff --git a/frontend/src/features/vessel/VesselDetail.tsx b/frontend/src/features/vessel/VesselDetail.tsx index ccd3d6c..b6930bc 100644 --- a/frontend/src/features/vessel/VesselDetail.tsx +++ b/frontend/src/features/vessel/VesselDetail.tsx @@ -1,6 +1,7 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { useParams } from 'react-router-dom'; import { Badge } from '@shared/components/ui/badge'; +import { PageContainer } from '@shared/components/layout'; import { Search, Ship, AlertTriangle, Radar, MapPin, Printer, @@ -157,7 +158,7 @@ export function VesselDetail() { const riskMeta = ALERT_LEVELS[riskLevel] ?? ALERT_LEVELS.LOW; return ( -
+ {/* ── 좌측: 선박 정보 패널 ── */}
@@ -427,6 +428,6 @@ export function VesselDetail() {
-
+ ); }