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/standard-avl-table.tsx | 146 +++++++++++++++++------------------
 1 file changed, 73 insertions(+), 73 deletions(-)

(limited to 'lib/avl/table/standard-avl-table.tsx')

diff --git a/lib/avl/table/standard-avl-table.tsx b/lib/avl/table/standard-avl-table.tsx
index cc39540b..bacb5812 100644
--- a/lib/avl/table/standard-avl-table.tsx
+++ b/lib/avl/table/standard-avl-table.tsx
@@ -15,6 +15,14 @@ import {
   SelectTrigger,
   SelectValue,
 } from "@/components/ui/select"
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+} from "@/components/ui/dialog"
 import { Search } from "lucide-react"
 import { toast } from "sonner"
 import { standardAvlColumns } from "./standard-avl-table-columns"
@@ -22,13 +30,9 @@ import { AvlVendorAddAndModifyDialog } from "./avl-vendor-add-and-modify-dialog"
 import { createAvlVendorInfo, updateAvlVendorInfo, deleteAvlVendorInfo, finalizeStandardAvl } from "../service"
 import { AvlVendorInfoInput } from "../types"
 import { useSession } from "next-auth/react"
+import { ShipTypeSelector, ShipTypeItem } from "@/components/common/ship-type"
 
 /**
- * 조선인 경우, 선종:
- * A-max, S-max, VLCC, LNGC, CONT
- * 해양인 경우, 선종:
- * FPSO, FLNG, FPU, Platform, WTIV, GOM
- * 
  * AVL종류:
  * Nearshore, Offshore, IOC, NOC
  */
@@ -39,31 +43,6 @@ const constructionSectorOptions = [
   { value: "해양", label: "해양" },
 ]
 
-// 공사부문에 따른 선종 옵션들
-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 avlKindOptions = [
   { value: "Nearshore", label: "Nearshore" },
   { value: "Offshore", label: "Offshore" },
@@ -123,7 +102,9 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
 
   // 검색 상태
   const [searchConstructionSector, setSearchConstructionSector] = React.useState(initialConstructionSector || "")
-  const [searchShipType, setSearchShipType] = React.useState(initialShipType || "")
+  const [selectedShipType, setSelectedShipType] = React.useState<ShipTypeItem | undefined>(
+    initialShipType ? { CD: initialShipType, CDNM: initialShipType, displayText: initialShipType } : undefined
+  )
   const [searchAvlKind, setSearchAvlKind] = React.useState(initialAvlKind || "")
   const [searchHtDivision, setSearchHtDivision] = React.useState(initialHtDivision || "")
 
@@ -173,34 +154,29 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
   const handleConstructionSectorChange = React.useCallback((value: string) => {
     setSearchConstructionSector(value)
     // 공사부문이 변경되면 선종을 빈 값으로 초기화
-    setSearchShipType("")
+    setSelectedShipType(undefined)
   }, [])
 
   // 검색 상태 변경 시 부모 컴포넌트에 전달
   React.useEffect(() => {
     onSearchConditionsChange?.({
       constructionSector: searchConstructionSector,
-      shipType: searchShipType,
+      shipType: selectedShipType?.CD || "",
       avlKind: searchAvlKind,
       htDivision: searchHtDivision
     })
-  }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision, onSearchConditionsChange])
+  }, [searchConstructionSector, selectedShipType, searchAvlKind, searchHtDivision, onSearchConditionsChange])
 
-  // 현재 공사부문에 따른 선종 옵션들
-  const currentShipTypeOptions = React.useMemo(() =>
-    getShipTypeOptions(searchConstructionSector),
-    [searchConstructionSector]
-  )
 
   // 모든 검색 조건이 선택되었는지 확인
   const isAllSearchConditionsSelected = React.useMemo(() => {
     return (
       searchConstructionSector.trim() !== "" &&
-      searchShipType.trim() !== "" &&
+      selectedShipType?.CD?.trim() !== "" &&
       searchAvlKind.trim() !== "" &&
       searchHtDivision.trim() !== ""
     )
-  }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
+  }, [searchConstructionSector, selectedShipType, searchAvlKind, searchHtDivision])
 
   // 데이터 로드 함수
   const loadData = React.useCallback(async (searchParams: Partial<GetStandardAvlSchema> = {}) => {
@@ -213,7 +189,7 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
         sort: searchParams.sort ?? [{ id: "no", desc: false }],
         flags: searchParams.flags ?? [],
         constructionSector: searchConstructionSector,
-        shipType: searchShipType,
+        shipType: selectedShipType?.CD || "",
         avlKind: searchAvlKind,
         htDivision: searchHtDivision as "공통" | "H" | "T" | "",
         equipBulkDivision: searchParams.equipBulkDivision || "",
@@ -249,7 +225,7 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
     } finally {
       setLoading(false)
     }
-  }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
+  }, [searchConstructionSector, selectedShipType, searchAvlKind, searchHtDivision])
 
   // reloadTrigger가 변경될 때마다 데이터 리로드
   React.useEffect(() => {
@@ -262,7 +238,7 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
   // 검색 초기화 핸들러
   const handleResetSearch = React.useCallback(() => {
     setSearchConstructionSector("")
-    setSearchShipType("")
+    setSelectedShipType(undefined)
     setSearchAvlKind("")
     setSearchHtDivision("")
     // 초기화 시 빈 데이터로 설정
@@ -365,6 +341,9 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
     }
   }, [table, loadData])
 
+  // 최종 확정 다이얼로그 상태
+  const [isConfirmDialogOpen, setIsConfirmDialogOpen] = React.useState(false)
+
   // 최종 확정 핸들러 (표준 AVL)
   const handleFinalizeStandardAvl = React.useCallback(async () => {
     // 1. 필수 조건 검증
@@ -378,27 +357,20 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
       return
     }
 
-    // 2. 사용자 확인
-    const confirmed = window.confirm(
-      `현재 표준 AVL을 최종 확정하시겠습니까?\n\n` +
-      `- 공사부문: ${searchConstructionSector}\n` +
-      `- 선종: ${searchShipType}\n` +
-      `- AVL종류: ${searchAvlKind}\n` +
-      `- H/T 구분: ${searchHtDivision}\n` +
-      `- 벤더 정보: ${data.length}개\n\n` +
-      `확정 후에는 수정이 어려울 수 있습니다.`
-    )
-
-    if (!confirmed) return
+    // 2. 확인 다이얼로그 열기
+    setIsConfirmDialogOpen(true)
+  }, [isAllSearchConditionsSelected, data.length])
 
