From 3d3a5858e3a4f91db3265c9fbd1b359b5a9a6ff3 Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 27 May 2025 09:48:21 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20fileUploadForm.tsx=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=EC=97=86=EC=9D=B4=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?,=20page.tsx=20JSON=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EB=B0=B1=EC=97=94=EB=93=9C=20API=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/components/ui/fileUploadForm.tsx | 108 +++++-- apps/sn/app/ii/irsetting/page.tsx | 296 +++++++++++++------ 2 files changed, 278 insertions(+), 126 deletions(-) diff --git a/apps/sn/app/components/ui/fileUploadForm.tsx b/apps/sn/app/components/ui/fileUploadForm.tsx index f4c7292e9..58712b130 100644 --- a/apps/sn/app/components/ui/fileUploadForm.tsx +++ b/apps/sn/app/components/ui/fileUploadForm.tsx @@ -8,36 +8,67 @@ import { handleUpload } from "@utils"; import { set } from 'react-hook-form'; interface FileUploadFormProps { - onSubmit: (files: string, year: string, quarter: string, code: string, id: string) => void; + onSubmit?: (files: string, year: string, quarter: string, code: string, id: string) => void; + onFileSelect?: (file: File | null, atflCd: string | null, atflId: string | null) => void; // 파일 선택 시 호출될 콜백 추가 showButton?: boolean; // 버튼 표시 여부 (기본값 true) showPreview?: boolean; // 파일명 프리뷰 표시 여부 accept?: string; // 파일 형식 지정 + fileIdx?: number; // 부모가 어떤 FileUploadForm인지 구분하기 위한 인덱스 } -const FileUploadForm = ({ onSubmit, showButton = true, showPreview = false, accept = ".jpeg,.jpg,.png", }: FileUploadFormProps) => { - const [atflCd, setAtflCd] = useState(null); - const [atflId, setAtflId] = useState(null); - const handleUploadResponse = (file: File) => async (res: HttpResponse) => { - const fileInfo = res.getHeader("X-File-Info"); - if (!fileInfo) return; - const { atflCd, atflId } = JSON.parse(fileInfo) ?? {}; - const orgnlFileNm = file.name; - console.log('orgnlFileNm', orgnlFileNm, atflCd, atflId); - setAtflCd(atflCd); - setAtflId(atflId); - }; +const FileUploadForm = ({ + onSubmit, + onFileSelect, + showButton = true, + showPreview = false, + accept = ".jpeg,.jpg,.png", + fileIdx // props에서 fileIdx 받기 +}: FileUploadFormProps) => { + const [internalAtflCd, setInternalAtflCd] = useState(null); + const [internalAtflId, setInternalAtflId] = useState(null); + const [currentFile, setCurrentFile] = useState(null); // 현재 선택된 파일을 저장할 상태 + const [files, setFiles] = useState(null); + const [upload, setUpload] = useState(null); + const uniqueId = useId(); // 각 FileUploadForm 인스턴스에 대한 고유 ID 생성 + const quater = [{ text: '1분기', val: '1' }, { text: '2분기', val: '2' }, { text: '3분기', val: '3' }, { text: '4분기', val: '4' }]; // 현재 년도부터 10년 전까지의 년도 옵션 생성 const yearOptions = Array.from({ length: 10 }, (_, i) => { const year = new Date().getFullYear() - i; return { text: `${year}년`, val: year.toString() }; }); - const quater = [{ text: '1분기', val: '1' }, { text: '2분기', val: '2' }, { text: '3분기', val: '3' }, { text: '4분기', val: '4' }] - const [files, setFiles] = useState(null); const [selectedYear, setSelectedYear] = useState(yearOptions[0]?.val || ''); const [selectedQuarter, setSelectedQuarter] = useState(quater[0]?.val || ''); - const [upload, setUpload] = useState(null); - const uniqueId = useId(); // 각 FileUploadForm 인스턴스에 대한 고유 ID 생성 + + // const handleUploadResponse = (file: File) => async (res: HttpResponse) => { + // const fileInfo = res.getHeader("X-File-Info"); + // if (!fileInfo) return; + // const { atflCd: newAtflCd, atflId: newAtflId } = JSON.parse(fileInfo) ?? {}; + // const orgnlFileNm = file.name; + // console.log('orgnlFileNm', orgnlFileNm, atflCd, atflId); + // setAtflCd(newAtflCd); + // setAtflId(newAtflId); + // // 파일 정보가 업데이트되면 onFileSelect 호출 + // if (onFileSelect) onFileSelect(file, newAtflCd, newAtflId); + // }; + + const internalHandleUploadResponse = (file: File) => async (res: HttpResponse) => { + const fileInfo = res.getHeader("X-File-Info"); + if (!fileInfo) { + if (onFileSelect) onFileSelect(file, null, null); + return; + } + const { atflCd: newAtflCd, atflId: newAtflId } = JSON.parse(fileInfo) ?? {}; + const orgnlFileNm = file.name; + console.log(`FileUploadForm (idx: ${fileIdx ?? 'N/A'}) - orgnlFileNm:`, orgnlFileNm, 'New AtflCd:', newAtflCd, 'New AtflId:', newAtflId); + setInternalAtflCd(newAtflCd); + setInternalAtflId(newAtflId); + + if (onFileSelect) { + onFileSelect(file, newAtflCd, newAtflId); + } + }; + return (
{/* 컴포넌트 루트 div */} @@ -50,16 +81,34 @@ const FileUploadForm = ({ onSubmit, showButton = true, showPreview = false, acce accept={accept} onUpload={(e) => { const selectedFiles = e.target.files; - if (!selectedFiles) return; + if (!selectedFiles || selectedFiles.length === 0) { + setFiles(null); + setCurrentFile(null); + setInternalAtflCd(null); + setInternalAtflId(null); + if (onFileSelect) { + onFileSelect(null, null, null); // 파일 선택 취소 시 null 전달 + } + return; + } + + const firstFile = selectedFiles[0]; + if (!firstFile) return; // 타입스크립트 undefined 가능성 제거 setFiles(selectedFiles); - if (selectedFiles[0]) { - handleUpload(selectedFiles, { - handleUploadStart: setUpload, - handleSuccess: setUpload, - handleResponse: handleUploadResponse(selectedFiles[0]), - }); + setCurrentFile(firstFile); + + if (onFileSelect) { + onFileSelect(firstFile, internalAtflCd, internalAtflId); } + + handleUpload(selectedFiles, { + handleUploadStart: setUpload, + handleSuccess: setUpload, + // handleResponse는 tus-js-client의 Upload 인스턴스 콜백과 연동 필요 + // 여기서는 handleUpload 유틸리티가 응답을 직접 처리한다고 가정 + handleResponse: internalHandleUploadResponse(firstFile), + }); }} customPreview={ showPreview ? ( @@ -72,13 +121,13 @@ const FileUploadForm = ({ onSubmit, showButton = true, showPreview = false, acce } />
- {showButton ? ( + {showButton ? ( // showButton이 true일 때만 버튼 렌더링