"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 { RfqWithAll } from "@/db/schema/rfq" import { createRfqCommentWithAttachments } from "../../rfqs/service" import { formatDate } from "@/lib/utils" // 코멘트 + 첨부파일 구조 (단순 예시) // 실제 DB 스키마에 맞춰 조정 export interface TbeComment { id: number commentText: string commentedBy?: number createdAt?: string | Date attachments?: { id: number fileName: string filePath: string }[] } interface CommentSheetProps extends React.ComponentPropsWithRef { /** 코멘트를 작성할 RFQ 정보 */ /** 이미 존재하는 모든 코멘트 목록 (서버에서 불러와 주입) */ initialComments?: TbeComment[] /** 사용자(작성자) ID (로그인 세션 등에서 가져옴) */ currentUserId: number rfqId:number vendorId:number /** 댓글 저장 후 갱신용 콜백 (옵션) */ onCommentsUpdated?: (comments: TbeComment[]) => 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, 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" }) // 1) 기존 코멘트 + 첨부 보여주기 // 간단히 테이블 하나로 표현 // 실제로는 Bubble 형태의 UI, Accordion, Timeline 등 다양하게 구성할 수 있음 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 || c.attachments.length === 0) && ( No files )} {c.attachments && c.attachments.length > 0 && (
{c.attachments.map((att) => ( ))}
)}
{ c.createdAt ? formatDate(c.createdAt): "-"} {c.commentedBy ?? "-"}
))}
) } // 2) 새 파일 Drop function handleDropAccepted(files: File[]) { // 드롭된 File[]을 RHF field array에 추가 const toAppend = files.map((f) => f) append(toAppend) } // 3) 저장(Submit) async function onSubmit(data: CommentFormValues) { if (!rfqId) return startTransition(async () => { try { // 서버 액션 호출 const res = await createRfqCommentWithAttachments({ rfqId: rfqId, vendorId: vendorId, // 필요시 세팅 commentText: data.commentText, commentedBy: currentUserId, evaluationId: null, // 필요시 세팅 files: data.newFiles }) if (!res.ok) { throw new Error("Failed to create comment") } toast.success("Comment created") // 새 코멘트를 다시 불러오거나, // 여기서는 임시로 "새로운 코멘트가 추가됐다" 라고 가정하여 클라이언트에서 상태 업데이트 const newComment: TbeComment = { id: res.commentId, // 서버에서 반환된 commentId commentText: data.commentText, commentedBy: currentUserId, createdAt: new Date().toISOString(), 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