"use client" import * as React from "react" import { Send, Eye, CheckCircle, Clock, RefreshCw, AlertTriangle, Loader2 } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" import { Badge } from "@/components/ui/badge" import { Separator } from "@/components/ui/separator" import { Progress } from "@/components/ui/progress" import type { EnhancedDocument } from "@/types/enhanced-documents" interface SWPWorkflowPanelProps { contractId: number documents: EnhancedDocument[] onWorkflowUpdate?: () => void } type WorkflowStatus = | 'IDLE' // 대기 상태 | 'SUBMITTED' // 목록 전송됨 | 'UNDER_REVIEW' // 검토 중 | 'CONFIRMED' // 컨펌됨 | 'REVISION_REQUIRED' // 수정 요청됨 | 'RESUBMITTED' // 재전송됨 | 'APPROVED' // 최종 승인됨 interface WorkflowState { status: WorkflowStatus lastUpdatedAt?: string pendingActions: string[] confirmationData?: any revisionComments?: string[] approvalData?: any } export function SWPWorkflowPanel({ contractId, documents, onWorkflowUpdate }: SWPWorkflowPanelProps) { const [workflowState, setWorkflowState] = React.useState(null) const [isLoading, setIsLoading] = React.useState(false) const [actionProgress, setActionProgress] = React.useState(0) // 워크플로우 상태 조회 const fetchWorkflowStatus = async () => { setIsLoading(true) try { const response = await fetch(`/api/sync/workflow/status?contractId=${contractId}&targetSystem=SWP`) if (!response.ok) throw new Error('Failed to fetch workflow status') const status = await response.json() setWorkflowState(status) } catch (error) { console.error('Failed to fetch workflow status:', error) toast.error('워크플로우 상태를 확인할 수 없습니다') } finally { setIsLoading(false) } } // 컴포넌트 마운트 시 상태 조회 React.useEffect(() => { fetchWorkflowStatus() }, [contractId]) // 워크플로우 액션 실행 const executeWorkflowAction = async (action: string) => { setActionProgress(0) setIsLoading(true) try { // 진행률 시뮬레이션 const progressInterval = setInterval(() => { setActionProgress(prev => Math.min(prev + 20, 90)) }, 200) const response = await fetch('/api/sync/workflow/action', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contractId, targetSystem: 'SWP', action, documents: documents.map(doc => ({ id: doc.id, documentNo: doc.documentNo })) }) }) if (!response.ok) { const errorData = await response.json() throw new Error(errorData.message || 'Workflow action failed') } const result = await response.json() clearInterval(progressInterval) setActionProgress(100) setTimeout(() => { setActionProgress(0) if (result?.success) { toast.success( `${getActionLabel(action)} 완료`, { description: result?.message || '워크플로우가 성공적으로 진행되었습니다.' } ) } else { toast.error( `${getActionLabel(action)} 실패`, { description: result?.message || '워크플로우 실행에 실패했습니다.' } ) } fetchWorkflowStatus() // 상태 갱신 onWorkflowUpdate?.() }, 500) } catch (error) { setActionProgress(0) toast.error(`${getActionLabel(action)} 실패`, { description: error instanceof Error ? error.message : '알 수 없는 오류가 발생했습니다.' }) } finally { setIsLoading(false) } } const getActionLabel = (action: string): string => { switch (action) { case 'SUBMIT_LIST': return '목록 전송' case 'CHECK_CONFIRMATION': return '컨펌 확인' case 'RESUBMIT_REVISED': return '수정본 재전송' case 'CHECK_APPROVAL': return '승인 확인' default: return action } } const getStatusBadge = () => { if (isLoading) { return 확인 중... } if (!workflowState) { return 오류 } switch (workflowState.status) { case 'IDLE': return 대기 case 'SUBMITTED': return ( 전송됨 ) case 'UNDER_REVIEW': return ( 검토 중 ) case 'CONFIRMED': return ( 컨펌됨 ) case 'REVISION_REQUIRED': return ( 수정 요청 ) case 'RESUBMITTED': return ( 재전송됨 ) case 'APPROVED': return ( 승인 완료 ) default: return 알 수 없음 } } const getAvailableActions = (): string[] => { if (!workflowState) return [] switch (workflowState.status) { case 'IDLE': return ['SUBMIT_LIST'] case 'SUBMITTED': return ['CHECK_CONFIRMATION'] case 'UNDER_REVIEW': return ['CHECK_CONFIRMATION'] case 'CONFIRMED': return [] // 컨펌되면 자동으로 다음 단계로 case 'REVISION_REQUIRED': return ['RESUBMIT_REVISED'] case 'RESUBMITTED': return ['CHECK_APPROVAL'] case 'APPROVED': return [] // 완료 상태 default: return [] } } const availableActions = getAvailableActions() return (

SWP 워크플로우 상태

현재 상태 {getStatusBadge()}
{workflowState && (
{/* 대기 중인 액션들 */} {workflowState.pendingActions && workflowState.pendingActions.length > 0 && (
대기 중인 작업
{workflowState.pendingActions.map((action, index) => ( {getActionLabel(action)} ))}
)} {/* 수정 요청 사항 */} {workflowState.revisionComments && workflowState.revisionComments.length > 0 && (
수정 요청 사항
{workflowState.revisionComments.map((comment, index) => (
{comment}
))}
)} {/* 마지막 업데이트 시간 */} {workflowState.lastUpdatedAt && (
마지막 업데이트
{new Date(workflowState.lastUpdatedAt).toLocaleString()}
)} {/* 진행률 표시 */} {isLoading && actionProgress > 0 && (
진행률 {actionProgress}%
)}
)} {/* 액션 버튼들 */}
{availableActions.length > 0 ? ( availableActions.map((action) => ( )) ) : (
{workflowState?.status === 'APPROVED' ? '워크플로우가 완료되었습니다.' : '실행 가능한 작업이 없습니다.'}
)} {/* 상태 새로고침 버튼 */}
) }