From ba8cd44a0ed2c613a5f2cee06bfc9bd0f61f21c7 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 7 Nov 2025 08:39:04 +0000 Subject: (최겸) 입찰/견적 수정사항 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/general-contract-review-comments.tsx | 194 +++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 lib/general-contracts/detail/general-contract-review-comments.tsx (limited to 'lib/general-contracts/detail/general-contract-review-comments.tsx') diff --git a/lib/general-contracts/detail/general-contract-review-comments.tsx b/lib/general-contracts/detail/general-contract-review-comments.tsx new file mode 100644 index 00000000..e80211f2 --- /dev/null +++ b/lib/general-contracts/detail/general-contract-review-comments.tsx @@ -0,0 +1,194 @@ +'use client' + +import React, { useState, useEffect } from 'react' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Label } from '@/components/ui/label' +import { Textarea } from '@/components/ui/textarea' +import { Button } from '@/components/ui/button' +import { MessageSquare, Send, Save } from 'lucide-react' +import { toast } from 'sonner' +import { useSession } from 'next-auth/react' +import { + getContractReviewComments, + confirmContractReview +} from '../service' + +interface ContractReviewCommentsProps { + contractId: number + contractStatus: string +} + +export function ContractReviewComments({ contractId, contractStatus }: ContractReviewCommentsProps) { + const session = useSession() + const userId = session.data?.user?.id ? Number(session.data.user.id) : null + + const [vendorComment, setVendorComment] = useState('') + const [shiComment, setShiComment] = useState('') + const [isSaving, setIsSaving] = useState(false) + const [isEditingShiComment, setIsEditingShiComment] = useState(false) + + // 계약 상태에 따른 표시 여부 + const showVendorComment = ['Request to Review', 'Vendor Replied Review', 'SHI Confirmed Review'].includes(contractStatus) + const showShiComment = ['Vendor Replied Review', 'SHI Confirmed Review'].includes(contractStatus) + const canEditShiComment = contractStatus === 'Vendor Replied Review' && userId + + useEffect(() => { + const loadComments = async () => { + try { + const result = await getContractReviewComments(contractId) + if (result.success) { + if (result.vendorComment) { + setVendorComment(result.vendorComment) + } + if (result.shiComment) { + setShiComment(result.shiComment) + setIsEditingShiComment(false) // 이미 저장된 의견이 있으면 편집 모드 해제 + } else { + setIsEditingShiComment(canEditShiComment ? true : false) // 의견이 없고 편집 가능하면 편집 모드 + } + } + } catch (error) { + console.error('의견 로드 오류:', error) + } + } + + if (showVendorComment || showShiComment) { + loadComments() + } + }, [contractId, showVendorComment, showShiComment, canEditShiComment]) + + const handleConfirmReview = async () => { + if (!shiComment.trim()) { + toast.error('SHI 의견을 입력해주세요.') + return + } + + if (!userId) { + toast.error('로그인이 필요합니다.') + return + } + + setIsSaving(true) + try { + await confirmContractReview(contractId, shiComment, userId) + toast.success('검토가 확정되었습니다.') + // 페이지 새로고침 + window.location.reload() + } catch (error) { + console.error('검토 확정 오류:', error) + const errorMessage = error instanceof Error ? error.message : '검토 확정에 실패했습니다.' + toast.error(errorMessage) + } finally { + setIsSaving(false) + } + } + + return ( + + + + + 계약 조건 검토 의견 + + + + {/* Vendor Comment */} + {showVendorComment && ( +
+ +
+ {vendorComment ? ( +

{vendorComment}

+ ) : ( +

협력업체 의견이 없습니다.

+ )} +
+
+ )} + + {/* SHI Comment */} + {showShiComment && ( +
+ + {isEditingShiComment ? ( +
+