import { useEffect, useState, useCallback } from 'react'; import { api } from '@common/services/api'; interface SensitiveLayerPanelProps { categoryCode: string; title: string; } interface LayerAdminItem { layerCd: string; upLayerCd: string | null; layerFullNm: string; layerNm: string; layerLevel: number; wmsLayerNm: string | null; useYn: string; sortOrd: number; regDtm: string | null; } interface LayerListResponse { items: LayerAdminItem[]; total: number; page: number; totalPages: number; } const PAGE_SIZE = 10; async function fetchSensitiveLayers( page: number, search: string, useYn: string, rootCd: string, ): Promise { const params = new URLSearchParams({ page: String(page), limit: String(PAGE_SIZE), rootCd }); if (search) params.set('search', search); if (useYn) params.set('useYn', useYn); const res = await api.get(`/layers/admin/list?${params}`); return res.data; } async function toggleLayerUse(layerCd: string): Promise<{ layerCd: string; useYn: string }> { const res = await api.post<{ layerCd: string; useYn: string }>('/layers/admin/toggle-use', { layerCd, }); return res.data; } // ---------- SensitiveLayerPanel ---------- const SensitiveLayerPanel = ({ categoryCode, title }: SensitiveLayerPanelProps) => { const [items, setItems] = useState([]); const [total, setTotal] = useState(0); const [totalPages, setTotalPages] = useState(1); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const [toggling, setToggling] = useState(null); const [error, setError] = useState(null); const [searchInput, setSearchInput] = useState(''); const [appliedSearch, setAppliedSearch] = useState(''); const [filterUseYn, setFilterUseYn] = useState(''); const load = useCallback( async (p: number, search: string, useYn: string) => { setLoading(true); setError(null); try { const res = await fetchSensitiveLayers(p, search, useYn, categoryCode); setItems(res.items); setTotal(res.total); setTotalPages(res.totalPages); } catch { setError('레이어 목록을 불러오지 못했습니다.'); } finally { setLoading(false); } }, [categoryCode], ); useEffect(() => { setPage(1); setAppliedSearch(''); setFilterUseYn(''); setSearchInput(''); }, [categoryCode]); useEffect(() => { load(page, appliedSearch, filterUseYn); }, [load, page, appliedSearch, filterUseYn]); const handleSearch = () => { setAppliedSearch(searchInput); setPage(1); }; const handleToggle = async (layerCd: string) => { if (toggling) return; setToggling(layerCd); try { const result = await toggleLayerUse(layerCd); setItems((prev) => prev.map((item) => item.layerCd === result.layerCd ? { ...item, useYn: result.useYn } : item, ), ); } catch { setError('사용여부 변경에 실패했습니다.'); } finally { setToggling(null); } }; const buildPageButtons = () => { const buttons: (number | 'ellipsis')[] = []; const delta = 2; const left = page - delta; const right = page + delta; for (let i = 1; i <= totalPages; i++) { if (i === 1 || i === totalPages || (i >= left && i <= right)) { buttons.push(i); } else if (buttons[buttons.length - 1] !== 'ellipsis') { buttons.push('ellipsis'); } } return buttons; }; return (
{/* 헤더 */}

{title}

총 {total}개

setSearchInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} placeholder="레이어코드 / 레이어명 검색" className="flex-1 px-3 py-1.5 text-xs bg-bg-elevated border border-stroke rounded text-fg placeholder-fg-disabled focus:border-color-accent focus:outline-none font-korean" />
{/* 오류 메시지 */} {error && (
{error}
)} {/* 테이블 영역 */}
{loading ? (
불러오는 중...
) : ( {items.length === 0 ? ( ) : ( items.map((item, idx) => ( )) )}
번호 레이어코드 레이어명 레이어전체명 레벨 WMS레이어명 정렬 등록일시 사용여부
데이터가 없습니다.
{(page - 1) * PAGE_SIZE + idx + 1} {item.layerCd} {item.layerNm} {item.layerFullNm} {item.layerLevel} {item.wmsLayerNm ?? -} {item.sortOrd} {item.regDtm ?? '-'}
)}
{/* 페이지네이션 */} {!loading && totalPages > 1 && (
{(page - 1) * PAGE_SIZE + 1}–{Math.min(page * PAGE_SIZE, total)} / {total}개
{buildPageButtons().map((btn, i) => btn === 'ellipsis' ? ( ) : ( ), )}
)}
); }; export default SensitiveLayerPanel;