summaryrefslogtreecommitdiff
path: root/lib/basic-contract/gtc-vendor/gtc-clauses-table-toolbar-actions.tsx
diff options
context:
space:
mode:
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.tsx350
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