mirror of
https://github.com/mmahdium/portfolio.git
synced 2026-08-17 05:24:30 +03:30
Story 3-1: Create PDF Generation API Route - Add server/api/resume/pdf.get.ts with Puppeteer integration - Support both dev (puppeteer) and prod (puppeteer-core + chromium) - Navigate to /resume?print=true for WYSIWYG capture - Return PDF with proper headers (Content-Type, Content-Disposition) - Add error handling with 500 status and JSON response - Update vercel.json with function config (memory: 1024, maxDuration: 10) Story 3-2: Create PDF Download Composable - Add app/composables/useResumePdf.ts - Implement isGenerating ref for loading state - Implement downloadPdf() with blob handling - Add toast notifications for errors - Revoke object URL to prevent memory leaks Story 3-3: Connect Download Button to PDF Generation - Update ResumeDownloadButton.vue to use useResumePdf() - Bind :loading and :disabled to isGenerating - Connect @click to downloadPdf - Remove placeholder handler Dependencies Added: - puppeteer ^24.31.0 - puppeteer-core ^24.31.0 - @sparticuz/chromium ^141.0.0 Closes Epic 3 Closes Story 3-1, 3-2, 3-3
52 lines
1.3 KiB
TypeScript
52 lines
1.3 KiB
TypeScript
/**
|
|
* PDF Download Composable
|
|
* Handles PDF download logic with loading state and error handling
|
|
*/
|
|
|
|
export function useResumePdf() {
|
|
const isGenerating = ref(false)
|
|
const toast = useToast()
|
|
const { getPdfFilename } = useResumeData()
|
|
|
|
async function downloadPdf() {
|
|
isGenerating.value = true
|
|
|
|
try {
|
|
// Fetch PDF as blob (AC1)
|
|
const response = await $fetch<Blob>('/api/resume/pdf', {
|
|
responseType: 'blob',
|
|
})
|
|
|
|
// Create object URL from blob (AC2)
|
|
const url = URL.createObjectURL(response)
|
|
|
|
// Create temporary anchor element and trigger download
|
|
const a = document.createElement('a')
|
|
a.href = url
|
|
a.download = getPdfFilename() // AC3: filename from composable
|
|
a.click()
|
|
|
|
// Revoke object URL to prevent memory leaks (AC8)
|
|
URL.revokeObjectURL(url)
|
|
} catch (error) {
|
|
// Error handling (AC6)
|
|
console.error('PDF generation failed:', error)
|
|
|
|
toast.add({
|
|
title: 'Error generating PDF',
|
|
description: 'Please try again',
|
|
color: 'error',
|
|
})
|
|
} finally {
|
|
// Always reset loading state (AC7)
|
|
isGenerating.value = false
|
|
}
|
|
}
|
|
|
|
// Return composable interface (AC4, AC5)
|
|
return {
|
|
isGenerating,
|
|
downloadPdf,
|
|
}
|
|
}
|