diff options
| author | joonhoekim <26rote@gmail.com> | 2025-09-15 01:23:00 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-09-15 01:23:00 +0000 |
| commit | e7818a457371849e29519497ebf046f385f05ab6 (patch) | |
| tree | 9bf08ba1b31a512c481dc521c9dd7c90091a75b8 /lib/avl/table/avl-registration-area.tsx | |
| parent | 3f293c90beb58ce206a66ff444d7acfc41b56429 (diff) | |
(김준회) AVL 기능 구현 1차 및 벤더풀 E/B 구분 개선
Diffstat (limited to 'lib/avl/table/avl-registration-area.tsx')
| -rw-r--r-- | lib/avl/table/avl-registration-area.tsx | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/lib/avl/table/avl-registration-area.tsx b/lib/avl/table/avl-registration-area.tsx new file mode 100644 index 00000000..def3d30a --- /dev/null +++ b/lib/avl/table/avl-registration-area.tsx @@ -0,0 +1,278 @@ +"use client" + +import * as React from "react" +import { Card } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react" +import { useAtom } from "jotai" +import { ProjectAvlTable } from "./project-avl-table" +import { StandardAvlTable } from "./standard-avl-table" +import { VendorPoolTable } from "./vendor-pool-table" +import { selectedAvlRecordAtom } from "../avl-atoms" +import type { AvlListItem } from "../types" + +// 선택된 테이블 타입 +type SelectedTable = 'project' | 'standard' | 'vendor' | null + +// 선택 상태 액션 타입 +type SelectionAction = + | { type: 'SELECT_PROJECT'; count: number } + | { type: 'SELECT_STANDARD'; count: number } + | { type: 'SELECT_VENDOR'; count: number } + | { type: 'CLEAR_SELECTION' } + +// 선택 상태 +interface SelectionState { + selectedTable: SelectedTable + selectedRowCount: number + resetCounters: { + project: number + standard: number + vendor: number + } +} + +// 선택 상태 리듀서 +const selectionReducer = (state: SelectionState, action: SelectionAction): SelectionState => { + switch (action.type) { + case 'SELECT_PROJECT': + if (action.count > 0) { + return { + selectedTable: 'project', + selectedRowCount: action.count, + resetCounters: { + ...state.resetCounters, + standard: state.selectedTable !== 'project' ? state.resetCounters.standard + 1 : state.resetCounters.standard, + vendor: state.selectedTable !== 'project' ? state.resetCounters.vendor + 1 : state.resetCounters.vendor, + } + } + } else if (state.selectedTable === 'project') { + return { + ...state, + selectedTable: null, + selectedRowCount: 0, + } + } + return state + + case 'SELECT_STANDARD': + if (action.count > 0) { + return { + selectedTable: 'standard', + selectedRowCount: action.count, + resetCounters: { + ...state.resetCounters, + project: state.selectedTable !== 'standard' ? state.resetCounters.project + 1 : state.resetCounters.project, + vendor: state.selectedTable !== 'standard' ? state.resetCounters.vendor + 1 : state.resetCounters.vendor, + } + } + } else if (state.selectedTable === 'standard') { + return { + ...state, + selectedTable: null, + selectedRowCount: 0, + } + } + return state + + case 'SELECT_VENDOR': + if (action.count > 0) { + return { + selectedTable: 'vendor', + selectedRowCount: action.count, + resetCounters: { + ...state.resetCounters, + project: state.selectedTable !== 'vendor' ? state.resetCounters.project + 1 : state.resetCounters.project, + standard: state.selectedTable !== 'vendor' ? state.resetCounters.standard + 1 : state.resetCounters.standard, + } + } + } else if (state.selectedTable === 'vendor') { + return { + ...state, + selectedTable: null, + selectedRowCount: 0, + } + } + return state + + default: + return state + } +} + +interface AvlRegistrationAreaProps { + disabled?: boolean // 비활성화 상태 +} + +export function AvlRegistrationArea({ disabled = false }: AvlRegistrationAreaProps) { + // 선택된 AVL 레코드 구독 + const [selectedAvlRecord] = useAtom(selectedAvlRecordAtom) + + // 단일 선택 상태 관리 (useReducer 사용) + const [selectionState, dispatch] = React.useReducer(selectionReducer, { + selectedTable: null, + selectedRowCount: 0, + resetCounters: { + project: 0, + standard: 0, + vendor: 0, + }, + }) + + // 선택 핸들러들 + const handleProjectSelection = React.useCallback((count: number) => { + dispatch({ type: 'SELECT_PROJECT', count }) + }, []) + + const handleStandardSelection = React.useCallback((count: number) => { + dispatch({ type: 'SELECT_STANDARD', count }) + }, []) + + const handleVendorSelection = React.useCallback((count: number) => { + dispatch({ type: 'SELECT_VENDOR', count }) + }, []) + + const { selectedTable, selectedRowCount, resetCounters } = selectionState + + // 선택된 AVL에 따른 필터 값들 + const [currentProjectCode, setCurrentProjectCode] = React.useState<string>("") + const constructionSector = selectedAvlRecord?.constructionSector || "" + const shipType = selectedAvlRecord?.shipType || "" + const avlKind = selectedAvlRecord?.avlKind || "" + const htDivision = selectedAvlRecord?.htDivision || "" + const avlListId = selectedAvlRecord?.id ? String(selectedAvlRecord.id) : "" + + // 선택된 AVL 레코드가 변경될 때 프로젝트 코드 초기화 + React.useEffect(() => { + setCurrentProjectCode(selectedAvlRecord?.projectCode || "") + }, [selectedAvlRecord?.projectCode]) + + // 프로젝트 코드 변경 핸들러 + const handleProjectCodeChange = React.useCallback((projectCode: string) => { + setCurrentProjectCode(projectCode) + }, []) + + return ( + <Card className={`h-full min-w-full overflow-visible ${disabled ? 'opacity-50 pointer-events-none' : ''}`}> + {/* 고정 헤더 영역 */} + <div className="sticky top-0 z-10 p-4 border-b"> + <div className="flex items-center justify-between"> + <h3 className="text-lg font-semibold">AVL 등록 {disabled ? "(비활성화)" : ""}</h3> + <div className="flex gap-2"> + <Button variant="outline" size="sm" disabled={disabled}> + AVL 불러오기 + </Button> + </div> + </div> + </div> + + {/* 스크롤되는 콘텐츠 영역 */} + <div className="overflow-x-auto overflow-y-hidden"> + <div className="grid grid-cols-[2.2fr_2fr_2.5fr] gap-0 min-w-[1200px] w-fit"> + {/* 프로젝트 AVL 테이블 - 9개 컬럼 */} + <div className="p-4 border-r relative"> + <ProjectAvlTable + onSelectionChange={handleProjectSelection} + resetCounter={resetCounters.project} + projectCode={currentProjectCode} + avlListId={parseInt(avlListId) || 1} + onProjectCodeChange={handleProjectCodeChange} + /> + + {/* 이동 버튼들 - 첫 번째 border 위에 오버레이 */} + <div className="absolute right-0 top-1/2 transform -translate-y-1/2 translate-x-1/2 z-10"> + <div className="flex flex-col gap-2 bg-background border rounded-md p-1 shadow-sm"> + + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="프로젝트AVL로 복사" + disabled={disabled || selectedTable !== 'standard' || selectedRowCount === 0} + > + <ChevronLeft className="w-4 h-4" /> + </Button> + + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="선종별표준AVL로 복사" + disabled={disabled || selectedTable !== 'project' || selectedRowCount === 0} + > + <ChevronRight className="w-4 h-4" /> + </Button> + + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="벤더풀로 복사" + disabled={disabled || selectedTable !== 'project' || selectedRowCount === 0} + > + <ChevronsRight className="w-4 h-4" /> + </Button> + + </div> + </div> + </div> + + {/* 선종별 표준 AVL 테이블 - 8개 컬럼 */} + <div className="p-4 border-r relative"> + <StandardAvlTable + onSelectionChange={handleStandardSelection} + resetCounter={resetCounters.standard} + constructionSector={constructionSector} + shipType={shipType} + avlKind={avlKind} + htDivision={htDivision} + /> + + {/* 이동 버튼들 - 두 번째 border 위에 오버레이 */} + <div className="absolute right-0 top-1/2 transform -translate-y-1/2 translate-x-1/2 z-10"> + <div className="flex flex-col gap-2 bg-background border rounded-md p-1 shadow-sm"> + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="프로젝트AVL로 복사" + disabled={disabled || selectedTable !== 'vendor' || selectedRowCount === 0} + > + <ChevronsLeft className="w-4 h-4" /> + </Button> + + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="선종별표준AVL로 복사" + disabled={disabled || selectedTable !== 'vendor' || selectedRowCount === 0} + > + <ChevronLeft className="w-4 h-4" /> + </Button> + <Button + variant="outline" + size="sm" + className="w-8 h-8 p-0" + title="벤더풀로 복사" + disabled={disabled || selectedTable !== 'standard' || selectedRowCount === 0} + > + <ChevronRight className="w-4 h-4" /> + </Button> + + </div> + </div> + </div> + + {/* Vendor Pool 테이블 - 10개 컬럼 */} + <div className="p-4 relative"> + <VendorPoolTable + onSelectionChange={handleVendorSelection} + resetCounter={resetCounters.vendor} + /> + </div> + </div> + </div> + </Card> + ) +} |
