"use client" import * as React from "react" import { ChevronsUpDown, MessagesSquare, Download, Loader2 } from "lucide-react" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { PQGroupData } from "@/lib/pq/service" import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Textarea } from "@/components/ui/textarea" import { addReviewCommentAction, getItemReviewLogsAction } from "@/lib/pq/service" import { useToast } from "@/hooks/use-toast" import { formatDate } from "@/lib/utils" import { downloadFileAction } from "@/lib/downloadFile" import { useSession } from "next-auth/react" interface ReviewLog { id: number reviewerComment: string reviewerName: string | null createdAt: Date } interface VendorPQReviewPageProps { data: PQGroupData[]; onCommentAdded?: () => void; // 코멘트 추가 콜백 } export default function VendorPQReviewPage({ data, onCommentAdded }: VendorPQReviewPageProps) { const { toast } = useToast() // 파일 다운로드 함수 - 서버 액션 사용 const handleFileDownload = async (filePath: string, fileName: string) => { try { toast({ title: "Download Started", description: `Preparing ${fileName} for download...`, }); // 서버 액션 호출 const result = await downloadFileAction(filePath); if (!result.ok || !result.data) { throw new Error(result.error || 'Failed to download file'); } // Base64 디코딩하여 Blob 생성 const binaryString = atob(result.data.content); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } // Blob 생성 및 다운로드 const blob = new Blob([bytes.buffer], { type: result.data.mimeType }); const url = URL.createObjectURL(blob); // 다운로드 링크 생성 및 클릭 const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); // 정리 URL.revokeObjectURL(url); document.body.removeChild(a); toast({ title: "Download Complete", description: `${fileName} downloaded successfully`, }); } catch (error) { console.error('Download error:', error); toast({ title: "Download Error", description: error instanceof Error ? error.message : "Failed to download file", variant: "destructive" }); } }; return (
N/A
; } // fetchLogs 함수를 useCallback으로 메모이제이션 const fetchLogs = React.useCallback(async () => { try { setIsLoading(true); const res = await getItemReviewLogsAction({ answerId }); if (res.ok && res.data) { setLogs(res.data); // 코멘트 존재 여부 설정 setHasComments(res.data.length > 0); } else { console.error("Error response:", res.error); toast({ title: "Error", description: res.error, variant: "destructive" }); } } catch (error) { console.error("Fetch error:", error); toast({ title: "Error", description: String(error), variant: "destructive" }); } finally { setIsLoading(false); } }, [answerId, toast]); // 초기 로드 시 코멘트 존재 여부 확인 (아이콘 색상용) React.useEffect(() => { const checkComments = async () => { try { const res = await getItemReviewLogsAction({ answerId }); if (res.ok && res.data) { setHasComments(res.data.length > 0); } } catch (error) { console.error("Error checking comments:", error); } }; checkComments(); }, [answerId]); // open 상태가 변경될 때 로그 가져오기 React.useEffect(() => { if (open) { fetchLogs(); } }, [open, fetchLogs]); // 버튼 클릭 핸들러 - 다이얼로그 열기 const handleButtonClick = React.useCallback(() => { setOpen(true); }, []); // 다이얼로그 상태 변경 핸들러 const handleOpenChange = React.useCallback((nextOpen: boolean) => { setOpen(nextOpen); }, []); // 코멘트 추가 핸들러 const handleAddComment = React.useCallback(async () => { try { setIsLoading(true); const res = await addReviewCommentAction({ answerId, comment: newComment, reviewerName, }); if (res.ok) { toast({ title: "Comment added", description: "New review comment saved" }); setNewComment(""); setHasComments(true); // 코멘트 추가 성공 시 상태 업데이트 // 코멘트가 추가되었음을 부모 컴포넌트에 알림 if (onCommentAdded) { onCommentAdded(); } // 로그 다시 가져오기 fetchLogs(); } else { toast({ title: "Error", description: res.error, variant: "destructive" }); } } catch (error) { toast({ title: "Error", description: String(error), variant: "destructive" }); } finally { setIsLoading(false); } }, [answerId, newComment, onCommentAdded, fetchLogs, toast]); return ( <> > ); }