diff options
Diffstat (limited to 'lib/tech-vendor-candidates/table/import-button.tsx')
| -rw-r--r-- | lib/tech-vendor-candidates/table/import-button.tsx | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/lib/tech-vendor-candidates/table/import-button.tsx b/lib/tech-vendor-candidates/table/import-button.tsx deleted file mode 100644 index ad1e6862..00000000 --- a/lib/tech-vendor-candidates/table/import-button.tsx +++ /dev/null @@ -1,233 +0,0 @@ -"use client" - -import React, { useRef } from 'react' -import ExcelJS from 'exceljs' -import { toast } from 'sonner' -import { Button } from '@/components/ui/button' -import { Upload, Loader } from 'lucide-react' -import { createVendorCandidate } from '../service' -import { Input } from '@/components/ui/input' -import { useSession } from "next-auth/react" // next-auth 세션 훅 추가 -import { decryptWithServerAction } from '@/components/drm/drmUtils' // DRM 복호화 함수 import - -interface ImportExcelProps { - onSuccess?: () => void -} - -export function ImportVendorCandidatesButton({ onSuccess }: ImportExcelProps) { - const fileInputRef = useRef<HTMLInputElement>(null) - const [isImporting, setIsImporting] = React.useState(false) - const { data: session } = useSession() // status 제거 (사용하지 않음) - - // Helper function to get cell value as string - const getCellValueAsString = (cell: ExcelJS.Cell): string => { - if (!cell || cell.value === undefined || cell.value === null) return ''; - - if (typeof cell.value === 'string') return cell.value.trim(); - if (typeof cell.value === 'number') return cell.value.toString(); - - // Handle rich text - if (typeof cell.value === 'object' && 'richText' in cell.value) { - return cell.value.richText.map((rt: { text: string }) => rt.text).join(''); - } - - // Handle dates - if (cell.value instanceof Date) { - return cell.value.toISOString().split('T')[0]; - } - - // Fallback - return String(cell.value); - } - - const handleImport = async (event: React.ChangeEvent<HTMLInputElement>) => { - const file = event.target.files?.[0] - if (!file) return - - setIsImporting(true) - - try { - // DRM 복호화 시도 (실패시 원본 파일 사용) - let data: ArrayBuffer; - try { - data = await decryptWithServerAction(file); - console.log('[Import] DRM 복호화 성공'); - } catch (decryptError) { - console.warn('[Import] DRM 복호화 실패, 원본 파일 사용:', decryptError); - data = await file.arrayBuffer(); - } - - // Read the Excel file using ExcelJS - const workbook = new ExcelJS.Workbook() - await workbook.xlsx.load(data) - - // Get the first worksheet - const worksheet = workbook.getWorksheet(1) - if (!worksheet) { - toast.error("No worksheet found in the spreadsheet") - return - } - - // Check if there's an instruction row - const hasInstructionRow = worksheet.getRow(1).getCell(1).value !== null && - worksheet.getRow(1).getCell(2).value === null; - - // Get header row index (row 2 if there's an instruction row, otherwise row 1) - const headerRowIndex = hasInstructionRow ? 2 : 1; - - // Get column headers and their indices - const headerRow = worksheet.getRow(headerRowIndex); - const headers: Record<number, string> = {}; - const columnIndices: Record<string, number> = {}; - - headerRow.eachCell((cell, colNumber) => { - const header = getCellValueAsString(cell); - headers[colNumber] = header; - columnIndices[header] = colNumber; - }); - - // Process data rows - const rows: Record<string, string>[] = []; - const startRow = headerRowIndex + 1; - - for (let i = startRow; i <= worksheet.rowCount; i++) { - const row = worksheet.getRow(i); - - // Skip empty rows - if (row.cellCount === 0) continue; - - // Check if this is likely an example row - const isExample = i === startRow && worksheet.getRow(i + 1).values?.length === 0; - if (isExample) continue; - - const rowData: Record<string, string> = {}; - let hasData = false; - - // Map the data using header indices - Object.entries(columnIndices).forEach(([header, colIndex]) => { - const value = getCellValueAsString(row.getCell(colIndex)); - if (value) { - rowData[header] = value; - hasData = true; - } - }); - - if (hasData) { - rows.push(rowData); - } - } - - if (rows.length === 0) { - toast.error("No data found in the spreadsheet") - setIsImporting(false) - return - } - - // Process each row - let successCount = 0; - let errorCount = 0; - - // Create promises for all vendor candidate creation operations - const promises = rows.map(async (row) => { - try { - // Map Excel columns to our data model - const candidateData = { - companyName: String(row['Company Name'] || ''), - contactEmail: String(row['Contact Email'] || ''), - contactPhone: String(row['Contact Phone'] || ''), - taxId: String(row['Tax ID'] || ''), - address: String(row['Address'] || ''), - country: String(row['Country'] || ''), - source: String(row['Source'] || ''), - items: String(row['Items'] || ''), - remark: String(row['Remark'] || row['Remarks'] || ''), - // Default to COLLECTED if not specified - status: (row['Status'] || 'COLLECTED') as "COLLECTED" | "INVITED" | "DISCARDED" - }; - - // Validate required fields - if (!candidateData.companyName || !candidateData.source || - !candidateData.items) { - console.error("Missing required fields", candidateData); - errorCount++; - return null; - } - - if (!session || !session.user || !session.user.id) { - toast.error("인증 오류. 로그인 정보를 찾을 수 없습니다.") - return - } - - // Create the vendor candidate (userId는 이미 number 타입이므로 변환 불필요) - const result = await createVendorCandidate(candidateData) - - if (result.error) { - console.error(`Failed to import row: ${result.error}`, candidateData); - errorCount++; - return null; - } - - successCount++; - return result.data; - } catch (error) { - console.error("Error processing row:", error, row); - errorCount++; - return null; - } - }); - - // Wait for all operations to complete - await Promise.all(promises); - - // Show results - if (successCount > 0) { - toast.success(`Successfully imported ${successCount} vendor candidates`); - if (errorCount > 0) { - toast.warning(`Failed to import ${errorCount} rows due to errors`); - } - // Call the success callback to refresh data - onSuccess?.(); - } else if (errorCount > 0) { - toast.error(`Failed to import all ${errorCount} rows due to errors`); - } - - } catch (error) { - console.error("Import error:", error); - toast.error("Error importing data. Please check file format."); - } finally { - setIsImporting(false); - // Reset the file input - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - } - } - - return ( - <> - <Input - type="file" - ref={fileInputRef} - onChange={handleImport} - accept=".xlsx,.xls" - className="hidden" - /> - <Button - variant="outline" - size="sm" - onClick={() => fileInputRef.current?.click()} - disabled={isImporting} - className="gap-2" - > - {isImporting ? ( - <Loader className="size-4 animate-spin" aria-hidden="true" /> - ) : ( - <Upload className="size-4" aria-hidden="true" /> - )} - <span className="hidden sm:inline"> - {isImporting ? "Importing..." : "Import"} - </span> - </Button> - </> - ) -}
\ No newline at end of file |
