153 lines
6.6 KiB
TypeScript
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 |