import { useState, useEffect, useMemo } from 'react'; import { fetchOrganizations } from '@tabs/assets/services/assetsApi'; import type { AssetOrgCompat } from '@tabs/assets/services/assetsApi'; import { typeTagCls } from '@tabs/assets/components/assetTypes'; const PAGE_SIZE = 20; const regionShort = (j: string) => j.includes('남해') ? '남해청' : j.includes('서해') ? '서해청' : j.includes('중부') ? '중부청' : j.includes('동해') ? '동해청' : j.includes('제주') ? '제주청' : j; function CleanupEquipPanel() { const [organizations, setOrganizations] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [regionFilter, setRegionFilter] = useState('전체'); const [typeFilter, setTypeFilter] = useState('전체'); const [equipFilter, setEquipFilter] = useState('전체'); const [currentPage, setCurrentPage] = useState(1); const load = () => { setLoading(true); fetchOrganizations() .then(setOrganizations) .catch((err) => console.error('[CleanupEquipPanel] 데이터 로드 실패:', err)) .finally(() => setLoading(false)); }; useEffect(() => { let cancelled = false; fetchOrganizations() .then((data) => { if (!cancelled) setOrganizations(data); }) .catch((err) => console.error('[CleanupEquipPanel] 데이터 로드 실패:', err)) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, []); const typeOptions = useMemo(() => { const set = new Set(organizations.map((o) => o.type)); return Array.from(set).sort(); }, [organizations]); const EQUIP_FIELDS: Record = { 방제선: 'vessel', 유회수기: 'skimmer', 이송펌프: 'pump', 방제차량: 'vehicle', 살포장치: 'sprayer', }; const filtered = useMemo( () => organizations .filter((o) => regionFilter === '전체' || o.jurisdiction.includes(regionFilter)) .filter((o) => typeFilter === '전체' || o.type === typeFilter) .filter((o) => equipFilter === '전체' || (o[EQUIP_FIELDS[equipFilter]] as number) > 0) .filter( (o) => !searchTerm || o.name.includes(searchTerm) || o.address.includes(searchTerm), ), [organizations, regionFilter, typeFilter, equipFilter, searchTerm], ); const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE)); const safePage = Math.min(currentPage, totalPages); const paged = filtered.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE); const handleFilterChange = (setter: (v: string) => void) => (e: React.ChangeEvent) => { setter(e.target.value); setCurrentPage(1); }; const pageNumbers = (() => { const range: number[] = []; const start = Math.max(1, safePage - 2); const end = Math.min(totalPages, safePage + 2); for (let i = start; i <= end; i++) range.push(i); return range; })(); return (
{/* 헤더 */}

방제장비 현황

총 {filtered.length}개 기관

{ setSearchTerm(e.target.value); setCurrentPage(1); }} className="w-56 px-3 py-2 text-caption bg-bg-elevated border border-stroke rounded-md text-fg placeholder-fg-disabled focus:border-color-accent focus:outline-none font-korean" />
{/* 테이블 */}
{loading ? (
불러오는 중...
) : ( {paged.length === 0 ? ( ) : ( paged.map((org, idx) => ( )) )}
번호 유형 관할청 기관명 주소 방제선 유회수기 이송펌프 방제차량 살포장치 총자산
조회된 기관이 없습니다.
{(safePage - 1) * PAGE_SIZE + idx + 1} {org.type} {regionShort(org.jurisdiction)} {org.name} {org.address} {org.vessel > 0 ? org.vessel : } {org.skimmer > 0 ? org.skimmer : } {org.pump > 0 ? org.pump : } {org.vehicle > 0 ? org.vehicle : } {org.sprayer > 0 ? org.sprayer : } {org.totalAssets.toLocaleString()}
)}
{/* 합계 */} {!loading && filtered.length > 0 && (
합계 ({filtered.length}개 기관) {[ { label: '방제선', value: filtered.reduce((s, o) => s + o.vessel, 0), unit: '척' }, { label: '유회수기', value: filtered.reduce((s, o) => s + o.skimmer, 0), unit: '대' }, { label: '이송펌프', value: filtered.reduce((s, o) => s + o.pump, 0), unit: '대' }, { label: '방제차량', value: filtered.reduce((s, o) => s + o.vehicle, 0), unit: '대' }, { label: '살포장치', value: filtered.reduce((s, o) => s + o.sprayer, 0), unit: '대' }, { label: '총자산', value: filtered.reduce((s, o) => s + o.totalAssets, 0), unit: '' }, ].map((t) => { const isActive = t.label === equipFilter || t.label === '총자산'; return (
{t.label} {t.value.toLocaleString()} {t.unit}
); })}
)} {/* 페이지네이션 */} {!loading && filtered.length > 0 && (
{(safePage - 1) * PAGE_SIZE + 1}–{Math.min(safePage * PAGE_SIZE, filtered.length)} / 전체 {filtered.length}개
{pageNumbers.map((p) => ( ))}
)}
); } export default CleanupEquipPanel;