Initial state for GitNexus analysis
This commit is contained in:
34
packages/features/document-generator/package.json
Normal file
34
packages/features/document-generator/package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "@kit/document-generator",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
"./api": "./src/server/api.ts",
|
||||
"./schema/*": "./src/schema/*.ts",
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .turbo node_modules",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/next": "workspace:*",
|
||||
"@kit/shared": "workspace:*",
|
||||
"@kit/supabase": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "catalog:",
|
||||
"@types/react": "catalog:",
|
||||
"next": "catalog:",
|
||||
"next-safe-action": "catalog:",
|
||||
"react": "catalog:",
|
||||
"zod": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const DocumentTypeEnum = z.enum(['pdf', 'excel', 'word', 'label']);
|
||||
export const DocumentTemplateTypeEnum = z.enum([
|
||||
'member_card', 'invoice', 'label_avery', 'report', 'letter', 'certificate', 'custom',
|
||||
]);
|
||||
|
||||
export const GenerateDocumentSchema = z.object({
|
||||
accountId: z.string().uuid(),
|
||||
documentType: DocumentTypeEnum,
|
||||
templateType: DocumentTemplateTypeEnum,
|
||||
title: z.string().min(1),
|
||||
data: z.record(z.string(), z.unknown()),
|
||||
options: z.object({
|
||||
format: z.enum(['A4', 'A5', 'letter', 'label']).default('A4'),
|
||||
orientation: z.enum(['portrait', 'landscape']).default('portrait'),
|
||||
labelFormat: z.string().optional(), // e.g. 'avery-l7163'
|
||||
}).optional(),
|
||||
});
|
||||
export type GenerateDocumentInput = z.infer<typeof GenerateDocumentSchema>;
|
||||
|
||||
export const GenerateBatchLabelsSchema = z.object({
|
||||
accountId: z.string().uuid(),
|
||||
labelFormat: z.string().default('avery-l7163'),
|
||||
records: z.array(z.object({
|
||||
line1: z.string(),
|
||||
line2: z.string().optional(),
|
||||
line3: z.string().optional(),
|
||||
line4: z.string().optional(),
|
||||
})).min(1),
|
||||
});
|
||||
96
packages/features/document-generator/src/server/api.ts
Normal file
96
packages/features/document-generator/src/server/api.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Document Generation API
|
||||
* Services for PDF, Excel, Word, and label generation.
|
||||
* Phase 9 — runtime deps (@react-pdf/renderer, exceljs, docx) added when installed.
|
||||
* This file provides the API surface; implementations use dynamic imports.
|
||||
*/
|
||||
|
||||
export function createDocumentGeneratorApi() {
|
||||
return {
|
||||
/**
|
||||
* Generate a PDF document (member card, invoice, certificate, etc.)
|
||||
* Uses @react-pdf/renderer or jspdf at runtime.
|
||||
*/
|
||||
async generatePdf(params: {
|
||||
title: string;
|
||||
content: Record<string, unknown>;
|
||||
format?: 'A4' | 'A5' | 'letter';
|
||||
orientation?: 'portrait' | 'landscape';
|
||||
}): Promise<Uint8Array> {
|
||||
// Dynamic import to avoid bundle bloat in SSR
|
||||
// Actual implementation will use @react-pdf/renderer
|
||||
throw new Error(
|
||||
'PDF generation requires @react-pdf/renderer. Install it and implement the renderer in pdf-generator.service.ts'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate an Excel workbook (reports, data exports)
|
||||
* Uses exceljs at runtime.
|
||||
*/
|
||||
async generateExcel(params: {
|
||||
title: string;
|
||||
sheets: Array<{
|
||||
name: string;
|
||||
columns: Array<{ header: string; key: string; width?: number }>;
|
||||
rows: Array<Record<string, unknown>>;
|
||||
}>;
|
||||
}): Promise<Uint8Array> {
|
||||
throw new Error(
|
||||
'Excel generation requires exceljs. Install it and implement in excel-generator.service.ts'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a Word document (mail merge, letters)
|
||||
* Uses docx at runtime.
|
||||
*/
|
||||
async generateWord(params: {
|
||||
title: string;
|
||||
templateContent: string;
|
||||
mergeFields: Record<string, string>;
|
||||
}): Promise<Uint8Array> {
|
||||
throw new Error(
|
||||
'Word generation requires docx. Install it and implement in word-generator.service.ts'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate address labels in Avery format
|
||||
* Pure implementation — no external deps needed.
|
||||
*/
|
||||
generateLabelsHtml(params: {
|
||||
labelFormat: string;
|
||||
records: Array<{ line1: string; line2?: string; line3?: string; line4?: string }>;
|
||||
}): string {
|
||||
const { records } = params;
|
||||
|
||||
// Avery L7163 = 14 labels per page, 2 columns x 7 rows
|
||||
const labelsPerPage = 14;
|
||||
const pages: string[] = [];
|
||||
|
||||
for (let i = 0; i < records.length; i += labelsPerPage) {
|
||||
const pageRecords = records.slice(i, i + labelsPerPage);
|
||||
const labels = pageRecords.map((r) => `
|
||||
<div style="width:99.1mm;height:38.1mm;padding:4mm;box-sizing:border-box;overflow:hidden;font-size:10pt;font-family:Arial,sans-serif;">
|
||||
<div>${r.line1}</div>
|
||||
${r.line2 ? `<div>${r.line2}</div>` : ''}
|
||||
${r.line3 ? `<div>${r.line3}</div>` : ''}
|
||||
${r.line4 ? `<div>${r.line4}</div>` : ''}
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
pages.push(`
|
||||
<div style="width:210mm;display:grid;grid-template-columns:1fr 1fr;gap:0;page-break-after:always;">
|
||||
${labels}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
return `<!DOCTYPE html><html><head><meta charset="utf-8"><style>
|
||||
@page { size: A4; margin: 5mm 5mm; }
|
||||
body { margin: 0; }
|
||||
</style></head><body>${pages.join('')}</body></html>`;
|
||||
},
|
||||
};
|
||||
}
|
||||
6
packages/features/document-generator/tsconfig.json
Normal file
6
packages/features/document-generator/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "@kit/tsconfig/base.json",
|
||||
"compilerOptions": { "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" },
|
||||
"include": ["*.ts", "*.tsx", "src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user