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-storage-info.tsx | 249 +++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 lib/general-contracts/detail/general-contract-storage-info.tsx (limited to 'lib/general-contracts/detail/general-contract-storage-info.tsx') diff --git a/lib/general-contracts/detail/general-contract-storage-info.tsx b/lib/general-contracts/detail/general-contract-storage-info.tsx new file mode 100644 index 00000000..2c9b230c --- /dev/null +++ b/lib/general-contracts/detail/general-contract-storage-info.tsx @@ -0,0 +1,249 @@ +'use client' + +import React, { useState, useEffect } from 'react' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import { Button } from '@/components/ui/button' +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' +import { Save, Plus, Trash2, LoaderIcon } from 'lucide-react' +import { toast } from 'sonner' +import { useSession } from 'next-auth/react' +import { getStorageInfo, saveStorageInfo } from '../service' + +interface StorageInfoItem { + id?: number + poNumber: string + hullNumber: string + remainingAmount: number +} + +interface ContractStorageInfoProps { + contractId: number + readOnly?: boolean +} + +export function ContractStorageInfo({ contractId, readOnly = false }: ContractStorageInfoProps) { + const session = useSession() + const userId = session.data?.user?.id ? Number(session.data.user.id) : null + const [isLoading, setIsLoading] = useState(false) + const [isSaving, setIsSaving] = useState(false) + const [items, setItems] = useState([]) + + // 데이터 로드 + useEffect(() => { + const loadStorageInfo = async () => { + setIsLoading(true) + try { + const data = await getStorageInfo(contractId) + setItems(data || []) + } catch (error) { + console.error('Error loading storage info:', error) + toast.error('임치계약 정보를 불러오는 중 오류가 발생했습니다.') + } finally { + setIsLoading(false) + } + } + + if (contractId) { + loadStorageInfo() + } + }, [contractId]) + + // 행 추가 + const addRow = () => { + setItems(prev => [...prev, { + poNumber: '', + hullNumber: '', + remainingAmount: 0 + }]) + } + + // 행 삭제 + const deleteRow = (index: number) => { + setItems(prev => prev.filter((_, i) => i !== index)) + } + + // 항목 업데이트 + const updateItem = (index: number, field: keyof StorageInfoItem, value: string | number) => { + setItems(prev => prev.map((item, i) => + i === index ? { ...item, [field]: value } : item + )) + } + + // 저장 + const handleSave = async () => { + if (!userId) { + toast.error('사용자 정보를 찾을 수 없습니다.') + return + } + + // 유효성 검사 + const errors: string[] = [] + items.forEach((item, index) => { + if (!item.poNumber.trim()) errors.push(`${index + 1}번째 행의 PO No.`) + if (!item.hullNumber.trim()) errors.push(`${index + 1}번째 행의 호선`) + if (item.remainingAmount < 0) errors.push(`${index + 1}번째 행의 미입고 잔여금액`) + }) + + if (errors.length > 0) { + toast.error(`다음 항목을 확인해주세요: ${errors.join(', ')}`) + return + } + + setIsSaving(true) + try { + await saveStorageInfo(contractId, items, userId) + toast.success('임치계약 정보가 저장되었습니다.') + } catch (error) { + console.error('Error saving storage info:', error) + toast.error('임치계약 정보 저장 중 오류가 발생했습니다.') + } finally { + setIsSaving(false) + } + } + + if (isLoading) { + return ( + + + 임치(물품보관)계약 상세 정보 + + +
+ + 로딩 중... +
+
+
+ ) + } + + return ( + + +
+ 임치(물품보관)계약 상세 정보 + {!readOnly && ( +
+ + +
+ )} +
+
+ + {items.length === 0 ? ( +
+

등록된 정보가 없습니다.

+ {!readOnly && ( + + )} +
+ ) : ( +
+ + + + 번호 + PO No. + 호선 + 미입고 잔여금액 + {!readOnly && 삭제} + + + + {items.map((item, index) => ( + + {index + 1} + + {readOnly ? ( + {item.poNumber || '-'} + ) : ( + updateItem(index, 'poNumber', e.target.value)} + placeholder="PO No. 입력" + className="h-8 text-sm" + /> + )} + + + {readOnly ? ( + {item.hullNumber || '-'} + ) : ( + updateItem(index, 'hullNumber', e.target.value)} + placeholder="호선 입력" + className="h-8 text-sm" + /> + )} + + + {readOnly ? ( + + {item.remainingAmount.toLocaleString()} + + ) : ( + updateItem(index, 'remainingAmount', parseFloat(e.target.value) || 0)} + placeholder="0" + className="h-8 text-sm text-right" + min="0" + /> + )} + + {!readOnly && ( + + + + )} + + ))} + +
+
+ )} +
+
+ ) +} + -- cgit v1.2.3