From 5c9b39eb011763a7491b3e8542de9f6d4976dd65 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 23 Jun 2025 09:02:07 +0000 Subject: (최겸) 기술영업 벤더 개발 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../additional-info/tech-vendor-info-form.tsx | 513 +++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 components/additional-info/tech-vendor-info-form.tsx (limited to 'components/additional-info') diff --git a/components/additional-info/tech-vendor-info-form.tsx b/components/additional-info/tech-vendor-info-form.tsx new file mode 100644 index 00000000..8e6f7eaf --- /dev/null +++ b/components/additional-info/tech-vendor-info-form.tsx @@ -0,0 +1,513 @@ +"use client" + +import * as React from "react" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import { useSession } from "next-auth/react" + +import { Button } from "@/components/ui/button" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { toast } from "@/hooks/use-toast" +import { Download, Loader2, Mail, Phone, User } from "lucide-react" +import { Badge } from "@/components/ui/badge" + +// 기술영업 벤더 관련 임포트 +import { getTechVendorDetailById, modifyTechVendor } from "@/lib/tech-vendors/service" +import { updateTechVendorSchema, type UpdateTechVendorSchema } from "@/lib/tech-vendors/validations" + +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card" + +// 타입 정의 +interface TechVendorContact { + id: number + contactName: string + contactPosition: string | null + contactEmail: string + contactPhone: string | null + isPrimary: boolean +} + +interface TechVendorAttachment { + id: number + fileName: string + filePath: string + attachmentType: string + createdAt: Date + updatedAt: Date +} + +export function TechVendorInfoForm() { + const { data: session } = useSession() + const techCompanyId = session?.user?.techCompanyId + + // 기술영업 벤더 데이터 상태 + const [vendor, setVendor] = React.useState(null) + const [contacts, setContacts] = React.useState([]) + const [attachments, setAttachments] = React.useState([]) + const [isLoading, setIsLoading] = React.useState(true) + const [isSubmitting, setIsSubmitting] = React.useState(false) + const [isDownloading, setIsDownloading] = React.useState(false) + + // React Hook Form (기술영업 벤더용 스키마 사용) + const form = useForm({ + resolver: zodResolver(updateTechVendorSchema), + defaultValues: { + vendorName: "", + vendorCode: "", + address: "", + email: "", + phone: "", + country: "", + website: "", + techVendorType: "", + status: "ACTIVE", + }, + mode: "onChange", + }) + + const isFormValid = form.formState.isValid + + // 기술영업 벤더 정보 가져오기 + React.useEffect(() => { + async function fetchTechVendorData() { + if (!techCompanyId) return + + try { + setIsLoading(true) + // 기술영업 벤더 상세 정보 가져오기 (연락처, 첨부파일 포함) + const vendorData = await getTechVendorDetailById(Number(techCompanyId)) + + if (!vendorData) { + toast({ + variant: "destructive", + title: "오류", + description: "기술영업 벤더 정보를 찾을 수 없습니다.", + }) + return + } + + setVendor(vendorData) + setContacts(vendorData.contacts || []) + setAttachments(vendorData.attachments || []) + + // 폼 기본값 설정 + const formValues = { + vendorName: vendorData.vendorName || "", + vendorCode: vendorData.vendorCode || "", + address: vendorData.address || "", + email: vendorData.email || "", + phone: vendorData.phone || "", + country: vendorData.country || "", + website: vendorData.website || "", + techVendorType: vendorData.techVendorType || "", + status: vendorData.status || "ACTIVE", + } + + form.reset(formValues) + } catch (error) { + console.error("Error fetching tech vendor data:", error) + toast({ + variant: "destructive", + title: "데이터 로드 오류", + description: "기술영업 벤더 정보를 불러오는 중 오류가 발생했습니다.", + }) + } finally { + setIsLoading(false) + } + } + + fetchTechVendorData() + }, [techCompanyId, form]) + + const handleDownloadFile = async (file: TechVendorAttachment) => { + try { + setIsDownloading(true) + + const downloadUrl = `/api/tech-vendors/attachments/download?id=${file.id}&vendorId=${Number(techCompanyId)}` + + const downloadLink = document.createElement('a') + downloadLink.href = downloadUrl + downloadLink.download = file.fileName + downloadLink.target = '_blank' + document.body.appendChild(downloadLink) + downloadLink.click() + + setTimeout(() => { + document.body.removeChild(downloadLink) + }, 100) + + toast({ + title: "다운로드 시작", + description: "파일 다운로드가 시작되었습니다.", + }) + } catch (error) { + console.error("Error downloading file:", error) + toast({ + variant: "destructive", + title: "다운로드 오류", + description: "파일 다운로드 중 오류가 발생했습니다.", + }) + } finally { + setIsDownloading(false) + } + } + + const handleDownloadAllFiles = async () => { + try { + setIsDownloading(true) + + const downloadUrl = `/api/tech-vendors/attachments/download-all?vendorId=${Number(techCompanyId)}` + + const downloadLink = document.createElement('a') + downloadLink.href = downloadUrl + downloadLink.download = `tech-vendor-${techCompanyId}-files.zip` + downloadLink.target = '_blank' + document.body.appendChild(downloadLink) + downloadLink.click() + + setTimeout(() => { + document.body.removeChild(downloadLink) + }, 100) + + toast({ + title: "다운로드 시작", + description: "전체 파일 다운로드가 시작되었습니다.", + }) + } catch (error) { + console.error("Error downloading files:", error) + toast({ + variant: "destructive", + title: "다운로드 오류", + description: "파일 다운로드 중 오류가 발생했습니다.", + }) + } finally { + setIsDownloading(false) + } + } + + async function onSubmit(values: UpdateTechVendorSchema) { + if (!techCompanyId) return + + setIsSubmitting(true) + + try { + const { error } = await modifyTechVendor({ + ...values, + id: String(techCompanyId), + }) + + if (error) { + throw new Error(error) + } + + toast({ + title: "업데이트 완료", + description: "기술영업 벤더 정보가 성공적으로 업데이트되었습니다.", + }) + } catch (error) { + console.error("Error updating tech vendor:", error) + toast({ + variant: "destructive", + title: "업데이트 오류", + description: "기술영업 벤더 정보 업데이트 중 오류가 발생했습니다.", + }) + } finally { + setIsSubmitting(false) + } + } + + if (isLoading) { + return ( +
+ + 기술영업 벤더 정보를 불러오는 중... +
+ ) + } + + if (!vendor) { + return ( +
+ 기술영업 벤더 정보를 찾을 수 없습니다. +
+ ) + } + + return ( +
+
+
+

기술영업 벤더 정보

+

기술영업 벤더 정보를 확인하고 업데이트할 수 있습니다.

+
+ {attachments.length > 0 && ( + + )} +
+ +
+ + + + 기본 정보 + + +
+ ( + + 벤더명 + + + + + + )} + /> + ( + + 벤더 코드 + + + + + + )} + /> +
+ + {/* 사업자등록번호 */} + {vendor.taxId && ( +
+ +

{vendor.taxId}

+
+ )} + + {/* 공급품목 */} + {vendor.items && ( +
+ +

{vendor.items}

+
+ )} + +
+ ( + + 이메일 + + + + + + )} + /> + ( + + 전화번호 + + + + + + )} + /> +
+ + ( + + 주소 + + + + + + )} + /> + +
+ ( + + 국가 + + + + + + )} + /> + ( + + 웹사이트 + + + + + + )} + /> +
+
+
+ + + {/* 연락처 정보 */} + {contacts.length > 0 && ( + + + 연락처 정보 + + 등록된 연락처 정보입니다. + + + +
+ {contacts.map((contact) => ( +
+
+
+ +
+
+
+

{contact.contactName}

+ {contact.isPrimary && ( + 주 담당자 + )} +
+ {contact.contactPosition && ( +

{contact.contactPosition}

+ )} +
+
+
+ {contact.contactEmail && ( + + )} + {contact.contactPhone && ( + + )} +
+
+ ))} +
+
+
+ )} + + {/* 첨부파일 정보 */} + {attachments.length > 0 && ( + + + 첨부파일 + + 업로드된 파일들을 확인하고 다운로드할 수 있습니다. + + + +
+ {attachments.map((file) => ( +
+
+

{file.fileName}

+
+ {file.attachmentType} + + {new Date(file.createdAt).toLocaleDateString()} +
+
+ +
+ ))} +
+
+
+ )} + +
+ +
+
+ +
+ ) +} \ No newline at end of file -- cgit v1.2.3