From e711be359b8d0840735b0189122647c46e90d6b6 Mon Sep 17 00:00:00 2001 From: Hyunkyung Date: Mon, 15 Jun 2026 23:30:18 +0200 Subject: [PATCH] save pdf as blob in vercel --- .../web/app/(portal)/mypage/invoices/page.tsx | 34 ++-- .../web/app/(portal)/mypage/projects/page.tsx | 43 +++-- apps/web/app/(portal)/mypage/quotes/page.tsx | 11 +- .../projects/[id]/GenerateContractButton.tsx | 3 + .../admin/projects/[id]/InvoiceIssueForm.tsx | 22 ++- .../app/admin/quotes/[id]/EstimateBuilder.tsx | 11 +- apps/web/app/api/docs/contract/[id]/route.ts | 58 +++++++ apps/web/app/api/docs/invoice/[id]/route.ts | 53 ++++++ apps/web/app/api/docs/quote/[id]/route.ts | 51 ++++++ apps/web/app/docs/contract/[id]/page.tsx | 162 ++++++++++++++++++ apps/web/app/docs/invoice/[id]/page.tsx | 156 +++++++++++++++++ apps/web/app/docs/quote/[id]/page.tsx | 138 +++++++++++++++ apps/web/lib/actions/invoices.ts | 20 +-- apps/web/lib/actions/projects.ts | 1 + apps/web/lib/actions/quotes.ts | 12 +- apps/web/lib/email/index.ts | 37 ++-- 16 files changed, 745 insertions(+), 67 deletions(-) create mode 100644 apps/web/app/api/docs/contract/[id]/route.ts create mode 100644 apps/web/app/api/docs/invoice/[id]/route.ts create mode 100644 apps/web/app/api/docs/quote/[id]/route.ts create mode 100644 apps/web/app/docs/contract/[id]/page.tsx create mode 100644 apps/web/app/docs/invoice/[id]/page.tsx create mode 100644 apps/web/app/docs/quote/[id]/page.tsx diff --git a/apps/web/app/(portal)/mypage/invoices/page.tsx b/apps/web/app/(portal)/mypage/invoices/page.tsx index 77d3bc6..0998a15 100644 --- a/apps/web/app/(portal)/mypage/invoices/page.tsx +++ b/apps/web/app/(portal)/mypage/invoices/page.tsx @@ -93,16 +93,21 @@ export default async function MyInvoicesPage() { > Pay Now โ€” Card / Apple Pay - {/* PDF download */} + {/* View / download PDF */} {inv.pdfUrl && !inv.pdfUrl.startsWith('data:') && ( - - Download PDF - + <> + + View Invoice + + + Download PDF + + )} @@ -159,9 +164,14 @@ export default async function MyInvoicesPage() { {inv.pdfUrl && !inv.pdfUrl.startsWith('data:') ? ( - - Download - +
+ + View + + + PDF + +
) : ( โ€” )} diff --git a/apps/web/app/(portal)/mypage/projects/page.tsx b/apps/web/app/(portal)/mypage/projects/page.tsx index c0132b9..7e10082 100644 --- a/apps/web/app/(portal)/mypage/projects/page.tsx +++ b/apps/web/app/(portal)/mypage/projects/page.tsx @@ -145,18 +145,26 @@ export default async function MyProjectsPage() { {/* Contract PDFs */} -
- {proj.contractPdfUrl && !proj.contractPdfUrl.startsWith('data:') && ( - - ๐Ÿ“„ Download Contract - - )} - {proj.signedContractPdfUrl && !proj.signedContractPdfUrl.startsWith('data:') && ( - - โœ… Signed Contract - - )} -
+ {(proj.contractPdfUrl || proj.signedContractPdfUrl) && ( +
+ {(proj.contractPdfUrl && !proj.contractPdfUrl.startsWith('data:')) || + (proj.signedContractPdfUrl && !proj.signedContractPdfUrl.startsWith('data:')) ? ( + + ๐Ÿ“„ View Contract + + ) : null} + {proj.contractPdfUrl && !proj.contractPdfUrl.startsWith('data:') && ( + + Download PDF + + )} + {proj.signedContractPdfUrl && !proj.signedContractPdfUrl.startsWith('data:') && ( + + โœ… Signed PDF + + )} +
+ )} {/* Invoices */} {proj.invoices.length > 0 && ( @@ -179,9 +187,14 @@ export default async function MyProjectsPage() { )} {inv.pdfUrl && !inv.pdfUrl.startsWith('data:') && ( - - PDF - + <> + + View + + + PDF + + )} diff --git a/apps/web/app/(portal)/mypage/quotes/page.tsx b/apps/web/app/(portal)/mypage/quotes/page.tsx index f988c20..9e252af 100644 --- a/apps/web/app/(portal)/mypage/quotes/page.tsx +++ b/apps/web/app/(portal)/mypage/quotes/page.tsx @@ -84,9 +84,14 @@ export default async function MyQuotesPage() { )} - - Download Estimate PDF - +
+ + View Estimate + + + Download PDF + +
)} diff --git a/apps/web/app/admin/projects/[id]/GenerateContractButton.tsx b/apps/web/app/admin/projects/[id]/GenerateContractButton.tsx index eb5dcd5..4f8a75b 100644 --- a/apps/web/app/admin/projects/[id]/GenerateContractButton.tsx +++ b/apps/web/app/admin/projects/[id]/GenerateContractButton.tsx @@ -54,6 +54,9 @@ export default function GenerateContractButton({ projectId, contractPdfUrl: init {pdfUrl && !pdfUrl.startsWith('data:') && ( <> + + ๐Ÿ”— Public Link + ๐Ÿ“„ View PDF diff --git a/apps/web/app/admin/projects/[id]/InvoiceIssueForm.tsx b/apps/web/app/admin/projects/[id]/InvoiceIssueForm.tsx index 50edfcd..5f5ffcf 100644 --- a/apps/web/app/admin/projects/[id]/InvoiceIssueForm.tsx +++ b/apps/web/app/admin/projects/[id]/InvoiceIssueForm.tsx @@ -118,9 +118,14 @@ export default function InvoiceIssueForm({
โ€” {invoice.pdfUrl && ( - - PDF - + <> + + ๐Ÿ”— + + + PDF + + )}
); @@ -131,9 +136,14 @@ export default function InvoiceIssueForm({
{/* View PDF */} {invoice.pdfUrl && ( - - PDF - + <> + + ๐Ÿ”— Public + + + PDF + + )} {/* DRAFT: Issue */} diff --git a/apps/web/app/admin/quotes/[id]/EstimateBuilder.tsx b/apps/web/app/admin/quotes/[id]/EstimateBuilder.tsx index 6866edb..0cee31f 100644 --- a/apps/web/app/admin/quotes/[id]/EstimateBuilder.tsx +++ b/apps/web/app/admin/quotes/[id]/EstimateBuilder.tsx @@ -116,9 +116,14 @@ export default function EstimateBuilder({
{quotePdfUrl && !quotePdfUrl.startsWith('data:') && ( - - ๐Ÿ“„ View PDF - + <> + + ๐Ÿ”— Public Link + + + ๐Ÿ“„ View PDF + + )} {!isEditing && existingAmount && (