Files
frontend/apps/sn/app/components/ui/fileUploadForm.tsx
T
swcho 97b0a2e5bf fix, feat:
- I/I 분석 화면 CSS 수정 (간격 통일
- I/I 분석 화면 Enter 클릭 이벤트 추가
2025-07-29 16:09:49 +09:00

153 lines
6.6 KiB
TypeScript

"use client"
import { FileUploader } from "@common/components";
import { Button } from '@common/components/ui';
import { handleUpload } from "@/components/lib/utils";
import { useId, useState } from 'react';
import type { HttpResponse, Upload } from "tus-js-client";
interface FileUploadFormProps {
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,
onFileSelect,
showButton = true,
showPreview = false,
accept = ".jpeg, .jpg, .png",
fileIdx // props에서 fileIdx 받기
}: FileUploadFormProps) => {
const [internalAtflCd, setInternalAtflCd] = useState<string | null>(null);
const [internalAtflId, setInternalAtflId] = useState<string | null>(null);
const [currentFile, setCurrentFile] = useState<File | null>(null); // 현재 선택된 파일을 저장할 상태
const [fileName, setFileName] = useState<string>('');
const [files, setFiles] = useState<FileList | null>(null);
const [upload, setUpload] = useState<Upload | null>(null);
const uniqueId = useId(); // 각 FileUploadForm 인스턴스에 대한 고유 ID 생성
// FileUploader 컴포넌트를 강제로 재마운트하기 위한 key 상태 추가
const [uploaderKey, setUploaderKey] = useState(0);
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 [selectedYear, setSelectedYear] = useState<string>(yearOptions[0]?.val || '');
const [selectedQuarter, setSelectedQuarter] = useState<string>(quater[0]?.val || '');
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);
setFileName(orgnlFileNm);
setInternalAtflCd(newAtflCd);
setInternalAtflId(newAtflId);
if (onFileSelect) {
onFileSelect(file, newAtflCd, newAtflId);
}
};
return (
<div> {/* 컴포넌트 루트 div */}
<div className="card p-6"> {/* 카드 스타일링 */}
<div className='flex items-center gap-2'> {/* FileUploader와 Button을 정렬하는 메인 flex 컨테이너 */}
<div className="w-[300px] mr-4"> {/* FileUploader의 너비와 오른쪽 여백을 제어하는 컨테이너 */}
<FileUploader
key={uploaderKey} // key 추가: 변경 시 컴포넌트 재마운트됨
id={uniqueId}
className="!h-auto !max-w-none flex-row items-center gap-2"
accept={accept}
onUpload={(e) => {
const selectedFiles = e.target.files;
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);
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 ? (
<div className="file-uploader-preview text-center">
{files && files.length > 0
? fileName
: "파일을 선택하세요."}
</div>
) : null
}
/>
</div>
{showButton ? ( // showButton이 true일 때만 버튼 렌더링
<Button
className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700"
size="sm"
onClick={() => {
console.log(files?.[0]?.name)
if (!currentFile) {
alert('파일을 선택해주세요.');
return;
}
if (!selectedYear) {
alert('등록년도를 선택해주세요.');
return;
}
if (!selectedQuarter) {
alert('분기를 선택해주세요.');
return;
}
const fileNm = currentFile.name;
if (onSubmit) {
// 부모에게 전달할 때는 내부 상태인 internalAtflCd, internalAtflId 사용
onSubmit(fileNm, selectedYear, selectedQuarter, internalAtflCd || '', internalAtflId || '');
setFiles(null); // 파일 업로드 후 파일 목록 초기화
setFileName(''); // 파일명 초기화
// 파일 업로드 후 FileUploader 컴포넌트를 재마운트하기 위해 key 값 변경
setUploaderKey(prev => prev + 1);
}
}}
>
등록
</Button>
) : null}
</div>
</div>
</div>
)
}
export default FileUploadForm