diff options
Diffstat (limited to 'lib/vendor-document-list')
| -rw-r--r-- | lib/vendor-document-list/plant/upload/columns.tsx | 198 | ||||
| -rw-r--r-- | lib/vendor-document-list/plant/upload/table.tsx | 37 | ||||
| -rw-r--r-- | lib/vendor-document-list/ship-all/enhanced-documents-table.tsx | 20 |
3 files changed, 141 insertions, 114 deletions
diff --git a/lib/vendor-document-list/plant/upload/columns.tsx b/lib/vendor-document-list/plant/upload/columns.tsx index 01fc61df..9c2fe228 100644 --- a/lib/vendor-document-list/plant/upload/columns.tsx +++ b/lib/vendor-document-list/plant/upload/columns.tsx @@ -17,16 +17,16 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" -import { - Ellipsis, - Upload, - Eye, - RefreshCw, - CheckCircle2, - XCircle, +import { + Ellipsis, + Upload, + Eye, + RefreshCw, + CheckCircle2, + XCircle, AlertCircle, Clock, - Download + Download } from "lucide-react" interface GetColumnsProps { @@ -109,7 +109,7 @@ export function getColumns({ const stageName = row.getValue("stageName") as string const stageStatus = row.original.stageStatus const stageOrder = row.original.stageOrder - + return ( <div className="space-y-1"> <div className="flex items-center gap-2"> @@ -119,12 +119,12 @@ export function getColumns({ <span className="text-sm">{stageName}</span> </div> {stageStatus && ( - <Badge + <Badge variant={ stageStatus === "COMPLETED" ? "success" : - stageStatus === "IN_PROGRESS" ? "default" : - stageStatus === "REJECTED" ? "destructive" : - "secondary" + stageStatus === "IN_PROGRESS" ? "default" : + stageStatus === "REJECTED" ? "destructive" : + "secondary" } className="text-xs" > @@ -145,9 +145,9 @@ export function getColumns({ const planDate = row.getValue("stagePlanDate") as Date | null const isOverdue = row.original.isOverdue const daysUntilDue = row.original.daysUntilDue - + if (!planDate) return <span className="text-muted-foreground">-</span> - + return ( <div className="space-y-1"> <div className={isOverdue ? "text-destructive font-medium" : ""}> @@ -187,7 +187,7 @@ export function getColumns({ const reviewStatus = row.original.latestReviewStatus const revisionNumber = row.original.latestRevisionNumber const revisionCode = row.original.latestRevisionCode - + if (!status) { return ( <Badge variant="outline" className="gap-1"> @@ -196,20 +196,20 @@ export function getColumns({ </Badge> ) } - + return ( <div className="space-y-1"> - <Badge + <Badge variant={ reviewStatus === "APPROVED" ? "success" : - reviewStatus === "REJECTED" ? "destructive" : - status === "SUBMITTED" ? "default" : - "secondary" + reviewStatus === "REJECTED" ? "destructive" : + status === "SUBMITTED" ? "default" : + "secondary" } > {reviewStatus || status} </Badge> - {revisionCode !== null &&( + {revisionCode !== null && ( <div className="text-xs text-muted-foreground"> {revisionCode} </div> @@ -229,7 +229,7 @@ export function getColumns({ const syncStatus = row.getValue("latestSyncStatus") as string | null const syncProgress = row.original.syncProgress const requiresSync = row.original.requiresSync - + if (!syncStatus || syncStatus === "pending") { if (requiresSync) { return ( @@ -241,15 +241,15 @@ export function getColumns({ } return <span className="text-muted-foreground">-</span> } - + return ( <div className="space-y-2"> - <Badge + <Badge variant={ syncStatus === "synced" ? "success" : - syncStatus === "failed" ? "destructive" : - syncStatus === "syncing" ? "default" : - "secondary" + syncStatus === "failed" ? "destructive" : + syncStatus === "syncing" ? "default" : + "secondary" } className="gap-1" > @@ -274,9 +274,9 @@ export function getColumns({ cell: ({ row }) => { const totalFiles = row.getValue("totalFiles") as number const syncedFiles = row.original.syncedFilesCount - + if (!totalFiles) return <span className="text-muted-foreground">0</span> - + return ( <div className="text-sm"> {syncedFiles !== null && syncedFiles !== undefined ? ( @@ -297,7 +297,7 @@ export function getColumns({ // cell: ({ row }) => { // const vendorName = row.getValue("vendorName") as string // const vendorCode = row.original.vendorCode - + // return ( // <div className="space-y-1"> // <div className="text-sm">{vendorName}</div> @@ -309,82 +309,88 @@ export function getColumns({ // }, // size: 150, // }, - { - id: "actions", - enableHiding: false, - cell: function Cell({ row }) { - const requiresSubmission = row.original.requiresSubmission - const requiresSync = row.original.requiresSync - const latestSubmissionId = row.original.latestSubmissionId - - return ( - <DropdownMenu> - <DropdownMenuTrigger asChild> - <Button - aria-label="Open menu" - variant="ghost" - className="flex size-7 p-0" +// columns.tsx +{ + id: "actions", + enableHiding: false, + cell: function Cell({ row }) { + const requiresSubmission = row.original.requiresSubmission + const requiresSync = row.original.requiresSync + const latestSubmissionId = row.original.latestSubmissionId + const projectCode = row.original.projectCode // 프로젝트 코드 가져오기 + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button + aria-label="Open menu" + variant="ghost" + className="flex size-7 p-0" + > + <Ellipsis className="size-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end" className="w-48"> + {requiresSubmission && ( + <DropdownMenuItem + onSelect={() => setRowAction({ row, type: "upload" })} + className="gap-2" + > + <Upload className="h-4 w-4" /> + Upload Documents + </DropdownMenuItem> + )} + + {latestSubmissionId && ( + <> + <DropdownMenuItem + onSelect={() => setRowAction({ row, type: "view" })} + className="gap-2" > - <Ellipsis className="size-4" /> - </Button> - </DropdownMenuTrigger> - <DropdownMenuContent align="end" className="w-48"> - {requiresSubmission && ( + <Eye className="h-4 w-4" /> + View Submission + </DropdownMenuItem> + + {requiresSync && ( <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "upload" })} + onSelect={() => setRowAction({ row, type: "sync" })} className="gap-2" > - <Upload className="h-4 w-4" /> - Upload Documents + <RefreshCw className="h-4 w-4" /> + Retry Sync </DropdownMenuItem> )} - - {latestSubmissionId && ( - <> - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "view" })} - className="gap-2" - > - <Eye className="h-4 w-4" /> - View Submission - </DropdownMenuItem> - - {requiresSync && ( - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "sync" })} - className="gap-2" - > - <RefreshCw className="h-4 w-4" /> - Retry Sync - </DropdownMenuItem> - )} - </> - )} - - - {/* ✅ 커버 페이지 다운로드 */} - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "downloadCover" })} - className="gap-2" - > - <Download className="h-4 w-4" /> - Download Cover Page - </DropdownMenuItem> + </> + )} + {/* ✅ 커버 페이지 다운로드 - projectCode가 있을 때만 표시 */} + {projectCode && ( + <> <DropdownMenuSeparator /> - <DropdownMenuItem - onSelect={() => setRowAction({ row, type: "history" })} + onSelect={() => setRowAction({ row, type: "downloadCover" })} className="gap-2" > - <Clock className="h-4 w-4" /> - View History + <Download className="h-4 w-4" /> + Download Cover Page </DropdownMenuItem> - </DropdownMenuContent> - </DropdownMenu> - ) - }, - size: 40, - } + </> + )} + + <DropdownMenuSeparator /> + + <DropdownMenuItem + onSelect={() => setRowAction({ row, type: "history" })} + className="gap-2" + > + <Clock className="h-4 w-4" /> + View History + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ) + }, + size: 40, +} ] }
\ No newline at end of file diff --git a/lib/vendor-document-list/plant/upload/table.tsx b/lib/vendor-document-list/plant/upload/table.tsx index 84b04092..2247fc57 100644 --- a/lib/vendor-document-list/plant/upload/table.tsx +++ b/lib/vendor-document-list/plant/upload/table.tsx @@ -21,6 +21,7 @@ import { SingleUploadDialog } from "./components/single-upload-dialog" import { HistoryDialog } from "./components/history-dialog" import { ViewSubmissionDialog } from "./components/view-submission-dialog" import { toast } from "sonner" +import { quickDownload } from "@/lib/file-download" interface StageSubmissionsTableProps { promises: Promise<[ @@ -167,23 +168,43 @@ export function StageSubmissionsTable({ promises, selectedProjectId }: StageSubm const { type, row } = rowAction; if (type === "downloadCover") { - // 2) 서버에서 생성 후 다운로드 (예: API 호출) + const projectCode = row.original.projectCode; + const project = projects.find(p => p.code === projectCode); + + if (!project) { + toast.error("프로젝트 정보를 찾을 수 없습니다."); + setRowAction(null); + return; + } + (async () => { try { - const res = await fetch(`/api/stages/${row.original.stageId}/cover`, { method: "POST" }); - if (!res.ok) throw new Error("failed"); - const { fileUrl } = await res.json(); // 서버 응답: { fileUrl: string } - window.open(fileUrl, "_blank", "noopener,noreferrer"); + const res = await fetch(`/api/projects/${project.id}/cover`, { + method: "GET" + }); + + if (!res.ok) { + const error = await res.json(); + throw new Error(error.message || "커버 페이지를 가져올 수 없습니다"); + } + + const { fileUrl, fileName } = await res.json(); + + // quickDownload 사용 + quickDownload(fileUrl, fileName || `${projectCode}_cover.docx`); + + toast.success("커버 페이지 다운로드를 시작했습니다."); + } catch (e) { - toast.error("커버 페이지 생성에 실패했습니다."); + toast.error(e instanceof Error ? e.message : "커버 페이지 다운로드에 실패했습니다."); console.error(e); } finally { setRowAction(null); } })(); } - }, [rowAction, setRowAction]); - + }, [rowAction, setRowAction, projects]); + return ( <> <DataTable table={table}> diff --git a/lib/vendor-document-list/ship-all/enhanced-documents-table.tsx b/lib/vendor-document-list/ship-all/enhanced-documents-table.tsx index 255aa56c..b8b7542a 100644 --- a/lib/vendor-document-list/ship-all/enhanced-documents-table.tsx +++ b/lib/vendor-document-list/ship-all/enhanced-documents-table.tsx @@ -167,16 +167,16 @@ export function SimplifiedDocumentsTable({ label: "Second Actual Date", type: "date", }, - { - id: "issuedDate", - label: "Issue Date", - type: "date", - }, - { - id: "createdAt", - label: "Created Date", - type: "date", - }, + // { + // id: "issuedDate", + // label: "Issue Date", + // type: "date", + // }, + // { + // id: "createdAt", + // label: "Created Date", + // type: "date", + // }, { id: "updatedAt", label: "Updated Date", |
