"use client" import * as React from "react" import { useForm, useFieldArray } from "react-hook-form" import { z } from "zod" import { zodResolver } from "@hookform/resolvers/zod" import { Loader, Download, X ,Loader2} from "lucide-react" import prettyBytes from "pretty-bytes" import { toast } from "sonner" import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Button } from "@/components/ui/button" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Textarea, } from "@/components/ui/textarea" import { Dropzone, DropzoneZone, DropzoneUploadIcon, DropzoneTitle, DropzoneDescription, DropzoneInput } from "@/components/ui/dropzone" import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/ui/table" // DB 스키마에서 필요한 타입들을 가져온다고 가정 // (실제 프로젝트에 맞춰 import를 수정하세요.) import { formatDate } from "@/lib/utils" import { createRfqCommentWithAttachments } from "@/lib/rfqs/service" // 코멘트 + 첨부파일 구조 (단순 예시) // 실제 DB 스키마에 맞춰 조정 export interface CbeComment { id: number commentText: string commentedBy?: number commentedByEmail?: string createdAt?: Date attachments?: { id: number fileName: string filePath: string }[] } interface CommentSheetProps extends React.ComponentPropsWithRef { initialComments?: CbeComment[] currentUserId: number rfqId: number // tbeId?: number cbeId?: number vendorId: number onCommentsUpdated?: (comments: CbeComment[]) => void isLoading?: boolean // New prop } // 새 코멘트 작성 폼 스키마 const commentFormSchema = z.object({ commentText: z.string().min(1, "댓글을 입력하세요."), newFiles: z.array(z.any()).optional() // File[] }) type CommentFormValues = z.infer const MAX_FILE_SIZE = 30e6 // 30MB export function CommentSheet({ rfqId, vendorId, initialComments = [], currentUserId, // tbeId, cbeId, onCommentsUpdated, isLoading = false, // Default to false ...props }: CommentSheetProps) { const [comments, setComments] = React.useState(initialComments) const [isPending, startTransition] = React.useTransition() React.useEffect(() => { setComments(initialComments) }, [initialComments]) // RHF 세팅 const form = useForm({ resolver: zodResolver(commentFormSchema), defaultValues: { commentText: "", newFiles: [] } }) // formFieldArray 예시 (파일 목록) const { fields: newFileFields, append, remove } = useFieldArray({ control: form.control, name: "newFiles" }) // (A) 기존 코멘트 렌더링 function renderExistingComments() { if (isLoading) { return (
Loading comments...
) } if (comments.length === 0) { return

No comments yet

} return ( Comment Attachments Created At Created By {comments.map((c) => ( {c.commentText} {/* 첨부파일 표시 */} {!c.attachments?.length && ( No files )} {c.attachments?.length && (
{c.attachments.map((att) => ( ))}
)}
{ c.createdAt ? formatDate(c.createdAt): "-"} {c.commentedByEmail ?? "-"}
))}
) } // 2) 새 파일 Drop function handleDropAccepted(files: File[]) { append(files) } // 3) 저장(Submit) async function onSubmit(data: CommentFormValues) { if (!rfqId) return startTransition(async () => { try { // console.log("rfqId", rfqId) // console.log("vendorId", vendorId) // console.log("cbeId", cbeId) // console.log("currentUserId", currentUserId) const res = await createRfqCommentWithAttachments({ rfqId: rfqId, vendorId: vendorId, // 필요시 세팅 commentText: data.commentText, commentedBy: currentUserId, evaluationId: null, // 필요시 세팅 cbeId: cbeId, files: data.newFiles }) if (!res.ok) { throw new Error("Failed to create comment") } toast.success("Comment created") // 새 코멘트를 다시 불러오거나, // 여기서는 임시로 "새로운 코멘트가 추가됐다" 라고 가정하여 클라이언트에서 상태 업데이트 const newComment: CbeComment = { id: res.commentId, // 서버에서 반환된 commentId commentText: data.commentText, commentedBy: currentUserId, createdAt: res.createdAt, attachments: (data.newFiles?.map((f, idx) => ({ id: Math.random() * 100000, fileName: f.name, filePath: "/uploads/" + f.name, })) || []) } setComments((prev) => [...prev, newComment]) onCommentsUpdated?.([...comments, newComment]) // 폼 리셋 form.reset() } catch (err: any) { console.error(err) toast.error("Error: " + err.message) } }) } return ( Comments 필요시 첨부파일과 함께 문의/코멘트를 남길 수 있습니다. {/* 기존 코멘트 목록 */}
{renderExistingComments()}
{/* 새 코멘트 작성 Form */}
( New Comment