From 553ec7eadd1a0fd93f208e9a041ee0251bf49c3f Mon Sep 17 00:00:00 2001 From: DanielS Date: Fri, 3 Jul 2026 15:14:34 +0200 Subject: [PATCH] fix(admin-orders): make PDF download/view always available by generating PDF dynamically on the fly if missing --- .../api/admin/orders/[id]/download/route.ts | 86 +++++++++++++++---- shop/components/admin/orders-table.tsx | 26 +++--- 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/shop/app/api/admin/orders/[id]/download/route.ts b/shop/app/api/admin/orders/[id]/download/route.ts index 01f09cf..4f4b163 100644 --- a/shop/app/api/admin/orders/[id]/download/route.ts +++ b/shop/app/api/admin/orders/[id]/download/route.ts @@ -1,5 +1,8 @@ import { NextRequest, NextResponse } from "next/server"; import { createAdminClient } from "@/lib/supabase/admin"; +import { InvoicePDF } from "@/components/invoice-pdf"; +import { renderToBuffer } from "@react-pdf/renderer"; +import React from "react"; export async function GET( request: NextRequest, @@ -8,41 +11,92 @@ export async function GET( try { const { id } = await params; const adminDb = createAdminClient(); + const inline = request.nextUrl.searchParams.get("inline") === "true"; // 1. Get the order from database const { data: order, error } = await adminDb .from("orders") - .select("pdf_url, order_number") + .select("customer_data, order_data, total_price, created_at, pdf_url, order_number") .eq("id", id) .single(); - if (error || !order || !order.pdf_url) { - return new NextResponse("PDF not found", { status: 404 }); + if (error || !order) { + return new NextResponse("Order not found", { status: 404 }); } - // 2. Determine file name in storage bucket const storageFileName = `ab_${id}.pdf`; + let fileBuffer: Uint8Array | ArrayBuffer | null = null; - // 3. Download file from Supabase storage - const { data: fileData, error: downloadError } = await adminDb - .storage - .from("invoices") - .download(storageFileName); + // 2. Try to download from storage if pdf_url is set + if (order.pdf_url) { + try { + const { data: fileData, error: downloadError } = await adminDb + .storage + .from("invoices") + .download(storageFileName); - if (downloadError || !fileData) { - console.error("Failed to download PDF from storage:", downloadError); - return new NextResponse("Error downloading file from storage", { status: 500 }); + if (!downloadError && fileData) { + fileBuffer = await fileData.arrayBuffer(); + } + } catch (storageErr) { + console.warn("Could not retrieve file from storage, will regenerate:", storageErr); + } } - // 4. Return as attachment - const buffer = await fileData.arrayBuffer(); + // 3. If file not found or pdf_url not set, generate dynamically + if (!fileBuffer) { + try { + const formattedDate = new Date(order.created_at).toLocaleDateString('de-DE', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }); + + const buffer = await renderToBuffer( + React.createElement(InvoicePDF, { + orderNumber: order.order_number || `AE-${id.slice(0, 8)}`, + dateStr: formattedDate, + customer: order.customer_data, + orderData: order.order_data, + totalPrice: Number(order.total_price), + }) + ); + + // Upload/Upsert to storage bucket + const { error: uploadError } = await adminDb.storage + .from("invoices") + .upload(storageFileName, Buffer.from(buffer), { + contentType: "application/pdf", + upsert: true, + }); + + if (uploadError) { + console.error("Failed to upload regenerated PDF:", uploadError); + } else { + // Update db with pdf_url + const path = `invoices/${storageFileName}`; + await adminDb.from("orders").update({ pdf_url: path }).eq("id", id); + } + + fileBuffer = buffer; + } catch (genErr: any) { + console.error("PDF generation failed inside API:", genErr); + return new NextResponse("Error generating PDF: " + genErr.message, { status: 500 }); + } + } + + // 4. Return as PDF response const downloadFileName = `Anfragebestaetigung_${order.order_number || id.slice(0, 8)}.pdf`; const headers = new Headers(); - headers.append("Content-Disposition", `attachment; filename="${downloadFileName}"`); + if (inline) { + headers.append("Content-Disposition", "inline"); + } else { + headers.append("Content-Disposition", `attachment; filename="${downloadFileName}"`); + } headers.append("Content-Type", "application/pdf"); - return new NextResponse(buffer, { + return new NextResponse(fileBuffer as any, { status: 200, headers, }); diff --git a/shop/components/admin/orders-table.tsx b/shop/components/admin/orders-table.tsx index 9a5a5de..a65453f 100644 --- a/shop/components/admin/orders-table.tsx +++ b/shop/components/admin/orders-table.tsx @@ -223,22 +223,16 @@ export function OrdersTable({ initialOrders }: OrdersTableProps) { Bearbeiten - {order.pdf_url ? ( - <> - - - - ) : ( - Keine Bestätigung - )} + +