From 00092099271ff743ac195511c03994e80f91a2e9 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 10 Oct 2025 07:37:26 +0000
Subject: (최겸) 기술영업 import 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../contact-table-toolbar-actions.tsx              | 124 ++++++++++++++++++++-
 1 file changed, 119 insertions(+), 5 deletions(-)

(limited to 'lib/tech-vendors/contacts-table/contact-table-toolbar-actions.tsx')

diff --git a/lib/tech-vendors/contacts-table/contact-table-toolbar-actions.tsx b/lib/tech-vendors/contacts-table/contact-table-toolbar-actions.tsx
index 84228a54..7b81967e 100644
--- a/lib/tech-vendors/contacts-table/contact-table-toolbar-actions.tsx
+++ b/lib/tech-vendors/contacts-table/contact-table-toolbar-actions.tsx
@@ -10,10 +10,13 @@ import { exportTableToExcel } from "@/lib/export"
 import { Button } from "@/components/ui/button"
 import { TechVendorContact } from "@/db/schema/techVendors"
 import { AddContactDialog } from "./add-contact-dialog"
-import { 
-  importTechVendorContacts, 
-  generateContactImportTemplate, 
-  parseContactImportFile 
+import {
+  importTechVendorContacts,
+  generateContactImportTemplate,
+  parseContactImportFile,
+  importTechVendorDistinctContacts,
+  generateDistinctContactImportTemplate,
+  parseDistinctContactImportFile
 } from "@/lib/tech-vendors/service"
 
 interface TechVendorContactsTableToolbarActionsProps {
@@ -24,6 +27,7 @@ interface TechVendorContactsTableToolbarActionsProps {
 export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechVendorContactsTableToolbarActionsProps) {
   // 파일 input을 숨기고, 버튼 클릭 시 참조해 클릭하는 방식
   const fileInputRef = React.useRef<HTMLInputElement>(null)
+  const distinctFileInputRef = React.useRef<HTMLInputElement>(null)
 
   // 파일이 선택되었을 때 처리
   async function onFileChange(event: React.ChangeEvent<HTMLInputElement>) {
@@ -99,6 +103,11 @@ export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechV
     fileInputRef.current?.click()
   }
 
+  function handleDistinctImportClick() {
+    // Distinct Import용 숨겨진 <input type="file" /> 요소를 클릭
+    distinctFileInputRef.current?.click()
+  }
+
   async function handleTemplateDownload() {
     try {
       const templateBlob = await generateContactImportTemplate()
@@ -115,6 +124,89 @@ export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechV
     }
   }
 
+  // Distinct Import 파일 처리 함수
+  async function onDistinctFileChange(event: React.ChangeEvent<HTMLInputElement>) {
+    const file = event.target.files?.[0]
+    if (!file) return
+
+    // 파일 초기화 (동일 파일 재업로드 시에도 onChange가 트리거되도록)
+    event.target.value = ""
+
+    try {
+      // Excel 파일 파싱 (새로운 함수 사용)
+      const distinctContactData = await parseDistinctContactImportFile(file)
+
+      if (distinctContactData.length === 0) {
+        toast.error("유효한 데이터가 없습니다. 템플릿 형식을 확인해주세요.")
+        return
+      }
+
+      // 서버로 데이터 전송 (새로운 함수 사용)
+      const result = await importTechVendorDistinctContacts(distinctContactData)
+
+      if (result.successCount > 0) {
+        toast.success(`${result.successCount}개 담당자가 성공적으로 추가되었습니다.`)
+      }
+
+      if (result.failedRows.length > 0) {
+        toast.error(`${result.failedRows.length}개 행에서 오류가 발생했습니다.`)
+
+        // 에러 데이터를 Excel로 다운로드
+        const errorWorkbook = new ExcelJS.Workbook()
+        const errorWorksheet = errorWorkbook.addWorksheet("오류내역")
+
+        // 헤더 추가
+        errorWorksheet.columns = [
+          { header: "행번호", key: "row", width: 10 },
+          { header: "벤더이름", key: "vendorName", width: 20 },
+          { header: "이메일", key: "email", width: 25 },
+          { header: "오류내용", key: "error", width: 80, style: { alignment: { wrapText: true }, font: { color: { argb: "FFFF0000" } } } },
+        ]
+
+        // 오류 데이터 추가
+        result.failedRows.forEach(failedRow => {
+          errorWorksheet.addRow({
+            row: failedRow.row,
+            error: failedRow.error,
+            vendorName: failedRow.vendorName,
+            email: failedRow.email,
+          })
+        })
+
+        const buffer = await errorWorkbook.xlsx.writeBuffer()
+        const blob = new Blob([buffer], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        })
+        const url = URL.createObjectURL(blob)
+        const link = document.createElement("a")
+        link.href = url
+        link.download = "distinct-contact-import-errors.xlsx"
+        link.click()
+        URL.revokeObjectURL(url)
+      }
+
+    } catch (error) {
+      toast.error("파일 업로드 중 오류가 발생했습니다.")
+      console.error("Distinct Import error:", error)
+    }
+  }
+
+  async function handleDistinctTemplateDownload() {
+    try {
+      const templateBlob = await generateDistinctContactImportTemplate()
+      const url = URL.createObjectURL(templateBlob)
+      const link = document.createElement("a")
+      link.href = url
+      link.download = "tech-vendor-distinct-contacts-template.xlsx"
+      link.click()
+      URL.revokeObjectURL(url)
+      toast.success("Distinct Import 템플릿이 다운로드되었습니다.")
+    } catch (error) {
+      toast.error("템플릿 다운로드 중 오류가 발생했습니다.")
+      console.error("Distinct Template download error:", error)
+    }
+  }
+
   return (
     <div className="flex items-center gap-2">
 
@@ -123,7 +215,13 @@ export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechV
       {/** 템플릿 다운로드 버튼 */}
       <Button variant="outline" size="sm" className="gap-2" onClick={handleTemplateDownload}>
         <Download className="size-4" aria-hidden="true" />
-        <span className="hidden sm:inline">템플릿</span>
+        <span className="hidden sm:inline">기본 템플릿</span>
+      </Button>
+
+      {/** Distinct Import 템플릿 다운로드 버튼 */}
+      <Button variant="outline" size="sm" className="gap-2" onClick={handleDistinctTemplateDownload}>
+        <Download className="size-4" aria-hidden="true" />
+        <span className="hidden sm:inline">Distinct 템플릿</span>
       </Button>
 
       {/** Import 버튼 (파일 업로드) */}
@@ -131,6 +229,13 @@ export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechV
         <Upload className="size-4" aria-hidden="true" />
         <span className="hidden sm:inline">Import</span>
       </Button>
+
+      {/** Distinct Import 버튼 (대표 이메일과 다른 담당자 추가) */}
+      <Button variant="outline" size="sm" className="gap-2" onClick={handleDistinctImportClick}>
+        <Upload className="size-4" aria-hidden="true" />
+        <span className="hidden sm:inline">Distinct Import</span>
+      </Button>
+
       {/*
         실제로는 숨겨진 input과 연결:
         - accept=".xlsx,.xls" 등으로 Excel 파일만 업로드 허용
@@ -143,6 +248,15 @@ export function TechVendorContactsTableToolbarActions({ table, vendorId }: TechV
         onChange={onFileChange}
       />
 
+      {/** Distinct Import용 숨겨진 input */}
+      <input
+        ref={distinctFileInputRef}
+        type="file"
+        accept=".xlsx,.xls"
+        className="hidden"
+        onChange={onDistinctFileChange}
+      />
+
       {/** Export 버튼 */}
       <Button
         variant="outline"
-- 
cgit v1.2.3

