import { useEffect, useMemo, useState } from 'react' import { Navigate } from 'react-router-dom' import { Button, Field, Notice, PageHeader } from '@sims/ui' import { getTemplateSettings, previewSample, putTemplateSettings, role, uploadTemplateLogo } from '../api' import { LivePreview } from '../components/LivePreview' const COMPANY_FIELDS: { key: string; setting: string; label: string; area: boolean }[] = [ { key: 'name', setting: 'company.name', label: 'Company name', area: false }, { key: 'address', setting: 'company.address', label: 'Address', area: true }, { key: 'gstin', setting: 'company.gstin', label: 'GSTIN', area: false }, { key: 'stateCode', setting: 'company.state_code', label: 'State code', area: false }, { key: 'phone', setting: 'company.phone', label: 'Phone', area: false }, { key: 'email', setting: 'company.email', label: 'Email', area: false }, { key: 'bank', setting: 'company.bank', label: 'Bank details', area: true }, ] const TEMPLATE_FIELDS: { key: string; setting: string; label: string; area: boolean }[] = [ { key: 'terms', setting: 'template.terms', label: 'Default terms', area: true }, { key: 'declaration', setting: 'template.declaration', label: 'GST declaration', area: true }, { key: 'jurisdiction', setting: 'template.jurisdiction', label: 'Jurisdiction line', area: false }, { key: 'footerNote', setting: 'template.footer_note', label: 'Footer note', area: false }, { key: 'signatoryLabel', setting: 'template.signatory_label', label: 'Signatory label', area: false }, ] const DOC_TITLES: { type: string; setting: string; label: string }[] = [ { type: 'INVOICE', setting: 'template.title_INVOICE', label: 'Invoice title' }, { type: 'QUOTATION', setting: 'template.title_QUOTATION', label: 'Quotation title' }, { type: 'PROFORMA', setting: 'template.title_PROFORMA', label: 'Proforma title' }, ] type Dict = Record /** Owner-only: all letterhead text data (company.* + template.*) with a live * letterhead preview beside the form. One fixed layout — not a visual editor. */ export function DocumentTemplate() { const [company, setCompany] = useState({}) const [template, setTemplate] = useState({}) const [titles, setTitles] = useState({}) const [logo, setLogo] = useState('') const [commitNonce, setCommitNonce] = useState(0) const [msg, setMsg] = useState<{ tone: 'ok' | 'err'; text: string } | undefined>() const [saving, setSaving] = useState(false) const load = (s: Dict): void => { setCompany(Object.fromEntries(COMPANY_FIELDS.map((x) => [x.key, s[x.setting] ?? '']))) setTemplate(Object.fromEntries(TEMPLATE_FIELDS.map((x) => [x.key, s[x.setting] ?? '']))) setTitles(Object.fromEntries(DOC_TITLES.map((x) => [x.type, s[x.setting] ?? '']))) setLogo(s['template.logo'] ?? '') } useEffect(() => { getTemplateSettings().then(load).catch((e: Error) => setMsg({ tone: 'err', text: e.message })) }, []) // Logo excluded from the body — it is saved on pick and the preview reads it back. const previewBody = useMemo(() => JSON.stringify({ company, template, titles }), [company, template, titles]) const commit = () => setCommitNonce((n) => n + 1) if (role() !== 'owner') return const save = () => { setSaving(true); setMsg(undefined) putTemplateSettings({ company, template, titles }) .then((s) => { load(s); setMsg({ tone: 'ok', text: 'Saved. Every document uses the new template immediately.' }) }) .catch((e: Error) => setMsg({ tone: 'err', text: e.message })) .finally(() => setSaving(false)) } const onLogo = (file: File | undefined) => { if (file === undefined) return const reader = new FileReader() reader.onload = () => { uploadTemplateLogo(String(reader.result)) .then((saved) => { setLogo(saved); commit(); setMsg({ tone: 'ok', text: 'Logo saved.' }) }) .catch((e: Error) => setMsg({ tone: 'err', text: e.message })) } reader.readAsDataURL(file) } const textField = (dict: Dict, setDict: (u: (p: Dict) => Dict) => void) => (x: { key: string; label: string; area: boolean }) => ( {x.area ?