"use client"; import * as React from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Building2, Calendar, DollarSign, FileText, Package, Globe, MapPin, Clock, CheckCircle, XCircle, AlertCircle, Download, Eye, User, Mail, Phone, CreditCard, Truck, Shield, Paperclip, Info, Edit, X, } from "lucide-react"; import { format } from "date-fns"; import { ko } from "date-fns/locale"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; // Props 타입 정의 interface VendorResponseDetailDialogProps { open: boolean; onOpenChange: (open: boolean) => void; data: any; // mergedData의 row rfqId: number; } // 상태별 설정 const getStatusConfig = (status: string) => { switch (status) { case "초대됨": return { icon: , color: "text-blue-600", bgColor: "bg-blue-50", variant: "secondary" as const, }; case "작성중": return { icon: , color: "text-yellow-600", bgColor: "bg-yellow-50", variant: "outline" as const, }; case "제출완료": return { icon: , color: "text-green-600", bgColor: "bg-green-50", variant: "default" as const, }; case "수정요청": return { icon: , color: "text-orange-600", bgColor: "bg-orange-50", variant: "warning" as const, }; case "최종확정": return { icon: , color: "text-indigo-600", bgColor: "bg-indigo-50", variant: "success" as const, }; case "취소": return { icon: , color: "text-red-600", bgColor: "bg-red-50", variant: "destructive" as const, }; default: return { icon: , color: "text-gray-600", bgColor: "bg-gray-50", variant: "outline" as const, }; } }; export function VendorResponseDetailDialog({ open, onOpenChange, data, rfqId, }: VendorResponseDetailDialogProps) { if (!data) return null; const response = data.response; const statusConfig = getStatusConfig(response?.status || "초대됨"); const hasSubmitted = !!response?.submission?.submittedAt; // 이메일 발송 정보 파싱 let emailRecipients = { to: [], cc: [], sentBy: "" }; try { if (data.emailSentTo) { emailRecipients = JSON.parse(data.emailSentTo); } } catch (e) { console.error("Failed to parse emailSentTo"); } // 견적 아이템 (실제로는 response.quotationItems에서 가져옴) const quotationItems = response?.quotationItems || []; // 첨부파일 (실제로는 response.attachments에서 가져옴) const attachments = response?.attachments || []; return (
벤더 응답 상세 {data.vendorName} ({data.vendorCode || "코드없음"}) - {data.rfqCode}
{/* {onEdit && ( )} */}
개요 견적정보 품목상세 첨부파일 {/* 개요 탭 */} {/* 상태 정보 */} 응답 상태
현재 상태 {statusConfig.icon} {response?.status || "초대됨"}
응답 버전 v{response?.responseVersion || 1}
Short List {data.shortList ? "선정" : "대기"}
제출일시 {response?.submission?.submittedAt ? format(new Date(response.submission.submittedAt), "yyyy-MM-dd HH:mm", { locale: ko }) : "-"}
제출자 {response?.submission?.submittedByName || "-"}
최종 수정일 {data.updatedAt ? format(new Date(new Date(data.updatedAt).getTime() + 9 * 60 * 60 * 1000), "yyyy-MM-dd HH:mm", { locale: ko }) : "-"}
{/* 벤더 정보 */} 벤더 정보
업체명 {data.vendorName}
업체코드 {data.vendorCode || "-"}
국가 {data.vendorCountry === "KR" || data.vendorCountry === "한국" ? `내자(${data.vendorCountry})` : `외자(${data.vendorCountry})`}
이메일 {response?.vendor?.email || "-"}
업체분류 {data.vendorCategory || "-"}
AVL 등급 {data.vendorGrade || "-"}
{/* 이메일 발송 정보 */} {data.emailSentAt && ( 이메일 발송 정보
최초 발송일시 {format(new Date(new Date(data.emailSentAt).getTime() + 9 * 60 * 60 * 1000), "yyyy-MM-dd HH:mm", { locale: ko })}
{data.lastEmailSentAt && data.emailResentCount > 1 && (
최근 재발송일시 {format(new Date(new Date(data.lastEmailSentAt).getTime() + 9 * 60 * 60 * 1000), "yyyy-MM-dd HH:mm", { locale: ko })} 재발송 {data.emailResentCount - 1}회
)} {emailRecipients.to.length > 0 && (
수신자 {emailRecipients.to.join(", ")}
)} {emailRecipients.cc.length > 0 && (
참조 {emailRecipients.cc.join(", ")}
)} {emailRecipients.sentBy && (
발신자 {emailRecipients.sentBy}
)}
발송 상태 {data.emailStatus === "failed" ? "발송 실패" : "발송 완료"}
)}
{/* 견적정보 탭 */} {/* 요청 조건 */} 요청 조건
통화 {data.currency}
지급조건 {data.paymentTermsCode} {data.paymentTermsDescription && (

{data.paymentTermsDescription}

)}
인코텀즈 {data.incotermsCode} {data.incotermsDescription && (

{data.incotermsDescription}

{data.incotermsDetail &&

{data.incotermsDetail}

}
)}
Tax {data.taxCode || "-"}
납기일 {data.deliveryDate ? format(new Date(data.deliveryDate), "yyyy-MM-dd") : "-"}
계약기간 {data.contractDuration || "-"}
선적지 {data.placeOfShipping || "-"}
도착지 {data.placeOfDestination || "-"}
{/* 추가 조건 */}
{data.firstYn && (
초도품 요구사항
{data.firstDescription || "초도품 제출 필요"}
)} {data.sparepartYn && (
스페어파트 요구사항
{data.sparepartDescription || "스페어파트 제공 필요"}
)} {data.materialPriceRelatedYn && (
연동제 적용
적용
)}
{/* 벤더 제안 조건 (제출된 경우) */} {hasSubmitted && ( 벤더 제안 조건
제안 통화 {response?.pricing?.vendorCurrency || data.currency}
제안 지급조건 {response?.vendorTerms?.paymentTermsCode || data.paymentTermsCode}
제안 인코텀즈 {response?.vendorTerms?.incotermsCode || data.incotermsCode}
제안 납기일 {response?.vendorTerms?.deliveryDate ? format(new Date(response.vendorTerms.deliveryDate), "yyyy-MM-dd") : data.deliveryDate ? format(new Date(data.deliveryDate), "yyyy-MM-dd") : "-"}
총 견적금액 {response?.pricing?.totalAmount ? new Intl.NumberFormat("ko-KR", { style: "currency", currency: response.pricing.vendorCurrency || data.currency, }).format(response.pricing.totalAmount) : "-"}
{/* 벤더 추가 응답 */} {(response?.additionalRequirements?.firstArticle?.acceptance || response?.additionalRequirements?.sparePart?.acceptance) && ( <>
{response?.additionalRequirements?.firstArticle?.acceptance && (
초도품 수용여부 {response.additionalRequirements.firstArticle.acceptance}
)} {response?.additionalRequirements?.sparePart?.acceptance && (
스페어파트 수용여부 {response.additionalRequirements.sparePart.acceptance}
)}
)} {/* 벤더 비고 */} {(response?.remarks?.general || response?.remarks?.technical) && ( <>
{response?.remarks?.general && (
일반 비고

{response.remarks.general}

)} {response?.remarks?.technical && (
기술 제안

{response.remarks.technical}

)}
)}
)}
{/* 품목상세 탭 */} {quotationItems.length > 0 ? ( 견적 품목 상세 총 {quotationItems.length}개 품목 PR No. 자재코드 자재명 수량 단위 단가 금액 통화 납기일 {quotationItems.map((item: any) => ( {item.prNo} {item.materialCode} {item.materialDescription} {item.quantity} {item.uom} {new Intl.NumberFormat("ko-KR").format(item.unitPrice)} {new Intl.NumberFormat("ko-KR").format(item.totalPrice)} {response?.pricing?.vendorCurrency || data.currency || item.currency} {item.vendorDeliveryDate ? format(new Date(item.vendorDeliveryDate), "MM-dd") : "-"} ))}
) : (
아직 제출된 견적 품목이 없습니다.
)}
{/* 첨부파일 탭 */} {attachments.length > 0 ? ( 첨부파일 총 {attachments.length}개 파일
{attachments.map((file: any) => (

{file.originalFileName}

{file.attachmentType} • {file.fileSize ? `${(file.fileSize / 1024).toFixed(2)} KB` : "크기 미상"} {file.description && ` • ${file.description}`}

{/* */}
))}
) : (
아직 제출된 첨부파일이 없습니다.
)}
); }