From ba35e67845f935c8ce0151c9ef1fefa0b0510faf Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Mon, 22 Sep 2025 18:59:13 +0900
Subject: (김준회) AVL 피드백 반영 (이진용 프로 건)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/avl/table/avl-vendor-add-and-modify-dialog.tsx | 386 +++++++++++++--------
 1 file changed, 232 insertions(+), 154 deletions(-)

(limited to 'lib/avl/table/avl-vendor-add-and-modify-dialog.tsx')

diff --git a/lib/avl/table/avl-vendor-add-and-modify-dialog.tsx b/lib/avl/table/avl-vendor-add-and-modify-dialog.tsx
index 174982e4..4f0eb404 100644
--- a/lib/avl/table/avl-vendor-add-and-modify-dialog.tsx
+++ b/lib/avl/table/avl-vendor-add-and-modify-dialog.tsx
@@ -8,7 +8,6 @@ import {
   DialogFooter,
   DialogHeader,
   DialogTitle,
-  DialogTrigger,
 } from "@/components/ui/dialog"
 import { Button } from "@/components/ui/button"
 import { Input } from "@/components/ui/input"
@@ -24,6 +23,14 @@ import {
 } from "@/components/ui/select"
 import { toast } from "sonner"
 import type { AvlVendorInfoInput, AvlDetailItem } from "../types"
