summaryrefslogtreecommitdiff
path: root/lib/avl/table/avl-registration-area.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avl/table/avl-registration-area.tsx')
-rw-r--r--lib/avl/table/avl-registration-area.tsx278
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>
+ )
+}