summaryrefslogtreecommitdiff
path: root/lib/avl/table/standard-avl-table.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avl/table/standard-avl-table.tsx')
-rw-r--r--lib/avl/table/standard-avl-table.tsx603
1 files changed, 437 insertions, 166 deletions
diff --git a/lib/avl/table/standard-avl-table.tsx b/lib/avl/table/standard-avl-table.tsx
index 924b972a..cc39540b 100644
--- a/lib/avl/table/standard-avl-table.tsx
+++ b/lib/avl/table/standard-avl-table.tsx
@@ -1,10 +1,10 @@
"use client"
import * as React from "react"
-import { useReactTable, getCoreRowModel, getPaginationRowModel, getSortedRowModel, getFilteredRowModel, type ColumnDef } from "@tanstack/react-table"
+import { useReactTable, getCoreRowModel, getPaginationRowModel, getSortedRowModel, getFilteredRowModel } from "@tanstack/react-table"
+import { useLayoutEffect, useMemo, forwardRef, useImperativeHandle } from "react"
import { DataTable } from "@/components/data-table/data-table"
import { Button } from "@/components/ui/button"
-import { Checkbox } from "@/components/ui/checkbox"
import { getStandardAvlVendorInfo } from "../service"
import { GetStandardAvlSchema } from "../validations"
import { AvlDetailItem } from "../types"
@@ -17,40 +17,74 @@ import {
} from "@/components/ui/select"
import { Search } from "lucide-react"
import { toast } from "sonner"
+import { standardAvlColumns } from "./standard-avl-table-columns"
+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"
+
+/**
+ * 조선인 경우, 선종:
+ * A-max, S-max, VLCC, LNGC, CONT
+ * 해양인 경우, 선종:
+ * FPSO, FLNG, FPU, Platform, WTIV, GOM
+ *
+ * AVL종류:
+ * Nearshore, Offshore, IOC, NOC
+ */
// 검색 옵션들
const constructionSectorOptions = [
- { value: "all", label: "전체" },
{ value: "조선", label: "조선" },
{ value: "해양", label: "해양" },
]
-const shipTypeOptions = [
- { value: "all", label: "전체" },
- { value: "컨테이너선", label: "컨테이너선" },
- { value: "유조선", label: "유조선" },
- { value: "LNG선", label: "LNG선" },
- { value: "LPG선", label: "LPG선" },
- { value: "벌크선", label: "벌크선" },
- { 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: "all", label: "전체" },
- { value: "표준", label: "표준" },
- { value: "특별", label: "특별" },
- { value: "임시", label: "임시" },
+ { value: "Nearshore", label: "Nearshore" },
+ { value: "Offshore", label: "Offshore" },
+ { value: "IOC", label: "IOC" },
+ { value: "NOC", label: "NOC" },
]
const htDivisionOptions = [
- { value: "all", label: "전체" },
+ { value: "공통", label: "공통" },
{ value: "H", label: "Hull (H)" },
- { value: "T", label: "Topside (T)" },
+ { value: "T", label: "Top (T)" },
]
// 선종별 표준 AVL 테이블에서는 AvlDetailItem을 사용
export type StandardAvlItem = AvlDetailItem
+// ref를 통해 외부에서 접근할 수 있는 메소드들
+export interface StandardAvlTableRef {
+ getSelectedIds: () => number[]
+}
+
interface StandardAvlTableProps {
onSelectionChange?: (count: number) => void
resetCounter?: number
@@ -58,130 +92,154 @@ interface StandardAvlTableProps {
shipType?: string // 선종 필터
avlKind?: string // AVL 종류 필터
htDivision?: string // H/T 구분 필터
+ onSearchConditionsChange?: (conditions: {
+ constructionSector: string
+ shipType: string
+ avlKind: string
+ htDivision: string
+ }) => void
+ reloadTrigger?: number
}
-// 선종별 표준 AVL 테이블 컬럼
-const standardAvlColumns: ColumnDef<StandardAvlItem>[] = [
- {
- id: "select",
- header: ({ table }) => (
- <Checkbox
- checked={
- table.getIsAllPageRowsSelected() ||
- (table.getIsSomePageRowsSelected() && "indeterminate")
- }
- onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
- aria-label="Select all"
- />
- ),
- cell: ({ row, table }) => {
- // 선종별 표준 AVL 테이블의 단일 선택 핸들러
- const handleRowSelection = (checked: boolean) => {
- if (checked) {
- // 다른 모든 행의 선택 해제
- table.getRowModel().rows.forEach(r => {
- if (r !== row && r.getIsSelected()) {
- r.toggleSelected(false)
- }
- })
- }
- // 현재 행 선택/해제
- row.toggleSelected(checked)
- }
-
- return (
- <Checkbox
- checked={row.getIsSelected()}
- onCheckedChange={handleRowSelection}
- aria-label="Select row"
- />
- )
- },
- enableSorting: false,
- enableHiding: false,
- size: 50,
- },
- {
- accessorKey: "no",
- header: "No.",
- size: 60,
- },
- {
- accessorKey: "disciplineName",
- header: "설계공종",
- size: 120,
- },
- {
- accessorKey: "avlVendorName",
- header: "AVL 등재업체명",
- size: 140,
- },
- {
- accessorKey: "materialGroupCode",
- header: "자재그룹 코드",
- size: 120,
- },
- {
- accessorKey: "materialGroupName",
- header: "자재그룹 명",
- size: 130,
- },
- {
- accessorKey: "vendorCode",
- header: "협력업체 코드",
- size: 120,
- },
- {
- accessorKey: "vendorName",
- header: "협력업체 명",
- size: 130,
- },
- {
- accessorKey: "headquarterLocation",
- header: "본사 위치 (국가)",
- size: 140,
- },
- {
- accessorKey: "tier",
- header: "등급 (Tier)",
- size: 120,
- },
-]
-
-export function StandardAvlTable({
+export const StandardAvlTable = forwardRef<StandardAvlTableRef, StandardAvlTableProps>(({
onSelectionChange,
resetCounter,
constructionSector: initialConstructionSector,
shipType: initialShipType,
avlKind: initialAvlKind,
- htDivision: initialHtDivision
-}: StandardAvlTableProps) {
+ htDivision: initialHtDivision,
+ onSearchConditionsChange,
+ reloadTrigger
+}, ref) => {
+ const { data: sessionData } = useSession()
+
const [data, setData] = React.useState<StandardAvlItem[]>([])
const [loading, setLoading] = React.useState(false)
const [pageCount, setPageCount] = React.useState(0)
+ // 다이얼로그 상태
+ const [isAddDialogOpen, setIsAddDialogOpen] = React.useState(false)
+ const [editingItem, setEditingItem] = React.useState<StandardAvlItem | undefined>(undefined)
+
// 검색 상태
- const [searchConstructionSector, setSearchConstructionSector] = React.useState(initialConstructionSector || "all")
- const [searchShipType, setSearchShipType] = React.useState(initialShipType || "all")
- const [searchAvlKind, setSearchAvlKind] = React.useState(initialAvlKind || "all")
- const [searchHtDivision, setSearchHtDivision] = React.useState(initialHtDivision || "all")
+ const [searchConstructionSector, setSearchConstructionSector] = React.useState(initialConstructionSector || "")
+ const [searchShipType, setSearchShipType] = React.useState(initialShipType || "")
+ const [searchAvlKind, setSearchAvlKind] = React.useState(initialAvlKind || "")
+ const [searchHtDivision, setSearchHtDivision] = React.useState(initialHtDivision || "")
+
+ // 페이지네이션 상태
+ const [pagination, setPagination] = React.useState({
+ pageIndex: 0,
+ pageSize: 10,
+ })
+
+ const table = useReactTable({
+ data,
+ columns: standardAvlColumns,
+ getCoreRowModel: getCoreRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ manualPagination: true,
+ pageCount,
+ state: {
+ pagination,
+ },
+ onPaginationChange: (updater) => {
+ // 페이지네이션 상태 업데이트
+ const newPaginationState = typeof updater === 'function' ? updater(pagination) : updater
+
+ console.log('StandardAvlTable - Pagination changed:', {
+ currentState: pagination,
+ newPaginationState,
+ isAllSearchConditionsSelected,
+ willLoadData: isAllSearchConditionsSelected
+ })
+
+ setPagination(newPaginationState)
+
+ if (isAllSearchConditionsSelected) {
+ const apiParams = {
+ page: newPaginationState.pageIndex + 1,
+ perPage: newPaginationState.pageSize,
+ }
+ console.log('StandardAvlTable - Loading data with params:', apiParams)
+ loadData(apiParams)
+ }
+ },
+ })
+
+ // 공사부문 변경 시 선종 초기화
+ const handleConstructionSectorChange = React.useCallback((value: string) => {
+ setSearchConstructionSector(value)
+ // 공사부문이 변경되면 선종을 빈 값으로 초기화
+ setSearchShipType("")
+ }, [])
+
+ // 검색 상태 변경 시 부모 컴포넌트에 전달
+ React.useEffect(() => {
+ onSearchConditionsChange?.({
+ constructionSector: searchConstructionSector,
+ shipType: searchShipType,
+ avlKind: searchAvlKind,
+ htDivision: searchHtDivision
+ })
+ }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision, onSearchConditionsChange])
+
+ // 현재 공사부문에 따른 선종 옵션들
+ const currentShipTypeOptions = React.useMemo(() =>
+ getShipTypeOptions(searchConstructionSector),
+ [searchConstructionSector]
+ )
+
+ // 모든 검색 조건이 선택되었는지 확인
+ const isAllSearchConditionsSelected = React.useMemo(() => {
+ return (
+ searchConstructionSector.trim() !== "" &&
+ searchShipType.trim() !== "" &&
+ searchAvlKind.trim() !== "" &&
+ searchHtDivision.trim() !== ""
+ )
+ }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
// 데이터 로드 함수
- const loadData = React.useCallback(async (searchParams: Partial<GetStandardAvlSchema>) => {
+ const loadData = React.useCallback(async (searchParams: Partial<GetStandardAvlSchema> = {}) => {
try {
setLoading(true)
+
const params: GetStandardAvlSchema = {
page: searchParams.page ?? 1,
perPage: searchParams.perPage ?? 10,
sort: searchParams.sort ?? [{ id: "no", desc: false }],
- constructionSector: searchConstructionSector === "all" ? "" : searchConstructionSector || "",
- shipType: searchShipType === "all" ? "" : searchShipType || "",
- avlKind: searchAvlKind === "all" ? "" : searchAvlKind || "",
- htDivision: searchHtDivision === "all" ? "" : searchHtDivision || "",
+ flags: searchParams.flags ?? [],
+ constructionSector: searchConstructionSector,
+ shipType: searchShipType,
+ avlKind: searchAvlKind,
+ htDivision: searchHtDivision as "공통" | "H" | "T" | "",
+ equipBulkDivision: searchParams.equipBulkDivision || "",
+ disciplineCode: searchParams.disciplineCode ?? "",
+ disciplineName: searchParams.disciplineName ?? "",
+ materialNameCustomerSide: searchParams.materialNameCustomerSide ?? "",
+ packageCode: searchParams.packageCode ?? "",
+ packageName: searchParams.packageName ?? "",
+ materialGroupCode: searchParams.materialGroupCode ?? "",
+ materialGroupName: searchParams.materialGroupName ?? "",
+ vendorName: searchParams.vendorName ?? "",
+ vendorCode: searchParams.vendorCode ?? "",
+ avlVendorName: searchParams.avlVendorName ?? "",
+ tier: searchParams.tier ?? "",
+ filters: searchParams.filters ?? [],
+ joinOperator: searchParams.joinOperator ?? "and",
search: "",
...searchParams,
}
+ console.log('StandardAvlTable - API call params:', params)
const result = await getStandardAvlVendorInfo(params)
+ console.log('StandardAvlTable - API result:', {
+ dataCount: result.data.length,
+ pageCount: result.pageCount,
+ requestedPage: params.page
+ })
setData(result.data)
setPageCount(result.pageCount)
} catch (error) {
@@ -193,52 +251,230 @@ export function StandardAvlTable({
}
}, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
- // 검색 핸들러
- const handleSearch = React.useCallback(() => {
- loadData({})
- }, [loadData])
+ // reloadTrigger가 변경될 때마다 데이터 리로드
+ React.useEffect(() => {
+ if (reloadTrigger && reloadTrigger > 0) {
+ console.log('StandardAvlTable - reloadTrigger changed, reloading data')
+ loadData({})
+ }
+ }, [reloadTrigger, loadData])
// 검색 초기화 핸들러
const handleResetSearch = React.useCallback(() => {
- setSearchConstructionSector("all")
- setSearchShipType("all")
- setSearchAvlKind("all")
- setSearchHtDivision("all")
- loadData({})
+ setSearchConstructionSector("")
+ setSearchShipType("")
+ setSearchAvlKind("")
+ setSearchHtDivision("")
+ // 초기화 시 빈 데이터로 설정
+ setData([])
+ setPageCount(0)
+ }, [])
+
+ // 검색 핸들러
+ const handleSearch = React.useCallback(() => {
+ if (isAllSearchConditionsSelected) {
+ // 검색 시 페이지를 1페이지로 리셋
+ setPagination(prev => ({ ...prev, pageIndex: 0 }))
+ loadData({ page: 1, perPage: pagination.pageSize })
+ }
+ }, [loadData, isAllSearchConditionsSelected, pagination.pageSize])
+
+ // 항목 추가 핸들러
+ const handleAddItem = React.useCallback(async (itemData: Omit<AvlVendorInfoInput, 'avlListId'>) => {
+ try {
+ const result = await createAvlVendorInfo(itemData)
+
+ if (result) {
+ toast.success("표준 AVL 항목이 성공적으로 추가되었습니다.")
+ // 데이터 새로고침
+ loadData({})
+ } else {
+ toast.error("항목 추가에 실패했습니다.")
+ }
+ } catch (error) {
+ console.error("항목 추가 실패:", error)
+ toast.error("항목 추가 중 오류가 발생했습니다.")
+ }
}, [loadData])
- // 초기 데이터 로드
- React.useEffect(() => {
- loadData({})
+ // 항목 수정 핸들러
+ const handleUpdateItem = React.useCallback(async (id: number, itemData: Omit<AvlVendorInfoInput, 'avlListId'>) => {
+ try {
+ const result = await updateAvlVendorInfo(id, itemData)
+
+ if (result) {
+ toast.success("표준 AVL 항목이 성공적으로 수정되었습니다.")
+ // 데이터 새로고침
+ loadData({})
+ // 수정 모드 해제
+ setEditingItem(undefined)
+ } else {
+ toast.error("항목 수정에 실패했습니다.")
+ }
+ } catch (error) {
+ console.error("항목 수정 실패:", error)
+ toast.error("항목 수정 중 오류가 발생했습니다.")
+ }
}, [loadData])
- const table = useReactTable({
- data,
- columns: standardAvlColumns,
- getCoreRowModel: getCoreRowModel(),
- getPaginationRowModel: getPaginationRowModel(),
- getSortedRowModel: getSortedRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- manualPagination: true,
- pageCount,
- initialState: {
- pagination: {
- pageSize: 10,
- },
- },
- onPaginationChange: (updater) => {
- const newState = typeof updater === 'function' ? updater(table.getState().pagination) : updater
- loadData({
- page: newState.pageIndex + 1,
- perPage: newState.pageSize,
+ // 항목 수정 핸들러 (버튼 클릭)
+ const handleEditItem = React.useCallback(() => {
+ const selectedRows = table.getFilteredSelectedRowModel().rows
+
+ if (selectedRows.length !== 1) {
+ toast.error("수정할 항목을 하나만 선택해주세요.")
+ return
+ }
+
+ const selectedItem = selectedRows[0].original
+ setEditingItem(selectedItem)
+ setIsAddDialogOpen(true)
+ }, [table])
+
+ // 항목 삭제 핸들러
+ const handleDeleteItems = React.useCallback(async () => {
+ const selectedRows = table.getFilteredSelectedRowModel().rows
+
+ if (selectedRows.length === 0) {
+ toast.error("삭제할 항목을 선택해주세요.")
+ return
+ }
+
+ // 사용자 확인
+ const confirmed = window.confirm(`선택한 ${selectedRows.length}개 항목을 정말 삭제하시겠습니까?`)
+ if (!confirmed) return
+
+ try {
+ // 선택된 항목들을 DB에서 삭제
+ const deletePromises = selectedRows.map(async (row) => {
+ await deleteAvlVendorInfo(row.original.id)
})
- },
- })
- // 선택 상태 변경 시 콜백 호출
+ await Promise.all(deletePromises)
+
+ toast.success(`${selectedRows.length}개 항목이 삭제되었습니다.`)
+
+ // 데이터 새로고침
+ loadData({})
+
+ // 선택 해제
+ table.toggleAllPageRowsSelected(false)
+ } catch (error) {
+ console.error("항목 삭제 실패:", error)
+ toast.error("항목 삭제 중 오류가 발생했습니다.")
+ }
+ }, [table, loadData])
+
+ // 최종 확정 핸들러 (표준 AVL)
+ const handleFinalizeStandardAvl = React.useCallback(async () => {
+ // 1. 필수 조건 검증
+ if (!isAllSearchConditionsSelected) {
+ toast.error("검색 조건을 모두 선택해주세요.")
+ return
+ }
+
+ if (data.length === 0) {
+ toast.error("확정할 표준 AVL 벤더 정보가 없습니다.")
+ 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
+
+ try {
+ // 3. 현재 데이터의 모든 ID 수집
+ const avlVendorInfoIds = data.map(item => item.id)
+
+ // 4. 최종 확정 실행
+ const standardAvlInfo = {
+ constructionSector: searchConstructionSector,
+ shipType: searchShipType,
+ avlKind: searchAvlKind,
+ htDivision: searchHtDivision
+ }
+
+ const result = await finalizeStandardAvl(
+ standardAvlInfo,
+ avlVendorInfoIds,
+ sessionData?.user?.name || ""
+ )
+
+ if (result.success) {
+ toast.success(result.message)
+
+ // 5. 데이터 새로고침
+ loadData({})
+
+ // 6. 선택 해제
+ table.toggleAllPageRowsSelected(false)
+ } else {
+ toast.error(result.message)
+ }
+ } catch (error) {
+ console.error("표준 AVL 최종 확정 실패:", error)
+ toast.error("표준 AVL 최종 확정 중 오류가 발생했습니다.")
+ }
+ }, [searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision, isAllSearchConditionsSelected, data, table, loadData, sessionData?.user?.name])
+
+ // 초기 데이터 로드 (검색 조건이 모두 입력되었을 때만)
React.useEffect(() => {
- onSelectionChange?.(table.getFilteredSelectedRowModel().rows.length)
- }, [table.getFilteredSelectedRowModel().rows.length, onSelectionChange])
+ if (isAllSearchConditionsSelected) {
+ // 검색 조건이 모두 입력되면 페이지를 1페이지로 리셋하고 데이터 로드
+ setPagination(prev => ({ ...prev, pageIndex: 0 }))
+ loadData({ page: 1, perPage: pagination.pageSize })
+ } else {
+ // 검색 조건이 모두 입력되지 않은 경우 빈 데이터로 설정
+ setData([])
+ setPageCount(0)
+ }
+ }, [isAllSearchConditionsSelected, pagination.pageSize, searchConstructionSector, searchShipType, searchAvlKind, searchHtDivision])
+
+
+
+ // 외부에서 선택된 ID들을 가져올 수 있도록 ref에 메소드 노출
+ useImperativeHandle(ref, () => ({
+ getSelectedIds: () => {
+ const selectedRows = table.getFilteredSelectedRowModel().rows
+ return selectedRows.map(row => row.original.id)
+ }
+ }))
+
+ // 선택된 행 개수 (안정적인 계산을 위해 useMemo 사용)
+ const selectedRows = table.getFilteredSelectedRowModel().rows
+ const selectedRowCount = useMemo(() => {
+ const count = selectedRows.length
+ console.log('StandardAvlTable - selectedRowCount calculated:', count)
+ return count
+ }, [selectedRows])
+
+ // 페이지네이션 상태 디버깅
+ React.useEffect(() => {
+ const paginationState = table.getState().pagination
+ console.log('StandardAvlTable - Current pagination state:', {
+ pageIndex: paginationState.pageIndex,
+ pageSize: paginationState.pageSize,
+ canPreviousPage: table.getCanPreviousPage(),
+ canNextPage: table.getCanNextPage(),
+ pageCount: table.getPageCount(),
+ currentDataLength: data.length
+ })
+ }, [table, data])
+
+ // 선택 상태 변경 시 콜백 호출
+ useLayoutEffect(() => {
+ console.log('StandardAvlTable - onSelectionChange called with count:', selectedRowCount)
+ onSelectionChange?.(selectedRowCount)
+ }, [selectedRowCount, onSelectionChange])
// 선택 해제 요청이 오면 모든 선택 해제
React.useEffect(() => {
@@ -253,22 +489,35 @@ export function StandardAvlTable({
<div className="flex items-center justify-between mb-2">
<h4 className="font-medium">선종별 표준 AVL</h4>
<div className="flex gap-1">
- <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
+ <Button variant="outline" size="sm" onClick={() => setIsAddDialogOpen(true)}>
신규업체 추가
</Button>
- <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleEditItem}
+ disabled={table.getFilteredSelectedRowModel().rows.length !== 1}
+ >
+ 항목 수정
+ </Button>
+ {/* <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
파일 업로드
</Button>
<Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
일괄입력
+ </Button> */}
+ <Button variant="outline" size="sm" onClick={handleDeleteItems}>
+ 항목 삭제
</Button>
- <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
- 항목삭제
- </Button>
- <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
+ {/* <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
저장
- </Button>
- <Button variant="outline" size="sm" onClick={() => toast.info("개발 중입니다.")}>
+ </Button> */}
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleFinalizeStandardAvl}
+ disabled={!isAllSearchConditionsSelected || data.length === 0}
+ >
최종 확정
</Button>
</div>
@@ -281,7 +530,7 @@ export function StandardAvlTable({
{/* 공사부문 */}
<div className="space-y-2">
<label className="text-sm font-medium">공사부문</label>
- <Select value={searchConstructionSector} onValueChange={setSearchConstructionSector}>
+ <Select value={searchConstructionSector} onValueChange={handleConstructionSectorChange}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
@@ -303,7 +552,7 @@ export function StandardAvlTable({
<SelectValue />
</SelectTrigger>
<SelectContent>
- {shipTypeOptions.map((option) => (
+ {currentShipTypeOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
@@ -352,7 +601,7 @@ export function StandardAvlTable({
<div className="flex gap-1">
<Button
onClick={handleSearch}
- disabled={loading}
+ disabled={loading || !isAllSearchConditionsSelected}
size="sm"
className="px-3"
>
@@ -375,6 +624,28 @@ export function StandardAvlTable({
<div className="flex-1">
<DataTable table={table} />
</div>
+
+ {/* 신규업체 추가 다이얼로그 */}
+ <AvlVendorAddAndModifyDialog
+ open={isAddDialogOpen}
+ onOpenChange={(open) => {
+ setIsAddDialogOpen(open)
+ if (!open) {
+ setEditingItem(undefined) // 다이얼로그가 닫힐 때 수정 모드 해제
+ }
+ }}
+ onAddItem={handleAddItem}
+ editingItem={editingItem}
+ onUpdateItem={handleUpdateItem}
+ isTemplate={true} // 표준 AVL 모드
+ // 검색 조건에서 선택한 값들을 초기값으로 전달
+ initialConstructionSector={searchConstructionSector}
+ initialShipType={searchShipType}
+ initialAvlKind={searchAvlKind}
+ initialHtDivision={searchHtDivision}
+ />
</div>
)
-}
+})
+
+StandardAvlTable.displayName = "StandardAvlTable"