'use client' import { useState, useEffect, useCallback } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { toast } from 'sonner'; import { Loader2, List, Eye, RefreshCw, AlertCircle, Play, Pause, Clock } from 'lucide-react'; // API 함수 및 타입 import { getApprovalLogsAction, syncApprovalStatusAction } from '@/lib/knox-api/approval/approval'; import { formatDate } from '@/lib/utils'; // 상태 텍스트 매핑 (mock util 대체) const getStatusText = (status: string) => { const map: Record = { '-3': '암호화실패', '-2': '암호화중', '-1': '예약상신', '0': '보류', '1': '진행중', '2': '완결', '3': '반려', '4': '상신취소', '5': '전결', '6': '후완결', }; return map[status] || '알 수 없음'; }; interface ApprovalListProps { onItemClick?: (apInfId: string) => void; } type ListItem = { apInfId: string; subject: string; sbmDt: string; status: string; urgYn?: string; docSecuType?: string; actionType?: string; actionDt?: string; userId?: string; }; export default function ApprovalList({ onItemClick, }: ApprovalListProps) { const [listData, setListData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [isSyncing, setIsSyncing] = useState(false); const [autoSync, setAutoSync] = useState(false); const [lastSyncTime, setLastSyncTime] = useState(null); const fetchData = useCallback(async () => { setIsLoading(true); setError(null); try { // 데이터베이스에서 결재 로그 조회 const response = await getApprovalLogsAction(); if (response.success) { setListData(response.data as unknown as ListItem[]); } else { setError(response.message); toast.error(response.message); } } catch (err) { console.error('목록 조회 오류:', err); setError('목록을 가져오는 중 오류가 발생했습니다.'); toast.error('목록을 가져오는 중 오류가 발생했습니다.'); } finally { setIsLoading(false); } }, []); const getStatusBadgeVariant = (status: string) => { switch (status) { case '2': // 완결 return 'default'; case '1': // 진행중 return 'secondary'; case '3': // 반려 return 'destructive'; case '4': // 상신취소 return 'outline'; default: return 'outline'; } }; const handleItemClick = (apInfId: string) => { onItemClick?.(apInfId); }; // 결재 상황 동기화 함수 const handleSync = useCallback(async (silent = false) => { setIsSyncing(true); try { const result = await syncApprovalStatusAction(); if (result.success) { if (!silent) toast.success(result.message); setLastSyncTime(new Date()); // 동기화 후 데이터 새로고침 await fetchData(); } else { if (!silent) toast.error(result.message); } } catch (error) { console.error('동기화 오류:', error); if (!silent) toast.error('동기화 중 오류가 발생했습니다.'); } finally { setIsSyncing(false); } }, [fetchData]); // 컴포넌트 마운트 시 데이터 로드 useEffect(() => { fetchData(); }, [fetchData]); // 자동 동기화 Polling 효과 useEffect(() => { if (!autoSync) { return; } // 30초마다 자동 동기화 (조정 가능) const intervalId = setInterval(() => { handleSync(true); // silent 모드로 실행 }, 30000); return () => clearInterval(intervalId); }, [autoSync, handleSync]); return ( 결재 이력 데이터베이스에 저장된 결재 로그를 확인하고 상태를 동기화합니다. {/* 제어 버튼들 */}
총 {listData.length}건
{lastSyncTime && (
마지막 동기화: {formatDate(lastSyncTime.toISOString(), "kr")}
)}
{/* 에러 메시지 */} {error && (
오류

{error}

)} {/* 목록 테이블 */}
결재 ID 제목 상태 작업 {listData.length === 0 ? ( {isLoading ? '데이터를 불러오는 중...' : '데이터가 없습니다.'} ) : ( listData.map((item) => ( {item.apInfId} {item.subject} {getStatusText(item.status)} )) )}
{/* 페이지네이션 영역 (향후 구현 예정) */} {listData.length > 0 && (
페이지네이션 기능은 향후 구현 예정입니다.
)}
); }