From 07272374d4d74ed7a6d6e197867813c34c63c838 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:31:10 +0000 Subject: [PATCH 1/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/lib/forms-shared.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/forms-shared.ts b/src/lib/forms-shared.ts index f123154..de5ff4b 100644 --- a/src/lib/forms-shared.ts +++ b/src/lib/forms-shared.ts @@ -134,6 +134,15 @@ export async function fetchCustomFieldDefs(): Promise { return (data ?? []) as CustomFieldVar[]; } +export async function fetchClientCustomFieldDefs(): Promise { + const { data } = await supabase + .from("custom_client_fields") + .select("key,label,description") + .eq("active", true) + .order("sort_order"); + return (data ?? []) as CustomFieldVar[]; +} + // Case modifiers usable in templates as {{var|modifier}}. // Supported: upper, lower, title, sentence, capitalize (alias for sentence). export type CaseModifier = "upper" | "lower" | "title" | "sentence" | "capitalize"; From 6bbca318f63342f0020117aa1f09a9fb600f9a51 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:31:26 +0000 Subject: [PATCH 2/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/lib/forms-shared.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib/forms-shared.ts b/src/lib/forms-shared.ts index de5ff4b..978c481 100644 --- a/src/lib/forms-shared.ts +++ b/src/lib/forms-shared.ts @@ -198,6 +198,7 @@ export function applyVariables( homeowner?: HomeownerLite | null; firmName?: string; customValues?: Record; + clientCustomValues?: Record; fieldValues?: Record; }, ): string { @@ -215,11 +216,12 @@ export function applyVariables( let out = body; - // System variables: {{name}} or {{name|modifier}} + // Client custom-field variables: {{client.custom.key}} or {{client.custom.key|modifier}} + // Must run BEFORE the generic {{custom.key}} pattern so the prefix isn't swallowed. out = replaceWithModifier( out, - /\{\{\s*([a-zA-Z][a-zA-Z0-9_]*)\s*(\|\s*([a-zA-Z]+)\s*)?\}\}/g, - (name) => systemValues[name], + /\{\{\s*client\.custom\.([a-zA-Z0-9_]+)\s*(\|\s*([a-zA-Z]+)\s*)?\}\}/g, + (name) => ctx.clientCustomValues?.[name], ); // Custom case-field variables: {{custom.key}} or {{custom.key|modifier}} @@ -236,6 +238,13 @@ export function applyVariables( (name) => ctx.fieldValues?.[name], ); + // System variables: {{name}} or {{name|modifier}} — run LAST so dotted vars above win. + out = replaceWithModifier( + out, + /\{\{\s*([a-zA-Z][a-zA-Z0-9_]*)\s*(\|\s*([a-zA-Z]+)\s*)?\}\}/g, + (name) => systemValues[name], + ); + return out; } From 0db33652ebaf6e040c97f091f5b88eb5cc06eb6a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:31:39 +0000 Subject: [PATCH 3/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/lib/forms-shared.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/forms-shared.ts b/src/lib/forms-shared.ts index 978c481..2749753 100644 --- a/src/lib/forms-shared.ts +++ b/src/lib/forms-shared.ts @@ -355,3 +355,16 @@ export async function fetchCaseCustomValues(caseId: string): Promise> { + const { data } = await supabase + .from("client_field_values") + .select("value, field:custom_client_fields(key)") + .eq("client_id", clientId); + const map: Record = {}; + (data ?? []).forEach((row: any) => { + const k = row.field?.key; + if (k) map[k] = row.value ?? ""; + }); + return map; +} From 1dff181874e670d674b1edde5228823729f87db7 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:31:49 +0000 Subject: [PATCH 4/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/forms/custom-form-builder.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index 053efbc..d6a3fda 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -59,8 +59,10 @@ import { applyVariables, fetchFirm, fetchCustomFieldDefs, + fetchClientCustomFieldDefs, fetchAccessibleCases, fetchCaseCustomValues, + fetchClientCustomValues, savePdfToDocuments, SYSTEM_VARIABLES, type ClientLite, From bd92ebe39497a36a5463d9b1ed5e65bddb26c311 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:31:55 +0000 Subject: [PATCH 5/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/forms/custom-form-builder.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index d6a3fda..7d62289 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -261,6 +261,8 @@ export function CustomFormBuilder() { const [firm, setFirm] = useState(null); const [search, setSearch] = useState(""); const [customDefs, setCustomDefs] = useState([]); + const [clientCustomDefs, setClientCustomDefs] = useState([]); + const [clientCustomValues, setClientCustomValues] = useState>({}); const [fontFamily, setFontFamily] = useState("Bookman Old Style"); const [fontSize, setFontSize] = useState(12); const [lineHeight, setLineHeight] = useState(1.5); From a646add008d44246919eadeb9e6ad848b2d42b27 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:32:03 +0000 Subject: [PATCH 6/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/forms/custom-form-builder.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index 7d62289..d891614 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -318,9 +318,19 @@ export function CustomFormBuilder() { useEffect(() => { fetchFirm().then(setFirm); fetchCustomFieldDefs().then(setCustomDefs); + fetchClientCustomFieldDefs().then(setClientCustomDefs); loadTemplates(); }, []); + // Load client custom field values whenever the selected client changes. + useEffect(() => { + if (!client?.id) { + setClientCustomValues({}); + return; + } + fetchClientCustomValues(client.id).then(setClientCustomValues); + }, [client?.id]); + const loadTemplates = async () => { const { data } = await supabase .from("custom_form_templates") From f5517df765abaed2cf6eb1e2b14871db42cb1b65 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:32:18 +0000 Subject: [PATCH 7/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/forms/custom-form-builder.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index d891614..e3c993b 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -676,11 +676,17 @@ export function CustomFormBuilder() { if (selectedCaseId) { customValues = await fetchCaseCustomValues(selectedCaseId); } + // Always re-fetch the latest client custom values at render time so edits + // made in another tab show up without needing to reselect the client. + const freshClientCustomValues = client?.id + ? await fetchClientCustomValues(client.id) + : {}; return { client, homeowner, firmName: firm?.company_name ?? "", customValues, + clientCustomValues: freshClientCustomValues, fieldValues, }; }; From dae34a3ae264ece0b770c84af31bde7ef851c432 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:32:34 +0000 Subject: [PATCH 8/8] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/forms/custom-form-builder.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index e3c993b..8b837d3 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -1192,6 +1192,11 @@ export function CustomFormBuilder() { description: d.label + (d.description ? ` — ${d.description}` : ""), kind: "custom" as const, })), + ...clientCustomDefs.map((d) => ({ + key: `{{client.custom.${d.key}}}`, + description: `Client: ${d.label}` + (d.description ? ` — ${d.description}` : ""), + kind: "client-custom" as const, + })), ...formFields.map((f) => ({ key: `{{field.${f.key}}}`, description: `${f.label} (${f.type})`, @@ -1203,7 +1208,7 @@ export function CustomFormBuilder() { v.key.toLowerCase().includes(search.toLowerCase()) || v.description.toLowerCase().includes(search.toLowerCase()), ); - }, [customDefs, formFields, search]); + }, [customDefs, clientCustomDefs, formFields, search]); const filteredCases = useMemo(() => { const s = caseSearch.toLowerCase();