/** * Documents Generator API client (Phase L1-L3). * * Letterheads (Briefpapier), print templates (block compositions), * block registry and placeholders — all under /reports/... (documents * router of the report_generator plugin). */ import { apiClient, apiDelete, apiGet, apiPost, apiPut } from './client'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; // ─── Types ───────────────────────────────────────────────────────────────── export interface DocBlock { id: string; type: string; config: Record; } export interface LetterheadPageConfig { size?: string; orientation?: string; margins?: { top?: number; right?: number; bottom?: number; left?: number }; } export interface LetterheadConfig { page?: LetterheadPageConfig; header?: { enabled: boolean; blocks: DocBlock[] }; footer?: { enabled: boolean; blocks: DocBlock[] }; watermark?: { enabled: boolean; text?: string }; } export interface Letterhead { id: string; name: string; description: string; config: LetterheadConfig; is_default: boolean; created_by: string; created_at?: string | null; updated_at?: string | null; } export interface PrintTemplate { id: string; name: string; description: string; letterhead_id: string | null; entity_type: string; blocks: DocBlock[]; output_format: string; created_by: string; created_at?: string | null; updated_at?: string | null; } export interface DocumentBlockType { type: string; label: string; category: string; description: string; fields: Record; builtin: boolean; contributed_by?: string | null; } export interface DocumentPlaceholder { key: string; label: string; example: string; } export interface DocumentAsset { id: string; letterhead_id: string | null; filename: string; mime_type: string; size_bytes: number; data_url: string | null; created_at?: string | null; } export interface LetterheadInput { name: string; description?: string; config?: LetterheadConfig; is_default?: boolean; } export interface PrintTemplateInput { name: string; description?: string; letterhead_id?: string | null; entity_type?: string; blocks?: DocBlock[]; output_format?: string; } // ─── Query Keys ───────────────────────────────────────────────────────────── export const DOC_QUERY_KEYS = { letterheads: ['documents', 'letterheads'] as const, letterhead: (id: string) => ['documents', 'letterheads', id] as const, templates: ['documents', 'print-templates'] as const, template: (id: string) => ['documents', 'print-templates', id] as const, blocks: ['documents', 'block-types'] as const, placeholders: (entityType?: string) => ['documents', 'placeholders', entityType ?? 'all'] as const, assets: (letterheadId: string) => ['documents', 'assets', letterheadId] as const, }; // ─── Fetch helpers ───────────────────────────────────────────────────────── async function fetchLetterheads(): Promise { const res = await apiGet<{ items: Letterhead[]; total: number }>('/reports/letterheads'); return res.items ?? []; } async function fetchTemplates(): Promise { const res = await apiGet<{ items: PrintTemplate[]; total: number }>('/reports/print-templates'); return res.items ?? []; } async function fetchBlockTypes(): Promise { return apiGet('/reports/document-blocks'); } async function fetchPlaceholders(entityType?: string): Promise> { const url = entityType ? `/reports/document-placeholders?entity_type=${encodeURIComponent(entityType)}` : '/reports/document-placeholders'; return apiGet>(url); } async function fetchAssets(letterheadId: string): Promise { return apiGet(`/reports/letterheads/${letterheadId}/assets`); } // ─── Hooks: Letterheads ───────────────────────────────────────────────────── export function useLetterheads() { return useQuery({ queryKey: DOC_QUERY_KEYS.letterheads, queryFn: fetchLetterheads, }); } export function useCreateLetterhead() { const qc = useQueryClient(); return useMutation({ mutationFn: (input: LetterheadInput) => apiPost('/reports/letterheads', input), onSuccess: () => qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.letterheads }), }); } export function useUpdateLetterhead() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, input }: { id: string; input: Partial }) => apiPut(`/reports/letterheads/${id}`, input), onSuccess: (_data, vars) => { qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.letterheads }); qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.letterhead(vars.id) }); }, }); } export function useDeleteLetterhead() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/reports/letterheads/${id}`), onSuccess: () => qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.letterheads }), }); } // ─── Hooks: Print Templates ───────────────────────────────────────────────── export function usePrintTemplates() { return useQuery({ queryKey: DOC_QUERY_KEYS.templates, queryFn: fetchTemplates, }); } export function useCreatePrintTemplate() { const qc = useQueryClient(); return useMutation({ mutationFn: (input: PrintTemplateInput) => apiPost('/reports/print-templates', input), onSuccess: () => qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.templates }), }); } export function useUpdatePrintTemplate() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, input }: { id: string; input: Partial }) => apiPut(`/reports/print-templates/${id}`, input), onSuccess: (_data, vars) => { qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.templates }); qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.template(vars.id) }); }, }); } export function useDeletePrintTemplate() { const qc = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/reports/print-templates/${id}`), onSuccess: () => qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.templates }), }); } // ─── Hooks: Registry ──────────────────────────────────────────────────────── export function useDocumentBlockTypes() { return useQuery({ queryKey: DOC_QUERY_KEYS.blocks, queryFn: fetchBlockTypes, staleTime: 5 * 60 * 1000, }); } export function useDocumentPlaceholders(entityType?: string, enabled = true) { return useQuery>({ queryKey: DOC_QUERY_KEYS.placeholders(entityType), queryFn: () => fetchPlaceholders(entityType), enabled, staleTime: 5 * 60 * 1000, }); } export function useLetterheadAssets(letterheadId: string | null | undefined) { return useQuery({ queryKey: DOC_QUERY_KEYS.assets(letterheadId ?? 'none'), queryFn: () => fetchAssets(letterheadId as string), enabled: !!letterheadId, }); } export function useUploadLetterheadAsset() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ letterheadId, file }: { letterheadId: string; file: File }) => { const form = new FormData(); form.append('file', file); return apiClient .post(`/reports/letterheads/${letterheadId}/assets`, form, { headers: { 'Content-Type': 'multipart/form-data' }, }) .then((r) => r.data as DocumentAsset); }, onSuccess: (_data, vars) => qc.invalidateQueries({ queryKey: DOC_QUERY_KEYS.assets(vars.letterheadId) }), }); } // ─── Preview & Render ────────────────────────────────────────────────────── export interface PreviewInput { blocks: DocBlock[]; letterhead_config: LetterheadConfig | null; entity_type?: string | null; data?: Record | null; } export function usePreviewDocument() { return useMutation({ mutationFn: (input: PreviewInput) => apiPost<{ html: string }>('/reports/documents/preview', input), }); } export interface RenderInput { templateId: string; entityType: string; entityId: string; outputFormat?: string; } export async function renderPrintTemplate(input: RenderInput): Promise { const response = await apiClient.post( `/reports/print-templates/${input.templateId}/render`, { entity_type: input.entityType, entity_id: input.entityId, output_format: input.outputFormat ?? 'pdf', }, { responseType: 'blob' }, ); return response.data as Blob; } export function useRenderPrintTemplate() { return useMutation({ mutationFn: renderPrintTemplate }); }