+  // 실제 최종 확정 실행 함수
+  const executeFinalizeStandardAvl = React.useCallback(async () => {
     try {
-      // 3. 현재 데이터의 모든 ID 수집
+      // 3. 현재 데이터의 모든 ID 수집 (전체 레코드 기준)
       const avlVendorInfoIds = data.map(item => item.id)
 
       // 4. 최종 확정 실행
       const standardAvlInfo = {
         constructionSector: searchConstructionSector,
-        shipType: searchShipType,
+        shipType: selectedShipType?.CD || "",
         avlKind: searchAvlKind,
         htDivision: searchHtDivision
       }
@@ -423,8 +395,10 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
     } catch (error) {
       console.error("표준 AVL 최종 확정 실패:", error)
       toast.error("표준 AVL 최종 확정 중 오류가 발생했습니다.")
+    } finally {
+      setIsConfirmDialogOpen(false)
     }
-  }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision, isAllSearchConditionsSelected, data, table, loadData, sessionData?.user?.name])
+  }, [searchConstructionSector, selectedShipType, searchAvlKind, searchHtDivision, data, table, loadData, sessionData?.user?.name])
 
   // 초기 데이터 로드 (검색 조건이 모두 입력되었을 때만)
   React.useEffect(() => {
@@ -437,7 +411,8 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
       setData([])
       setPageCount(0)
     }
-  }, [isAllSearchConditionsSelected, pagination.pageSize, searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [isAllSearchConditionsSelected, pagination.pageSize, searchConstructionSector, selectedShipType, searchAvlKind, searchHtDivision])
 
   
 
@@ -547,18 +522,13 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
           {/* 선종 */}
           <div className="space-y-2">
             <label className="text-sm font-medium">선종</label>
-            <Select value={searchShipType} onValueChange={setSearchShipType}>
-              <SelectTrigger>
-                <SelectValue />
-              </SelectTrigger>
-              <SelectContent>
-                {currentShipTypeOptions.map((option) => (
-                  <SelectItem key={option.value} value={option.value}>
-                    {option.label}
-                  </SelectItem>
-                ))}
-              </SelectContent>
-            </Select>
+            <ShipTypeSelector
+              selectedShipType={selectedShipType}
+              onShipTypeSelect={setSelectedShipType}
+              placeholder="선종을 선택하세요"
+              disabled={!searchConstructionSector}
+              className="h-10"
+            />
           </div>
 
           {/* AVL종류 */}
@@ -640,10 +610,40 @@ export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTable
         isTemplate={true} // 표준 AVL 모드
         // 검색 조건에서 선택한 값들을 초기값으로 전달
         initialConstructionSector={searchConstructionSector}
-        initialShipType={searchShipType}
+        initialShipType={selectedShipType?.CD || ""}
         initialAvlKind={searchAvlKind}
         initialHtDivision={searchHtDivision}
       />
+
+      {/* 최종 확정 확인 다이얼로그 */}
+      <Dialog open={isConfirmDialogOpen} onOpenChange={setIsConfirmDialogOpen}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle>표준 AVL 최종 확정</DialogTitle>
+            <DialogDescription>
+              현재 표준 AVL을 최종 확정하시겠습니까?
+            </DialogDescription>
+          </DialogHeader>
+          <div className="space-y-2 text-sm">
+            <div>• 공사부문: {searchConstructionSector}</div>
+            <div>• 선종: {selectedShipType?.CD || ""}</div>
+            <div>• AVL종류: {searchAvlKind}</div>
+            <div>• H/T 구분: {searchHtDivision}</div>
+            <div>• 벤더 정보: {data.length}개 (전체 레코드)</div>
+            {/* <div className="text-amber-600 font-medium mt-4">
+              ⚠️ 확정 후 내용 수정을 필요로 하는 경우 동일 건을 다시 최종확정해 revision 처리로 수정해야 합니다.
+            </div> */}
+          </div>
+          <DialogFooter>
+            <Button variant="outline" onClick={() => setIsConfirmDialogOpen(false)}>
+              취소
+            </Button>
+            <Button onClick={executeFinalizeStandardAvl}>
+              최종 확정
+            </Button>
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
     </div>
   )
 })
-- 
cgit v1.2.3

