summaryrefslogtreecommitdiff
path: root/lib/general-contracts_old/detail/general-contract-basic-info.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/general-contracts_old/detail/general-contract-basic-info.tsx')
-rw-r--r--lib/general-contracts_old/detail/general-contract-basic-info.tsx1250
1 files changed, 0 insertions, 1250 deletions
diff --git a/lib/general-contracts_old/detail/general-contract-basic-info.tsx b/lib/general-contracts_old/detail/general-contract-basic-info.tsx
deleted file mode 100644
index d891fe63..00000000
--- a/lib/general-contracts_old/detail/general-contract-basic-info.tsx
+++ /dev/null
@@ -1,1250 +0,0 @@
-'use client'
-
-import React, { useState } from 'react'
-import { useSession } from 'next-auth/react'
-import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
-import { Input } from '@/components/ui/input'
-import { Label } from '@/components/ui/label'
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
-import { Textarea } from '@/components/ui/textarea'
-import { Button } from '@/components/ui/button'
-import { Save, LoaderIcon } from 'lucide-react'
-import { updateContractBasicInfo, getContractBasicInfo } from '../service'
-import { toast } from 'sonner'
-import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
-import { GeneralContract } from '@/db/schema'
-import { ContractDocuments } from './general-contract-documents'
-import { getPaymentTermsForSelection, getIncotermsForSelection, getPlaceOfShippingForSelection, getPlaceOfDestinationForSelection } from '@/lib/procurement-select/service'
-import { TAX_CONDITIONS, getTaxConditionName } from '@/lib/tax-conditions/types'
-
-interface ContractBasicInfoProps {
- contractId: number
-}
-
-export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
- const session = useSession()
- const [isLoading, setIsLoading] = useState(false)
- const [contract, setContract] = useState<GeneralContract | null>(null)
- const userId = session.data?.user?.id ? Number(session.data.user.id) : null
-
- // 독립적인 상태 관리
- const [paymentDeliveryPercent, setPaymentDeliveryPercent] = useState('')
-
- // Procurement 데이터 상태들
- const [paymentTermsOptions, setPaymentTermsOptions] = useState<Array<{code: string, description: string}>>([])
- const [incotermsOptions, setIncotermsOptions] = useState<Array<{code: string, description: string}>>([])
- const [shippingPlaces, setShippingPlaces] = useState<Array<{code: string, description: string}>>([])
- const [destinationPlaces, setDestinationPlaces] = useState<Array<{code: string, description: string}>>([])
- const [procurementLoading, setProcurementLoading] = useState(false)
-
- const [formData, setFormData] = useState({
- specificationType: '',
- specificationManualText: '',
- unitPriceType: '',
- warrantyPeriod: {
- 납품후: { enabled: false, period: 0, maxPeriod: 0 },
- 인도후: { enabled: false, period: 0, maxPeriod: 0 },
- 작업후: { enabled: false, period: 0, maxPeriod: 0 },
- 기타: { enabled: false, period: 0, maxPeriod: 0 },
- },
- contractAmount: null as number | null,
- currency: 'KRW',
- linkedPoNumber: '',
- linkedBidNumber: '',
- notes: '',
- // 개별 JSON 필드들 (스키마에 맞게)
- paymentBeforeDelivery: {} as any,
- paymentDelivery: '', // varchar 타입
- paymentAfterDelivery: {} as any,
- paymentTerm: '',
- taxType: '',
- liquidatedDamages: false as boolean,
- liquidatedDamagesPercent: '',
- deliveryType: '',
- deliveryTerm: '',
- shippingLocation: '',
- dischargeLocation: '',
- contractDeliveryDate: '',
- contractEstablishmentConditions: {
- regularVendorRegistration: false,
- projectAward: false,
- ownerApproval: false,
- other: false,
- },
- interlockingSystem: '',
- mandatoryDocuments: {
- technicalDataAgreement: false,
- nda: false,
- basicCompliance: false,
- safetyHealthAgreement: false,
- },
- contractTerminationConditions: {
- standardTermination: false,
- projectNotAwarded: false,
- other: false,
- },
- })
-
- const [errors] = useState<Record<string, string>>({})
-
- // 계약 데이터 로드
- React.useEffect(() => {
- const loadContract = async () => {
- try {
- console.log('Loading contract with ID:', contractId)
- const contractData = await getContractBasicInfo(contractId)
- console.log('Contract data received:', contractData)
- setContract(contractData as GeneralContract)
-
- // JSON 필드들 파싱 (null 체크) - 스키마에 맞게 개별 필드로 접근
- const paymentBeforeDelivery = (contractData?.paymentBeforeDelivery && typeof contractData.paymentBeforeDelivery === 'object') ? contractData.paymentBeforeDelivery as any : {}
- const paymentAfterDelivery = (contractData?.paymentAfterDelivery && typeof contractData.paymentAfterDelivery === 'object') ? contractData.paymentAfterDelivery as any : {}
- const warrantyPeriod = (contractData?.warrantyPeriod && typeof contractData.warrantyPeriod === 'object') ? contractData.warrantyPeriod as any : {}
- const contractEstablishmentConditions = (contractData?.contractEstablishmentConditions && typeof contractData.contractEstablishmentConditions === 'object') ? contractData.contractEstablishmentConditions as any : {}
- const mandatoryDocuments = (contractData?.mandatoryDocuments && typeof contractData.mandatoryDocuments === 'object') ? contractData.mandatoryDocuments as any : {}
- const contractTerminationConditions = (contractData?.contractTerminationConditions && typeof contractData.contractTerminationConditions === 'object') ? contractData.contractTerminationConditions as any : {}
-
- // paymentDelivery에서 퍼센트와 타입 분리
- const paymentDeliveryValue = contractData?.paymentDelivery || ''
- let paymentDeliveryType = ''
- let paymentDeliveryPercentValue = ''
-
- if (paymentDeliveryValue.includes('%')) {
- const match = paymentDeliveryValue.match(/(\d+)%\s*(.+)/)
- if (match) {
- paymentDeliveryPercentValue = match[1]
- paymentDeliveryType = match[2]
- }
- } else {
- paymentDeliveryType = paymentDeliveryValue
- }
-
- setPaymentDeliveryPercent(paymentDeliveryPercentValue)
-
- setFormData({
- specificationType: contractData?.specificationType || '',
- specificationManualText: contractData?.specificationManualText || '',
- unitPriceType: contractData?.unitPriceType || '',
- warrantyPeriod: warrantyPeriod || {
- 납품후: { enabled: false, period: 0, maxPeriod: 0 },
- 인도후: { enabled: false, period: 0, maxPeriod: 0 },
- 작업후: { enabled: false, period: 0, maxPeriod: 0 },
- 기타: { enabled: false, period: 0, maxPeriod: 0 },
- },
- contractAmount: contractData?.contractAmount || null,
- currency: contractData?.currency || 'KRW',
- linkedPoNumber: contractData?.linkedPoNumber || '',
- linkedBidNumber: contractData?.linkedBidNumber || '',
- notes: contractData?.notes || '',
- // 개별 JSON 필드들
- paymentBeforeDelivery: paymentBeforeDelivery || {} as any,
- paymentDelivery: paymentDeliveryType, // 분리된 타입만 저장
- paymentAfterDelivery: paymentAfterDelivery || {} as any,
- paymentTerm: contractData?.paymentTerm || '',
- taxType: contractData?.taxType || '',
- liquidatedDamages: Boolean(contractData?.liquidatedDamages),
- liquidatedDamagesPercent: contractData?.liquidatedDamagesPercent || '',
- deliveryType: contractData?.deliveryType || '',
- deliveryTerm: contractData?.deliveryTerm || '',
- shippingLocation: contractData?.shippingLocation || '',
- dischargeLocation: contractData?.dischargeLocation || '',
- contractDeliveryDate: contractData?.contractDeliveryDate || '',
- contractEstablishmentConditions: contractEstablishmentConditions || {
- regularVendorRegistration: false,
- projectAward: false,
- ownerApproval: false,
- other: false,
- },
- interlockingSystem: contractData?.interlockingSystem || '',
- mandatoryDocuments: mandatoryDocuments || {
- technicalDataAgreement: false,
- nda: false,
- basicCompliance: false,
- safetyHealthAgreement: false,
- },
- contractTerminationConditions: contractTerminationConditions || {
- standardTermination: false,
- projectNotAwarded: false,
- other: false,
- },
- })
- } catch (error) {
- console.error('Error loading contract:', error)
- toast.error('계약 정보를 불러오는 중 오류가 발생했습니다.')
- }
- }
-
- if (contractId) {
- loadContract()
- }
- }, [contractId])
-
- // Procurement 데이터 로드 함수들
- const loadPaymentTerms = React.useCallback(async () => {
- setProcurementLoading(true);
- try {
- const data = await getPaymentTermsForSelection();
- setPaymentTermsOptions(data);
- } catch (error) {
- console.error("Failed to load payment terms:", error);
- toast.error("결제조건 목록을 불러오는데 실패했습니다.");
- } finally {
- setProcurementLoading(false);
- }
- }, []);
-
- const loadIncoterms = React.useCallback(async () => {
- setProcurementLoading(true);
- try {
- const data = await getIncotermsForSelection();
- setIncotermsOptions(data);
- } catch (error) {
- console.error("Failed to load incoterms:", error);
- toast.error("운송조건 목록을 불러오는데 실패했습니다.");
- } finally {
- setProcurementLoading(false);
- }
- }, []);
-
- const loadShippingPlaces = React.useCallback(async () => {
- setProcurementLoading(true);
- try {
- const data = await getPlaceOfShippingForSelection();
- setShippingPlaces(data);
- } catch (error) {
- console.error("Failed to load shipping places:", error);
- toast.error("선적지 목록을 불러오는데 실패했습니다.");
- } finally {
- setProcurementLoading(false);
- }
- }, []);
-
- const loadDestinationPlaces = React.useCallback(async () => {
- setProcurementLoading(true);
- try {
- const data = await getPlaceOfDestinationForSelection();
- setDestinationPlaces(data);
- } catch (error) {
- console.error("Failed to load destination places:", error);
- toast.error("하역지 목록을 불러오는데 실패했습니다.");
- } finally {
- setProcurementLoading(false);
- }
- }, []);
-
- // 컴포넌트 마운트 시 procurement 데이터 로드
- React.useEffect(() => {
- loadPaymentTerms();
- loadIncoterms();
- loadShippingPlaces();
- loadDestinationPlaces();
- }, [loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces]);
- const handleSaveContractInfo = async () => {
- if (!userId) {
- toast.error('사용자 정보를 찾을 수 없습니다.')
- return
- }
- try {
- setIsLoading(true)
-
- // 필수값 validation 체크
- const validationErrors: string[] = []
- if (!formData.specificationType) validationErrors.push('사양')
- if (!formData.paymentDelivery) validationErrors.push('납품 지급조건')
- if (!formData.currency) validationErrors.push('계약통화')
- if (!formData.paymentTerm) validationErrors.push('지불조건')
- if (!formData.taxType) validationErrors.push('세금조건')
-
- if (validationErrors.length > 0) {
- toast.error(`다음 필수 항목을 입력해주세요: ${validationErrors.join(', ')}`)
- return
- }
-
- // paymentDelivery와 paymentDeliveryPercent 합쳐서 저장
- const dataToSave = {
- ...formData,
- paymentDelivery: (formData.paymentDelivery === 'L/C' || formData.paymentDelivery === 'T/T') && paymentDeliveryPercent
- ? `${paymentDeliveryPercent}% ${formData.paymentDelivery}`
- : formData.paymentDelivery
- }
-
- await updateContractBasicInfo(contractId, dataToSave, userId as number)
- toast.success('계약 정보가 저장되었습니다.')
- } catch (error) {
- console.error('Error saving contract info:', error)
- toast.error('계약 정보 저장 중 오류가 발생했습니다.')
- } finally {
- setIsLoading(false)
- }
- }
-
- return (
- <Card className="w-full">
- <CardHeader>
- <CardTitle>계약 기본 정보</CardTitle>
- </CardHeader>
- <CardContent>
- <Tabs defaultValue="basic" className="w-full">
- <TabsList className="grid w-full grid-cols-4 h-auto overflow-x-auto">
- <TabsTrigger value="basic" className="text-xs px-2 py-2 whitespace-nowrap">기본 정보</TabsTrigger>
- <TabsTrigger value="conditions" className="text-xs px-2 py-2 whitespace-nowrap">지급/인도 조건</TabsTrigger>
- <TabsTrigger value="additional" className="text-xs px-2 py-2 whitespace-nowrap">추가 조건</TabsTrigger>
- <TabsTrigger value="documents" className="text-xs px-2 py-2 whitespace-nowrap">계약첨부문서</TabsTrigger>
- </TabsList>
-
- {/* 기본 정보 탭 */}
- <TabsContent value="basic" className="space-y-6">
- <Card>
- {/* 보증기간 및 단가유형 */}
- <CardHeader>
- <CardTitle>보증기간 및 단가유형</CardTitle>
- </CardHeader>
- <CardContent className="space-y-4">
- {/* 3그리드: 보증기간, 사양, 단가 */}
- <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
- {/* 보증기간 */}
- <div className="flex flex-col gap-2">
- <Label htmlFor="warrantyPeriod">품질/하자 보증기간</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="warrantyAfterDelivery"
- checked={formData.warrantyPeriod.납품후?.enabled || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 납품후: {
- ...prev.warrantyPeriod.납품후,
- enabled: e.target.checked
- }
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="warrantyAfterDelivery" className="text-sm">납품 후</Label>
- </div>
- {formData.warrantyPeriod.납품후?.enabled && (
- <div className="ml-6 flex items-center space-x-2">
- <Input
- type="number"
- placeholder="보증기간"
- value={formData.warrantyPeriod.납품후?.period || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 납품후: {
- ...prev.warrantyPeriod.납품후,
- period: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월, 최대</span>
- <Input
- type="number"
- placeholder="최대"
- value={formData.warrantyPeriod.납품후?.maxPeriod || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 납품후: {
- ...prev.warrantyPeriod.납품후,
- maxPeriod: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월</span>
- </div>
- )}
-
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="warrantyAfterHandover"
- checked={formData.warrantyPeriod.인도후?.enabled || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 인도후: {
- ...prev.warrantyPeriod.인도후,
- enabled: e.target.checked
- }
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="warrantyAfterHandover" className="text-sm">인도 후</Label>
- </div>
- {formData.warrantyPeriod.인도후?.enabled && (
- <div className="ml-6 flex items-center space-x-2">
- <Input
- type="number"
- placeholder="보증기간"
- value={formData.warrantyPeriod.인도후?.period || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 인도후: {
- ...prev.warrantyPeriod.인도후,
- period: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월, 최대</span>
- <Input
- type="number"
- placeholder="최대"
- value={formData.warrantyPeriod.인도후?.maxPeriod || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 인도후: {
- ...prev.warrantyPeriod.인도후,
- maxPeriod: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월</span>
- </div>
- )}
-
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="warrantyAfterWork"
- checked={formData.warrantyPeriod.작업후?.enabled || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 작업후: {
- ...prev.warrantyPeriod.작업후,
- enabled: e.target.checked
- }
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="warrantyAfterWork" className="text-sm">작업 후</Label>
- </div>
- {formData.warrantyPeriod.작업후?.enabled && (
- <div className="ml-6 flex items-center space-x-2">
- <Input
- type="number"
- placeholder="보증기간"
- value={formData.warrantyPeriod.작업후?.period || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 작업후: {
- ...prev.warrantyPeriod.작업후,
- period: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월, 최대</span>
- <Input
- type="number"
- placeholder="최대"
- value={formData.warrantyPeriod.작업후?.maxPeriod || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 작업후: {
- ...prev.warrantyPeriod.작업후,
- maxPeriod: parseInt(e.target.value) || 0
- }
- }
- }))}
- className="w-20 h-8 text-sm"
- />
- <span className="text-xs text-muted-foreground">개월</span>
- </div>
- )}
-
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="warrantyOther"
- checked={formData.warrantyPeriod.기타?.enabled || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- warrantyPeriod: {
- ...prev.warrantyPeriod,
- 기타: {
- ...prev.warrantyPeriod.기타,
- enabled: e.target.checked
- }
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="warrantyOther" className="text-sm">기타/미적용</Label>
- </div>
- </div>
- </div>
- {/* 사양 */}
- <div className="flex flex-col gap-2">
- <Label htmlFor="specificationType">사양 <span className="text-red-600">*</span></Label>
- <Select value={formData.specificationType} onValueChange={(value) => setFormData(prev => ({ ...prev, specificationType: value }))}>
- <SelectTrigger className={errors.specificationType ? 'border-red-500' : ''}>
- <SelectValue placeholder="사양을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="첨부파일">첨부파일</SelectItem>
- <SelectItem value="표준사양">표준사양</SelectItem>
- <SelectItem value="수기사양">수기사양</SelectItem>
- </SelectContent>
- </Select>
- {errors.specificationType && (
- <p className="text-sm text-red-600">사양은 필수값입니다.</p>
- )}
- </div>
- {/* 단가 */}
- <div className="flex flex-col gap-2">
- <Label htmlFor="unitPriceType">단가 유형</Label>
- <Select value={formData.unitPriceType} onValueChange={(value) => setFormData(prev => ({ ...prev, unitPriceType: value }))}>
- <SelectTrigger>
- <SelectValue placeholder="단가 유형을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="자재개별단가">자재개별단가</SelectItem>
- <SelectItem value="서비스용역단가">서비스용역단가</SelectItem>
- <SelectItem value="프로젝트단가">프로젝트단가</SelectItem>
- <SelectItem value="지역별단가">지역별단가</SelectItem>
- <SelectItem value="직무직급단가">직무직급단가</SelectItem>
- <SelectItem value="단계별단가">단계별단가</SelectItem>
- <SelectItem value="기타">기타</SelectItem>
- </SelectContent>
- </Select>
- </div>
- {/* 선택에 따른 폼: vertical로 출력 */}
-
-
- {/* 사양이 수기사양일 때 매뉴얼 텍스트 */}
- {formData.specificationType === '수기사양' && (
- <div className="flex flex-col gap-2">
- <Label htmlFor="specificationManualText">사양 매뉴얼 텍스트</Label>
- <Textarea
- value={formData.specificationManualText}
- onChange={(e) => setFormData(prev => ({ ...prev, specificationManualText: e.target.value }))}
- placeholder="사양 매뉴얼 텍스트를 입력하세요"
- rows={3}
- />
- </div>
- )}
-
- </div>
-
-
- </CardContent>
- </Card>
- </TabsContent>
-
- {/* 지급/인도 조건 탭 */}
- <TabsContent value="conditions" className="space-y-6">
- <Card>
- <CardHeader>
- <CardTitle>Payment & Delivery Conditions (지급/인도 조건)</CardTitle>
- </CardHeader>
- <CardContent className="space-y-6">
- <div className="grid grid-cols-5 gap-6">
- {/* 납품 전 지급조건 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">납품 전</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="apBond"
- checked={formData.paymentBeforeDelivery.apBond || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- apBond: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="apBond" className="text-sm">AP Bond & Performance Bond</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.paymentBeforeDelivery.apBondPercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- apBondPercent: e.target.value
- }
- }))}
- disabled={!formData.paymentBeforeDelivery.apBond}
- />
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="drawingSubmission"
- checked={formData.paymentBeforeDelivery.drawingSubmission || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- drawingSubmission: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="drawingSubmission" className="text-sm">도면제출</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.paymentBeforeDelivery.drawingSubmissionPercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- drawingSubmissionPercent: e.target.value
- }
- }))}
- disabled={!formData.paymentBeforeDelivery.drawingSubmission}
- />
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="materialPurchase"
- checked={formData.paymentBeforeDelivery.materialPurchase || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- materialPurchase: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="materialPurchase" className="text-sm">소재구매 문서</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.paymentBeforeDelivery.materialPurchasePercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentBeforeDelivery: {
- ...prev.paymentBeforeDelivery,
- materialPurchasePercent: e.target.value
- }
- }))}
- disabled={!formData.paymentBeforeDelivery.materialPurchase}
- />
- </div>
- </div>
- </div>
-
- {/* 납품 지급조건 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">납품</Label>
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="paymentDelivery">납품 지급조건 <span className="text-red-600">*</span></Label>
- <Select value={formData.paymentDelivery} onValueChange={(value) => setFormData(prev => ({ ...prev, paymentDelivery: value }))}>
- <SelectTrigger className={errors.paymentDelivery ? 'border-red-500' : ''}>
- <SelectValue placeholder="납품 지급조건을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="L/C">L/C</SelectItem>
- <SelectItem value="T/T">T/T</SelectItem>
- <SelectItem value="거래명세서 기반 정기지급조건">거래명세서 기반 정기지급조건</SelectItem>
- <SelectItem value="작업 및 입고 검사 완료">작업 및 입고 검사 완료</SelectItem>
- <SelectItem value="청구내역서 제출 및 승인">청구내역서 제출 및 승인</SelectItem>
- <SelectItem value="정규금액 월 단위 정산(지정일 지급)">정규금액 월 단위 정산(지정일 지급)</SelectItem>
- </SelectContent>
- </Select>
- {/* L/C 또는 T/T 선택 시 퍼센트 입력 필드 */}
- {(formData.paymentDelivery === 'L/C' || formData.paymentDelivery === 'T/T') && (
- <div className="flex items-center gap-2 mt-2">
- <Input
- type="number"
- min="0"
- value={paymentDeliveryPercent}
- onChange={(e) => setPaymentDeliveryPercent(e.target.value)}
- placeholder="퍼센트"
- className="w-20 h-8 text-sm"
- />
- <span className="text-sm text-gray-600">%</span>
- </div>
- )}
- {errors.paymentDelivery && (
- <p className="text-sm text-red-600">납품 지급조건은 필수값입니다.</p>
- )}
- </div>
- </div>
- </div>
-
- {/* 납품 외 지급조건 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">납품 외</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="commissioning"
- checked={formData.paymentAfterDelivery.commissioning || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- commissioning: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="commissioning" className="text-sm">Commissioning 완료</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.paymentAfterDelivery.commissioningPercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- commissioningPercent: e.target.value
- }
- }))}
- disabled={!formData.paymentAfterDelivery.commissioning}
- />
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="finalDocument"
- checked={formData.paymentAfterDelivery.finalDocument || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- finalDocument: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="finalDocument" className="text-sm">최종문서 승인</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.paymentAfterDelivery.finalDocumentPercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- finalDocumentPercent: e.target.value
- }
- }))}
- disabled={!formData.paymentAfterDelivery.finalDocument}
- />
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="other"
- checked={formData.paymentAfterDelivery.other || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- other: e.target.checked
- }
- }))}
- className="rounded"
- />
- <Label htmlFor="other" className="text-sm">기타</Label>
- <Input
- type="text"
- placeholder="기타 조건을 입력하세요"
- className="w-48"
- value={formData.paymentAfterDelivery.otherText || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- paymentAfterDelivery: {
- ...prev.paymentAfterDelivery,
- otherText: e.target.value
- }
- }))}
- disabled={!formData.paymentAfterDelivery.other}
- />
- </div>
- </div>
- </div>
-
- {/* 지불조건 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">지불조건</Label>
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="paymentTerm">지불조건 <span className="text-red-600">*</span></Label>
- <Select
- value={formData.paymentTerm}
- onValueChange={(value) => setFormData(prev => ({ ...prev, paymentTerm: value }))}
- >
- <SelectTrigger className={errors.paymentTerm ? 'border-red-500' : ''}>
- <SelectValue placeholder="지불조건을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- {paymentTermsOptions.length > 0 ? (
- paymentTermsOptions.map((option) => (
- <SelectItem key={option.code} value={option.code}>
- {option.code} {option.description && `(${option.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- {errors.paymentTerm && (
- <p className="text-sm text-red-600">지불조건은 필수값입니다.</p>
- )}
- </div>
- <div className="space-y-2">
- <Label htmlFor="taxType">세금조건 <span className="text-red-600">*</span></Label>
- <Select
- value={formData.taxType}
- onValueChange={(value) => setFormData(prev => ({ ...prev, taxType: value }))}
- >
- <SelectTrigger className={errors.taxType ? 'border-red-500' : ''}>
- <SelectValue placeholder="세금조건을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- {TAX_CONDITIONS.map((condition) => (
- <SelectItem key={condition.code} value={condition.code}>
- {condition.name}
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- {errors.taxType && (
- <p className="text-sm text-red-600">세금조건은 필수값입니다.</p>
- )}
- </div>
- </div>
- </div>
-
- {/* 클레임금액 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">클레임금액</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="liquidatedDamages"
- checked={formData.liquidatedDamages || false}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- liquidatedDamages: e.target.checked
- }))}
- className="rounded"
- />
- <Label htmlFor="liquidatedDamages" className="text-sm">지체상금</Label>
- <Input
- type="number"
- min="0"
- placeholder="%"
- className="w-16"
- value={formData.liquidatedDamagesPercent || ''}
- onChange={(e) => setFormData(prev => ({
- ...prev,
- liquidatedDamagesPercent: e.target.value
- }))}
- disabled={!formData.liquidatedDamages}
- />
- </div>
- </div>
- </div>
- </div>
-
- {/* 인도조건 섹션 */}
- <div className="mt-8">
- <h3 className="text-lg font-semibold mb-4">인도조건</h3>
- <div className="grid grid-cols-5 gap-6">
- {/* 납기종류 */}
- <div className="space-y-4">
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="deliveryType">납기종류</Label>
- <Select value={formData.deliveryType} onValueChange={(value) => setFormData(prev => ({ ...prev, deliveryType: value }))}>
- <SelectTrigger>
- <SelectValue placeholder="납기종류를 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="단일납기">단일납기</SelectItem>
- <SelectItem value="분할납기">분할납기</SelectItem>
- <SelectItem value="구간납기">구간납기</SelectItem>
- </SelectContent>
- </Select>
- </div>
- </div>
- </div>
-
- {/* 인도조건 */}
- <div className="space-y-4">
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="deliveryTerm">인도조건</Label>
- <Select
- value={formData.deliveryTerm}
- onValueChange={(value) => setFormData(prev => ({ ...prev, deliveryTerm: value }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="인도조건을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- {incotermsOptions.length > 0 ? (
- incotermsOptions.map((option) => (
- <SelectItem key={option.code} value={option.code}>
- {option.code} {option.description && `(${option.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
- </div>
- </div>
-
- {/* 선적지 */}
- <div className="space-y-4">
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="shippingLocation">선적지</Label>
- <Select
- value={formData.shippingLocation}
- onValueChange={(value) => setFormData(prev => ({ ...prev, shippingLocation: value }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="선적지를 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- {shippingPlaces.length > 0 ? (
- shippingPlaces.map((place) => (
- <SelectItem key={place.code} value={place.code}>
- {place.code} {place.description && `(${place.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
- </div>
- </div>
-
- {/* 하역지 */}
- <div className="space-y-4">
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="dischargeLocation">하역지</Label>
- <Select
- value={formData.dischargeLocation}
- onValueChange={(value) => setFormData(prev => ({ ...prev, dischargeLocation: value }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="하역지를 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- {destinationPlaces.length > 0 ? (
- destinationPlaces.map((place) => (
- <SelectItem key={place.code} value={place.code}>
- {place.code} {place.description && `(${place.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
- </div>
- </div>
-
- {/* 계약납기일 */}
- <div className="space-y-4">
- <div className="space-y-3">
- <div className="space-y-2">
- <Label htmlFor="contractDeliveryDate">계약납기일</Label>
- <Input
- type="date"
- value={formData.contractDeliveryDate}
- onChange={(e) => setFormData(prev => ({ ...prev, contractDeliveryDate: e.target.value }))}
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- </CardContent>
- </Card>
- </TabsContent>
-
- {/* 추가 조건 탭 */}
- <TabsContent value="additional" className="space-y-6">
- <Card>
- <CardHeader>
- <CardTitle>Additional Conditions (추가조건)</CardTitle>
- </CardHeader>
- <CardContent className="space-y-6">
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
- <div className="space-y-2">
- <Label htmlFor="contractAmount">계약금액 (자동계산)</Label>
- <Input
- type="text"
- value={contract?.contractAmount ? new Intl.NumberFormat('ko-KR').format(Number(contract.contractAmount)) : '품목정보 없음'}
- readOnly
- className="bg-gray-50"
- placeholder="품목정보에서 자동 계산됩니다"
- />
- </div>
- <div className="space-y-2">
- <Label htmlFor="currency">계약통화 <span className="text-red-600">*</span></Label>
- <Input
- type="text"
- value={formData.currency}
- onChange={(e) => setFormData(prev => ({ ...prev, currency: e.target.value }))}
- placeholder="계약통화를 입력하세요"
- className={errors.currency ? 'border-red-500' : ''}
- />
- {errors.currency && (
- <p className="text-sm text-red-600">계약통화는 필수값입니다.</p>
- )}
- </div>
-
- {/* 계약성립조건 */}
- <div className="space-y-4 col-span-2">
- <Label className="text-base font-medium">계약성립조건</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="regularVendorRegistration"
- checked={formData.contractEstablishmentConditions.regularVendorRegistration}
- onChange={(e) => setFormData(prev => ({ ...prev, contractEstablishmentConditions: { ...prev.contractEstablishmentConditions, regularVendorRegistration: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="regularVendorRegistration">정규업체 등록(실사 포함) 시</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="projectAward"
- checked={formData.contractEstablishmentConditions.projectAward}
- onChange={(e) => setFormData(prev => ({ ...prev, contractEstablishmentConditions: { ...prev.contractEstablishmentConditions, projectAward: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="projectAward">프로젝트 수주 시</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="ownerApproval"
- checked={formData.contractEstablishmentConditions.ownerApproval}
- onChange={(e) => setFormData(prev => ({ ...prev, contractEstablishmentConditions: { ...prev.contractEstablishmentConditions, ownerApproval: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="ownerApproval">선주 승인 시</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="establishmentOther"
- checked={formData.contractEstablishmentConditions.other}
- onChange={(e) => setFormData(prev => ({ ...prev, contractEstablishmentConditions: { ...prev.contractEstablishmentConditions, other: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="establishmentOther">기타</Label>
- </div>
- </div>
- </div>
-
- {/* 연동제적용 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">연동제적용</Label>
- <div className="space-y-2">
- <Select value={formData.interlockingSystem} onValueChange={(value) => setFormData(prev => ({ ...prev, interlockingSystem: value }))}>
- <SelectTrigger>
- <SelectValue placeholder="연동제적용을 선택하세요" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="Y">Y</SelectItem>
- <SelectItem value="N">N</SelectItem>
- </SelectContent>
- </Select>
- </div>
- </div>
-
- {/* 필수문서동의 */}
- {/* <div className="space-y-4">
- <Label className="text-base font-medium">필수문서동의</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="technicalDataAgreement"
- checked={formData.mandatoryDocuments.technicalDataAgreement}
- onChange={(e) => setFormData(prev => ({ ...prev, mandatoryDocuments: { ...prev.mandatoryDocuments, technicalDataAgreement: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="technicalDataAgreement">기술자료제공동의서</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="nda"
- checked={formData.mandatoryDocuments.nda}
- onChange={(e) => setFormData(prev => ({ ...prev, mandatoryDocuments: { ...prev.mandatoryDocuments, nda: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="nda">비밀유지계약서(NDA)</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="basicCompliance"
- checked={formData.mandatoryDocuments.basicCompliance}
- onChange={(e) => setFormData(prev => ({ ...prev, mandatoryDocuments: { ...prev.mandatoryDocuments, basicCompliance: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="basicCompliance">기본준수서약서</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="safetyHealthAgreement"
- checked={formData.mandatoryDocuments.safetyHealthAgreement}
- onChange={(e) => setFormData(prev => ({ ...prev, mandatoryDocuments: { ...prev.mandatoryDocuments, safetyHealthAgreement: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="safetyHealthAgreement">안전보건관리 약정서</Label>
- </div>
- </div>
- </div> */}
-
- {/* 계약해지조건 */}
- <div className="space-y-4">
- <Label className="text-base font-medium">계약해지조건</Label>
- <div className="space-y-3">
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="standardTermination"
- checked={formData.contractTerminationConditions.standardTermination}
- onChange={(e) => setFormData(prev => ({ ...prev, contractTerminationConditions: { ...prev.contractTerminationConditions, standardTermination: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="standardTermination">표준 계약해지조건</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="projectNotAwarded"
- checked={formData.contractTerminationConditions.projectNotAwarded}
- onChange={(e) => setFormData(prev => ({ ...prev, contractTerminationConditions: { ...prev.contractTerminationConditions, projectNotAwarded: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="projectNotAwarded">프로젝트 미수주 시</Label>
- </div>
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="terminationOther"
- checked={formData.contractTerminationConditions.other}
- onChange={(e) => setFormData(prev => ({ ...prev, contractTerminationConditions: { ...prev.contractTerminationConditions, other: e.target.checked } }))}
- className="rounded"
- />
- <Label htmlFor="terminationOther">기타</Label>
- </div>
- </div>
- </div>
-
- <div className="space-y-2 col-span-2">
- <Label htmlFor="notes">비고</Label>
- <Textarea
- value={formData.notes}
- onChange={(e) => setFormData(prev => ({ ...prev, notes: e.target.value }))}
- placeholder="비고사항을 입력하세요"
- rows={4}
- />
- </div>
- </div>
- </CardContent>
- </Card>
- </TabsContent>
-
-
- {/* 계약첨부문서 탭 */}
- <TabsContent value="documents" className="space-y-6">
- <ContractDocuments
- contractId={contractId}
- userId={userId?.toString() || "1"}
- />
- </TabsContent>
- </Tabs>
-
- {/* 저장 버튼 */}
- <div className="flex justify-end mt-6 pt-4 border-t border-gray-200">
- <Button
- onClick={handleSaveContractInfo}
- disabled={isLoading}
- className="flex items-center gap-2"
- >
- {isLoading ? (
- <LoaderIcon className="w-4 h-4 animate-spin" />
- ) : (
- <Save className="w-4 h-4" />
- )}
- 계약 정보 저장
- </Button>
- </div>
- </CardContent>
- </Card>
- )
-}