diff --git a/src/components/forms/letter-generator.tsx b/src/components/forms/letter-generator.tsx index f7f2ac2..88ffae8 100644 --- a/src/components/forms/letter-generator.tsx +++ b/src/components/forms/letter-generator.tsx @@ -16,6 +16,7 @@ import { type HomeownerLite, type FirmInfo, } from "@/lib/forms-shared"; +import { supabase } from "@/integrations/supabase/client"; import { jsPDF } from "jspdf"; import { toast } from "sonner"; @@ -28,18 +29,54 @@ If you have any questions, please contact our office. Sincerely, {{firmName}}`; +async function loadLogoDataUrl(path: string | null | undefined): Promise { + if (!path) return null; + const { data: signed } = await supabase.storage.from("firm-logos").createSignedUrl(path, 60); + if (!signed?.signedUrl) return null; + try { + const res = await fetch(signed.signedUrl); + const blob = await res.blob(); + return await new Promise((resolve) => { + const r = new FileReader(); + r.onload = () => resolve(r.result as string); + r.readAsDataURL(blob); + }); + } catch { + return null; + } +} + export function LetterGenerator() { const [client, setClient] = useState(null); const [homeowner, setHomeowner] = useState(null); const [clientId, setClientId] = useState(""); const [homeownerId, setHomeownerId] = useState(""); const [firm, setFirm] = useState(null); + const [logoDataUrl, setLogoDataUrl] = useState(null); + const [attorneyName, setAttorneyName] = useState(""); const [subject, setSubject] = useState(""); const [body, setBody] = useState(DEFAULT_BODY); const [date, setDate] = useState(new Date().toISOString().slice(0, 10)); useEffect(() => { - fetchFirm().then(setFirm); + fetchFirm().then(async (f) => { + setFirm(f); + const url = await loadLogoDataUrl((f as any)?.logo_storage_path); + setLogoDataUrl(url); + }); + supabase.auth.getUser().then(async ({ data }) => { + const uid = data.user?.id; + if (!uid) return; + const { data: prof } = await supabase + .from("profiles") + .select("full_name,title") + .eq("id", uid) + .maybeSingle(); + if (prof?.full_name) { + const t = prof.title ? `, ${prof.title}` : ""; + setAttorneyName(`${prof.full_name}${t}`); + } + }); }, []); const handleExport = () => { @@ -50,52 +87,88 @@ export function LetterGenerator() { const pageW = doc.internal.pageSize.getWidth(); const margin = 60; const maxW = pageW - margin * 2; + const centerX = pageW / 2; - doc.setFont("helvetica", "bold"); - doc.setFontSize(13); - if (firm?.company_name) doc.text(firm.company_name, margin, 60); - doc.setFont("helvetica", "normal"); - doc.setFontSize(9); - const firmLines = [ + let y = 50; + + // Centered logo + if (logoDataUrl) { + try { + const imgW = 50; + const imgH = 50; + doc.addImage(logoDataUrl, "PNG", centerX - imgW / 2, y, imgW, imgH); + y += imgH + 8; + } catch { + /* ignore */ + } + } + + // Firm name (left) + Attorney name italic (right) on same line + const firmName = (firm?.company_name ?? "").toUpperCase(); + doc.setFont("times", "bold"); + doc.setFontSize(12); + if (firmName) doc.text(firmName, margin, y); + if (attorneyName) { + doc.setFont("times", "italic"); + doc.setFontSize(11); + doc.text(attorneyName, pageW - margin, y, { align: "right" }); + } + y += 14; + + // Contact row centered, dot-separated + const contactParts: string[] = []; + const addr = [ firm?.address_line1, [firm?.city, firm?.state, firm?.postal_code].filter(Boolean).join(", "), - firm?.contact_phone, - firm?.contact_email, - ].filter(Boolean) as string[]; - let y = 75; - firmLines.forEach((l) => { - doc.text(l, margin, y); - y += 11; - }); - - y += 20; + ] + .filter(Boolean) + .join(", "); + if (addr) contactParts.push(addr); + if (firm?.contact_phone) contactParts.push(firm.contact_phone); + if (firm?.contact_email) contactParts.push(firm.contact_email); + doc.setFont("times", "normal"); doc.setFontSize(10); - doc.text(fmtDateLong(date), margin, y); + if (contactParts.length) { + doc.text(contactParts.join(" \u00B7 "), centerX, y, { align: "center" }); + y += 8; + } + + // Horizontal rule + doc.setLineWidth(0.75); + doc.line(margin, y, pageW - margin, y); y += 28; + // Centered bold date + doc.setFont("times", "bold"); + doc.setFontSize(11); + doc.text(fmtDateLong(date), centerX, y, { align: "center" }); + y += 28; + + // Recipient block + doc.setFont("times", "normal"); + doc.setFontSize(11); ownerMailingLines(homeowner).forEach((l) => { doc.text(l, margin, y); - y += 12; + y += 13; }); if (!homeowner && client) { doc.text(client.name, margin, y); - y += 12; + y += 13; clientAddressLines(client).forEach((l) => { doc.text(l, margin, y); - y += 12; + y += 13; }); } - y += 20; + y += 18; if (renderedSubject) { - doc.setFont("helvetica", "bold"); + doc.setFont("times", "bold"); const subjLines = doc.splitTextToSize(`Re: ${renderedSubject}`, maxW); doc.text(subjLines, margin, y); - y += subjLines.length * 12 + 14; - doc.setFont("helvetica", "normal"); + y += subjLines.length * 13 + 14; + doc.setFont("times", "normal"); } - doc.setFontSize(11); const bodyLines = doc.splitTextToSize(renderedBody, maxW); for (const line of bodyLines) { if (y > 740) { @@ -126,11 +199,19 @@ export function LetterGenerator() { setHomeowner(h); }} /> -
+
setDate(e.target.value)} />
+
+ + setAttorneyName(e.target.value)} + placeholder="Jane Doe, Esq." + /> +
setSubject(e.target.value)} />