From ef4c533ebacc2cdc97e518f30e9a9350004fcdfb Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 28 Apr 2025 02:13:30 +0000
Subject: ~20250428 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/rfqs/tbe-table/comments-sheet.tsx | 145 ++++++++++++++++------------------
 1 file changed, 68 insertions(+), 77 deletions(-)

(limited to 'lib/rfqs/tbe-table/comments-sheet.tsx')

diff --git a/lib/rfqs/tbe-table/comments-sheet.tsx b/lib/rfqs/tbe-table/comments-sheet.tsx
index bea1fc8e..6efd631f 100644
--- a/lib/rfqs/tbe-table/comments-sheet.tsx
+++ b/lib/rfqs/tbe-table/comments-sheet.tsx
@@ -4,7 +4,7 @@ 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 } from "lucide-react"
+import { Download, X, Loader2 } from "lucide-react"
 import prettyBytes from "pretty-bytes"
 import { toast } from "sonner"
 
@@ -26,41 +26,34 @@ import {
   FormLabel,
   FormMessage,
 } from "@/components/ui/form"
-import {
-  Textarea,
-} from "@/components/ui/textarea"
-
+import { Textarea } from "@/components/ui/textarea"
 import {
   Dropzone,
   DropzoneZone,
   DropzoneUploadIcon,
   DropzoneTitle,
   DropzoneDescription,
-  DropzoneInput
+  DropzoneInput,
 } from "@/components/ui/dropzone"
-
 import {
   Table,
   TableHeader,
   TableRow,
   TableHead,
   TableBody,
-  TableCell
+  TableCell,
 } from "@/components/ui/table"
 
-// DB 스키마에서 필요한 타입들을 가져온다고 가정
-// (실제 프로젝트에 맞춰 import를 수정하세요.)
-import { RfqWithAll } from "@/db/schema/rfq"
 import { createRfqCommentWithAttachments } from "../service"
 import { formatDate } from "@/lib/utils"
 
