From 19e97331446ead58847cb5ee40b42cd7bf17fa03 Mon Sep 17 00:00:00 2001 From: DanielS Date: Tue, 30 Jun 2026 15:36:42 +0200 Subject: [PATCH] feat(admin): add API endpoint to download order confirmation PDF securely as attachment --- .../api/admin/orders/[id]/download/route.ts | 53 +++++++++++++++++++ shop/components/admin/orders-table.tsx | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 shop/app/api/admin/orders/[id]/download/route.ts diff --git a/shop/app/api/admin/orders/[id]/download/route.ts b/shop/app/api/admin/orders/[id]/download/route.ts new file mode 100644 index 0000000..01f09cf --- /dev/null +++ b/shop/app/api/admin/orders/[id]/download/route.ts @@ -0,0 +1,53 @@ +import { NextRequest, NextResponse } from "next/server"; +import { createAdminClient } from "@/lib/supabase/admin"; + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const { id } = await params; + const adminDb = createAdminClient(); + + // 1. Get the order from database + const { data: order, error } = await adminDb + .from("orders") + .select("pdf_url, order_number") + .eq("id", id) + .single(); + + if (error || !order || !order.pdf_url) { + return new NextResponse("PDF not found", { status: 404 }); + } + + // 2. Determine file name in storage bucket + const storageFileName = `ab_${id}.pdf`; + + // 3. Download file from Supabase storage + 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 }); + } + + // 4. Return as attachment + const buffer = await fileData.arrayBuffer(); + const downloadFileName = `Anfragebestaetigung_${order.order_number || id.slice(0, 8)}.pdf`; + + const headers = new Headers(); + headers.append("Content-Disposition", `attachment; filename="${downloadFileName}"`); + headers.append("Content-Type", "application/pdf"); + + return new NextResponse(buffer, { + status: 200, + headers, + }); + } catch (err: any) { + console.error("Download endpoint failed:", err); + return new NextResponse(err.message || "Internal Server Error", { status: 500 }); + } +} diff --git a/shop/components/admin/orders-table.tsx b/shop/components/admin/orders-table.tsx index ab4beb8..da4aeb9 100644 --- a/shop/components/admin/orders-table.tsx +++ b/shop/components/admin/orders-table.tsx @@ -224,7 +224,7 @@ export function OrdersTable({ initialOrders }: OrdersTableProps) {