'use client'; import { Correspondence } from '@/types/correspondence'; import { StatusBadge } from '@/components/common/status-badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { format } from 'date-fns'; import { ArrowLeft, Download, FileText, Loader2, Send, CheckCircle, XCircle, Edit, Ban, AlertTriangle } from 'lucide-react'; import Link from 'next/link'; import { useSubmitCorrespondence, useProcessWorkflow, useCancelCorrespondence } from '@/hooks/use-correspondence'; import { ReferenceSelector } from '@/components/correspondences/reference-selector'; import { TagManager } from '@/components/correspondences/tag-manager'; import { CirculationStatusCard } from '@/components/correspondences/circulation-status-card'; import { RevisionHistory } from '@/components/correspondences/revision-history'; import { Can } from '@/components/common/can'; import { useAuthStore } from '@/lib/stores/auth-store'; import { useState } from 'react'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; interface CorrespondenceDetailProps { data: Correspondence; selectedRevisionId?: string; } const normalizeUuid = (value?: string): string | undefined => { if (typeof value !== 'string') { return undefined; } const normalized = value.trim().toLowerCase(); return normalized.length > 0 ? normalized : undefined; }; export function CorrespondenceDetail({ data, selectedRevisionId }: CorrespondenceDetailProps) { const submitMutation = useSubmitCorrespondence(); const processMutation = useProcessWorkflow(); const cancelMutation = useCancelCorrespondence(); const { user, hasPermission } = useAuthStore(); const [actionState, setActionState] = useState<'approve' | 'reject' | 'cancel' | null>(null); const [comments, setComments] = useState(''); const [cancelReason, setCancelReason] = useState(''); if (!data) return
No data found
; const normalizedSelectedRevisionId = normalizeUuid(selectedRevisionId); const selectedRevision = normalizedSelectedRevisionId ? data.revisions?.find((r) => normalizeUuid(r.publicId) === normalizedSelectedRevisionId) : undefined; const currentRevision = selectedRevision || data.revisions?.find((r) => r.isCurrent) || data.revisions?.[0]; const subject = currentRevision?.subject || '-'; const description = currentRevision?.description || '-'; const status = currentRevision?.status?.statusCode || 'UNKNOWN'; // [FIX v1.8.1] flatten attachmentLinks จาก junction table แทน attachments โดยตรง const attachments = currentRevision?.attachmentLinks?.map((link) => link.attachment) ?? []; const importance = (currentRevision?.details?.importance as string) || 'NORMAL'; const canEditMetadata = hasPermission('correspondence.edit'); const privilegedEditableStatuses = ['SUBCSC', 'SUBOWN', 'IN_REVIEW_CSC']; const normalizedRole = (user?.role || '').toUpperCase().replace(/\s+/g, '_'); const isPrivilegedEditRole = ['SUPERADMIN', 'SUPER_ADMIN', 'ADMIN', 'DC', 'DOCUMENT_CONTROL'].includes( normalizedRole ); const canEditInStatus = status === 'DRAFT' || (privilegedEditableStatuses.includes(status) && isPrivilegedEditRole); const canEditDocument = canEditInStatus && (hasPermission('correspondence.edit') || isPrivilegedEditRole); const toRecipients = data.recipients?.filter((r) => r.recipientType === 'TO') || []; const ccRecipients = data.recipients?.filter((r) => r.recipientType === 'CC') || []; const handleSubmit = () => { if (confirm('Are you sure you want to submit this correspondence?')) { submitMutation.mutate({ uuid: data.publicId, data: {} }); } }; const handleProcess = () => { if (!actionState || actionState === 'cancel') return; const action = actionState === 'approve' ? 'APPROVE' : 'REJECT'; processMutation.mutate( { uuid: data.publicId, data: { action, comments } }, { onSuccess: () => { setActionState(null); setComments(''); } } ); }; const handleCancel = () => { if (!cancelReason.trim()) return; cancelMutation.mutate( { uuid: data.publicId, reason: cancelReason }, { onSuccess: () => { setActionState(null); setCancelReason(''); } } ); }; return (
{/* EC-CORR-002 Warning: Replying to cancelled document */} {status === 'CANCELLED' && (

This correspondence has been cancelled

You can still create a new correspondence referencing this document to acknowledge the cancellation.

)} {/* Header / Actions */}

{data.correspondenceNumber}

Created on {data.createdAt ? format(new Date(data.createdAt), 'dd MMM yyyy HH:mm') : '-'}

{canEditDocument && ( )} {status === 'DRAFT' && ( )} {status === 'IN_REVIEW' && ( <> )} {status !== 'CANCELLED' && ( )}
{/* Approve / Reject Input Area */} {(actionState === 'approve' || actionState === 'reject') && ( {actionState === 'approve' ? 'Confirm Approval' : 'Confirm Rejection'}