diff --git a/src/components/contacts/contacts-link-tab.tsx b/src/components/contacts/contacts-link-tab.tsx index 44f5eec..c022448 100644 --- a/src/components/contacts/contacts-link-tab.tsx +++ b/src/components/contacts/contacts-link-tab.tsx @@ -4,6 +4,13 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { supabase } from "@/integrations/supabase/client"; import { useAuth } from "@/lib/auth"; import { toast } from "sonner"; @@ -11,7 +18,7 @@ import { Plus, Trash2, Mail, Phone, Building2, MapPin, Search, UserPlus } from " import { ContactFormDialog, CONTACT_TYPES } from "./contact-form-dialog"; interface LinkedContact { - id: string; // join row id + id: string; role: string | null; contact: { id: string; @@ -28,6 +35,12 @@ interface LinkedContact { }; } +const CASE_ROLE_OPTIONS = [ + { value: "other", label: "Other" }, + { value: "homeowner", label: "Homeowner" }, + { value: "tenant", label: "Tenant" }, +] as const; + export function ContactsLinkTab({ parentId, parentTable, @@ -37,15 +50,19 @@ export function ContactsLinkTab({ }) { const { user } = useAuth(); const fkColumn = parentTable === "case_contacts" ? "case_id" : "client_id"; + const isCaseContacts = parentTable === "case_contacts"; const [linked, setLinked] = useState([]); const [loading, setLoading] = useState(true); const [pickerOpen, setPickerOpen] = useState(false); const [createOpen, setCreateOpen] = useState(false); + const [caseLinkRole, setCaseLinkRole] = useState("other"); const load = async () => { setLoading(true); const { data, error } = await (supabase.from(parentTable) as any) - .select("id, role, contact:contacts(id, name, company, title, email, phone, contact_type, address_line1, city, state, postal_code)") + .select( + "id, role, contact:contacts(id, name, company, title, email, phone, contact_type, address_line1, city, state, postal_code)", + ) .eq(fkColumn, parentId); if (error) toast.error(error.message); setLinked(((data ?? []) as any[]).filter((d) => d.contact)); @@ -56,12 +73,15 @@ export function ContactsLinkTab({ load(); }, [parentId, parentTable]); - const linkContact = async (contactId: string) => { + const linkContact = async (contactId: string, roleOverride?: string | null) => { const payload: Record = { contact_id: contactId, created_by: user?.id, }; payload[fkColumn] = parentId; + if (isCaseContacts) { + payload.role = roleOverride && roleOverride !== "other" ? roleOverride : null; + } const { error } = await supabase.from(parentTable).insert(payload as any); if (error) { if (error.code === "23505") toast.info("Already linked"); @@ -73,6 +93,46 @@ export function ContactsLinkTab({ load(); }; + const relinkCaseRole = async (row: LinkedContact, nextRole: string) => { + const normalizedRole = nextRole === "other" ? null : nextRole; + + const { error: updateError } = await supabase + .from("case_contacts") + .update({ role: normalizedRole }) + .eq("id", row.id); + + if (!updateError) { + toast.success("Case role updated"); + load(); + return; + } + + const { error: deleteError } = await supabase + .from("case_contacts") + .delete() + .eq("id", row.id); + if (deleteError) { + toast.error(deleteError.message); + return; + } + + const { error: insertError } = await supabase.from("case_contacts").insert({ + case_id: parentId, + contact_id: row.contact.id, + role: normalizedRole, + created_by: user?.id, + }); + + if (insertError) { + toast.error(insertError.message); + await load(); + return; + } + + toast.success("Case role updated"); + load(); + }; + const unlink = async (joinId: string) => { const { error } = await supabase.from(parentTable).delete().eq("id", joinId); if (error) { @@ -87,7 +147,7 @@ export function ContactsLinkTab({ return ( -
+
{parentTable === "client_contacts" ? "Additional contacts" : "Contacts"} @@ -96,8 +156,27 @@ export function ContactsLinkTab({ {linked.length} linked contact{linked.length === 1 ? "" : "s"} {parentTable === "client_contacts" && " — accountants, vendors, board liaisons, etc."}
+ {isCaseContacts && ( +
+ Collections uses contacts linked to this case as homeowner or tenant. +
+ )}
-
+
+ {isCaseContacts && ( + + )} @@ -117,12 +196,18 @@ export function ContactsLinkTab({ const c = row.contact; const typeLabel = CONTACT_TYPES.find((t) => t.value === c.contact_type)?.label ?? c.contact_type; const addr = [c.address_line1, c.city, c.state, c.postal_code].filter(Boolean).join(", "); + const roleValue = row.role ?? "other"; return (
  • {c.name} {typeLabel} + {isCaseContacts && row.role && ( + + Case role: {row.role} + + )} {c.title && {c.title}}
    @@ -132,9 +217,28 @@ export function ContactsLinkTab({ {addr && {addr}}
    - +
    + {isCaseContacts && ( + + )} + +
  • ); })} @@ -145,13 +249,13 @@ export function ContactsLinkTab({ open={pickerOpen} onOpenChange={setPickerOpen} excludeIds={linkedIds} - onPick={linkContact} + onPick={(contactId) => linkContact(contactId, caseLinkRole)} /> { - await linkContact(saved.id); + await linkContact(saved.id, caseLinkRole); }} />