This commit adds full quote PDF generation functionality with per-company letterhead branding: - Server-side PDF rendering using @react-pdf/renderer matching the sample quote layout - In-app modal PDF viewer with print, download, and new-tab controls - Letterhead service to fetch and apply company-specific branding (CNL/ISHERWOOD) - ZAR currency and date formatting utilities for South African quotes - Updated QuoteAttachment type to handle PocketBase's array-based file tokens - Fixed PocketBase attachment URL generation in quote email card - Removed deprecated `included_in_quote` field from QuoteItem and quotes service - Updated quote item creation test to validate draft item logic - Added comprehensive unit tests for PDF rendering and formatting helpers - Added dev scripts for debugging PDF and image rendering issues - Added sample generated PDF files for visual verification - Updated tsconfig to exclude development scripts directory - Added @react-pdf/renderer production dependency - Removed JEI as a valid letterhead option per requirements
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
import * as React from "react";
|
|
import { Document, Page, View, Image, StyleSheet, pdf } from "@react-pdf/renderer";
|
|
import fs from "fs";
|
|
|
|
async function main() {
|
|
const buf = fs.readFileSync("/tmp/debug-logo.bin");
|
|
const dataUri = `data:image/jpeg;base64,${buf.toString("base64")}`;
|
|
|
|
// Try several layout strategies
|
|
const styles = StyleSheet.create({
|
|
page: { padding: 40, fontFamily: "Helvetica" },
|
|
// Strategy A: just header with explicit padding, logo wrapped in flex:0
|
|
headerA: { flexDirection: "row", alignItems: "flex-start", marginBottom: 30 },
|
|
companyA: { flex: 1, paddingRight: 12 },
|
|
logoA: { width: 110, height: 68 },
|
|
});
|
|
|
|
const inst = pdf(
|
|
<Document>
|
|
<Page size="A4" style={styles.page}>
|
|
<View style={styles.headerA}>
|
|
<View style={styles.companyA}>
|
|
<View><Image src={dataUri} style={{ width: 323, height: 200 }} /></View>
|
|
</View>
|
|
</View>
|
|
<View>
|
|
<View style={{ marginBottom: 8 }}><Image src={dataUri} style={{ width: 200, height: 124 }} /></View>
|
|
<View style={{ marginBottom: 8 }}><Image src={dataUri} style={{ width: 100, height: 62 }} /></View>
|
|
</View>
|
|
</Page>
|
|
</Document>
|
|
);
|
|
const pdfBuf = Buffer.from(await inst.toString(), "binary");
|
|
fs.writeFileSync("/tmp/debug-image-test2.pdf", pdfBuf);
|
|
console.log("Size:", pdfBuf.length);
|
|
}
|
|
main().catch((e) => { console.error("FAIL", e); process.exit(1); });
|