summaryrefslogtreecommitdiff
path: root/lib/tech-vendor-rfq-response/vendor-tbe-table/tbeFileHandler.tsx
diff options
context:
space:
mode:
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.tsx354
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 &&currentvendorResponseId) {
- 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