diff options
Diffstat (limited to 'lib/approval-template/table/approval-template-table-toolbar-actions.tsx')
| -rw-r--r-- | lib/approval-template/table/approval-template-table-toolbar-actions.tsx | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/lib/approval-template/table/approval-template-table-toolbar-actions.tsx b/lib/approval-template/table/approval-template-table-toolbar-actions.tsx new file mode 100644 index 00000000..08aba97a --- /dev/null +++ b/lib/approval-template/table/approval-template-table-toolbar-actions.tsx @@ -0,0 +1,114 @@ +"use client" + +import * as React from "react" +import { type Table } from "@tanstack/react-table" +import { Download, Plus, Trash } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { type ApprovalTemplate } from "@/lib/approval-template/service" +import { toast } from "sonner" +import { DeleteApprovalTemplateDialog } from "./delete-approval-template-dialog" + +interface ApprovalTemplateTableToolbarActionsProps { + table: Table<ApprovalTemplate> + onCreateTemplate: () => void +} + +export function ApprovalTemplateTableToolbarActions({ + table, + onCreateTemplate, +}: ApprovalTemplateTableToolbarActionsProps) { + const [showDeleteDialog, setShowDeleteDialog] = React.useState(false) + + const selectedRows = table.getFilteredSelectedRowModel().rows + const selectedTemplates = selectedRows.map((row) => row.original) + + // CSV 내보내기 + const exportToCsv = React.useCallback(() => { + const headers = [ + "이름", + "제목", + "카테고리", + "생성일", + "수정일", + ] + + const csvData = [ + headers, + ...table.getFilteredRowModel().rows.map((row) => { + const t = row.original + return [ + t.name, + t.subject, + t.category ?? "-", + new Date(t.createdAt).toLocaleDateString("ko-KR"), + new Date(t.updatedAt).toLocaleDateString("ko-KR"), + ] + }), + ] + + const csvContent = csvData + .map((row) => row.map((field) => `"${field}"`).join(",")) + .join("\n") + + const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }) + const link = document.createElement("a") + + if (link.download !== undefined) { + const url = URL.createObjectURL(blob) + link.setAttribute("href", url) + link.setAttribute( + "download", + `approval_templates_${new Date().toISOString().split("T")[0]}.csv`, + ) + link.style.visibility = "hidden" + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } + + toast.success("템플릿 목록이 CSV로 내보내졌습니다.") + }, [table]) + + return ( + <div className="flex items-center gap-2"> + {/* 새 템플릿 버튼 */} + <Button variant="default" size="sm" onClick={onCreateTemplate}> + <Plus className="mr-2 size-4" aria-hidden="true" /> + 새 템플릿 + </Button> + + {/* CSV 내보내기 */} + <Button variant="outline" size="sm" onClick={exportToCsv}> + <Download className="mr-2 size-4" aria-hidden="true" /> + 내보내기 + </Button> + + {/* 일괄 삭제 */} + {selectedTemplates.length > 0 && ( + <> + <Button + variant="outline" + size="sm" + onClick={() => setShowDeleteDialog(true)} + className="text-destructive hover:text-destructive" + > + <Trash className="mr-2 size-4" aria-hidden="true" /> + 삭제 ({selectedTemplates.length}) + </Button> + + <DeleteApprovalTemplateDialog + open={showDeleteDialog} + onOpenChange={setShowDeleteDialog} + templates={selectedTemplates} + showTrigger={false} + onSuccess={() => { + table.toggleAllRowsSelected(false) + setShowDeleteDialog(false) + }} + /> + </> + )} + </div> + ) +} |
