diff options
Diffstat (limited to 'lib/procurement-rfqs/table/rfq-table.tsx')
| -rw-r--r-- | lib/procurement-rfqs/table/rfq-table.tsx | 412 |
1 files changed, 0 insertions, 412 deletions
diff --git a/lib/procurement-rfqs/table/rfq-table.tsx b/lib/procurement-rfqs/table/rfq-table.tsx deleted file mode 100644 index ca976172..00000000 --- a/lib/procurement-rfqs/table/rfq-table.tsx +++ /dev/null @@ -1,412 +0,0 @@ -"use client" - -import * as React from "react" -import { useSearchParams } from "next/navigation" -import { Button } from "@/components/ui/button" -import { PanelLeftClose, PanelLeftOpen } from "lucide-react" -import type { - DataTableAdvancedFilterField, - DataTableRowAction, -} from "@/types/table" -import { - ResizablePanelGroup, - ResizablePanel, - ResizableHandle, -} from "@/components/ui/resizable" - -import { useDataTable } from "@/hooks/use-data-table" -import { DataTable } from "@/components/data-table/data-table" -import { getColumns, EditingCellState } from "./rfq-table-column" -import { useEffect, useCallback, useRef, useMemo, useLayoutEffect } from "react" -import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar" -import { RFQTableToolbarActions } from "./rfq-table-toolbar-actions" -import { ProcurementRfqsView } from "@/db/schema" -import { getPORfqs } from "../services" -import { toast } from "sonner" -import { updateRfqRemark } from "@/lib/procurement-rfqs/services" -import { useTablePresets } from "@/components/data-table/use-table-presets" -import { TablePresetManager } from "@/components/data-table/data-table-preset" -import { Loader2 } from "lucide-react" -import { RFQFilterSheet } from "./rfq-filter-sheet" -import { RfqDetailTables } from "./detail-table/rfq-detail-table" -import { cn } from "@/lib/utils" - -interface RFQListTableProps { - promises: Promise<[Awaited<ReturnType<typeof getPORfqs>>]> - className?: string; - calculatedHeight?: string; // 계산된 높이 추가 -} - -export function RFQListTable({ - promises, - className, - calculatedHeight -}: RFQListTableProps) { - const searchParams = useSearchParams() - - // 필터 패널 상태 - const [isFilterPanelOpen, setIsFilterPanelOpen] = React.useState(false) - - // 선택된 RFQ 상태 - const [selectedRfq, setSelectedRfq] = React.useState<ProcurementRfqsView | null>(null) - - // 패널 collapse 상태 - const [isTopCollapsed, setIsTopCollapsed] = React.useState(false) - const [panelHeight, setPanelHeight] = React.useState<number>(55) - - // refs - const headerRef = React.useRef<HTMLDivElement>(null) - - // 고정 높이 설정을 위한 상수 (실제 측정값으로 조정 필요) - const LAYOUT_HEADER_HEIGHT = 64 // Layout Header 높이 - const LAYOUT_FOOTER_HEIGHT = 60 // Layout Footer 높이 (있다면 실제 값) - const LOCAL_HEADER_HEIGHT = 72 // 로컬 헤더 바 높이 (p-4 + border) - const FILTER_PANEL_WIDTH = 400 // 필터 패널 너비 - - // 높이 계산 - // 필터 패널 높이 - Layout Header와 Footer 사이 - const FIXED_FILTER_HEIGHT = `calc(100vh - ${LAYOUT_HEADER_HEIGHT*2}px)` - - console.log(calculatedHeight) - - // 테이블 컨텐츠 높이 - 전달받은 높이에서 로컬 헤더 제외 - const FIXED_TABLE_HEIGHT = calculatedHeight - ? `calc(${calculatedHeight} - ${LOCAL_HEADER_HEIGHT}px)` - : `calc(100vh - ${LAYOUT_HEADER_HEIGHT + LAYOUT_FOOTER_HEIGHT + LOCAL_HEADER_HEIGHT+76}px)` // fallback - - // Suspense 방식으로 데이터 처리 - const [promiseData] = React.use(promises) - const tableData = promiseData - - const [rowAction, setRowAction] = React.useState<DataTableRowAction<ProcurementRfqsView> | null>(null) - const [editingCell, setEditingCell] = React.useState<EditingCellState | null>(null) - - // 초기 설정 정의 - const initialSettings = React.useMemo(() => ({ - page: parseInt(searchParams.get('page') || '1'), - perPage: parseInt(searchParams.get('perPage') || '10'), - sort: searchParams.get('sort') ? JSON.parse(searchParams.get('sort')!) : [{ id: "updatedAt", desc: true }], - filters: searchParams.get('filters') ? JSON.parse(searchParams.get('filters')!) : [], - joinOperator: (searchParams.get('joinOperator') as "and" | "or") || "and", - basicFilters: searchParams.get('basicFilters') ? JSON.parse(searchParams.get('basicFilters')!) : [], - basicJoinOperator: (searchParams.get('basicJoinOperator') as "and" | "or") || "and", - search: searchParams.get('search') || '', - from: searchParams.get('from') || undefined, - to: searchParams.get('to') || undefined, - columnVisibility: {}, - columnOrder: [], - pinnedColumns: { left: [], right: [] }, - groupBy: [], - expandedRows: [] - }), [searchParams]) - - // DB 기반 프리셋 훅 사용 - const { - presets, - activePresetId, - hasUnsavedChanges, - isLoading: presetsLoading, - createPreset, - applyPreset, - updatePreset, - deletePreset, - setDefaultPreset, - renamePreset, - getCurrentSettings, - } = useTablePresets<ProcurementRfqsView>('rfq-list-table', initialSettings) - - // 비고 업데이트 함수 - const updateRemark = async (rfqId: number, remark: string) => { - try { - const result = await updateRfqRemark(rfqId, remark); - - if (result.success) { - toast.success("비고가 업데이트되었습니다"); - } else { - toast.error(result.message || "업데이트 중 오류가 발생했습니다"); - } - } catch (error) { - console.error("비고 업데이트 오류:", error); - toast.error("업데이트 중 오류가 발생했습니다"); - } - } - - // 행 액션 처리 - useEffect(() => { - if (rowAction) { - switch (rowAction.type) { - case "select": - setSelectedRfq(rowAction.row.original) - break; - case "update": - console.log("Update rfq:", rowAction.row.original) - break; - case "delete": - console.log("Delete rfq:", rowAction.row.original) - break; - } - setRowAction(null) - } - }, [rowAction]) - - const columns = React.useMemo( - () => getColumns({ - setRowAction, - editingCell, - setEditingCell, - updateRemark - }), - [setRowAction, editingCell, setEditingCell, updateRemark] - ) - - // 고급 필터 필드 정의 - const advancedFilterFields: DataTableAdvancedFilterField<ProcurementRfqsView>[] = [ - { - id: "rfqCode", - label: "RFQ No.", - type: "text", - }, - { - id: "projectCode", - label: "프로젝트", - type: "text", - }, - { - id: "itemCode", - label: "자재그룹", - type: "text", - }, - { - id: "itemName", - label: "자재명", - type: "text", - }, - { - id: "rfqSealedYn", - label: "RFQ 밀봉여부", - type: "text", - }, - { - id: "majorItemMaterialCode", - label: "자재코드", - type: "text", - }, - { - id: "rfqSendDate", - label: "RFQ 전송일", - type: "date", - }, - { - id: "dueDate", - label: "RFQ 마감일", - type: "date", - }, - { - id: "createdByUserName", - label: "요청자", - type: "text", - }, - ] - - // 현재 설정 가져오기 - const currentSettings = useMemo(() => { - return getCurrentSettings() - }, [getCurrentSettings]) - - // useDataTable 초기 상태 설정 - const initialState = useMemo(() => { - return { - sorting: initialSettings.sort.filter(sortItem => { - const columnExists = columns.some(col => col.accessorKey === sortItem.id) - return columnExists - }) as any, - columnVisibility: currentSettings.columnVisibility, - columnPinning: currentSettings.pinnedColumns, - } - }, [currentSettings, initialSettings.sort, columns]) - - // useDataTable 훅 설정 (PQ와 동일한 설정) - const { table } = useDataTable({ - data: tableData?.data || [], - columns, - pageCount: tableData?.pageCount || 0, - rowCount: tableData?.total || 0, - filterFields: [], // PQ와 동일하게 빈 배열 - enablePinning: true, - enableAdvancedFilter: true, - initialState, - getRowId: (originalRow) => String(originalRow.id), - shallow: false, // PQ와 동일하게 false - clearOnDefault: true, - }) - - // 조회 버튼 클릭 핸들러 - const handleSearch = () => { - setIsFilterPanelOpen(false) - } - - // Get active basic filter count (PQ와 동일한 방식) - const getActiveBasicFilterCount = () => { - try { - const basicFilters = searchParams.get('basicFilters') - return basicFilters ? JSON.parse(basicFilters).length : 0 - } catch (e) { - return 0 - } - } - - console.log(panelHeight) - - return ( - <div - className={cn("flex flex-col relative", className)} - style={{ height: calculatedHeight }} - > - {/* Filter Panel - 계산된 높이 적용 */} - <div - className={cn( - "fixed left-0 bg-background border-r z-30 flex flex-col transition-all duration-300 ease-in-out overflow-hidden", - isFilterPanelOpen ? "border-r shadow-lg" : "border-r-0" - )} - style={{ - width: isFilterPanelOpen ? `${FILTER_PANEL_WIDTH}px` : '0px', - top: `${LAYOUT_HEADER_HEIGHT*2}px`, - height: FIXED_FILTER_HEIGHT - }} - > - {/* Filter Content */} - <div className="h-full"> - <RFQFilterSheet - isOpen={isFilterPanelOpen} - onClose={() => setIsFilterPanelOpen(false)} - onSearch={handleSearch} - isLoading={false} - /> - </div> - </div> - - {/* Main Content */} - <div - className="flex flex-col transition-all duration-300 ease-in-out" - style={{ - width: isFilterPanelOpen ? `calc(100% - ${FILTER_PANEL_WIDTH}px)` : '100%', - marginLeft: isFilterPanelOpen ? `${FILTER_PANEL_WIDTH}px` : '0px', - height: '100%' - }} - > - {/* Header Bar - 고정 높이 */} - <div - ref={headerRef} - className="flex items-center justify-between p-4 bg-background border-b" - style={{ - height: `${LOCAL_HEADER_HEIGHT}px`, - flexShrink: 0 - }} - > - <div className="flex items-center gap-3"> - <Button - variant="outline" - size="sm" - type='button' - onClick={() => setIsFilterPanelOpen(!isFilterPanelOpen)} - className="flex items-center shadow-sm" - > - {isFilterPanelOpen ? <PanelLeftClose className="size-4"/> : <PanelLeftOpen className="size-4"/>} - {getActiveBasicFilterCount() > 0 && ( - <span className="ml-2 bg-primary text-primary-foreground rounded-full px-2 py-0.5 text-xs"> - {getActiveBasicFilterCount()} - </span> - )} - </Button> - </div> - - {/* Right side info */} - <div className="text-sm text-muted-foreground"> - {tableData && ( - <span>총 {tableData.total || 0}건</span> - )} - </div> - </div> - - {/* Table Content Area - 계산된 높이 사용 */} - <div - className="relative bg-background" - style={{ - height: FIXED_TABLE_HEIGHT, - display: 'grid', - gridTemplateRows: '1fr', - gridTemplateColumns: '1fr' - }} - > - <ResizablePanelGroup - direction="vertical" - className="w-full h-full" - > - <ResizablePanel - defaultSize={60} - minSize={25} - maxSize={75} - collapsible={false} - onResize={(size) => { - setPanelHeight(size) - }} - className="flex flex-col overflow-hidden" - > - {/* 상단 테이블 영역 */} - <div className="flex-1 min-h-0 overflow-hidden"> - <DataTable - table={table} - // className="h-full" - maxHeight={`${panelHeight*0.5}vh`} - > - <DataTableAdvancedToolbar - table={table} - filterFields={advancedFilterFields} - shallow={false} - > - <div className="flex items-center gap-2"> - <TablePresetManager<ProcurementRfqsView> - presets={presets} - activePresetId={activePresetId} - currentSettings={currentSettings} - hasUnsavedChanges={hasUnsavedChanges} - isLoading={presetsLoading} - onCreatePreset={createPreset} - onUpdatePreset={updatePreset} - onDeletePreset={deletePreset} - onApplyPreset={applyPreset} - onSetDefaultPreset={setDefaultPreset} - onRenamePreset={renamePreset} - /> - - <RFQTableToolbarActions - table={table} - localData={tableData} - setLocalData={() => {}} - onSuccess={() => {}} - /> - </div> - </DataTableAdvancedToolbar> - </DataTable> - </div> - </ResizablePanel> - - <ResizableHandle withHandle /> - - <ResizablePanel - minSize={25} - defaultSize={40} - collapsible={false} - className="flex flex-col overflow-hidden" - > - {/* 하단 상세 테이블 영역 */} - <div className="flex-1 min-h-0 overflow-hidden bg-background"> - <RfqDetailTables selectedRfq={selectedRfq} maxHeight={`${(100-panelHeight)*0.4}vh`}/> - </div> - </ResizablePanel> - </ResizablePanelGroup> - </div> - </div> - </div> - ) -}
\ No newline at end of file |
