From 33be47506f0aa62b969d82521580a29e95080268 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 13 Aug 2025 11:05:09 +0000 Subject: (대표님) 입찰, 법무검토, EDP 변경사항 대응, dolce 개선, form-data 개선, 정규업체 등록관리 추가 (최겸) pq 미사용 컴포넌트 및 페이지 제거, 파일 라우트에 pq 적용 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/pq/pq-review-table.tsx | 344 -------------------------------------- 1 file changed, 344 deletions(-) delete mode 100644 components/pq/pq-review-table.tsx (limited to 'components/pq/pq-review-table.tsx') diff --git a/components/pq/pq-review-table.tsx b/components/pq/pq-review-table.tsx deleted file mode 100644 index ce30bac0..00000000 --- a/components/pq/pq-review-table.tsx +++ /dev/null @@ -1,344 +0,0 @@ -"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 ( -
- {data.map((group) => ( - - -
-

{group.groupName}

- -
-
- - - - - - - Code - Check Point - Answer - Attachments - Comments - - - - - {group.items.map((item) => ( - - {item.code} - {item.checkPoint} - - - {item.answer ? ( -

- {item.answer} -

- ) : ( -

(no answer)

- )} -
- - - {item.attachments.length > 0 ? ( -
    - {item.attachments.map((file) => ( -
  • - -
  • - ))} -
- ) : ( -

(none)

- )} -
- - - - -
- ))} -
-
-
-
-
- ))} -
- ) -} - -interface ItemReviewButtonProps { - answerId?: number; - checkPoint: string; // Check Point 추가 - onCommentAdded?: () => void; -} - -/** - * A button that opens a dialog to show logs + add new comment for a single item (vendorPqCriteriaAnswers). - */ -function ItemReviewButton({ answerId, checkPoint, onCommentAdded }: ItemReviewButtonProps) { - const { toast } = useToast(); - const [open, setOpen] = React.useState(false); - const [logs, setLogs] = React.useState([]); - const [newComment, setNewComment] = React.useState(""); - const [isLoading, setIsLoading] = React.useState(false); - const [hasComments, setHasComments] = React.useState(false); - const { data: session } = useSession() - const reviewerName = session?.user?.name || "Unknown Reviewer" - const reviewerId = session?.user?.id - - // If there's no answerId, item wasn't answered - if (!answerId) { - 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 ( - <> - - - - - - {checkPoint} Comments - - - {/* Logs section */} -
- {isLoading ? ( -
- -
- ) : logs.length > 0 ? ( - logs.map((log) => ( -
-

{log.reviewerName}

-

{log.reviewerComment}

-

- {formatDate(log.createdAt, "KR")} -

-
- )) - ) : ( -

No comments yet.

- )} -
- - {/* Add new comment */} -
-