- UI 고정 텍스트 다국어 메타 파일(screeningTexts.ts) 추가 - -999/null 값 'No Data'/'데이터 없음' 표시 처리 - Screening Guide 탭 분리 (Ship/Company Compliance) - Change History ↔ Screening Guide 간 언어 설정 공유 - 섹션 헤더에 Screening Guide 연결 링크 추가
88 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
}
|