diff options
Diffstat (limited to 'lib/docu-list-rule/document-class/table/document-class-options-table.tsx')
| -rw-r--r-- | lib/docu-list-rule/document-class/table/document-class-options-table.tsx | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/lib/docu-list-rule/document-class/table/document-class-options-table.tsx b/lib/docu-list-rule/document-class/table/document-class-options-table.tsx new file mode 100644 index 00000000..644e3599 --- /dev/null +++ b/lib/docu-list-rule/document-class/table/document-class-options-table.tsx @@ -0,0 +1,176 @@ +"use client" + +import * as React from "react" +import { useDataTable } from "@/hooks/use-data-table" +import { DataTable } from "@/components/data-table/data-table" +import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar" +import type { DataTableAdvancedFilterField, DataTableRowAction } from "@/types/table" + +import { getDocumentClassSubOptions } from "@/lib/docu-list-rule/document-class/service" +import { getColumns } from "./document-class-options-table-columns" +import { DocumentClassOptionEditSheet } from "./document-class-option-edit-sheet" +import { DeleteDocumentClassOptionDialog } from "./delete-document-class-option-dialog" +import { DocumentClassOptionsTableToolbarActions } from "./document-class-options-table-toolbar" +import { documentClasses, documentClassOptions } from "@/db/schema/docu-list-rule" + +type DocumentClass = typeof documentClasses.$inferSelect + +interface DocumentClassOptionsTableProps { + selectedDocumentClass: DocumentClass | null + documentClasses: DocumentClass[] + onSelectDocumentClass: (documentClass: DocumentClass) => void +} + +export function DocumentClassOptionsTable({ + selectedDocumentClass, + documentClasses, + onSelectDocumentClass +}: DocumentClassOptionsTableProps) { + const [rowAction, setRowAction] = React.useState<DataTableRowAction<typeof documentClassOptions.$inferSelect> | null>(null) + + // 선택된 Document Class의 옵션 데이터 로드 + const [options, setOptions] = React.useState<typeof documentClassOptions.$inferSelect[]>([]) + + // DB 등록 순서대로 정렬된 Document Classes + const sortedDocumentClasses = React.useMemo(() => { + return [...documentClasses].sort((a, b) => a.id - b.id) + }, [documentClasses]) + + const handleSuccess = React.useCallback(async () => { + // 옵션 테이블 새로고침 + if (selectedDocumentClass) { + try { + const result = await getDocumentClassSubOptions(selectedDocumentClass.id) + if (result.success && result.data) { + setOptions(result.data) + } + } catch (error) { + console.error("Error refreshing options:", error) + } + } + }, [selectedDocumentClass]) + + const columns = React.useMemo(() => getColumns({ setRowAction }), [setRowAction]) + + // 고급 필터 필드 설정 + const advancedFilterFields: DataTableAdvancedFilterField<typeof documentClassOptions.$inferSelect>[] = [ + { id: "optionCode", label: "코드", type: "text" }, + { id: "optionValue", label: "옵션 값", type: "text" }, + { id: "createdAt", label: "생성일", type: "date" }, + ] + + const { table } = useDataTable({ + data: options, + columns, + pageCount: 1, + enablePinning: true, + enableAdvancedFilter: true, + manualSorting: false, + initialState: { + sorting: [{ id: "id", desc: false }], + columnPinning: { right: ["actions"] }, + }, + getRowId: (originalRow) => String(originalRow.id), + shallow: false, + clearOnDefault: true, + }) + + React.useEffect(() => { + const loadOptions = async () => { + if (!selectedDocumentClass) { + setOptions([]) + return + } + + try { + const result = await getDocumentClassSubOptions(selectedDocumentClass.id) + if (result.success && result.data) { + setOptions(result.data) + } + } catch (error) { + console.error("Error loading options:", error) + setOptions([]) + } + } + + loadOptions() + }, [selectedDocumentClass]) + + if (!selectedDocumentClass) { + return ( + <div className="space-y-4"> + <div className="flex gap-2"> + {sortedDocumentClasses.map((documentClass) => ( + <button + key={documentClass.id} + onClick={() => onSelectDocumentClass(documentClass)} + className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${ + selectedDocumentClass?.id === documentClass.id + ? "bg-primary text-primary-foreground" + : "bg-muted text-muted-foreground hover:bg-muted/80" + }`} + > + {documentClass.value} + </button> + ))} + </div> + <div className="text-center text-muted-foreground py-4"> + Document Class를 선택하면 옵션을 관리할 수 있습니다. + </div> + </div> + ) + } + + return ( + <> + <div className="space-y-2"> + <div className="flex gap-2"> + {sortedDocumentClasses.map((documentClass) => ( + <button + key={documentClass.id} + onClick={() => onSelectDocumentClass(documentClass)} + className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${ + selectedDocumentClass?.id === documentClass.id + ? "bg-primary text-primary-foreground" + : "bg-muted text-muted-foreground hover:bg-muted/80" + }`} + > + {documentClass.value} + </button> + ))} + </div> + + <DataTable table={table}> + <DataTableAdvancedToolbar + table={table} + filterFields={advancedFilterFields} + > + <DocumentClassOptionsTableToolbarActions + table={table} + selectedDocumentClass={selectedDocumentClass} + onSuccess={handleSuccess} + /> + </DataTableAdvancedToolbar> + </DataTable> + </div> + + <DeleteDocumentClassOptionDialog + open={rowAction?.type === "delete"} + onOpenChange={() => setRowAction(null)} + options={rowAction?.row.original ? [rowAction?.row.original] : []} + showTrigger={false} + onSuccess={() => { + rowAction?.row.toggleSelected(false) + handleSuccess() + }} + /> + + <DocumentClassOptionEditSheet + open={rowAction?.type === "update"} + onOpenChange={() => setRowAction(null)} + data={rowAction?.row.original ?? null} + onSuccess={handleSuccess} + /> + </> + ) +}
\ No newline at end of file |
