'use client' import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; import { Separator } from '@/components/ui/separator'; import { Textarea } from '@/components/ui/textarea'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog'; import { toast } from 'sonner'; import { Loader2, XCircle, AlertTriangle, CheckCircle } from 'lucide-react'; // API 함수 및 타입 import { cancelApproval, getApprovalDetail } from '@/lib/knox-api/approval/approval'; import type { ApprovalDetailResponse } 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 ApprovalCancelProps { initialApInfId?: string; onCancelSuccess?: (apInfId: string) => void; } export default function ApprovalCancel({ initialApInfId = '', onCancelSuccess }: ApprovalCancelProps) { const [apInfId, setApInfId] = useState(initialApInfId); const [approvalDetail, setApprovalDetail] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isCancelling, setIsCancelling] = useState(false); const [error, setError] = useState(null); const [cancelResult, setCancelResult] = useState<{ apInfId: string } | null>(null); const [cancelOpinion, setCancelOpinion] = useState(''); const fetchApprovalDetail = async () => { if (!apInfId.trim()) { toast.error('결재 ID를 입력해주세요.'); return; } setIsLoading(true); setError(null); setApprovalDetail(null); setCancelResult(null); setCancelOpinion(''); try { const response = await getApprovalDetail(apInfId); if (response.result === 'success') { setApprovalDetail(response.data); } else { setError('결재 정보를 가져오는데 실패했습니다.'); toast.error('결재 정보를 가져오는데 실패했습니다.'); } } catch (err) { console.error('결재 상세 조회 오류:', err); setError('결재 정보를 가져오는 중 오류가 발생했습니다.'); toast.error('결재 정보를 가져오는 중 오류가 발생했습니다.'); } finally { setIsLoading(false); } }; const handleCancelApproval = async () => { if (!approvalDetail) return; if (!cancelOpinion.trim()) { toast.error('상신취소 의견을 입력해주세요.'); return; } setIsCancelling(true); try { const response = await cancelApproval(approvalDetail.apInfId, cancelOpinion); if (response.result === 'success') { setCancelResult({ apInfId: response.data.apInfId }); toast.success('결재가 성공적으로 취소되었습니다.'); onCancelSuccess?.(response.data.apInfId); // 상태 업데이트 setApprovalDetail({ ...approvalDetail, status: '4' // 상신취소 }); // 의견 초기화 setCancelOpinion(''); } else { toast.error('결재 취소에 실패했습니다.'); } } catch (err) { console.error('결재 취소 오류:', err); toast.error('결재 취소 중 오류가 발생했습니다.'); } finally { setIsCancelling(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 canCancelApproval = (status: string) => { // 진행중(1), 보류(0) 상태에서만 취소 가능 return ['0', '1'].includes(status); }; const getCancelabilityMessage = (status: string) => { if (canCancelApproval(status)) { return '이 결재는 취소할 수 있습니다.'; } switch (status) { case '2': return '완결된 결재는 취소할 수 없습니다.'; case '3': return '반려된 결재는 취소할 수 없습니다.'; case '4': return '이미 취소된 결재입니다.'; case '5': return '전결 처리된 결재는 취소할 수 없습니다.'; case '6': return '후완결된 결재는 취소할 수 없습니다.'; default: return '현재 상태에서는 취소할 수 없습니다.'; } }; return ( 결재 취소 상신한 결재를 취소합니다. {/* 검색 영역 */}
setApInfId(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && fetchApprovalDetail()} />
{/* 취소 완료 메시지 */} {cancelResult && (
취소 완료

결재 ID: {cancelResult.apInfId}가 성공적으로 취소되었습니다.

)} {/* 에러 메시지 */} {error && (
오류

{error}

)} {/* 결재 정보 */} {approvalDetail && (

결재 정보

{approvalDetail.apInfId}

{approvalDetail.subject}

{formatDate(approvalDetail.sbmDt, "kr")}

{getStatusText(approvalDetail.status)}
{/* 취소 가능 여부 */}

취소 가능 여부

{canCancelApproval(approvalDetail.status) ? ( ) : ( )} {canCancelApproval(approvalDetail.status) ? '취소 가능' : '취소 불가'}

{getCancelabilityMessage(approvalDetail.status)}

{/* 취소 의견 및 버튼 */} {canCancelApproval(approvalDetail.status) && ( <>