From ba8cd44a0ed2c613a5f2cee06bfc9bd0f61f21c7 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
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-yard-entry-info.tsx    | 232 +++++++++++++++++++++
 1 file changed, 232 insertions(+)
 create mode 100644 lib/general-contracts/detail/general-contract-yard-entry-info.tsx

(limited to 'lib/general-contracts/detail/general-contract-yard-entry-info.tsx')

diff --git a/lib/general-contracts/detail/general-contract-yard-entry-info.tsx b/lib/general-contracts/detail/general-contract-yard-entry-info.tsx
new file mode 100644
index 00000000..1fb1e310
--- /dev/null
+++ b/lib/general-contracts/detail/general-contract-yard-entry-info.tsx
@@ -0,0 +1,232 @@
+'use client'
+
+import React, { useState, useEffect } from 'react'
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { Input } from '@/components/ui/input'
+import { Label } from '@/components/ui/label'
+import { Button } from '@/components/ui/button'
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
+import { Save, LoaderIcon } from 'lucide-react'
+import { toast } from 'sonner'
+import { useSession } from 'next-auth/react'
+import { getProjects, getYardEntryInfo, saveYardEntryInfo } from '../service'
+
+interface YardEntryInfo {
+  projectId: number | null
+  projectCode: string
+  projectName: string
+  managerName: string
+  managerDepartment: string
+  rehandlingContractor: string
+}
+
+interface ContractYardEntryInfoProps {
+  contractId: number
+  readOnly?: boolean
+}
+
+export function ContractYardEntryInfo({ contractId, readOnly = false }: ContractYardEntryInfoProps) {
+  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 [projects, setProjects] = useState<Array<{ id: number; code: string; name: string }>>([])
+  const [formData, setFormData] = useState<YardEntryInfo>({
+    projectId: null,
+    projectCode: '',
+    projectName: '',
+    managerName: '',
+    managerDepartment: '',
+    rehandlingContractor: ''
+  })
+
+  // 프로젝트 목록 로드
+  useEffect(() => {
+    const loadProjects = async () => {
+      try {
+        const projectList = await getProjects()
+        setProjects(projectList)
+      } catch (error) {
+        console.error('Error loading projects:', error)
+      }
+    }
+    loadProjects()
+  }, [])
+
+  // 데이터 로드
+  useEffect(() => {
+    const loadYardEntryInfo = async () => {
+      setIsLoading(true)
+      try {
+        const data = await getYardEntryInfo(contractId)
+        if (data) {
+          setFormData(data)
+        }
+      } catch (error) {
+        console.error('Error loading yard entry info:', error)
+        toast.error('사외업체 야드투입 정보를 불러오는 중 오류가 발생했습니다.')
+      } finally {
+        setIsLoading(false)
+      }
+    }
+
+    if (contractId) {
+      loadYardEntryInfo()
+    }
+  }, [contractId])
+
+  // 저장
+  const handleSave = async () => {
+    if (!userId) {
+      toast.error('사용자 정보를 찾을 수 없습니다.')
+      return
+    }
+
+    // 유효성 검사
+    if (!formData.projectId) {
+      toast.error('프로젝트를 선택해주세요.')
+      return
+    }
+
+    setIsSaving(true)
+    try {
+      await saveYardEntryInfo(contractId, formData, userId)
+      toast.success('사외업체 야드투입 정보가 저장되었습니다.')
+    } catch (error) {
+      console.error('Error saving yard entry info:', error)
+      toast.error('사외업체 야드투입 정보 저장 중 오류가 발생했습니다.')
+    } finally {
+      setIsSaving(false)
+    }
+  }
+
+  const selectedProject = projects.find(p => p.id === formData.projectId)
+
+  if (isLoading) {
+    return (
+      <Card>
+        <CardHeader>
+          <CardTitle>사외업체 야드투입 정보</CardTitle>
+        </CardHeader>
+        <CardContent>
+          <div className="flex items-center justify-center py-8">
+            <LoaderIcon className="w-6 h-6 animate-spin mr-2" />
+            <span>로딩 중...</span>
+          </div>
+        </CardContent>
+      </Card>
+    )
+  }
+
+  return (
+    <Card>
+      <CardHeader>
+        <div className="flex items-center justify-between">
+          <CardTitle>사외업체 야드투입 정보</CardTitle>
+          {!readOnly && (
+            <Button
+              onClick={handleSave}
+              disabled={isSaving}
+            >
+              {isSaving ? (
+                <>
+                  <LoaderIcon className="w-4 h-4 mr-2 animate-spin" />
+                  저장 중...
+                </>
+              ) : (
+                <>
+                  <Save className="w-4 h-4 mr-2" />
+                  저장
+                </>
+              )}
+            </Button>
+          )}
+        </div>
+      </CardHeader>
+      <CardContent>
+        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+          {/* 프로젝트 */}
+          <div className="flex flex-col gap-2">
+            <Label htmlFor="project">프로젝트 *</Label>
+            {readOnly ? (
+              <div className="text-sm">
+                {selectedProject ? `${selectedProject.code} - ${selectedProject.name}` : '-'}
+              </div>
+            ) : (
+              <Select
+                value={formData.projectId?.toString() || ''}
+                onValueChange={(value) => {
+                  const projectId = parseInt(value)
+                  const project = projects.find(p => p.id === projectId)
+                  setFormData(prev => ({
+                    ...prev,
+                    projectId: projectId,
+                    projectCode: project?.code || '',
+                    projectName: project?.name || ''
+                  }))
+                }}
+              >
+                <SelectTrigger>
+                  <SelectValue placeholder="프로젝트 선택" />
+                </SelectTrigger>
+                <SelectContent>
+                  {projects.map((project) => (
+                    <SelectItem key={project.id} value={project.id.toString()}>
+                      {project.code} - {project.name}
+                    </SelectItem>
+                  ))}
+                </SelectContent>
+              </Select>
+            )}
+          </div>
+
+          {/* 관리담당자 */}
+          <div className="flex flex-col gap-2">
+            <Label htmlFor="managerName">관리담당자</Label>
+            {readOnly ? (
+              <div className="text-sm">{formData.managerName || '-'}</div>
+            ) : (
+              <Input
+                id="managerName"
+                value={formData.managerName}
+                onChange={(e) => setFormData(prev => ({ ...prev, managerName: e.target.value }))}
+                placeholder="관리담당자 입력"
+              />
+            )}
+          </div>
+
+          {/* 관리부서 */}
+          <div className="flex flex-col gap-2">
+            <Label htmlFor="managerDepartment">관리부서</Label>
+            {readOnly ? (
+              <div className="text-sm">{formData.managerDepartment || '-'}</div>
+            ) : (
+              <Input
+                id="managerDepartment"
+                value={formData.managerDepartment}
+                onChange={(e) => setFormData(prev => ({ ...prev, managerDepartment: e.target.value }))}
+                placeholder="관리부서 입력"
+              />
+            )}
+          </div>
+
+          {/* 재하도협력사 */}
+          <div className="flex flex-col gap-2">
+            <Label htmlFor="rehandlingContractor">재하도협력사</Label>
+            {readOnly ? (
+              <div className="text-sm">{formData.rehandlingContractor || '-'}</div>
+            ) : (
+              <Input
+                id="rehandlingContractor"
+                value={formData.rehandlingContractor}
+                onChange={(e) => setFormData(prev => ({ ...prev, rehandlingContractor: e.target.value }))}
+                placeholder="재하도협력사 입력"
+              />
+            )}
+          </div>
+        </div>
+      </CardContent>
+    </Card>
+  )
+}
+
-- 
cgit v1.2.3

