diff options
Diffstat (limited to 'lib/general-contract-template/template/general-contract-template.tsx')
| -rw-r--r-- | lib/general-contract-template/template/general-contract-template.tsx | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/lib/general-contract-template/template/general-contract-template.tsx b/lib/general-contract-template/template/general-contract-template.tsx new file mode 100644 index 00000000..f66e8cf9 --- /dev/null +++ b/lib/general-contract-template/template/general-contract-template.tsx @@ -0,0 +1,287 @@ +"use client"; + +import * as React from "react"; +import { useRouter } from "next/navigation"; +import { DataTable } from "@/components/data-table/data-table"; +import { useDataTable } from "@/hooks/use-data-table"; +import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"; +import type { + DataTableAdvancedFilterField, + DataTableRowAction, +} from "@/types/table" +import { getContractTemplates} from "../service"; +import { getColumns } from "./general-contract-template-columns"; +import { GeneralContractTemplateToolbarActions } from "./general-contract-template-toolbar-actions"; +import { UpdateTemplateSheet } from "./update-generalContract-sheet"; +import { CreateRevisionDialog } from "./create-revision-dialog"; +import { removeTemplates } from "../service"; +import { disposeTemplates, restoreTemplates } from "../actions"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; + +import { GeneralContractTemplate } from "@/db/schema"; + +interface ContractTemplateTableProps { + promises: Promise< + [ + Awaited<ReturnType<typeof getContractTemplates>>, + ] + > +} + +export function ContractTemplateTable({ promises }: ContractTemplateTableProps) { + const router = useRouter(); + const [rowAction, setRowAction] = + React.useState<DataTableRowAction<GeneralContractTemplate> | null>(null) + const [selectedRows, setSelectedRows] = React.useState<GeneralContractTemplate[]>([]) + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = React.useState(false) + const [isDisposeDialogOpen, setIsDisposeDialogOpen] = React.useState(false) + const [isRestoreDialogOpen, setIsRestoreDialogOpen] = React.useState(false) + const [isCreateRevisionDialogOpen, setIsCreateRevisionDialogOpen] = React.useState(false) + const [{ data, pageCount }] = + React.use(promises) + + // 컬럼 설정 - router와 setRowAction을 전달 + const columns = React.useMemo( + () => getColumns({ setRowAction, router }), + [setRowAction, router] + ) + + // config 기반으로 필터 필드 설정 + const advancedFilterFields: DataTableAdvancedFilterField<GeneralContractTemplate>[] = [ + { id: "contractTemplateName", label: "계약문서명", type: "text" }, + { + id: "status", label: "상태", type: "select", options: [ + { label: "전체", value: "ALL" }, + { label: "활성화(A)", value: "ACTIVE" }, + { label: "비활성화(Null)", value: "INACTIVE" }, + { label: "폐기(D)", value: "DISPOSED" }, + ] + }, + { id: "contractTemplateType", label: "계약종류", type: "text" }, + { id: "fileName", label: "파일명", type: "text" }, + { id: "createdAt", label: "생성일", type: "date" }, + { id: "updatedAt", label: "수정일", type: "date" }, + ]; + + const { table } = useDataTable({ + data, + columns, + pageCount, + enablePinning: true, + enableAdvancedFilter: true, + initialState: { + sorting: [{ id: "createdAt", desc: true }], + columnPinning: { right: ["actions"] }, + }, + getRowId: (originalRow) => String(originalRow.id), + shallow: false, + clearOnDefault: true, + }) + + // 선택된 행들 추적 + React.useEffect(() => { + const selectedRowModels = table.getFilteredSelectedRowModel().rows + const selectedData = selectedRowModels.map(row => row.original) + setSelectedRows(selectedData) + }, [table.getState().rowSelection]) + + // rowAction 처리 + React.useEffect(() => { + if (rowAction?.type === "delete") { + setIsDeleteDialogOpen(true) + } else if (rowAction?.type === "dispose") { + setIsDisposeDialogOpen(true) + } else if (rowAction?.type === "restore") { + setIsRestoreDialogOpen(true) + } else if (rowAction?.type === "create-revision") { + setIsCreateRevisionDialogOpen(true) + } + }, [rowAction]) + + // 삭제 확인 처리 + const handleConfirmDelete = async () => { + if (!rowAction?.row) return + + try { + const result = await removeTemplates({ ids: [rowAction.row.original.id] }) + + if (result.error) { + toast.error(result.error) + return + } + + toast.success("템플릿이 삭제되었습니다.") + setIsDeleteDialogOpen(false) + setRowAction(null) + + // 페이지 새로고침 + window.location.reload() + } catch (error) { + console.error('삭제 처리 오류:', error) + toast.error("삭제 처리 중 오류가 발생했습니다.") + } + } + + // 폐기 확인 처리 + const handleConfirmDispose = async () => { + if (!rowAction?.row) return + + try { + const result = await disposeTemplates([rowAction.row.original.id]) + + toast.success(result.message) + setIsDisposeDialogOpen(false) + setRowAction(null) + + // 페이지 새로고침 + window.location.reload() + } catch (error) { + console.error('폐기 처리 오류:', error) + toast.error("폐기 처리 중 오류가 발생했습니다.") + } + } + + // 복구 확인 처리 + const handleConfirmRestore = async () => { + if (!rowAction?.row) return + + try { + const result = await restoreTemplates([rowAction.row.original.id]) + + toast.success(result.message) + setIsRestoreDialogOpen(false) + setRowAction(null) + + // 페이지 새로고침 + window.location.reload() + } catch (error) { + console.error('복구 처리 오류:', error) + toast.error("복구 처리 중 오류가 발생했습니다.") + } + } + + return ( + <> + <DataTable table={table}> + <DataTableAdvancedToolbar + table={table} + filterFields={advancedFilterFields} + shallow={false} + > + <GeneralContractTemplateToolbarActions selectedRows={selectedRows} /> + </DataTableAdvancedToolbar> + </DataTable> + + <UpdateTemplateSheet + open={rowAction?.type === "update"} + onOpenChange={() => setRowAction(null)} + template={rowAction?.row.original ?? null} + /> + + {/* 삭제 확인 다이얼로그 */} + <Dialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}> + <DialogContent> + <DialogHeader> + <DialogTitle>템플릿 삭제 확인</DialogTitle> + <DialogDescription> + "{rowAction?.row?.original?.contractTemplateName}" 템플릿을 삭제하시겠습니까? + <br /> + 삭제된 템플릿은 복구할 수 없습니다. + </DialogDescription> + </DialogHeader> + <div className="flex justify-end gap-2"> + <Button + variant="outline" + onClick={() => { + setIsDeleteDialogOpen(false) + setRowAction(null) + }} + > + 취소 + </Button> + <Button + variant="destructive" + onClick={handleConfirmDelete} + > + 삭제 + </Button> + </div> + </DialogContent> + </Dialog> + + {/* 폐기 확인 다이얼로그 */} + <Dialog open={isDisposeDialogOpen} onOpenChange={setIsDisposeDialogOpen}> + <DialogContent> + <DialogHeader> + <DialogTitle>템플릿 폐기 확인</DialogTitle> + <DialogDescription> + "{rowAction?.row?.original?.contractTemplateName}" 템플릿을 폐기하시겠습니까? + <br /> + 폐기된 템플릿은 복구할 수 있습니다. + </DialogDescription> + </DialogHeader> + <div className="flex justify-end gap-2"> + <Button + variant="outline" + onClick={() => { + setIsDisposeDialogOpen(false) + setRowAction(null) + }} + > + 취소 + </Button> + <Button + variant="destructive" + onClick={handleConfirmDispose} + > + 폐기 + </Button> + </div> + </DialogContent> + </Dialog> + + {/* 복구 확인 다이얼로그 */} + <Dialog open={isRestoreDialogOpen} onOpenChange={setIsRestoreDialogOpen}> + <DialogContent> + <DialogHeader> + <DialogTitle>템플릿 복구 확인</DialogTitle> + <DialogDescription> + "{rowAction?.row?.original?.contractTemplateName}" 템플릿을 복구하시겠습니까? + <br /> + 복구된 템플릿은 다시 사용할 수 있습니다. + </DialogDescription> + </DialogHeader> + <div className="flex justify-end gap-2"> + <Button + variant="outline" + onClick={() => { + setIsRestoreDialogOpen(false) + setRowAction(null) + }} + > + 취소 + </Button> + <Button + variant="default" + onClick={handleConfirmRestore} + > + 복구 + </Button> + </div> + </DialogContent> + </Dialog> + + {/* 리비전 생성 다이얼로그 */} + <CreateRevisionDialog + open={isCreateRevisionDialogOpen} + onOpenChange={setIsCreateRevisionDialogOpen} + baseTemplate={rowAction?.row?.original || null} + onSuccess={() => { + setRowAction(null) + }} + /> + </> + ); +}
\ No newline at end of file |
