From cc2c3def63f47063d4fa8b01f9f61eafdd52805c Mon Sep 17 00:00:00 2001 From: rlaks5757 Date: Tue, 1 Apr 2025 11:58:20 +0900 Subject: template-upload-dialog component 세분화 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form-data-report-temp-upload-dialog.tsx | 544 +-------------------- 1 file changed, 15 insertions(+), 529 deletions(-) (limited to 'components/form-data/form-data-report-temp-upload-dialog.tsx') diff --git a/components/form-data/form-data-report-temp-upload-dialog.tsx b/components/form-data/form-data-report-temp-upload-dialog.tsx index 32273415..51fe5aca 100644 --- a/components/form-data/form-data-report-temp-upload-dialog.tsx +++ b/components/form-data/form-data-report-temp-upload-dialog.tsx @@ -1,59 +1,14 @@ "use client"; -import React, { - FC, - Dispatch, - SetStateAction, - useState, - useEffect, -} from "react"; -import { useToast } from "@/hooks/use-toast"; -import { toast as toastMessage } from "sonner"; -import prettyBytes from "pretty-bytes"; -import { X, Loader2, Download, Delete, Trash2, BookDown } from "lucide-react"; -import ExcelJS from "exceljs"; -import { saveAs } from "file-saver"; -import { Badge } from "@/components/ui/badge"; +import React, { FC, Dispatch, SetStateAction, useState } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, - DialogFooter, } from "@/components/ui/dialog"; -import { ScrollArea } from "@/components/ui/scroll-area"; import { Label } from "@/components/ui/label"; -import { Button } from "@/components/ui/button"; -import { - Dropzone, - DropzoneDescription, - DropzoneInput, - DropzoneTitle, - DropzoneUploadIcon, - DropzoneZone, -} from "@/components/ui/dropzone"; -import { - FileList, - FileListAction, - FileListDescription, - FileListHeader, - FileListIcon, - FileListInfo, - FileListItem, - FileListName, -} from "@/components/ui/file-list"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -61,13 +16,10 @@ import { TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; -import { - getReportTempList, - uploadReportTemp, - getReportTempFileData, - deleteReportTempFile, -} from "@/lib/forms/services"; -import { VendorDataReportTemps } from "@/db/schema/vendorData"; +import { TempDownloadBtn } from "./temp-download-btn"; +import { VarListDownloadBtn } from "./var-list-download-btn"; +import { FormDataReportTempUploadTab } from "./form-data-report-temp-upload-tab"; +import { FormDataReportTempUploadedListTab } from "./form-data-report-temp-uploaded-list-tab"; import { DataTableColumnJSON } from "./form-data-table-columns"; interface FormDataReportTempUploadDialogProps { @@ -80,9 +32,6 @@ interface FormDataReportTempUploadDialogProps { uploaderType: string; } -// 최대 파일 크기 설정 (3000MB) -const MAX_FILE_SIZE = 3000000; - export const FormDataReportTempUploadDialog: FC< FormDataReportTempUploadDialogProps > = ({ @@ -94,98 +43,8 @@ export const FormDataReportTempUploadDialog: FC< formCode, uploaderType, }) => { - const { toast } = useToast(); const [tabValue, setTabValue] = useState<"upload" | "uploaded">("upload"); - const downloadTempFile = async () => { - try { - const { fileName, fileType, base64 } = await getReportTempFileData(); - - saveAs(`data:${fileType};base64,${base64}`, fileName); - - toastMessage.success("Report Sample File 다운로드 완료!"); - } catch (err) { - console.log(err); - toast({ - title: "Error", - description: "Sample File을 찾을 수가 없습니다.", - variant: "destructive", - }); - } - }; - - const downloadReportVarList = async () => { - try { - // Create a new workbook - const workbook = new ExcelJS.Workbook(); - - // 데이터 시트 생성 - const worksheet = workbook.addWorksheet("Data"); - - // 유효성 검사용 숨김 시트 생성 - const validationSheet = workbook.addWorksheet("ValidationData"); - validationSheet.state = "hidden"; // 시트 숨김 처리 - - // 1. 데이터 시트에 헤더 추가 - const headers = ["Table Column Label", "Report Variable"]; - worksheet.addRow(headers); - - // 헤더 스타일 적용 - const headerRow = worksheet.getRow(1); - headerRow.font = { bold: true }; - headerRow.alignment = { horizontal: "center" }; - headerRow.eachCell((cell) => { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "FFCCCCCC" }, - }; - }); - - // 2. 데이터 행 추가 - columnsJSON.forEach((row) => { - const { displayLabel, label } = row; - - const labelConvert = label.replaceAll(" ", "_"); - - worksheet.addRow([displayLabel, labelConvert]); - }); - - // 3. 컬럼 너비 자동 조정 - headers.forEach((col, idx) => { - const column = worksheet.getColumn(idx + 1); - - // 최적 너비 계산 - let maxLength = col.length; - columnsJSON.forEach((row) => { - const valueKey = idx === 0 ? "displayLabel" : "label"; - - const value = row[valueKey]; - if (value !== undefined && value !== null) { - const valueLength = String(value).length; - if (valueLength > maxLength) { - maxLength = valueLength; - } - } - }); - - // 너비 설정 (최소 10, 최대 50) - column.width = Math.min(Math.max(maxLength + 2, 10), 50); - }); - - const buffer = await workbook.xlsx.writeBuffer(); - saveAs(new Blob([buffer]), `${formCode}_report_varible_list.xlsx`); - toastMessage.success("Report Varible List File 다운로드 완료!"); - } catch (err) { - console.log(err); - toast({ - title: "Error", - description: "Variable List 파일을 찾을 수가 없습니다.", - variant: "destructive", - }); - } - }; - return ( @@ -213,14 +72,7 @@ export const FormDataReportTempUploadDialog: FC< - + @@ -228,14 +80,10 @@ export const FormDataReportTempUploadDialog: FC< - + @@ -245,382 +93,20 @@ export const FormDataReportTempUploadDialog: FC< - - + ); }; - -interface TempUploadTabProps { - packageId: number; - formId: number; - uploaderType: string; -} - -const TempUploadTab: FC = ({ - packageId, - formId, - uploaderType, -}) => { - const { toast } = useToast(); - const [selectedFiles, setSelectedFiles] = useState([]); - const [isUploading, setIsUploading] = useState(false); - const [uploadProgress, setUploadProgress] = useState(0); - - // 드롭존 - 파일 드랍 처리 - const handleDropAccepted = (acceptedFiles: File[]) => { - const newFiles = [...selectedFiles, ...acceptedFiles]; - setSelectedFiles(newFiles); - }; - - // 드롭존 - 파일 거부(에러) 처리 - const handleDropRejected = (fileRejections: any[]) => { - fileRejections.forEach((rejection) => { - toast({ - variant: "destructive", - title: "File Error", - description: `${rejection.file.name}: ${ - rejection.errors[0]?.message || "Upload failed" - }`, - }); - }); - }; - - // 파일 제거 핸들러 - const removeFile = (index: number) => { - const updatedFiles = [...selectedFiles]; - updatedFiles.splice(index, 1); - setSelectedFiles(updatedFiles); - }; - - const submitData = async () => { - setIsUploading(true); - setUploadProgress(0); - try { - const totalFiles = selectedFiles.length; - let successCount = 0; - - for (let i = 0; i < totalFiles; i++) { - const file = selectedFiles[i]; - - const formData = new FormData(); - formData.append("file", file); - formData.append("customFileName", file.name); - formData.append("uploaderType", uploaderType); - - await uploadReportTemp(packageId, formId, formData); - - successCount++; - setUploadProgress(Math.round((successCount / totalFiles) * 100)); - } - } catch (err) { - console.error(err); - toast({ - title: "Error", - description: "파일 업로드 중 오류가 발생했습니다.", - variant: "destructive", - }); - } finally { - setIsUploading(false); - setUploadProgress(0); - } - }; - - return ( - <> -
- - - {({ maxSize }) => ( - <> - - -
- -
- 파일을 여기에 드롭하세요 - - 또는 클릭하여 파일을 선택하세요. 최대 크기:{" "} - {maxSize ? prettyBytes(maxSize) : "무제한"} - -
-
-
- - - )} -
-
- - {selectedFiles.length > 0 && ( -
-
-
- 선택된 파일 ({selectedFiles.length}) -
- {selectedFiles.length}개 파일 -
- - - -
- )} - - {isUploading && } - - - - - ); -}; - -interface UploadFileItemProps { - selectedFiles: File[]; - removeFile: (index: number) => void; - isUploading: boolean; -} - -const UploadFileItem: FC = ({ - selectedFiles, - removeFile, - isUploading, -}) => { - return ( - - {selectedFiles.map((file, index) => ( - - - - - {file.name} - - {prettyBytes(file.size)} - - - removeFile(index)} - disabled={isUploading} - > - - Remove - - - - ))} - - ); -}; - -const UploadProgressBox: FC<{ uploadProgress: number }> = ({ - uploadProgress, -}) => { - return ( -
-
- - {uploadProgress}% 업로드 중... -
-
-
-
-
- ); -}; - -type UpdateReportTempList = ( - packageId: number, - formId: number, - setPrevReportTemp: Dispatch> -) => Promise; - -const updateReportTempList: UpdateReportTempList = async ( - packageId, - formId, - setPrevReportTemp -) => { - const tempList = await getReportTempList(packageId, formId); - setPrevReportTemp(tempList); -}; - -interface UploadedTempFiles { - prevReportTemp: VendorDataReportTemps[]; - updateReportTempList: () => void; - isLoading: boolean; -} - -const UploadedTempFiles: FC = ({ - prevReportTemp, - updateReportTempList, - isLoading, -}) => { - const { toast } = useToast(); - - const downloadTempFile = async (fileName: string, filePath: string) => { - try { - const getTempFile = await fetch(filePath); - - if (getTempFile.ok) { - const blob = await getTempFile.blob(); - - saveAs(blob, fileName); - - toastMessage.success("Report 다운로드 완료!"); - } else { - const err = await getTempFile.json(); - console.error("에러:", err); - throw new Error(err.message); - } - - toastMessage.success("Template File 다운로드 완료!"); - } catch (err) { - console.error(err); - toast({ - title: "Error", - description: "Template File 다운로드 중 오류가 발생했습니다.", - variant: "destructive", - }); - } - }; - - const deleteTempFile = async (id: number) => { - try { - const { result, error } = await deleteReportTempFile(id); - - if (result) { - updateReportTempList(); - toastMessage.success("Template File 삭제 완료!"); - } else { - throw new Error(error); - } - } catch (err) { - toast({ - title: "Error", - description: "Template File 삭제 중 오류가 발생했습니다.", - variant: "destructive", - }); - } - }; - - if (isLoading) { - return ( -
- -
- ); - } - - return ( - - - {prevReportTemp.map((c) => { - const { fileName, filePath, id } = c; - - return ( - - - - - - {fileName} - - { - downloadTempFile(fileName, filePath); - }} - > - - Download - - - - - Delete - - - - - - Report Templete File({fileName})을 삭제하시겠습니까? - - - - - 취소 - { - deleteTempFile(id); - }} - > - 삭제 - - - - - - - ); - })} - - - ); -}; - -interface TempUploadedTabProps { - packageId: number; - formId: number; -} - -const TempUploadedTab: FC = ({ packageId, formId }) => { - const [prevReportTemp, setPrevReportTemp] = useState( - [] - ); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - const getTempFiles = async () => { - await updateReportTempList(packageId, formId, setPrevReportTemp); - setIsLoading(false); - }; - - getTempFiles(); - }, [packageId, formId]); - return ( -
- - - updateReportTempList(packageId, formId, setPrevReportTemp) - } - isLoading={isLoading} - /> -
- ); -}; -- cgit v1.2.3