diff options
Diffstat (limited to 'components/additional-info/join-form.tsx')
| -rw-r--r-- | components/additional-info/join-form.tsx | 130 |
1 files changed, 89 insertions, 41 deletions
diff --git a/components/additional-info/join-form.tsx b/components/additional-info/join-form.tsx index 2cd385c3..4a9a3379 100644 --- a/components/additional-info/join-form.tsx +++ b/components/additional-info/join-form.tsx @@ -41,7 +41,7 @@ import { cn } from "@/lib/utils" import { useTranslation } from "@/i18n/client" import { getVendorDetailById, downloadVendorAttachments, updateVendorInfo } from "@/lib/vendors/service" -import { updateVendorSchema, type UpdateVendorInfoSchema } from "@/lib/vendors/validations" +import { updateVendorSchema, updateVendorSchemaWithConditions, type UpdateVendorInfoSchema } from "@/lib/vendors/validations" import { Select, SelectContent, @@ -104,6 +104,14 @@ const creditRatingScaleMap: Record<string, string[]> = { SCI: ["AAA", "AA+", "AA", "AA-", "A+", "A", "A-", "BBB+", "BBB-", "B"], } +const cashFlowRatingScaleMap: Record<string, string[]> = { + NICE: ["우수", "양호", "보통", "미흡", "불량"], + KIS: ["A+", "A", "B+", "B", "C", "D"], + KED: ["1등급", "2등급", "3등급", "4등급", "5등급"], + SCI: ["Level 1", "Level 2", "Level 3", "Level 4"], +} + + const MAX_FILE_SIZE = 3e9 // 파일 타입 정의 @@ -124,7 +132,7 @@ export function InfoForm() { const companyId = session?.user?.companyId || "17" - // 벤더 데이터 상태 + // 협력업체 데이터 상태 const [vendor, setVendor] = React.useState<any>(null) const [isLoading, setIsLoading] = React.useState(true) const [isSubmitting, setIsSubmitting] = React.useState(false) @@ -137,10 +145,11 @@ export function InfoForm() { const [selectedFiles, setSelectedFiles] = React.useState<File[]>([]) const [creditRatingFile, setCreditRatingFile] = React.useState<File[]>([]) const [cashFlowRatingFile, setCashFlowRatingFile] = React.useState<File[]>([]) + const [isDownloading, setIsDownloading] = React.useState(false); // React Hook Form const form = useForm<UpdateVendorInfoSchema>({ - resolver: zodResolver(updateVendorSchema), + resolver: zodResolver(updateVendorSchemaWithConditions), defaultValues: { vendorName: "", taxId: "", @@ -181,21 +190,21 @@ export function InfoForm() { name: "contacts", }) - // 벤더 정보 가져오기 + // 협력업체 정보 가져오기 React.useEffect(() => { async function fetchVendorData() { if (!companyId) return try { setIsLoading(true) - // 벤더 상세 정보 가져오기 (view 사용) + // 협력업체 상세 정보 가져오기 (view 사용) const vendorData = await getVendorDetailById(Number(companyId)) if (!vendorData) { toast({ variant: "destructive", title: "오류", - description: "벤더 정보를 찾을 수 없습니다.", + description: "협력업체 정보를 찾을 수 없습니다.", }) return } @@ -258,7 +267,7 @@ export function InfoForm() { toast({ variant: "destructive", title: "데이터 로드 오류", - description: "벤더 정보를 불러오는 중 오류가 발생했습니다.", + description: "협력업체 정보를 불러오는 중 오류가 발생했습니다.", }) } finally { setIsLoading(false) @@ -268,43 +277,82 @@ export function InfoForm() { fetchVendorData() }, [companyId, form, replaceContacts]) - // 파일 다운로드 처리 - const handleDownloadFile = async (fileId: number) => { + const handleDownloadFile = async (file: AttachmentFile) => { try { - const downloadInfo = await downloadVendorAttachments(Number(companyId), fileId) - - if (downloadInfo && downloadInfo.url) { - // 브라우저에서 다운로드 링크 열기 - window.open(downloadInfo.url, '_blank') - } - } catch (error) { - console.error("Error downloading file:", error) + setIsDownloading(true); + + // 파일이 객체인지 ID인지 확인하고 처리 + const fileId = typeof file === 'object' ? file.id : file; + const fileName = typeof file === 'object' ? file.fileName : `file-${fileId}`; + + // 다운로드 링크 생성 (URL 인코딩 적용) + const downloadUrl = `/api/vendors/attachments/download?id=${fileId}&vendorId=${Number(companyId)}`; + + // a 태그를 사용한 다운로드 + const downloadLink = document.createElement('a'); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + downloadLink.target = '_blank'; // 추가: 새 탭에서 열도록 설정 (일부 브라우저에서 더 안정적) + document.body.appendChild(downloadLink); + downloadLink.click(); + + // 정리 (메모리 누수 방지) + setTimeout(() => { + document.body.removeChild(downloadLink); + }, 100); + toast({ - variant: "destructive", - title: "다운로드 오류", - description: "파일 다운로드 중 오류가 발생했습니다.", - }) - } - } - - // 모든 첨부파일 다운로드 - const handleDownloadAllFiles = async () => { - try { - const downloadInfo = await downloadVendorAttachments(Number(companyId)) - - if (downloadInfo && downloadInfo.url) { - window.open(downloadInfo.url, '_blank') - } + title: "다운로드 시작", + description: "파일 다운로드가 시작되었습니다.", + }); } catch (error) { - console.error("Error downloading files:", error) + console.error("Error downloading file:", error); toast({ variant: "destructive", title: "다운로드 오류", description: "파일 다운로드 중 오류가 발생했습니다.", - }) + }); + } finally { + setIsDownloading(false); } + }; + + // 전체 파일 다운로드 함수 +const handleDownloadAllFiles = async () => { + try { + setIsDownloading(true); + + // 다운로드 URL 생성 + const downloadUrl = `/api/vendors/attachments/download-all?vendorId=${Number(companyId)}`; + + // a 태그를 사용한 다운로드 + const downloadLink = document.createElement('a'); + downloadLink.href = downloadUrl; + downloadLink.download = `vendor-${companyId}-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); } - +}; // Dropzone handlers const handleDropAccepted = (acceptedFiles: File[]) => { const newFiles = [...selectedFiles, ...acceptedFiles] @@ -476,7 +524,7 @@ export function InfoForm() { return ( <div className="container py-10 flex justify-center items-center"> <Loader2 className="h-8 w-8 animate-spin text-primary" /> - <span className="ml-2">벤더 정보를 불러오는 중입니다...</span> + <span className="ml-2">협력업체 정보를 불러오는 중입니다...</span> </div> ) } @@ -543,7 +591,7 @@ export function InfoForm() { </FileListDescription> </FileListInfo> <div className="flex items-center space-x-2"> - <FileListAction onClick={() => handleDownloadFile(file.id)}> + <FileListAction onClick={() => handleDownloadFile(file)}> <Download className="h-4 w-4" /> </FileListAction> <FileListAction onClick={() => handleDeleteExistingFile(file.id)}> @@ -574,7 +622,7 @@ export function InfoForm() { </FileListDescription> </FileListInfo> <div className="flex items-center space-x-2"> - <FileListAction onClick={() => handleDownloadFile(file.id)}> + <FileListAction onClick={() => handleDownloadFile(file)}> <Download className="h-4 w-4" /> </FileListAction> <FileListAction onClick={() => handleDeleteExistingFile(file.id)}> @@ -605,7 +653,7 @@ export function InfoForm() { </FileListDescription> </FileListInfo> <div className="flex items-center space-x-2"> - <FileListAction onClick={() => handleDownloadFile(file.id)}> + <FileListAction onClick={() => handleDownloadFile(file)}> <Download className="h-4 w-4" /> </FileListAction> <FileListAction onClick={() => handleDeleteExistingFile(file.id)}> @@ -1095,8 +1143,8 @@ export function InfoForm() { render={({ field }) => { const selectedAgency = form.watch("creditAgency") const ratingScale = - creditRatingScaleMap[ - selectedAgency as keyof typeof creditRatingScaleMap + cashFlowRatingScaleMap[ + selectedAgency as keyof typeof cashFlowRatingScaleMap ] || [] return ( <FormItem> |
