import React, { useEffect, useMemo, useState } from 'react'; import { approveRequest, listPendingRequests, rejectRequest } from '../api'; import { VisitRequestView } from '../types'; import { formatVisitRange } from '../status'; import { Dialog } from '../components/Dialog'; type SortKey = 'visitorName' | 'company' | 'zoneName' | 'purpose' | 'visitFrom'; type BusyAction = 'approve' | 'reject'; const COLUMNS: { key: SortKey; label: string }[] = [ { key: 'visitorName', label: '방문자' }, { key: 'company', label: '회사' }, { key: 'zoneName', label: '출입구역' }, { key: 'purpose', label: '출입목적' }, { key: 'visitFrom', label: '출입기간' }, ]; export const ApprovalQueuePage: React.FC = () => { const [items, setItems] = useState([]); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [busyAction, setBusyAction] = useState<{ id: number; action: BusyAction } | null>(null); const [sortKey, setSortKey] = useState(null); const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc'); const [rejectingId, setRejectingId] = useState(null); const onSort = (key: SortKey) => { if (sortKey === key) { setSortDir((d) => (d === 'asc' ? 'desc' : 'asc')); } else { setSortKey(key); setSortDir('asc'); } }; const sortedItems = useMemo(() => { if (!sortKey) return items; const arr = [...items]; arr.sort((a, b) => { const cmp = sortKey === 'visitFrom' ? new Date(a.visitFrom).getTime() - new Date(b.visitFrom).getTime() : String(a[sortKey] ?? '').localeCompare(String(b[sortKey] ?? ''), 'ko'); return sortDir === 'asc' ? cmp : -cmp; }); return arr; }, [items, sortKey, sortDir]); const load = () => { setLoading(true); listPendingRequests() .then(setItems) .catch((e) => setError(e instanceof Error ? e.message : '조회 실패')) .finally(() => setLoading(false)); }; useEffect(load, []); const approve = async (id: number) => { setError(null); setBusyAction({ id, action: 'approve' }); try { await approveRequest(id); load(); } catch (e) { setError(e instanceof Error ? e.message : '처리 실패'); } finally { setBusyAction(null); } }; const confirmReject = async (comment?: string) => { const id = rejectingId; setRejectingId(null); if (id == null) return; setError(null); setBusyAction({ id, action: 'reject' }); try { await rejectRequest(id, comment); load(); } catch (e) { setError(e instanceof Error ? e.message : '처리 실패'); } finally { setBusyAction(null); } }; return (

승인 대기 ({items.length})

{error &&
{error}
}
{loading ? (

불러오는 중…

) : items.length === 0 ? (

승인 대기 중인 신청이 없습니다.

) : ( {COLUMNS.map((c) => ( ))} {sortedItems.map((r) => ( ))}
onSort(c.key)} style={{ cursor: 'pointer', userSelect: 'none', whiteSpace: 'nowrap' }} title="클릭하여 정렬" > {c.label}{sortKey === c.key ? (sortDir === 'asc' ? ' ▲' : ' ▼') : ''} 처리
{r.visitorName} {r.company || '-'} {r.zoneName || '-'} {r.purpose} {formatVisitRange(r.visitFrom, r.visitTo)}
)}
{rejectingId != null && ( setRejectingId(null)} /> )}
); };