summaryrefslogtreecommitdiff
path: root/lib/general-contracts/detail/general-contract-review-comments.tsx
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-10 11:25:19 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-10 11:25:19 +0900
commita5501ad1d1cb836d2b2f84e9b0f06049e22c901e (patch)
tree667ed8c5d6ec35b109190e9f976d66ae54def4ce /lib/general-contracts/detail/general-contract-review-comments.tsx
parentb0fe980376fcf1a19ff4b90851ca8b01f378fdc0 (diff)
parentf8a38907911d940cb2e8e6c9aa49488d05b2b578 (diff)
Merge remote-tracking branch 'origin/dujinkim' into master_homemaster
Diffstat (limited to 'lib/general-contracts/detail/general-contract-review-comments.tsx')
-rw-r--r--lib/general-contracts/detail/general-contract-review-comments.tsx194
1 files changed, 194 insertions, 0 deletions
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<string>('')
+ const [shiComment, setShiComment] = useState<string>('')
+ 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 (
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <MessageSquare className="h-5 w-5" />
+ 계약 조건 검토 의견
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-6">
+ {/* Vendor Comment */}
+ {showVendorComment && (
+ <div className="space-y-2">
+ <Label className="text-sm font-medium">Vendor Comment</Label>
+ <div className="min-h-[120px] p-4 bg-yellow-50 border-2 border-yellow-200 rounded-lg">
+ {vendorComment ? (
+ <p className="text-sm whitespace-pre-wrap">{vendorComment}</p>
+ ) : (
+ <p className="text-sm text-muted-foreground">협력업체 의견이 없습니다.</p>
+ )}
+ </div>
+ </div>
+ )}
+
+ {/* SHI Comment */}
+ {showShiComment && (
+ <div className="space-y-2">
+ <Label className="text-sm font-medium">SHI Comment</Label>
+ {isEditingShiComment ? (
+ <div className="space-y-2">
+ <Textarea
+ value={shiComment}
+ onChange={(e) => setShiComment(e.target.value)}
+ placeholder="SHI 의견을 입력하세요"
+ rows={6}
+ className="resize-none"
+ disabled={isSaving}
+ />
+ <div className="flex gap-2">
+ <Button
+ onClick={handleConfirmReview}
+ disabled={isSaving || !shiComment.trim()}
+ className="flex-1"
+ >
+ {isSaving ? (
+ <>
+ <Save className="h-4 w-4 mr-2 animate-spin" />
+ 확정 중...
+ </>
+ ) : (
+ <>
+ <Send className="h-4 w-4 mr-2" />
+ 의견 회신 및 검토 확정
+ </>
+ )}
+ </Button>
+ {shiComment && (
+ <Button
+ variant="outline"
+ onClick={() => {
+ setIsEditingShiComment(false)
+ // 원래 값으로 복원하기 위해 다시 로드
+ getContractReviewComments(contractId).then((result) => {
+ if (result.success) {
+ setShiComment(result.shiComment || '')
+ }
+ })
+ }}
+ disabled={isSaving}
+ >
+ 취소
+ </Button>
+ )}
+ </div>
+ </div>
+ ) : (
+ <div className="space-y-2">
+ <div className="min-h-[120px] p-4 bg-gray-50 border rounded-lg">
+ {shiComment ? (
+ <p className="text-sm whitespace-pre-wrap">{shiComment}</p>
+ ) : (
+ <p className="text-sm text-muted-foreground">SHI 의견이 없습니다.</p>
+ )}
+ </div>
+ {canEditShiComment && (
+ <Button
+ variant="outline"
+ onClick={() => setIsEditingShiComment(true)}
+ className="w-full"
+ >
+ <Save className="h-4 w-4 mr-2" />
+ 의견 수정
+ </Button>
+ )}
+ </div>
+ )}
+ </div>
+ )}
+
+ {/* 상태가 아닌 경우 안내 메시지 */}
+ {!showVendorComment && !showShiComment && (
+ <div className="text-center py-8 text-muted-foreground">
+ <p>조건검토 요청 상태가 아닙니다.</p>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+ )
+}
+