+import { EngineeringDisciplineSelector, type DisciplineCode } from "@/components/common/discipline"
+import { MaterialGroupSelectorDialogSingle } from "@/components/common/material/material-group-selector-dialog-single"
+import type { MaterialSearchItem } from "@/lib/material/material-group-service"
+import { VendorSelectorDialogSingle } from "@/components/common/vendor"
+import type { VendorSearchItem } from "@/components/common/vendor"
+import { PlaceOfShippingSelector } from "@/components/common/selectors/place-of-shipping"
+import { VendorTierSelector } from "@/components/common/selectors/vendor-tier"
+import { DatePicker } from "@/components/ui/date-picker"
 
 interface AvlVendorAddAndModifyDialogProps {
   open: boolean
@@ -58,6 +65,16 @@ export function AvlVendorAddAndModifyDialog({
   initialHtDivision,
   initialProjectCode
 }: AvlVendorAddAndModifyDialogProps) {
+  // 설계공종 선택 상태
+  const [selectedDiscipline, setSelectedDiscipline] = React.useState<DisciplineCode | undefined>(undefined)
+  // 자재그룹 선택 상태
+  const [selectedMaterialGroup, setSelectedMaterialGroup] = React.useState<MaterialSearchItem | null>(null)
+  // 벤더 선택 상태
+  const [selectedVendor, setSelectedVendor] = React.useState<VendorSearchItem | null>(null)
+  // 날짜 상태 (Date 객체로 관리)
+  const [quoteReceivedDate, setQuoteReceivedDate] = React.useState<Date | undefined>(undefined)
+  const [recentQuoteDate, setRecentQuoteDate] = React.useState<Date | undefined>(undefined)
+  const [recentOrderDate, setRecentOrderDate] = React.useState<Date | undefined>(undefined)
   const [formData, setFormData] = React.useState<Omit<AvlVendorInfoInput, 'avlListId'>>({
     // 공통 기본 설정
     isTemplate: isTemplate,
@@ -137,9 +154,50 @@ export function AvlVendorAddAndModifyDialog({
     remarks: ""
   })
 
-  // 수정 모드일 때 폼 데이터 초기화
+  // 수정 모드일 때 설계공종 선택 상태 및 폼 데이터 초기화
   React.useEffect(() => {
     if (editingItem) {
+      // 설계공종 선택 상태 초기화
+      if (editingItem.disciplineCode && editingItem.disciplineName) {
+        setSelectedDiscipline({
+          CD: editingItem.disciplineCode,
+          USR_DF_CHAR_18: editingItem.disciplineName
+        })
+      } else {
+        setSelectedDiscipline(undefined)
+      }
+
+      // 자재그룹 선택 상태 초기화
+      if (editingItem.materialGroupCode && editingItem.materialGroupName) {
+        setSelectedMaterialGroup({
+          materialGroupCode: editingItem.materialGroupCode,
+          materialGroupDescription: editingItem.materialGroupName,
+          displayText: `${editingItem.materialGroupCode} - ${editingItem.materialGroupName}`
+        })
+      } else {
+        setSelectedMaterialGroup(null)
+      }
+
+      // 벤더 선택 상태 초기화 (기존 데이터가 있으면 가상의 벤더 객체 생성)
+      if (editingItem.vendorCode || editingItem.vendorName) {
+        setSelectedVendor({
+          id: -1, // 임시 ID (실제 벤더 ID는 알 수 없음)
+          vendorName: editingItem.vendorName || "",
+          vendorCode: editingItem.vendorCode || null,
+          status: "UNKNOWN", // 상태 정보 없음
+          displayText: editingItem.vendorCode 
+            ? `${editingItem.vendorName} (${editingItem.vendorCode})`
+            : editingItem.vendorName || ""
+        })
+      } else {
+        setSelectedVendor(null)
+      }
+
+      // 날짜 상태 초기화
+      setQuoteReceivedDate(editingItem.quoteReceivedDate ? new Date(editingItem.quoteReceivedDate) : undefined)
+      setRecentQuoteDate(editingItem.recentQuoteDate ? new Date(editingItem.recentQuoteDate) : undefined)
+      setRecentOrderDate(editingItem.recentOrderDate ? new Date(editingItem.recentOrderDate) : undefined)
+
       setFormData({
         // 공통 기본 설정
         isTemplate: editingItem.isTemplate ?? isTemplate,
@@ -224,6 +282,17 @@ export function AvlVendorAddAndModifyDialog({
   // 다이얼로그가 열릴 때 초기값 재설정 (수정 모드가 아닐 때만)
   React.useEffect(() => {
     if (open && !editingItem) {
+      // 설계공종 선택 상태 초기화
+      setSelectedDiscipline(undefined)
+      // 자재그룹 선택 상태 초기화
+      setSelectedMaterialGroup(null)
+      // 벤더 선택 상태 초기화
+      setSelectedVendor(null)
+      // 날짜 상태 초기화
+      setQuoteReceivedDate(undefined)
+      setRecentQuoteDate(undefined)
+      setRecentOrderDate(undefined)
+      
       setFormData(prev => ({
         ...prev,
         isTemplate: isTemplate,
@@ -236,6 +305,40 @@ export function AvlVendorAddAndModifyDialog({
     }
   }, [open, editingItem, isTemplate, initialProjectCode, initialConstructionSector, initialShipType, initialAvlKind, initialHtDivision])
 
+  // 설계공종 선택 핸들러
+  const handleDisciplineSelect = React.useCallback((discipline: DisciplineCode) => {
+    setSelectedDiscipline(discipline)
+    setFormData(prev => ({
+      ...prev,
+      disciplineCode: discipline.CD,
+      disciplineName: discipline.USR_DF_CHAR_18
+    }))
+  }, [])
+
+  // 자재그룹 선택 핸들러
+  const handleMaterialGroupSelect = React.useCallback((materialGroup: MaterialSearchItem | null) => {
+    setSelectedMaterialGroup(materialGroup)
+    setFormData(prev => ({
+      ...prev,
+      materialGroupCode: materialGroup?.materialGroupCode || "",
+      materialGroupName: materialGroup?.materialGroupDescription || ""
+    }))
+  }, [])
+
+  // 벤더 선택 핸들러 (선택기에서 벤더를 선택했을 때 Input 필드에 자동 입력)
+  const handleVendorSelect = React.useCallback((vendor: VendorSearchItem | null) => {
+    setSelectedVendor(vendor)
+    if (vendor) {
+      setFormData(prev => ({
+        ...prev,
+        vendorCode: vendor.vendorCode || "",
+        vendorName: vendor.vendorName || "",
+        // AVL 등재업체명도 기본적으로 벤더명으로 설정 (사용자가 수정 가능)
+        avlVendorName: vendor.vendorName || ""
+      }))
+    }
+  }, [])
+
   const handleSubmit = async () => {
     // 공통 필수 필드 검증
     if (!formData.disciplineName || !formData.materialNameCustomerSide) {
@@ -259,15 +362,34 @@ export function AvlVendorAddAndModifyDialog({
     }
 
     try {
+      // 날짜 필드들을 문자열로 변환
+      const formatDate = (date: Date | undefined): string => {
+        if (!date) return ""
+        return date.toISOString().split('T')[0] // YYYY-MM-DD 형식
+      }
+
+      const submissionData = {
+        ...formData,
+        quoteReceivedDate: formatDate(quoteReceivedDate),
+        recentQuoteDate: formatDate(recentQuoteDate),
+        recentOrderDate: formatDate(recentOrderDate),
+      }
+
       if (editingItem && onUpdateItem) {
         // 수정 모드
-        await onUpdateItem(editingItem.id, formData)
+        await onUpdateItem(editingItem.id, submissionData)
       } else {
         // 추가 모드
-        await onAddItem(formData)
+        await onAddItem(submissionData)
       }
 
-      // 폼 초기화
+      // 폼 및 선택 상태 초기화
+      setSelectedDiscipline(undefined)
+      setSelectedMaterialGroup(null)
+      setSelectedVendor(null)
+      setQuoteReceivedDate(undefined)
+      setRecentQuoteDate(undefined)
+      setRecentOrderDate(undefined)
       setFormData({
         isTemplate: isTemplate,
         projectCode: initialProjectCode || "",
@@ -313,12 +435,18 @@ export function AvlVendorAddAndModifyDialog({
       } as Omit<AvlVendorInfoInput, 'avlListId'>)
 
       onOpenChange(false)
-    } catch (error) {
+    } catch {
       // 에러 처리는 호출하는 쪽에서 담당
     }
   }
 
   const handleCancel = () => {
+    setSelectedDiscipline(undefined)
+    setSelectedMaterialGroup(null)
+    setSelectedVendor(null)
+    setQuoteReceivedDate(undefined)
+    setRecentQuoteDate(undefined)
+    setRecentOrderDate(undefined)
     setFormData({
       isTemplate: isTemplate,
       projectCode: initialProjectCode || "",
@@ -365,31 +493,6 @@ export function AvlVendorAddAndModifyDialog({
     onOpenChange(false)
   }
 
-  // 선종 옵션들 (공사부문에 따라 다름)
-  const getShipTypeOptions = (constructionSector: string) => {
-    if (constructionSector === "조선") {
-      return [
-        { value: "A-max", label: "A-max" },
-        { value: "S-max", label: "S-max" },
-        { value: "VLCC", label: "VLCC" },
-        { value: "LNGC", label: "LNGC" },
-        { value: "CONT", label: "CONT" },
-      ]
-    } else if (constructionSector === "해양") {
-      return [
-        { value: "FPSO", label: "FPSO" },
-        { value: "FLNG", label: "FLNG" },
-        { value: "FPU", label: "FPU" },
-        { value: "Platform", label: "Platform" },
-        { value: "WTIV", label: "WTIV" },
-        { value: "GOM", label: "GOM" },
-      ]
-    } else {
-      return []
-    }
-  }
-
-  const shipTypeOptions = getShipTypeOptions(formData.constructionSector)
 
   return (
     <Dialog open={open} onOpenChange={onOpenChange}>
@@ -419,6 +522,8 @@ export function AvlVendorAddAndModifyDialog({
                     value={formData.projectCode}
                     onChange={(e) => setFormData(prev => ({ ...prev, projectCode: e.target.value }))}
                     placeholder="프로젝트 코드를 입력하세요"
+                    readOnly
+                    className="bg-muted"
                   />
                 </div>
               </div>
@@ -430,82 +535,39 @@ export function AvlVendorAddAndModifyDialog({
               <div className="grid grid-cols-2 gap-4">
                 <div className="space-y-2">
                   <Label htmlFor="constructionSector">공사부문 *</Label>
-                  <Select
+                  <Input
                     value={formData.constructionSector}
-                    onValueChange={(value) => {
-                      setFormData(prev => ({
-                        ...prev,
-                        constructionSector: value,
-                        shipType: "" // 공사부문 변경 시 선종 초기화
-                      }))
-                    }}
-                  >
-                    <SelectTrigger>
-                      <SelectValue placeholder="공사부문을 선택하세요" />
-                    </SelectTrigger>
-                    <SelectContent>
-                      <SelectItem value="조선">조선</SelectItem>
-                      <SelectItem value="해양">해양</SelectItem>
-                    </SelectContent>
-                  </Select>
+                    readOnly
+                    className="bg-muted"
+                    placeholder="공사부문이 설정되지 않았습니다"
+                  />
                 </div>
                 <div className="space-y-2">
                   <Label htmlFor="shipType">선종 *</Label>
-                  <Select
+                  <Input
                     value={formData.shipType}
-                    onValueChange={(value) =>
-                      setFormData(prev => ({ ...prev, shipType: value }))
-                    }
-                    disabled={!formData.constructionSector}
-                  >
-                    <SelectTrigger>
-                      <SelectValue placeholder="선종을 선택하세요" />
-                    </SelectTrigger>
-                    <SelectContent>
-                      {shipTypeOptions.map((option) => (
-                        <SelectItem key={option.value} value={option.value}>
-                          {option.label}
-                        </SelectItem>
-                      ))}
-                    </SelectContent>
-                  </Select>
+                    readOnly
+                    className="bg-muted"
+                    placeholder="선종이 설정되지 않았습니다"
+                  />
                 </div>
                 <div className="space-y-2">
                   <Label htmlFor="avlKind">AVL종류 *</Label>
-                  <Select
+                  <Input
                     value={formData.avlKind}
-                    onValueChange={(value) =>
-                      setFormData(prev => ({ ...prev, avlKind: value }))
-                    }
-                  >
-                    <SelectTrigger>
-                      <SelectValue placeholder="AVL종류를 선택하세요" />
-                    </SelectTrigger>
-                    <SelectContent>
-                      <SelectItem value="Nearshore">Nearshore</SelectItem>
-                      <SelectItem value="Offshore">Offshore</SelectItem>
-                      <SelectItem value="IOC">IOC</SelectItem>
-                      <SelectItem value="NOC">NOC</SelectItem>
-                    </SelectContent>
-                  </Select>
+                    readOnly
+                    className="bg-muted"
+                    placeholder="AVL종류가 설정되지 않았습니다"
+                  />
                 </div>
                 <div className="space-y-2">
                   <Label htmlFor="htDivision">H/T 구분 *</Label>
-                  <Select
+                  <Input
                     value={formData.htDivision}
-                    onValueChange={(value) =>
-                      setFormData(prev => ({ ...prev, htDivision: value }))
-                    }
-                  >
-                    <SelectTrigger>
-                      <SelectValue placeholder="H/T 구분을 선택하세요" />
-                    </SelectTrigger>
-                    <SelectContent>
-                      <SelectItem value="공통">공통</SelectItem>
-                      <SelectItem value="H">Hull (H)</SelectItem>
-                      <SelectItem value="T">Topside (T)</SelectItem>
-                    </SelectContent>
-                  </Select>
+                    readOnly
+                    className="bg-muted"
+                    placeholder="H/T 구분이 설정되지 않았습니다"
+                  />
                 </div>
               </div>
             </div>
@@ -533,23 +595,19 @@ export function AvlVendorAddAndModifyDialog({
                   </SelectContent>
                 </Select>
               </div>
-              <div className="space-y-2">
-                <Label htmlFor="disciplineCode">설계공종코드</Label>
-                <Input
-                  id="disciplineCode"
-                  value={formData.disciplineCode}
-                  onChange={(e) => setFormData(prev => ({ ...prev, disciplineCode: e.target.value }))}
-                  placeholder="설계공종코드를 입력하세요"
-                />
-              </div>
               <div className="space-y-2 col-span-2">
-                <Label htmlFor="disciplineName">설계공종명 *</Label>
-                <Input
-                  id="disciplineName"
-                  value={formData.disciplineName}
-                  onChange={(e) => setFormData(prev => ({ ...prev, disciplineName: e.target.value }))}
-                  placeholder="설계공종명을 입력하세요"
-                />
+                <Label htmlFor="discipline">설계공종 *</Label>
+                <EngineeringDisciplineSelector
+                  selectedDiscipline={selectedDiscipline}
+                  onDisciplineSelect={handleDisciplineSelect}
+                  placeholder="설계공종을 선택하세요"
+                  className="h-9"
+                />
+                <div className="text-xs text-muted-foreground">
+                  {selectedDiscipline && (
+                    <span>선택됨: [{selectedDiscipline.CD}] {selectedDiscipline.USR_DF_CHAR_18}</span>
+                  )}
+                </div>
               </div>
               <div className="space-y-2 col-span-2">
                 <Label htmlFor="materialNameCustomerSide">고객사 AVL 자재명 *</Label>
@@ -591,31 +649,51 @@ export function AvlVendorAddAndModifyDialog({
           {/* 자재그룹 정보 */}
           <div className="space-y-4">
             <h4 className="text-sm font-semibold text-muted-foreground border-b pb-2">자재그룹 정보</h4>
-            <div className="grid grid-cols-2 gap-4">
-              <div className="space-y-2">
-                <Label htmlFor="materialGroupCode">자재그룹 코드</Label>
-                <Input
-                  id="materialGroupCode"
-                  value={formData.materialGroupCode}
-                  onChange={(e) => setFormData(prev => ({ ...prev, materialGroupCode: e.target.value }))}
-                  placeholder="자재그룹 코드를 입력하세요"
-                />
-              </div>
+            <div className="space-y-4">
               <div className="space-y-2">
-                <Label htmlFor="materialGroupName">자재그룹 명</Label>
-                <Input
-                  id="materialGroupName"
-                  value={formData.materialGroupName}
-                  onChange={(e) => setFormData(prev => ({ ...prev, materialGroupName: e.target.value }))}
-                  placeholder="자재그룹 명을 입력하세요"
-                />
+                {/* <Label htmlFor="materialGroup">자재그룹 선택</Label> */}
+                <MaterialGroupSelectorDialogSingle
+                  triggerLabel="자재그룹 선택"
+                  selectedMaterial={selectedMaterialGroup}
+                  onMaterialSelect={handleMaterialGroupSelect}
+                  placeholder="자재그룹을 검색하세요..."
+                  title="자재그룹 선택"
+                  description="AVL에 등록할 자재그룹을 선택해주세요."
+                  triggerVariant="outline"
+                />
+                <div className="text-xs text-muted-foreground">
+                  {selectedMaterialGroup && (
+                    <>
+                      <span>자재그룹코드: {selectedMaterialGroup.materialGroupCode}</span>
+                      <br />
+                      <span>자재그룹명: {selectedMaterialGroup.materialGroupDescription}</span>
+                    </>
+                  )}
+                </div>
               </div>
             </div>
           </div>
 
           {/* 협력업체 정보 */}
           <div className="space-y-4">
-            <h4 className="text-sm font-semibold text-muted-foreground border-b pb-2">협력업체 정보</h4>
+            <div className="flex items-center justify-between border-b pb-2">
+              <h4 className="text-sm font-semibold text-muted-foreground">협력업체 정보</h4>
+              <VendorSelectorDialogSingle
+                triggerLabel="협력업체 로드"
+                selectedVendor={selectedVendor}
+                onVendorSelect={handleVendorSelect}
+                title="협력업체 선택"
+                description="등록된 협력업체 목록에서 선택하여 정보를 자동으로 입력할 수 있습니다."
+                triggerVariant="outline"
+                statusFilter="ACTIVE"
+              />
+            </div>
+            {selectedVendor && (
+              <div className="text-xs text-muted-foreground bg-blue-50 p-2 rounded">
+                <span>선택된 협력업체: [{selectedVendor.vendorCode || '-'}] {selectedVendor.vendorName}</span>
+                <span className="ml-2 text-blue-600">({selectedVendor.status})</span>
+              </div>
+            )}
             <div className="grid grid-cols-2 gap-4">
               <div className="space-y-2">
                 <Label htmlFor="vendorCode">협력업체 코드</Label>
@@ -646,11 +724,11 @@ export function AvlVendorAddAndModifyDialog({
               </div>
               <div className="space-y-2">
                 <Label htmlFor="tier">등급 (Tier)</Label>
-                <Input
-                  id="tier"
+                <VendorTierSelector
                   value={formData.tier}
-                  onChange={(e) => setFormData(prev => ({ ...prev, tier: e.target.value }))}
-                  placeholder="등급을 입력하세요"
+                  onValueChange={(value) => setFormData(prev => ({ ...prev, tier: value }))}
+                  placeholder="등급을 선택하세요"
+                  className="h-9"
                 />
               </div>
             </div>
@@ -698,11 +776,11 @@ export function AvlVendorAddAndModifyDialog({
               </div>
               <div className="space-y-2">
                 <Label htmlFor="manufacturingLocation">제작/선적지 (국가)</Label>
-                <Input
-                  id="manufacturingLocation"
+                <PlaceOfShippingSelector
                   value={formData.manufacturingLocation}
-                  onChange={(e) => setFormData(prev => ({ ...prev, manufacturingLocation: e.target.value }))}
-                  placeholder="제작/선적지를 입력하세요"
+                  onValueChange={(value) => setFormData(prev => ({ ...prev, manufacturingLocation: value }))}
+                  placeholder="제작/선적지를 선택하세요"
+                  className="h-9"
                 />
               </div>
             </div>
@@ -862,12 +940,12 @@ export function AvlVendorAddAndModifyDialog({
                 />
               </div>
               <div className="space-y-2">
-                <Label htmlFor="quoteReceivedDate">견적접수일 (YYYY-MM-DD)</Label>
-                <Input
-                  id="quoteReceivedDate"
-                  value={formData.quoteReceivedDate}
-                  onChange={(e) => setFormData(prev => ({ ...prev, quoteReceivedDate: e.target.value }))}
-                  placeholder="YYYY-MM-DD"
+                <Label htmlFor="quoteReceivedDate">견적접수일</Label>
+                <DatePicker
+                  date={quoteReceivedDate}
+                  onSelect={setQuoteReceivedDate}
+                  placeholder="견적접수일 선택"
+                  className="h-9"
                 />
               </div>
             </div>
@@ -887,12 +965,12 @@ export function AvlVendorAddAndModifyDialog({
                 />
               </div>
               <div className="space-y-2">
-                <Label htmlFor="recentQuoteDate">최근견적일 (YYYY-MM-DD)</Label>
-                <Input
-                  id="recentQuoteDate"
-                  value={formData.recentQuoteDate}
-                  onChange={(e) => setFormData(prev => ({ ...prev, recentQuoteDate: e.target.value }))}
-                  placeholder="YYYY-MM-DD"
+                <Label htmlFor="recentQuoteDate">최근견적일</Label>
+                <DatePicker
+                  date={recentQuoteDate}
+                  onSelect={setRecentQuoteDate}
+                  placeholder="최근견적일 선택"
+                  className="h-9"
                 />
               </div>
               <div className="space-y-2">
@@ -905,12 +983,12 @@ export function AvlVendorAddAndModifyDialog({
                 />
               </div>
               <div className="space-y-2">
-                <Label htmlFor="recentOrderDate">최근발주일 (YYYY-MM-DD)</Label>
-                <Input
-                  id="recentOrderDate"
-                  value={formData.recentOrderDate}
-                  onChange={(e) => setFormData(prev => ({ ...prev, recentOrderDate: e.target.value }))}
-                  placeholder="YYYY-MM-DD"
+                <Label htmlFor="recentOrderDate">최근발주일</Label>
+                <DatePicker
+                  date={recentOrderDate}
+                  onSelect={setRecentOrderDate}
+                  placeholder="최근발주일 선택"
+                  className="h-9"
                 />
               </div>
             </div>
-- 
cgit v1.2.3

