diff --git a/src/lib/pleading-variables.ts b/src/lib/pleading-variables.ts new file mode 100644 index 0000000..7d10811 --- /dev/null +++ b/src/lib/pleading-variables.ts @@ -0,0 +1,148 @@ +import { supabase } from "@/integrations/supabase/client"; + +export type VarMap = Record; + +export type LoadedContext = { + client?: any; + cases?: any; + clientFields: { key: string; label: string; value: string }[]; + caseFields: { key: string; label: string; value: string }[]; +}; + +export type VarChip = { token: string; label: string; value: string }; + +export async function loadPleadingContext( + clientId: string | null, + caseId: string | null, +): Promise { + const result: LoadedContext = { clientFields: [], caseFields: [] }; + + if (clientId) { + const { data: client } = await supabase.from("clients").select("*").eq("id", clientId).maybeSingle(); + if (client) result.client = client; + const [{ data: defs }, { data: vals }] = await Promise.all([ + supabase.from("custom_client_fields").select("id, key, label").eq("active", true).order("sort_order"), + supabase.from("client_field_values").select("field_id, value").eq("client_id", clientId), + ]); + const valMap = new Map((vals || []).map((v: any) => [v.field_id, v.value || ""])); + result.clientFields = (defs || []).map((d: any) => ({ + key: d.key, + label: d.label, + value: valMap.get(d.id) || "", + })); + } + + if (caseId) { + const { data: caseRow } = await supabase.from("cases").select("*").eq("id", caseId).maybeSingle(); + if (caseRow) result.cases = caseRow; + const [{ data: defs }, { data: vals }] = await Promise.all([ + supabase.from("custom_case_fields").select("id, key, label").eq("active", true).order("sort_order"), + supabase.from("case_field_values").select("field_id, value").eq("case_id", caseId), + ]); + const valMap = new Map((vals || []).map((v: any) => [v.field_id, v.value || ""])); + result.caseFields = (defs || []).map((d: any) => ({ + key: d.key, + label: d.label, + value: valMap.get(d.id) || "", + })); + } + + return result; +} + +function fmtAddress(o: any): string { + if (!o) return ""; + const parts = [ + o.address_line1, + o.address_line2, + [o.city, o.state, o.postal_code].filter(Boolean).join(", "), + ].filter(Boolean); + return parts.join("\n"); +} + +export function buildVarMap(ctx: LoadedContext): VarMap { + const m: VarMap = {}; + const c = ctx.client; + if (c) { + m["client.name"] = c.name || ""; + m["client.address"] = fmtAddress(c); + m["client.address_line1"] = c.address_line1 || ""; + m["client.address_line2"] = c.address_line2 || ""; + m["client.city"] = c.city || ""; + m["client.state"] = c.state || ""; + m["client.postal_code"] = c.postal_code || ""; + m["client.contact_name"] = c.primary_contact_name || ""; + m["client.contact_email"] = c.primary_contact_email || ""; + m["client.contact_phone"] = c.primary_contact_phone || ""; + m["client.management_company"] = c.management_company || ""; + } + const k = ctx.cases; + if (k) { + m["case.number"] = k.case_number || ""; + m["case.title"] = k.title || ""; + m["case.caption"] = k.case_caption || ""; + m["case.court"] = k.court || ""; + m["case.court_case_number"] = k.court_case_number || ""; + m["case.judge"] = k.judge || ""; + m["case.jurisdiction"] = k.jurisdiction || ""; + m["case.opposing_party"] = k.opposing_party || ""; + m["case.opposing_counsel"] = k.opposing_counsel || ""; + m["case.opposing_counsel_firm"] = k.opposing_counsel_firm || ""; + m["case.opposing_counsel_email"] = k.opposing_counsel_email || ""; + m["case.opposing_counsel_phone"] = k.opposing_counsel_phone || ""; + m["case.filing_date"] = k.filing_date || ""; + m["case.next_hearing_date"] = k.next_hearing_date || ""; + } + ctx.clientFields.forEach((f) => { + m[`client.field.${f.key}`] = f.value; + }); + ctx.caseFields.forEach((f) => { + m[`case.field.${f.key}`] = f.value; + }); + return m; +} + +export function buildChips(ctx: LoadedContext): VarChip[] { + const m = buildVarMap(ctx); + const out: VarChip[] = []; + const labelMap: Record = { + "client.name": "Client name", + "client.address": "Client address (full)", + "client.contact_name": "Client primary contact", + "client.contact_email": "Client contact email", + "client.contact_phone": "Client contact phone", + "client.management_company": "Management company", + "case.number": "Case number", + "case.title": "Case title", + "case.caption": "Case caption", + "case.court": "Court", + "case.court_case_number": "Court case number", + "case.judge": "Judge", + "case.opposing_party": "Opposing party", + "case.opposing_counsel": "Opposing counsel", + "case.opposing_counsel_firm": "Opposing counsel firm", + "case.filing_date": "Filing date", + "case.next_hearing_date": "Next hearing date", + }; + for (const key of Object.keys(m)) { + let label = labelMap[key]; + if (!label) { + if (key.startsWith("client.field.")) label = `Client · ${key.replace("client.field.", "")}`; + else if (key.startsWith("case.field.")) label = `Case · ${key.replace("case.field.", "")}`; + else label = key; + } + out.push({ token: `{{${key}}}`, label, value: m[key] }); + } + return out; +} + +const TOKEN_RE = /\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/g; + +export function applyVars(text: string, map: VarMap): string { + if (!text) return text; + return text.replace(TOKEN_RE, (_, key) => (key in map ? map[key] : `{{${key}}}`)); +} + +export function applyVarsToHtml(html: string, map: VarMap): string { + return applyVars(html, map); +}