diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 4f7506b1..b1866d74 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -4153,6 +4153,7 @@ "new": "Neuer Vertrag" }, "detail": { + "previewPdf": "PDF-Vorschau", "integrity": { "title": "PDF-Integritätsprüfung", "help": "Berechnet die SHA-256-Hashes der unsignierten und signierten PDFs neu und vergleicht sie mit den beim Ausstellen gespeicherten Werten. Deckt Backup-Beschädigungen oder nachträgliche Änderungen an der Kundenkopie auf.", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 2bf1fd1b..64a55130 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -4151,6 +4151,7 @@ "new": "New contract" }, "detail": { + "previewPdf": "Preview PDF", "integrity": { "title": "PDF integrity check", "help": "Re-hashes the unsigned + signed PDFs on disk and compares them to the SHA-256 stored when the document was issued. Catches backup corruption or manual edits since the customer received their copy.", diff --git a/frontend/src/pages/admin/contracts/ContractDetailPage.tsx b/frontend/src/pages/admin/contracts/ContractDetailPage.tsx index c322b1a6..fc4325fc 100644 --- a/frontend/src/pages/admin/contracts/ContractDetailPage.tsx +++ b/frontend/src/pages/admin/contracts/ContractDetailPage.tsx @@ -197,6 +197,25 @@ export const ContractDetailPage: React.FC = () => { } } + // Pre-send preview: renders a fresh PDF from the current draft without + // writing/sending anything, so the admin can sanity-check layout + + // signature blocks before committing to send (no audit trail created). + async function handlePdfPreview() { + if (!numericId) return; + const previewWindow = window.open('about:blank', '_blank'); + if (!previewWindow) { + toast.error(t('contracts.detail.popupBlocked', 'Allow pop-ups for this site to preview the PDF.') as string); + return; + } + try { + const url = await contractsService.previewPdfUrl(numericId); + previewWindow.location.href = url; + } catch (err: any) { + previewWindow.close(); + toast.error(err?.response?.data?.error || 'Preview failed'); + } + } + async function handleSignedPdfDownload() { if (!numericId) return; const previewWindow = window.open('about:blank', '_blank'); @@ -241,6 +260,10 @@ export const ContractDetailPage: React.FC = () => { {t('contracts.detail.edit', 'Edit')} +