-// 코멘트 + 첨부파일 구조 (단순 예시)
-// 실제 DB 스키마에 맞춰 조정
+
 export interface TbeComment {
   id: number
   commentText: string
   commentedBy?: number
-  createdAt?: string | Date
+  commentedByEmail?: string
+  createdAt?: Date
   attachments?: {
     id: number
     fileName: string
@@ -68,23 +61,21 @@ export interface TbeComment {
   }[]
 }
 
+// 1) props 정의
 interface CommentSheetProps extends React.ComponentPropsWithRef<typeof Sheet> {
-  /** 코멘트를 작성할 RFQ 정보 */
-  /** 이미 존재하는 모든 코멘트 목록 (서버에서 불러와 주입) */
   initialComments?: TbeComment[]
-
-  /** 사용자(작성자) ID (로그인 세션 등에서 가져옴) */
   currentUserId: number
-  rfqId:number
-  vendorId:number
-  /** 댓글 저장 후 갱신용 콜백 (옵션) */
+  rfqId: number
+  tbeId: number
+  vendorId: number
   onCommentsUpdated?: (comments: TbeComment[]) => void
+  isLoading?: boolean // New prop
 }
 
-// 새 코멘트 작성 폼 스키마
+// 2) 폼 스키마
 const commentFormSchema = z.object({
   commentText: z.string().min(1, "댓글을 입력하세요."),
-  newFiles: z.array(z.any()).optional() // File[]
+  newFiles: z.array(z.any()).optional(), // File[]
 })
 type CommentFormValues = z.infer<typeof commentFormSchema>
 
@@ -95,40 +86,48 @@ export function CommentSheet({
   vendorId,
   initialComments = [],
   currentUserId,
+  tbeId,
   onCommentsUpdated,
+  isLoading = false, // Default to false
   ...props
 }: CommentSheetProps) {
+  console.log("tbeId", tbeId)
+
   const [comments, setComments] = React.useState<TbeComment[]>(initialComments)
   const [isPending, startTransition] = React.useTransition()
 
   React.useEffect(() => {
     setComments(initialComments)
   }, [initialComments])
-  
 
-  // RHF 세팅
   const form = useForm<CommentFormValues>({
     resolver: zodResolver(commentFormSchema),
     defaultValues: {
       commentText: "",
-      newFiles: []
-    }
+      newFiles: [],
+    },
   })
 
-  // formFieldArray 예시 (파일 목록)
   const { fields: newFileFields, append, remove } = useFieldArray({
     control: form.control,
-    name: "newFiles"
+    name: "newFiles",
   })
 
-  // 1) 기존 코멘트 + 첨부 보여주기
-  // 간단히 테이블 하나로 표현
-  // 실제로는 Bubble 형태의 UI, Accordion, Timeline 등 다양하게 구성할 수 있음
+  // (A) 기존 코멘트 렌더링
   function renderExistingComments() {
+
+    if (isLoading) {
+      return (
+        <div className="flex justify-center items-center h-32">
+          <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
+          <span className="ml-2 text-sm text-muted-foreground">Loading comments...</span>
+        </div>
+      )
+    }
+
     if (comments.length === 0) {
       return <p className="text-sm text-muted-foreground">No comments yet</p>
     }
-
     return (
       <Table>
         <TableHeader>
@@ -144,16 +143,15 @@ export function CommentSheet({
             <TableRow key={c.id}>
               <TableCell>{c.commentText}</TableCell>
               <TableCell>
-                {/* 첨부파일 표시 */}
-                {(!c.attachments || c.attachments.length === 0) && (
+                {!c.attachments?.length && (
                   <span className="text-sm text-muted-foreground">No files</span>
                 )}
-                {c.attachments && c.attachments.length > 0 && (
+                {c.attachments?.length && (
                   <div className="flex flex-col gap-1">
                     {c.attachments.map((att) => (
                       <div key={att.id} className="flex items-center gap-2">
                         <a
-                          href={att.filePath}
+                          href={`/api/rfq-download?path=${encodeURIComponent(att.filePath)}`}
                           download
                           target="_blank"
                           rel="noreferrer"
@@ -167,10 +165,8 @@ export function CommentSheet({
                   </div>
                 )}
               </TableCell>
-              <TableCell> { c.createdAt ? formatDate(c.createdAt): "-"}</TableCell>
-              <TableCell>
-                {c.commentedBy ?? "-"}
-              </TableCell>
+              <TableCell> {c.createdAt ? formatDate(c.createdAt) : "-"}</TableCell>
+              <TableCell>{c.commentedByEmail ?? "-"}</TableCell>
             </TableRow>
           ))}
         </TableBody>
@@ -178,28 +174,28 @@ export function CommentSheet({
     )
   }
 
-  // 2) 새 파일 Drop
+  // (B) 파일 드롭
   function handleDropAccepted(files: File[]) {
-    // 드롭된 File[]을 RHF field array에 추가
-    const toAppend = files.map((f) => f)
-    append(toAppend)
+    append(files)
   }
 
-
-  // 3) 저장(Submit)
+  // (C) Submit
   async function onSubmit(data: CommentFormValues) {
-
     if (!rfqId) return
     startTransition(async () => {
       try {
-        // 서버 액션 호출
+        console.log("rfqId", rfqId)
+        console.log("vendorId", vendorId)
+        console.log("tbeId", tbeId)
+        console.log("currentUserId", currentUserId)
         const res = await createRfqCommentWithAttachments({
-          rfqId: rfqId,
-          vendorId: vendorId, // 필요시 세팅
+          rfqId,
+          vendorId,
           commentText: data.commentText,
           commentedBy: currentUserId,
-          evaluationId: null, // 필요시 세팅
-          files: data.newFiles
+          evaluationId: tbeId,
+          cbeId: null,
+          files: data.newFiles,
         })
 
         if (!res.ok) {
@@ -208,23 +204,22 @@ export function CommentSheet({
 
         toast.success("Comment created")
 
-        // 새 코멘트를 다시 불러오거나,
-        // 여기서는 임시로 "새로운 코멘트가 추가됐다" 라고 가정하여 클라이언트에서 상태 업데이트
+        // 임시로 새 코멘트 추가
         const newComment: TbeComment = {
-          id: res.commentId, // 서버에서 반환된 commentId
+          id: res.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,
-          })) || [])
+          createdAt: res.createdAt,
+          attachments:
+            data.newFiles?.map((f) => ({
+              id: Math.floor(Math.random() * 1e6),
+              fileName: f.name,
+              filePath: "/uploads/" + f.name,
+            })) || [],
         }
         setComments((prev) => [...prev, newComment])
         onCommentsUpdated?.([...comments, newComment])
 
-        // 폼 리셋
         form.reset()
       } catch (err: any) {
         console.error(err)
@@ -243,12 +238,8 @@ export function CommentSheet({
           </SheetDescription>
         </SheetHeader>
 
-        {/* 기존 코멘트 목록 */}
-        <div className="max-h-[300px] overflow-y-auto">
-          {renderExistingComments()}
-        </div>
+        <div className="max-h-[300px] overflow-y-auto">{renderExistingComments()}</div>
 
-        {/* 새 코멘트 작성 Form */}
         <Form {...form}>
           <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-4">
             <FormField
@@ -258,17 +249,13 @@ export function CommentSheet({
                 <FormItem>
                   <FormLabel>New Comment</FormLabel>
                   <FormControl>
-                    <Textarea
-                      placeholder="Enter your comment..."
-                      {...field}
-                    />
+                    <Textarea placeholder="Enter your comment..." {...field} />
                   </FormControl>
                   <FormMessage />
                 </FormItem>
               )}
             />
 
-            {/* Dropzone (파일 첨부) */}
             <Dropzone
               maxSize={MAX_FILE_SIZE}
               onDropAccepted={handleDropAccepted}
@@ -292,15 +279,19 @@ export function CommentSheet({
               )}
             </Dropzone>
 
-            {/* 선택된 파일 목록 */}
             {newFileFields.length > 0 && (
               <div className="flex flex-col gap-2">
                 {newFileFields.map((field, idx) => {
                   const file = form.getValues(`newFiles.${idx}`)
                   if (!file) return null
                   return (
-                    <div key={field.id} className="flex items-center justify-between border rounded p-2">
-                      <span className="text-sm">{file.name} ({prettyBytes(file.size)})</span>
+                    <div
+                      key={field.id}
+                      className="flex items-center justify-between border rounded p-2"
+                    >
+                      <span className="text-sm">
+                        {file.name} ({prettyBytes(file.size)})
+                      </span>
                       <Button
                         variant="ghost"
                         size="icon"
@@ -322,7 +313,7 @@ export function CommentSheet({
                 </Button>
               </SheetClose>
               <Button disabled={isPending}>
-                {isPending && <Loader className="mr-2 h-4 w-4 animate-spin" />}
+                {isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
                 Save
               </Button>
             </SheetFooter>
-- 
cgit v1.2.3

