diff options
| author | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
| commit | 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 (patch) | |
| tree | 8a5587f10ca55b162d7e3254cb088b323a34c41b /lib/rfqs/tbe-table/file-dialog.tsx | |
initial commit
Diffstat (limited to 'lib/rfqs/tbe-table/file-dialog.tsx')
| -rw-r--r-- | lib/rfqs/tbe-table/file-dialog.tsx | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/lib/rfqs/tbe-table/file-dialog.tsx b/lib/rfqs/tbe-table/file-dialog.tsx new file mode 100644 index 00000000..1d1a65ea --- /dev/null +++ b/lib/rfqs/tbe-table/file-dialog.tsx @@ -0,0 +1,141 @@ +"use client" + +import * as React from "react" +import { Download, X } from "lucide-react" +import { toast } from "sonner" + +import { getErrorMessage } from "@/lib/handle-error" +import { formatDateTime } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" + +import { + FileList, + FileListItem, + FileListIcon, + FileListInfo, + FileListName, + FileListDescription, + FileListAction, +} from "@/components/ui/file-list" +import { getTbeFilesForVendor, getTbeSubmittedFiles } from "../service" + +interface TBEFileDialogProps { + isOpen: boolean + onOpenChange: (open: boolean) => void + tbeId: number + vendorId: number + rfqId: number + onRefresh?: () => void +} + +export function TBEFileDialog({ + isOpen, + onOpenChange, + vendorId, + rfqId, + onRefresh, +}: TBEFileDialogProps) { + const [submittedFiles, setSubmittedFiles] = React.useState<any[]>([]) + const [isFetchingFiles, setIsFetchingFiles] = React.useState(false) + + + // Fetch submitted files when dialog opens + React.useEffect(() => { + if (isOpen && rfqId && vendorId) { + fetchSubmittedFiles() + } + }, [isOpen, rfqId, vendorId]) + + // Fetch submitted files using the service function + const fetchSubmittedFiles = async () => { + if (!rfqId || !vendorId) return + + setIsFetchingFiles(true) + try { + const { files, error } = await getTbeFilesForVendor(rfqId, vendorId) + + if (error) { + throw new Error(error) + } + + setSubmittedFiles(files) + } catch (error) { + toast.error("Failed to load files: " + getErrorMessage(error)) + } finally { + setIsFetchingFiles(false) + } + } + + // Download submitted file + const downloadSubmittedFile = async (file: any) => { + try { + const response = await fetch(`/api/file/${file.id}/download`) + if (!response.ok) { + throw new Error("Failed to download file") + } + + const blob = await response.blob() + const url = window.URL.createObjectURL(blob) + const a = document.createElement("a") + a.href = url + a.download = file.fileName + document.body.appendChild(a) + a.click() + window.URL.revokeObjectURL(url) + document.body.removeChild(a) + } catch (error) { + toast.error("Failed to download file: " + getErrorMessage(error)) + } + } + + return ( + <Dialog open={isOpen} onOpenChange={onOpenChange}> + <DialogContent className="sm:max-w-lg"> + <DialogHeader> + <DialogTitle>TBE 응답 파일</DialogTitle> + <DialogDescription>제출된 파일 목록을 확인하고 다운로드하세요.</DialogDescription> + </DialogHeader> + + {/* 제출된 파일 목록 */} + {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"> + <Button variant="ghost" size="icon" onClick={() => downloadSubmittedFile(file)}> + <Download className="h-4 w-4" /> + <span className="sr-only">파일 다운로드</span> + </Button> + </FileListAction> + </FileListItem> + ))} + </FileList> + </div> + ) : ( + <div className="text-center py-8 text-muted-foreground">제출된 파일이 없습니다.</div> + )} + </DialogContent> + </Dialog> + ) +}
\ No newline at end of file |
