-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathreceipt-standard.json
More file actions
29 lines (29 loc) · 8.99 KB
/
receipt-standard.json
File metadata and controls
29 lines (29 loc) · 8.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"$schema": "https://pdfx.akashpise.dev/schema/registry-item.json",
"name": "receipt-standard",
"type": "registry:block",
"title": "Receipt Standard",
"description": "Compact purchase receipt with payment status badge, line-item table, and totals summary.",
"files": [
{
"path": "templates/pdfx/receipt-standard/receipt-standard.tsx",
"content": "import { PdfxThemeProvider, usePdfxTheme } from '../../lib/pdfx-theme-context';\nimport { Badge } from '../../components/pdfx/badge/pdfx-badge';\nimport { KeyValue } from '../../components/pdfx/key-value/pdfx-key-value';\nimport { Section } from '../../components/pdfx/section/pdfx-section';\nimport { Table, TableBody, TableCell, TableHeader, TableRow } from '../../components/pdfx/table/pdfx-table';\nimport { Text } from '../../components/pdfx/text/pdfx-text';\nimport type { PdfxTheme } from '../../lib/pdfx-theme';\nimport { Document, Page, StyleSheet, View } from '@react-pdf/renderer';\nimport type { ReceiptStandardData } from './receipt-standard.types';\n\nconst sampleData: ReceiptStandardData = {\n receiptNumber: 'RCPT-2026-0410',\n issuedAt: 'April 10, 2026 · 2:45 PM',\n merchantName: 'Northline Supply',\n merchantAddress: '118 Mercer Street, New York, NY 10012',\n merchantEmail: '[email protected]',\n cashier: 'A. Rivera',\n paymentStatus: 'Paid',\n paymentMethod: 'Visa •••• 2048',\n currency: '$',\n customerName: 'Maya Chen',\n items: [\n { name: 'Pocket Notebook Set', quantity: 2, unitPrice: 14.5 },\n { name: 'Archival Ink Pen', quantity: 3, unitPrice: 6.25 },\n { name: 'Desk Organizer Tray', quantity: 1, unitPrice: 28 },\n ],\n summary: {\n subtotal: 75.75,\n tax: 6.44,\n total: 82.19,\n },\n notes: 'Thanks for shopping with Northline Supply.',\n};\n\nfunction formatMoney(amount: number, currency: string) {\n return `${currency}${amount.toFixed(2)}`;\n}\n\nfunction getStatusVariant(status: ReceiptStandardData['paymentStatus']) {\n if (status === 'Paid') return 'success';\n if (status === 'Refunded') return 'outline';\n return 'warning';\n}\n\nexport function ReceiptStandardDocument({\n theme,\n data = sampleData,\n}: {\n theme?: PdfxTheme;\n data?: ReceiptStandardData;\n}) {\n return (\n <PdfxThemeProvider theme={theme}>\n <ReceiptStandardContent data={data} />\n </PdfxThemeProvider>\n );\n}\n\nfunction ReceiptStandardContent({ data }: { data: ReceiptStandardData }) {\n const theme = usePdfxTheme();\n\n const styles = StyleSheet.create({\n page: {\n paddingTop: theme.spacing.page.marginTop,\n paddingLeft: theme.spacing.page.marginLeft,\n paddingRight: theme.spacing.page.marginRight,\n paddingBottom: theme.spacing.page.marginBottom,\n backgroundColor: theme.colors.background,\n },\n shell: {\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: theme.colors.border,\n borderRadius: theme.primitives.borderRadius.lg,\n padding: 18,\n backgroundColor: theme.colors.background,\n },\n headerRow: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: 12,\n },\n metaRow: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n gap: 12,\n marginBottom: 8,\n },\n metaBlock: {\n flex: 1,\n },\n label: {\n fontSize: 8,\n letterSpacing: 0.8,\n textTransform: 'uppercase',\n color: theme.colors.mutedForeground,\n marginBottom: 3,\n },\n value: {\n fontSize: 9,\n color: theme.colors.foreground,\n marginBottom: 1,\n },\n totalCard: {\n marginTop: 10,\n marginLeft: 'auto',\n width: 220,\n paddingTop: 8,\n borderTopWidth: 1,\n borderTopStyle: 'solid',\n borderTopColor: theme.colors.border,\n },\n });\n\n return (\n <Document title={`Receipt ${data.receiptNumber}`}>\n <Page size=\"A4\" style={styles.page}>\n <View style={styles.shell}>\n <View style={styles.headerRow}>\n <View>\n <Text variant=\"lg\" style={{ fontWeight: 'bold', marginBottom: 3 }} noMargin>\n {data.merchantName}\n </Text>\n <Text variant=\"xs\" color=\"mutedForeground\" noMargin>\n {data.merchantAddress}\n </Text>\n <Text variant=\"xs\" color=\"mutedForeground\" noMargin>\n {data.merchantEmail}\n </Text>\n </View>\n <Badge\n label={data.paymentStatus}\n variant={getStatusVariant(data.paymentStatus)}\n size=\"sm\"\n />\n </View>\n\n <Section style={{ marginBottom: 10 }}>\n <View style={styles.metaRow}>\n <View style={styles.metaBlock}>\n <Text style={styles.label} noMargin>\n Receipt No.\n </Text>\n <Text style={styles.value} noMargin>\n {data.receiptNumber}\n </Text>\n </View>\n <View style={styles.metaBlock}>\n <Text style={styles.label} noMargin>\n Issued\n </Text>\n <Text style={styles.value} noMargin>\n {data.issuedAt}\n </Text>\n </View>\n <View style={styles.metaBlock}>\n <Text style={styles.label} noMargin>\n Cashier\n </Text>\n <Text style={styles.value} noMargin>\n {data.cashier}\n </Text>\n </View>\n </View>\n\n <View style={styles.metaRow}>\n <View style={styles.metaBlock}>\n <Text style={styles.label} noMargin>\n Customer\n </Text>\n <Text style={styles.value} noMargin>\n {data.customerName}\n </Text>\n </View>\n <View style={styles.metaBlock}>\n <Text style={styles.label} noMargin>\n Payment Method\n </Text>\n <Text style={styles.value} noMargin>\n {data.paymentMethod}\n </Text>\n </View>\n </View>\n </Section>\n\n <Table variant=\"compact\" zebraStripe>\n <TableHeader>\n <TableRow header>\n <TableCell>Item</TableCell>\n <TableCell align=\"center\">Qty</TableCell>\n <TableCell align=\"right\">Price</TableCell>\n <TableCell align=\"right\">Total</TableCell>\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.items.map((item) => (\n <TableRow key={`${item.name}-${item.quantity}-${item.unitPrice}`}>\n <TableCell>{item.name}</TableCell>\n <TableCell align=\"center\">{`${item.quantity}`}</TableCell>\n <TableCell align=\"right\">{formatMoney(item.unitPrice, data.currency)}</TableCell>\n <TableCell align=\"right\">\n {formatMoney(item.quantity * item.unitPrice, data.currency)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n\n <View style={styles.totalCard}>\n <KeyValue\n size=\"sm\"\n divided\n items={[\n { key: 'Subtotal', value: formatMoney(data.summary.subtotal, data.currency) },\n { key: 'Tax', value: formatMoney(data.summary.tax, data.currency) },\n {\n key: 'Total',\n value: formatMoney(data.summary.total, data.currency),\n keyStyle: { fontWeight: 'bold', color: theme.colors.foreground },\n valueStyle: { fontWeight: 'bold', fontSize: 12 },\n },\n ]}\n />\n </View>\n\n {data.notes ? (\n <Text variant=\"xs\" color=\"mutedForeground\" style={{ marginTop: 14 }} noMargin>\n {data.notes}\n </Text>\n ) : null}\n </View>\n </Page>\n </Document>\n );\n}\n",
"type": "registry:file"
},
{
"path": "templates/pdfx/receipt-standard/receipt-standard.types.ts",
"content": "export interface ReceiptStandardData {\n receiptNumber: string;\n issuedAt: string;\n merchantName: string;\n merchantAddress: string;\n merchantEmail: string;\n cashier: string;\n paymentStatus: 'Paid' | 'Pending' | 'Refunded';\n paymentMethod: string;\n currency: string;\n customerName: string;\n items: {\n name: string;\n quantity: number;\n unitPrice: number;\n }[];\n summary: {\n subtotal: number;\n tax: number;\n total: number;\n };\n notes?: string;\n}\n",
"type": "registry:file"
}
],
"dependencies": [
"@react-pdf/renderer"
],
"peerComponents": [
"badge",
"table",
"key-value",
"section",
"text"
]
}