summaryrefslogtreecommitdiff
path: root/lib/items/table/items-table-toolbar-actions.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
commitef4c533ebacc2cdc97e518f30e9a9350004fcdfb (patch)
tree345251a3ed0f4429716fa5edaa31024d8f4cb560 /lib/items/table/items-table-toolbar-actions.tsx
parent9ceed79cf32c896f8a998399bf1b296506b2cd4a (diff)
~20250428 작업사항
Diffstat (limited to 'lib/items/table/items-table-toolbar-actions.tsx')
-rw-r--r--lib/items/table/items-table-toolbar-actions.tsx155
1 files changed, 125 insertions, 30 deletions
diff --git a/lib/items/table/items-table-toolbar-actions.tsx b/lib/items/table/items-table-toolbar-actions.tsx
index 3444daab..b3178ce1 100644
--- a/lib/items/table/items-table-toolbar-actions.tsx
+++ b/lib/items/table/items-table-toolbar-actions.tsx
@@ -2,37 +2,119 @@
import * as React from "react"
import { type Table } from "@tanstack/react-table"
-import { Download, Upload } from "lucide-react"
-import { toast } from "sonner"
+import { Download, FileDown } from "lucide-react"
+import * as ExcelJS from 'exceljs'
+import { saveAs } from "file-saver"
-import { exportTableToExcel } from "@/lib/export"
import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
-
-// 만약 서버 액션이나 API 라우트를 이용해 업로드 처리한다면 import
-import { importTasksExcel } from "@/lib/tasks/service" // 예시
import { Item } from "@/db/schema/items"
import { DeleteItemsDialog } from "./delete-items-dialog"
import { AddItemDialog } from "./add-items-dialog"
+import { exportItemTemplate } from "./item-excel-template"
+import { ImportItemButton } from "./import-excel-button"
interface ItemsTableToolbarActionsProps {
table: Table<Item>
}
export function ItemsTableToolbarActions({ table }: ItemsTableToolbarActionsProps) {
- // 파일 input을 숨기고, 버튼 클릭 시 참조해 클릭하는 방식
- const fileInputRef = React.useRef<HTMLInputElement>(null)
-
+ const [refreshKey, setRefreshKey] = React.useState(0)
+ // 가져오기 성공 후 테이블 갱신
+ const handleImportSuccess = () => {
+ setRefreshKey(prev => prev + 1)
+ }
- function handleImportClick() {
- // 숨겨진 <input type="file" /> 요소를 클릭
- fileInputRef.current?.click()
+ // Excel 내보내기 함수
+ const exportTableToExcel = async (
+ table: Table<any>,
+ options: {
+ filename: string;
+ excludeColumns?: string[];
+ sheetName?: string;
+ }
+ ) => {
+ const { filename, excludeColumns = [], sheetName = "아이템 목록" } = options;
+
+ // 워크북 생성
+ const workbook = new ExcelJS.Workbook();
+ workbook.creator = 'Item Management System';
+ workbook.created = new Date();
+
+ // 워크시트 생성
+ const worksheet = workbook.addWorksheet(sheetName);
+
+ // 테이블 데이터 가져오기
+ const data = table.getFilteredRowModel().rows.map(row => row.original);
+
+ // 테이블 헤더 가져오기
+ const headers = table.getAllColumns()
+ .filter(column => !excludeColumns.includes(column.id))
+ .map(column => ({
+ key: column.id,
+ header: column.columnDef.header?.toString() || column.id
+ }));
+
+ // 컬럼 정의
+ worksheet.columns = headers.map(header => ({
+ header: header.header,
+ key: header.key,
+ width: 20 // 기본 너비
+ }));
+
+ // 스타일 적용
+ const headerRow = worksheet.getRow(1);
+ headerRow.font = { bold: true };
+ headerRow.fill = {
+ type: 'pattern',
+ pattern: 'solid',
+ fgColor: { argb: 'FFE0E0E0' }
+ };
+ headerRow.alignment = { vertical: 'middle', horizontal: 'center' };
+
+ // 데이터 행 추가
+ data.forEach(item => {
+ const row: Record<string, any> = {};
+ headers.forEach(header => {
+ row[header.key] = item[header.key];
+ });
+ worksheet.addRow(row);
+ });
+
+ // 전체 셀에 테두리 추가
+ worksheet.eachRow((row, rowNumber) => {
+ row.eachCell((cell) => {
+ cell.border = {
+ top: { style: 'thin' },
+ left: { style: 'thin' },
+ bottom: { style: 'thin' },
+ right: { style: 'thin' }
+ };
+ });
+ });
+
+ try {
+ // 워크북을 Blob으로 변환
+ const buffer = await workbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+ saveAs(blob, `${filename}.xlsx`);
+ return true;
+ } catch (error) {
+ console.error("Excel 내보내기 오류:", error);
+ return false;
+ }
}
return (
<div className="flex items-center gap-2">
- {/** 1) 선택된 로우가 있으면 삭제 다이얼로그 */}
+ {/* 선택된 로우가 있으면 삭제 다이얼로그 */}
{table.getFilteredSelectedRowModel().rows.length > 0 ? (
<DeleteItemsDialog
items={table
@@ -42,26 +124,39 @@ export function ItemsTableToolbarActions({ table }: ItemsTableToolbarActionsProp
/>
) : null}
- {/** 2) 새 Task 추가 다이얼로그 */}
+ {/* 새 아이템 추가 다이얼로그 */}
<AddItemDialog />
-
+ {/* Import 버튼 */}
+ <ImportItemButton onSuccess={handleImportSuccess} />
- {/** 4) Export 버튼 */}
- <Button
- variant="outline"
- size="sm"
- onClick={() =>
- exportTableToExcel(table, {
- filename: "tasks",
- excludeColumns: ["select", "actions"],
- })
- }
- className="gap-2"
- >
- <Download className="size-4" aria-hidden="true" />
- <span className="hidden sm:inline">Export</span>
- </Button>
+ {/* Export 드롭다운 메뉴 */}
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button variant="outline" size="sm" className="gap-2">
+ <Download className="size-4" aria-hidden="true" />
+ <span className="hidden sm:inline">Export</span>
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end">
+ <DropdownMenuItem
+ onClick={() =>
+ exportTableToExcel(table, {
+ filename: "items",
+ excludeColumns: ["select", "actions"],
+ sheetName: "아이템 목록"
+ })
+ }
+ >
+ <FileDown className="mr-2 h-4 w-4" />
+ <span>현재 데이터 내보내기</span>
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => exportItemTemplate()}>
+ <FileDown className="mr-2 h-4 w-4" />
+ <span>템플릿 다운로드</span>
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
</div>
)
} \ No newline at end of file