// lib/tbe-last/table/dialogs/evaluation-dialog.tsx "use client" import * as React from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import * as z from "zod" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Textarea } from "@/components/ui/textarea" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Alert, AlertDescription } from "@/components/ui/alert" import { TbeLastView } from "@/db/schema" import { toast } from "sonner" import { updateTbeEvaluation ,getTbeVendorDocuments} from "../service" import { FileText, CheckCircle, XCircle, AlertCircle, Clock, Loader2, Info } from "lucide-react" // 폼 스키마 const evaluationSchema = z.object({ evaluationResult: z.enum(["Acceptable", "Acceptable with Comment", "Not Acceptable"], { required_error: "평가 결과를 선택해주세요", }), conditionalRequirements: z.string().optional(), conditionsFulfilled: z.boolean().default(false), overallRemarks: z.string().optional(), }) type EvaluationFormValues = z.infer interface EvaluationDialogProps { open: boolean onOpenChange: (open: boolean) => void selectedSession: TbeLastView | null onSuccess?: () => void } export function EvaluationDialog({ open, onOpenChange, selectedSession, onSuccess }: EvaluationDialogProps) { const [isLoading, setIsLoading] = React.useState(false) const [isLoadingDocs, setIsLoadingDocs] = React.useState(false) const [vendorDocuments, setVendorDocuments] = React.useState([]) const form = useForm({ resolver: zodResolver(evaluationSchema), defaultValues: { evaluationResult: undefined, conditionalRequirements: "", conditionsFulfilled: false, overallRemarks: "", }, }) const watchEvaluationResult = form.watch("evaluationResult") const isFormValid = form.formState.isValid const fetchVendorDocuments = React.useCallback(async () => { if (!selectedSession?.tbeSessionId) return setIsLoadingDocs(true) try { // 서버 액션 호출 const result = await getTbeVendorDocuments(selectedSession.tbeSessionId) if (result.success) { setVendorDocuments(result.documents || []) } else { console.error("Failed to fetch vendor documents:", result.error) toast.error(result.error || "벤더 문서 정보를 불러오는데 실패했습니다") } } catch (error) { console.error("Failed to fetch vendor documents:", error) toast.error("벤더 문서 정보를 불러오는데 실패했습니다") } finally { setIsLoadingDocs(false) } }, [selectedSession?.tbeSessionId]) // 벤더 문서 리뷰 상태 가져오기 React.useEffect(() => { if (open && selectedSession?.tbeSessionId) { fetchVendorDocuments() // 기존 평가 데이터가 있으면 폼에 설정 if (selectedSession.evaluationResult) { form.reset({ evaluationResult: selectedSession.evaluationResult as any, conditionalRequirements: selectedSession.conditionalRequirements || "", conditionsFulfilled: selectedSession.conditionsFulfilled || false, overallRemarks: (selectedSession as any).overallRemarks || "", }) } else { // 기존 평가 데이터가 없으면 초기화 form.reset({ evaluationResult: undefined, conditionalRequirements: "", conditionsFulfilled: false, overallRemarks: "", }) } } else if (!open) { // 다이얼로그가 닫힐 때 폼 리셋 form.reset({ evaluationResult: undefined, conditionalRequirements: "", conditionsFulfilled: false, overallRemarks: "", }) setVendorDocuments([]) } }, [open, selectedSession?.tbeSessionId, selectedSession?.evaluationResult, selectedSession?.conditionalRequirements, selectedSession?.conditionsFulfilled, fetchVendorDocuments, form]) const getReviewStatusIcon = (status: string) => { switch (status) { case "승인": return case "반려": return case "재검토필요": return case "검토완료": return case "검토중": return default: return } } const getReviewStatusVariant = (status: string): any => { switch (status) { case "승인": return "default" case "반려": return "destructive" case "재검토필요": return "secondary" case "검토완료": return "outline" default: return "outline" } } const onSubmit = async (values: EvaluationFormValues) => { if (!selectedSession?.tbeSessionId) return // 벤더 문서가 없는 경우 경고 if (vendorDocuments.length === 0 && !isLoadingDocs) { const confirmed = window.confirm( "검토된 벤더 문서가 없습니다. 그래도 평가를 진행하시겠습니까?" ) if (!confirmed) return } setIsLoading(true) try { // 서버 액션 호출 const result = await updateTbeEvaluation(selectedSession.tbeSessionId, { ...values, status: "완료", // 평가 완료 시 상태 업데이트 }) if (result.success) { toast.success("평가가 성공적으로 저장되었습니다") form.reset() onOpenChange(false) onSuccess?.() } else { toast.error(result.error || "평가 저장에 실패했습니다") } } catch (error) { console.error("Failed to save evaluation:", error) toast.error("평가 저장 중 오류가 발생했습니다") } finally { setIsLoading(false) } } const allDocumentsApproved = vendorDocuments.length > 0 && vendorDocuments.every((doc: any) => doc.reviewStatus === "승인" || doc.reviewStatus === "검토완료") const hasRejectedDocuments = vendorDocuments.some((doc: any) => doc.reviewStatus === "반려") return ( TBE 결과 입력 {selectedSession?.sessionCode} - {selectedSession?.vendorName}
{/* 벤더 문서 검토 현황 */}

벤더 문서 검토 현황

{isLoadingDocs ? (
문서 정보 로딩 중...
) : vendorDocuments.length === 0 ? ( 검토할 벤더 문서가 없습니다. ) : (
{vendorDocuments.map((doc: any) => (

{doc.documentName}

{doc.documentType}

{getReviewStatusIcon(doc.reviewStatus)} {doc.reviewStatus}
))} {/* 문서 검토 상태 요약 */}
전체 문서: {vendorDocuments.length}개
승인: {vendorDocuments.filter(d => d.reviewStatus === "승인").length} 반려: {vendorDocuments.filter(d => d.reviewStatus === "반려").length} 미검토: {vendorDocuments.filter(d => d.reviewStatus === "미검토").length}
{hasRejectedDocuments && ( 반려된 문서가 있습니다. 평가 결과를 "Not Acceptable"로 설정하는 것을 권장합니다. )} {!allDocumentsApproved && !hasRejectedDocuments && ( 모든 문서 검토가 완료되지 않았습니다. )}
)}
{/* 평가 폼 */}
( 평가 결과 * 최종 평가 결과를 선택합니다. )} /> {/* 조건부 승인 필드 */} {watchEvaluationResult === "Acceptable with Comment" && ( <> ( 조건부 요구사항