diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-01 09:12:09 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-01 09:12:09 +0000 |
| commit | 18954df6565108a469fb1608ea3715dd9bb1b02d (patch) | |
| tree | 2675d254c547861a903a32459d89283a324e0e0d /lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx | |
| parent | f91cd16a872d9cda04aeb5c4e31538e3e2bd1895 (diff) | |
(대표님) 구매 기본계약, gtc 개발
Diffstat (limited to 'lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx')
| -rw-r--r-- | lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx b/lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx new file mode 100644 index 00000000..3a0fbdb6 --- /dev/null +++ b/lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx @@ -0,0 +1,350 @@ +"use client" + +import * as React from "react" +import { type Table } from "@tanstack/react-table" +import { + Download, + Upload, + Settings2, + ArrowUpDown, + Edit, + Eye, + FileText, + Wand2 +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" + +import { type GtcClauseTreeView } from "@/db/schema/gtc" +import { CreateVendorGtcClauseDialog } from "./create-gtc-clause-dialog" +import { PreviewDocumentDialog } from "./preview-document-dialog" +import { DeleteGtcClausesDialog } from "./delete-gtc-clauses-dialog" +import { exportTableToExcel } from "@/lib/export" +import { exportFullDataToExcel, type ExcelColumnDef } from "@/lib/export" +import { getAllGtcClausesForExport, importGtcClausesFromExcel } from "@/lib/gtc-contract/service" +import { ImportExcelDialog } from "./import-excel-dialog" +import { toast } from "@/hooks/use-toast" + +interface GtcClausesTableToolbarActionsProps { + table: Table<GtcClauseTreeView> + documentId: number + document: any + currentUserId?: number // 현재 사용자 ID 추가 +} + +// GTC 조항을 위한 Excel 컬럼 정의 (실용적으로 간소화) +const gtcClauseExcelColumns: ExcelColumnDef[] = [ + { + id: "itemNumber", + header: "채번", + accessor: "itemNumber", + group: "필수 정보" + }, + { + id: "subtitle", + header: "소제목", + accessor: "subtitle", + group: "필수 정보" + }, + { + id: "content", + header: "상세항목", + accessor: "content", + group: "기본 정보" + }, + { + id: "category", + header: "분류", + accessor: "category", + group: "기본 정보" + }, + { + id: "sortOrder", + header: "순서", + accessor: "sortOrder", + group: "순서" + }, + { + id: "parentId", + header: "상위 조항 ID", + accessor: "parentId", + group: "계층 구조" + }, + { + id: "isActive", + header: "활성 상태", + accessor: (row) => row.isActive ? "활성" : "비활성", + group: "상태" + }, + { + id: "editReason", + header: "편집 사유", + accessor: "editReason", + group: "추가 정보" + } +] + +export function GtcClausesTableToolbarActions({ + table, + documentId, + document, + currentUserId = 1, // 기본값 설정 (실제로는 auth에서 가져와야 함) +}: GtcClausesTableToolbarActionsProps) { + const [showCreateDialog, setShowCreateDialog] = React.useState(false) + const [showReorderDialog, setShowReorderDialog] = React.useState(false) + const [showBulkUpdateDialog, setShowBulkUpdateDialog] = React.useState(false) + const [showGenerateVariablesDialog, setShowGenerateVariablesDialog] = React.useState(false) + const [showPreviewDialog, setShowPreviewDialog] = React.useState(false) + const [isExporting, setIsExporting] = React.useState(false) + + const selectedRows = table.getSelectedRowModel().rows + const selectedCount = selectedRows.length + + // 테이블의 모든 데이터 가져오기 (현재 페이지만) + const allClauses = table.getRowModel().rows.map(row => row.original) + + const transformClausesForPreview = (clauses: GtcClauseTreeView[]) => { + return clauses.map(clause => { + // vendorInfo가 있고 수정된 값이 있는 경우 적용 + if (clause.vendorInfo) { + const { vendorInfo } = clause; + return { + ...clause, + // null이 아닌 수정값이 있으면 해당 값으로 대체 + category: vendorInfo.modifiedCategory ?? clause.category, + content: vendorInfo.modifiedContent ?? clause.content, + itemNumber: vendorInfo.modifiedItemNumber ?? clause.itemNumber, + subtitle: vendorInfo.modifiedSubtitle ?? clause.subtitle, + }; + } + // vendorInfo가 없으면 원본 그대로 반환 + return clause; + }); + }; + + // 컴포넌트 내에서 변환된 데이터 생성 + const previewClauses = React.useMemo( + () => transformClausesForPreview(allClauses), + [allClauses] + ); + + console.log(allClauses, "allClauses") + + // 현재 페이지 데이터만 Excel로 내보내기 + const handleExportCurrentPageToExcel = () => { + exportTableToExcel(table, { + filename: `gtc-clauses-page-${new Date().toISOString().split('T')[0]}`, + excludeColumns: ["select", "actions"], + }) + } + + // 전체 데이터를 Excel로 내보내기 + const handleExportAllToExcel = async () => { + try { + setIsExporting(true) + + // 서버에서 전체 데이터 가져오기 + const allData = await getAllGtcClausesForExport(documentId) + + // 전체 데이터를 Excel로 내보내기 + await exportFullDataToExcel( + allData, + gtcClauseExcelColumns, + { + filename: `gtc-clauses-all-${new Date().toISOString().split('T')[0]}`, + useGroupHeader: true + } + ) + + toast({ + title: "내보내기 완료", + description: `총 ${allData.length}개의 조항이 Excel 파일로 내보내졌습니다.`, + }) + } catch (error) { + console.error("Excel export failed:", error) + toast({ + title: "내보내기 실패", + description: "Excel 파일 내보내기 중 오류가 발생했습니다.", + variant: "destructive" + }) + } finally { + setIsExporting(false) + } + } + + // Excel 데이터 가져오기 처리 + const handleImportExcelData = async (data: Partial<GtcClauseTreeView>[]) => { + try { + const result = await importGtcClausesFromExcel(documentId, data, currentUserId) + + if (result.success) { + toast({ + title: "가져오기 성공", + description: `${result.importedCount}개의 조항이 성공적으로 가져와졌습니다.`, + }) + + // 테이블 새로고침 + handleRefreshTable() + } else { + const errorMessage = result.errors.length > 0 + ? `오류: ${result.errors.slice(0, 3).join(', ')}${result.errors.length > 3 ? '...' : ''}` + : "알 수 없는 오류가 발생했습니다." + + toast({ + title: "가져오기 실패", + description: errorMessage, + variant: "destructive" + }) + + // 오류가 있어도 일부는 성공했을 수 있음 + if (result.importedCount > 0) { + handleRefreshTable() + } + + throw new Error("Import failed with errors") + } + } catch (error) { + console.error("Excel import failed:", error) + throw error // ImportExcelDialog에서 처리하도록 다시 throw + } + } + + const handlePreviewDocument = () => { + setShowPreviewDialog(true) + } + + const handleGenerateDocument = () => { + // 최종 문서 생성 + console.log("Generate final document") + } + + const handleReorderClauses = () => { + setShowReorderDialog(true) + } + + const handleBulkUpdate = () => { + setShowBulkUpdateDialog(true) + } + + const handleGenerateVariables = () => { + setShowGenerateVariablesDialog(true) + } + + const handleRefreshTable = () => { + // 테이블 새로고침 로직 + console.log("Refresh table after creation") + // table.reset() 또는 상위 컴포넌트의 refetch 함수 호출 + } + + return ( + <> + <div className="flex items-center gap-2"> + {/* 조항 추가 버튼 */} + <CreateVendorGtcClauseDialog + documentId={documentId} + document={document} + onSuccess={handleRefreshTable} + /> + + {/* 선택된 항목이 있을 때 표시되는 액션들 */} + {selectedCount > 0 && ( + <> + <DeleteGtcClausesDialog + gtcClauses={allClauses} + onSuccess={() => table.toggleAllRowsSelected(false)} + /> + </> + )} + + {/* 관리 도구 드롭다운 */} + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="outline" size="sm" disabled={isExporting}> + <Settings2 className="mr-2 h-4 w-4" /> + 관리 도구 + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end" className="w-64"> + <DropdownMenuItem onClick={handleExportCurrentPageToExcel}> + <Download className="mr-2 h-4 w-4" /> + 현재 페이지 Excel로 내보내기 + </DropdownMenuItem> + + <DropdownMenuItem + onClick={handleExportAllToExcel} + disabled={isExporting} + > + <Download className="mr-2 h-4 w-4" /> + {isExporting ? "내보내는 중..." : "전체 데이터 Excel로 내보내기"} + </DropdownMenuItem> + + <DropdownMenuSeparator /> + + {/* <ImportExcelDialog + documentId={documentId} + columns={gtcClauseExcelColumns} + onSuccess={handleRefreshTable} + onImport={handleImportExcelData} + trigger={ + <DropdownMenuItem onSelect={(e) => e.preventDefault()}> + <Upload className="mr-2 h-4 w-4" /> + Excel에서 가져오기 + </DropdownMenuItem> + } + /> */} + + <DropdownMenuSeparator /> + + <DropdownMenuItem onClick={handlePreviewDocument}> + <Eye className="mr-2 h-4 w-4" /> + 문서 미리보기 + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + + {/* 조건부로 표시되는 다이얼로그들 */} + {showReorderDialog && ( + <div> + {/* ReorderGtcClausesDialog 컴포넌트가 여기에 올 예정 */} + </div> + )} + + {showBulkUpdateDialog && ( + <div> + {/* BulkUpdateGtcClausesDialog 컴포넌트가 여기에 올 예정 */} + </div> + )} + + {showGenerateVariablesDialog && ( + <div> + {/* GenerateVariableNamesDialog 컴포넌트가 여기에 올 예정 */} + </div> + )} + </div> + + {/* 미리보기 다이얼로그 */} + <PreviewDocumentDialog + open={showPreviewDialog} + onOpenChange={setShowPreviewDialog} + clauses={previewClauses} + document={document} + onExport={() => { + console.log("Export from preview dialog") + }} + /> + </> + ) +}
\ No newline at end of file |
