diff --git a/src/components/forms/letter-generator.tsx b/src/components/forms/letter-generator.tsx index 6a2465e..8c492f7 100644 --- a/src/components/forms/letter-generator.tsx +++ b/src/components/forms/letter-generator.tsx @@ -1,19 +1,26 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { Card, CardContent } from "@/components/ui/card"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { FileDown } from "lucide-react"; -import { ClientHomeownerPicker } from "./form-pickers"; import { applyVariables, - clientAddressLines, + contactMailingLines, + fetchAccessibleCases, + fetchContacts, fetchFirm, fmtDateLong, - ownerMailingLines, - type ClientLite, - type HomeownerLite, + type CaseLite, + type ContactLite, type FirmInfo, } from "@/lib/forms-shared"; import { fillTokens, loadFormTemplate, type FormTemplateConfig } from "@/lib/form-templates"; @@ -40,10 +47,11 @@ async function loadLogoDataUrl(path: string | null | undefined): Promise(null); - const [homeowner, setHomeowner] = useState(null); - const [clientId, setClientId] = useState(""); - const [homeownerId, setHomeownerId] = useState(""); + const [cases, setCases] = useState([]); + const [caseId, setCaseId] = useState(""); + const [contacts, setContacts] = useState([]); + const [caseContactIds, setCaseContactIds] = useState>(new Set()); + const [recipientId, setRecipientId] = useState(""); const [firm, setFirm] = useState(null); const [logoDataUrl, setLogoDataUrl] = useState(null); const [attorneyName, setAttorneyName] = useState(""); @@ -53,15 +61,31 @@ export function LetterGenerator() { const [certifiedMailNumber, setCertifiedMailNumber] = useState(""); const [template, setTemplate] = useState(null); + const recipient = useMemo( + () => contacts.find((c) => c.id === recipientId) ?? null, + [contacts, recipientId], + ); + + // Sort: case-linked contacts first, then everything else. + const sortedContacts = useMemo(() => { + const linked: ContactLite[] = []; + const others: ContactLite[] = []; + for (const c of contacts) { + (caseContactIds.has(c.id) ? linked : others).push(c); + } + return { linked, others }; + }, [contacts, caseContactIds]); + useEffect(() => { fetchFirm().then(async (f) => { setFirm(f); const url = await loadLogoDataUrl((f as any)?.logo_storage_path); setLogoDataUrl(url); }); + fetchAccessibleCases().then(setCases); + fetchContacts().then(setContacts); loadFormTemplate("letter").then((t) => { setTemplate(t); - // Seed the editable body with the template default on first load. setBody((prev) => prev || t.body || ""); }); supabase.auth.getUser().then(async ({ data }) => { @@ -79,9 +103,24 @@ export function LetterGenerator() { }); }, []); + // When case changes, fetch its linked contacts to surface them at the top. + useEffect(() => { + if (!caseId) { + setCaseContactIds(new Set()); + return; + } + supabase + .from("case_contacts") + .select("contact_id") + .eq("case_id", caseId) + .then(({ data }) => { + setCaseContactIds(new Set((data ?? []).map((r: any) => r.contact_id))); + }); + }, [caseId]); + const handleExport = () => { if (!template) return; - const ctx = { client, homeowner, firmName: firm?.company_name ?? "" }; + const ctx = { client: null, homeowner: null, firmName: firm?.company_name ?? "" }; const renderedBody = applyVariables(body, ctx); const renderedSubject = applyVariables(subject, ctx); @@ -104,8 +143,8 @@ export function LetterGenerator() { "firm.phone": firm?.contact_phone ?? "", "firm.email": firm?.contact_email ?? "", "firm.website": (firm as any)?.website ?? "", - "owner.name": homeowner ? `${homeowner.first_name} ${homeowner.last_name}`.trim() : "", - "client.name": client?.name ?? "", + "recipient.name": recipient?.name ?? "", + "recipient.company": recipient?.company ?? "", attorney: attorneyName, date: fmtDateLong(date), }; @@ -205,21 +244,13 @@ export function LetterGenerator() { doc.text(fmtDateLong(date), centerX, y, { align: "center" }); y += 28; - // ----- Recipient ----- + // ----- Recipient (from selected contact) ----- doc.setFont(bodyFont, "normal"); doc.setFontSize(bodyFontSize); - ownerMailingLines(homeowner).forEach((l) => { + contactMailingLines(recipient).forEach((l) => { doc.text(l, margin, y); y += lh - 1; }); - if (!homeowner && client) { - doc.text(client.name, margin, y); - y += lh - 1; - clientAddressLines(client).forEach((l) => { - doc.text(l, margin, y); - y += lh - 1; - }); - } // Certified mail line (right-aligned, italic) — only when a number is provided if (certifiedMailNumber.trim() && template.showCertifiedMail !== false) { @@ -312,18 +343,60 @@ export function LetterGenerator() {
- { - setClientId(id); - setClient(c); - }} - onHomeownerChange={(id, h) => { - setHomeownerId(id); - setHomeowner(h); - }} - /> +
+
+ + +
+
+ + +
+