From df9aa8333a0bc502f692ca73d6de5002820d4143 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:16:48 +0000 Subject: [PATCH] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/collections.$collectionId.tsx | 206 +++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/src/routes/collections.$collectionId.tsx b/src/routes/collections.$collectionId.tsx index e4eb5a4..a8665e3 100644 --- a/src/routes/collections.$collectionId.tsx +++ b/src/routes/collections.$collectionId.tsx @@ -727,3 +727,209 @@ function AddTaskDialog({ ); } + +function ApplyHomeownerDialog({ + open, + onOpenChange, + collection, + onSaved, +}: { + open: boolean; + onOpenChange: (v: boolean) => void; + collection: any; + onSaved: () => void; +}) { + const [contacts, setContacts] = useState([]); + const [homeowners, setHomeowners] = useState([]); + const [selectedHomeownerId, setSelectedHomeownerId] = useState(""); + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const clientId = collection?.case?.client?.id ?? null; + + useEffect(() => { + if (!open || !clientId) return; + setLoading(true); + (async () => { + // Load case contacts (people on this case) + const { data: cc } = await supabase + .from("case_contacts") + .select("contact:contacts(id, name, email, phone)") + .eq("case_id", collection.case.id); + const caseContacts = (cc ?? []) + .map((r: any) => r.contact) + .filter(Boolean); + setContacts(caseContacts); + + // Load existing homeowners for this client + const { data: hos } = await supabase + .from("homeowners") + .select("id, first_name, last_name, unit_number, email, phone") + .eq("client_id", clientId) + .is("archived_at", null) + .order("last_name"); + setHomeowners(hos ?? []); + setSelectedHomeownerId(collection.homeowner_id ?? ""); + setLoading(false); + })(); + }, [open, clientId, collection?.case?.id, collection?.homeowner_id]); + + const applyExisting = async () => { + if (!selectedHomeownerId) return toast.error("Select a homeowner"); + setSaving(true); + const ho = homeowners.find((h) => h.id === selectedHomeownerId); + const updates: any = { homeowner_id: selectedHomeownerId }; + // Refresh display name on the collection too + if (ho) updates.name = `${ho.last_name}, ${ho.first_name}`; + const { error } = await supabase + .from("collections") + .update(updates) + .eq("id", collection.id); + setSaving(false); + if (error) { + toast.error("Could not apply", { description: error.message }); + return; + } + toast.success("Homeowner applied"); + onOpenChange(false); + onSaved(); + }; + + const createFromContact = async (contactId: string) => { + const c = contacts.find((x) => x.id === contactId); + if (!c || !clientId) return; + setSaving(true); + // Split name → first/last + const parts = (c.name ?? "").trim().split(/\s+/); + const first = parts.shift() ?? c.name ?? "Homeowner"; + const last = parts.join(" ") || "—"; + const { data: ho, error: insErr } = await supabase + .from("homeowners") + .insert({ + client_id: clientId, + first_name: first, + last_name: last, + email: c.email, + phone: c.phone, + }) + .select("id, first_name, last_name") + .single(); + if (insErr || !ho) { + setSaving(false); + toast.error("Could not create homeowner", { description: insErr?.message }); + return; + } + const { error: updErr } = await supabase + .from("collections") + .update({ + homeowner_id: ho.id, + name: `${ho.last_name}, ${ho.first_name}`, + }) + .eq("id", collection.id); + setSaving(false); + if (updErr) { + toast.error("Created but could not apply", { description: updErr.message }); + return; + } + toast.success("Homeowner created and applied"); + onOpenChange(false); + onSaved(); + }; + + const clearHomeowner = async () => { + if (!confirm("Remove the homeowner from this collection?")) return; + setSaving(true); + const { error } = await supabase + .from("collections") + .update({ homeowner_id: null }) + .eq("id", collection.id); + setSaving(false); + if (error) { + toast.error("Could not clear", { description: error.message }); + return; + } + toast.success("Homeowner removed"); + onOpenChange(false); + onSaved(); + }; + + return ( + + + + + {collection?.homeowner ? "Change homeowner" : "Apply homeowner"} + + + Select an existing homeowner for this client, or promote a case contact into a homeowner record. + + + + {loading ? ( +
Loading…
+ ) : ( +
+
+ + {homeowners.length === 0 ? ( +

+ No homeowners on this client yet. +

+ ) : ( + ({ + value: h.id, + label: `${h.last_name}, ${h.first_name}${h.unit_number ? ` · Unit ${h.unit_number}` : ""}`, + }))} + /> + )} +
+ + {contacts.length > 0 && ( +
+ +
+ {contacts.map((c) => ( + + ))} +
+
+ )} +
+ )} + + + {collection?.homeowner_id ? ( + + ) : } +
+ + +
+
+
+
+ ); +}