snp-batch-validation/frontend/src/pages/ScreeningGuide.tsx
HYOJIN 5f7708962d feat(screening): Risk & Compliance 다국어 지원 및 사용자 편의성 개선 (#134)
- UI 고정 텍스트 다국어 메타 파일(screeningTexts.ts) 추가
- -999/null 값 'No Data'/'데이터 없음' 표시 처리
- Screening Guide 탭 분리 (Ship/Company Compliance)
- Change History ↔ Screening Guide 간 언어 설정 공유
- 섹션 헤더에 Screening Guide 연결 링크 추가
2026-04-02 11:14:00 +09:00

88 lines
3.9 KiB
TypeScript

import { useState, useCallback } from 'react';
import { useSearchParams } from 'react-router-dom';
import RiskTab from '../components/screening/RiskTab';
import ComplianceTab from '../components/screening/ComplianceTab';
import MethodologyTab from '../components/screening/MethodologyTab';
import { t } from '../constants/screeningTexts';
type ActiveTab = 'risk' | 'ship-compliance' | 'company-compliance' | 'methodology';
const VALID_TABS: ActiveTab[] = ['risk', 'ship-compliance', 'company-compliance', 'methodology'];
const LANG_KEY = 'screening-lang';
export default function ScreeningGuide() {
const [searchParams] = useSearchParams();
const initialTab = VALID_TABS.includes(searchParams.get('tab') as ActiveTab)
? (searchParams.get('tab') as ActiveTab)
: 'risk';
const [activeTab, setActiveTab] = useState<ActiveTab>(initialTab);
const [lang, setLangState] = useState(() => localStorage.getItem(LANG_KEY) || 'EN');
const setLang = useCallback((l: string) => {
setLangState(l);
localStorage.setItem(LANG_KEY, l);
}, []);
const tabs: { key: ActiveTab; label: string }[] = [
{ key: 'risk', label: t(lang, 'tabRiskIndicators') },
{ key: 'ship-compliance', label: t(lang, 'tabShipCompliance') },
{ key: 'company-compliance', label: t(lang, 'tabCompanyCompliance') },
{ key: 'methodology', label: t(lang, 'tabMethodology') },
];
return (
<div className="space-y-6">
{/* 헤더 */}
<div className="flex items-start justify-between">
<div>
<h1 className="text-2xl font-bold text-wing-text">
{t(lang, 'screeningGuideTitle')}
</h1>
<p className="mt-1 text-sm text-wing-muted">
{t(lang, 'screeningGuideSubtitle')}
</p>
</div>
{/* 언어 토글 */}
<div className="flex border border-wing-border rounded-lg overflow-hidden shrink-0">
{(['EN', 'KO'] as const).map((l) => (
<button
key={l}
onClick={() => setLang(l)}
className={`px-4 py-1.5 text-sm font-bold transition-colors ${
lang === l
? 'bg-wing-text text-wing-bg'
: 'bg-wing-card text-wing-muted hover:text-wing-text'
}`}
>
{l}
</button>
))}
</div>
</div>
{/* 언더라인 탭 */}
<div className="border-b border-wing-border">
<div className="flex gap-6">
{tabs.map((tab) => (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`pb-2.5 text-sm font-semibold transition-colors border-b-2 -mb-px ${
activeTab === tab.key
? 'text-blue-600 border-blue-600'
: 'text-wing-muted border-transparent hover:text-wing-text'
}`}
>
{tab.label}
</button>
))}
</div>
</div>
{/* 탭 내용 */}
{activeTab === 'risk' && <RiskTab lang={lang} />}
{activeTab === 'ship-compliance' && <ComplianceTab lang={lang} indicatorType="SHIP" />}
{activeTab === 'company-compliance' && <ComplianceTab lang={lang} indicatorType="COMPANY" />}
{activeTab === 'methodology' && <MethodologyTab lang={lang} />}
</div>
);
}