diff options
Diffstat (limited to 'lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx')
| -rw-r--r-- | lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx | 354 |
1 files changed, 0 insertions, 354 deletions
diff --git a/lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx b/lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx deleted file mode 100644 index 6c622fd1..00000000 --- a/lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx +++ /dev/null @@ -1,354 +0,0 @@ -"use client"; - -import { useCallback, useState, useEffect } from "react"; -import { toast } from "sonner"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { - fetchTbeTemplateFiles, - uploadTbeResponseFile, - getTbeSubmittedFiles, - getFileFromRfqAttachmentsbyid, -} from "../../rfqs-tech/service"; -import { - Dropzone, - DropzoneDescription, - DropzoneInput, - DropzoneTitle, - DropzoneUploadIcon, - DropzoneZone, -} from "@/components/ui/dropzone"; -import { - FileList, - FileListAction, - FileListDescription, - FileListIcon, - FileListInfo, - FileListItem, - FileListName, - FileListSize, -} from "@/components/ui/file-list"; -import { Download, X } from "lucide-react"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { formatDateTime } from "@/lib/utils"; - -export function useTbeFileHandlers() { - // 모달 열림 여부, 현재 선택된 IDs - const [isUploadDialogOpen, setIsUploadDialogOpen] = useState(false); - const [currentTbeId, setCurrentTbeId] = useState<number | null>(null); - const [currentVendorId, setCurrentVendorId] = useState<number | null>(null); - const [currentRfqId, setCurrentRfqId] = useState<number | null>(null); - const [currentvendorResponseId, setCurrentvendorResponseId] = useState<number | null>(null); - - - - // 로딩 상태들 - const [isLoading, setIsLoading] = useState(false); - const [isFetchingFiles, setIsFetchingFiles] = useState(false); - - // 업로드할 파일, 제출된 파일 목록 - const [selectedFile, setSelectedFile] = useState<File | null>(null); - const [submittedFiles, setSubmittedFiles] = useState< - Array<{ id: number; fileName: string; filePath: string; uploadedAt: Date }> - >([]); - - // =================================== - // 1) 제출된 파일 목록 가져오기 - // =================================== - const fetchSubmittedFiles = useCallback(async (vendorResponseId: number) => { - if (!vendorResponseId ) return; - - setIsFetchingFiles(true); - try { - const { files, error } = await getTbeSubmittedFiles(vendorResponseId); - if (error) { - console.error(error); - return; - } - setSubmittedFiles(files); - } catch (error) { - console.error("Failed to fetch submitted files:", error); - } finally { - setIsFetchingFiles(false); - } - }, []); - - // =================================== - // 2) TBE 템플릿 다운로드 - // =================================== - const handleDownloadTbeTemplate = useCallback( - async (tbeId: number, vendorId: number, rfqId: number) => { - setCurrentTbeId(tbeId); - setCurrentVendorId(vendorId); - setCurrentRfqId(rfqId); - setIsLoading(true); - - try { - const { files, error } = await fetchTbeTemplateFiles(tbeId); - if (error) { - toast.error(error); - return; - } - if (files.length === 0) { - toast.warning("다운로드할 템플릿 파일이 없습니다"); - return; - } - // 순차적으로 파일 다운로드 - for (const file of files) { - await downloadFile(file.id); - } - toast.success("모든 템플릿 파일이 다운로드되었습니다"); - } catch (error) { - toast.error("템플릿 파일을 다운로드하는 데 실패했습니다"); - console.error(error); - } finally { - setIsLoading(false); - } - }, - [] - ); - - // 실제 다운로드 로직 - const downloadFile = useCallback(async (fileId: number) => { - try { - const { file, error } = await getFileFromRfqAttachmentsbyid(fileId); - if (error || !file) { - throw new Error(error || "파일 정보를 가져오는 데 실패했습니다"); - } - - const link = document.createElement("a"); - link.href = `/api/rfq-download?path=${encodeURIComponent(file.filePath)}`; - link.download = file.fileName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - - return true; - } catch (error) { - console.error(error); - return false; - } - }, []); - - // =================================== - // 3) 제출된 파일 다운로드 - // =================================== - const downloadSubmittedFile = useCallback((file: { id: number; fileName: string; filePath: string }) => { - try { - const link = document.createElement("a"); - link.href = `/api/tbe-download?path=${encodeURIComponent(file.filePath)}`; - link.download = file.fileName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - - toast.success(`${file.fileName} 다운로드 시작`); - } catch (error) { - console.error("Failed to download file:", error); - toast.error("파일 다운로드에 실패했습니다"); - } - }, []); - - // =================================== - // 4) TBE 응답 업로드 모달 열기 - // (이 시점에서는 데이터 fetch하지 않음) - // =================================== - const handleUploadTbeResponse = useCallback((tbeId: number, vendorId: number, rfqId: number, vendorResponseId:number) => { - setCurrentTbeId(tbeId); - setCurrentVendorId(vendorId); - setCurrentRfqId(rfqId); - setCurrentvendorResponseId(vendorResponseId); - setIsUploadDialogOpen(true); - }, []); - - // =================================== - // 5) Dialog 열고 닫힐 때 상태 초기화 - // 열렸을 때 -> useEffect로 파일 목록 가져오기 - // =================================== - useEffect(() => { - if (!isUploadDialogOpen) { - // 닫힐 때는 파일 상태들 초기화 - setSelectedFile(null); - setSubmittedFiles([]); - } - }, [isUploadDialogOpen]); - - useEffect(() => { - // Dialog가 열렸고, ID들이 유효하면 - if (isUploadDialogOpen &¤tvendorResponseId) { - fetchSubmittedFiles(currentvendorResponseId); - } - }, [isUploadDialogOpen, currentvendorResponseId, fetchSubmittedFiles]); - - // =================================== - // 6) 드롭존 파일 선택 & 제거 - // =================================== - const handleFileDrop = useCallback((files: File[]) => { - if (files && files.length > 0) { - setSelectedFile(files[0]); - } - }, []); - - const handleRemoveFile = useCallback(() => { - setSelectedFile(null); - }, []); - - // =================================== - // 7) 응답 파일 업로드 - // =================================== - const handleSubmitResponse = useCallback(async () => { - if (!selectedFile || !currentTbeId || !currentVendorId || !currentRfqId ||!currentvendorResponseId) { - toast.error("업로드할 파일을 선택해주세요"); - return; - } - - setIsLoading(true); - try { - // FormData 생성 - const formData = new FormData(); - formData.append("file", selectedFile); - formData.append("rfqId", currentRfqId.toString()); - formData.append("vendorId", currentVendorId.toString()); - formData.append("evaluationId", currentTbeId.toString()); - formData.append("vendorResponseId", currentvendorResponseId.toString()); - - const result = await uploadTbeResponseFile(formData); - if (!result.success) { - throw new Error(result.error || "파일 업로드에 실패했습니다"); - } - - toast.success(result.message || "응답이 성공적으로 업로드되었습니다"); - - // 업로드 후 다시 제출된 파일 목록 가져오기 - await fetchSubmittedFiles(currentvendorResponseId); - - // 업로드 성공 시 선택 파일 초기화 - setSelectedFile(null); - - // 페이지 새로고침으로 테이블 데이터 업데이트 - window.location.reload(); - } catch (error) { - toast.error(error instanceof Error ? error.message : "응답 업로드에 실패했습니다"); - console.error(error); - } finally { - setIsLoading(false); - } - }, [selectedFile, currentTbeId, currentVendorId, currentRfqId, currentvendorResponseId,fetchSubmittedFiles]); - - // =================================== - // 8) 실제 Dialog 컴포넌트 - // =================================== - const UploadDialog = () => ( - <Dialog open={isUploadDialogOpen} onOpenChange={setIsUploadDialogOpen}> - <DialogContent className="sm:max-w-lg"> - <DialogHeader> - <DialogTitle>TBE 응답 파일</DialogTitle> - <DialogDescription>제출된 파일을 확인하거나 새 파일을 업로드하세요.</DialogDescription> - </DialogHeader> - - <Tabs defaultValue="upload" className="w-full"> - <TabsList className="grid w-full grid-cols-2"> - <TabsTrigger value="upload">새 파일 업로드</TabsTrigger> - <TabsTrigger - value="submitted" - disabled={submittedFiles.length === 0} - className={submittedFiles.length > 0 ? "relative" : ""} - > - 제출된 파일{" "} - {submittedFiles.length > 0 && ( - <span className="ml-2 inline-flex items-center justify-center rounded-full bg-primary w-4 h-4 text-[10px] text-primary-foreground"> - {submittedFiles.length} - </span> - )} - </TabsTrigger> - </TabsList> - - {/* 업로드 탭 */} - <TabsContent value="upload" className="pt-4"> - <div className="grid gap-4"> - {selectedFile ? ( - <FileList> - <FileListItem> - <FileListIcon /> - <FileListInfo> - <FileListName>{selectedFile.name}</FileListName> - <FileListSize>{selectedFile.size}</FileListSize> - </FileListInfo> - <FileListAction onClick={handleRemoveFile}> - <X className="h-4 w-4" /> - <span className="sr-only">파일 제거</span> - </FileListAction> - </FileListItem> - </FileList> - ) : ( - <Dropzone onDrop={handleFileDrop}> - <DropzoneInput className="sr-only" /> - <DropzoneZone className="flex flex-col items-center justify-center gap-2 p-6"> - <DropzoneUploadIcon className="h-10 w-10 text-muted-foreground" /> - <DropzoneTitle>파일을 드래그하거나 클릭하여 업로드</DropzoneTitle> - <DropzoneDescription>TBE 응답 파일 (XLSX, XLS, DOCX, PDF 등)</DropzoneDescription> - </DropzoneZone> - </Dropzone> - )} - - <DialogFooter className="mt-4"> - <Button type="submit" onClick={handleSubmitResponse} disabled={!selectedFile || isLoading}> - {isLoading ? "업로드 중..." : "응답 업로드"} - </Button> - </DialogFooter> - </div> - </TabsContent> - - {/* 제출된 파일 탭 */} - <TabsContent value="submitted" className="pt-4"> - {isFetchingFiles ? ( - <div className="flex justify-center items-center py-8"> - <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div> - </div> - ) : submittedFiles.length > 0 ? ( - <div className="grid gap-2"> - <FileList> - {submittedFiles.map((file) => ( - <FileListItem key={file.id} className="flex items-center justify-between gap-3"> - <div className="flex items-center gap-3 flex-1"> - <FileListIcon className="flex-shrink-0" /> - <FileListInfo className="flex-1 min-w-0"> - <FileListName className="text-sm font-medium truncate">{file.fileName}</FileListName> - <FileListDescription className="text-xs text-muted-foreground"> - {file.uploadedAt ? formatDateTime(file.uploadedAt) : ""} - </FileListDescription> - </FileListInfo> - </div> - <FileListAction className="flex-shrink-0 ml-2" onClick={() => downloadSubmittedFile(file)}> - <Download className="h-4 w-4" /> - <span className="sr-only">파일 다운로드</span> - </FileListAction> - </FileListItem> - ))} - </FileList> - </div> - ) : ( - <div className="text-center py-8 text-muted-foreground">제출된 파일이 없습니다.</div> - )} - </TabsContent> - </Tabs> - </DialogContent> - </Dialog> - ); - - // =================================== - // 9) Hooks 내보내기 - // =================================== - return { - handleDownloadTbeTemplate, - handleUploadTbeResponse, - UploadDialog, - }; -}
\ No newline at end of file |
