From 4513227338681999251a82ec5386283042212deb Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Wed, 4 Mar 2026 08:07:45 +0800 Subject: [PATCH] Fix share name toggle revert and stale table data for umbral contacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1: _to_settings_response() was missing share_first_name and share_last_name — the response always returned false (Pydantic default), causing the frontend to sync toggles back to off after save. Bug 2: Table column renderers read from stale Person record fields. Added sf() helper that overlays shared_fields for umbral contacts, applied to name, phone, email, role, and birthday columns. The table now shows live shared profile data matching the detail panel. Co-Authored-By: Claude Opus 4.6 --- backend/app/routers/settings.py | 2 + frontend/src/components/people/PeoplePage.tsx | 48 ++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/backend/app/routers/settings.py b/backend/app/routers/settings.py index 43f6f75..c99de7f 100644 --- a/backend/app/routers/settings.py +++ b/backend/app/routers/settings.py @@ -48,6 +48,8 @@ def _to_settings_response(s: Settings) -> SettingsResponse: # Social settings accept_connections=s.accept_connections, # Sharing defaults + share_first_name=s.share_first_name, + share_last_name=s.share_last_name, share_preferred_name=s.share_preferred_name, share_email=s.share_email, share_phone=s.share_phone, diff --git a/frontend/src/components/people/PeoplePage.tsx b/frontend/src/components/people/PeoplePage.tsx index 6b8ec70..3c89ca0 100644 --- a/frontend/src/components/people/PeoplePage.tsx +++ b/frontend/src/components/people/PeoplePage.tsx @@ -85,6 +85,14 @@ function sortPeople(people: Person[], key: string, dir: 'asc' | 'desc'): Person[ // --------------------------------------------------------------------------- // Column definitions // --------------------------------------------------------------------------- +/** Get a field value, preferring shared_fields for umbral contacts. */ +function sf(p: Person, key: string): string | null | undefined { + if (p.is_umbral_contact && p.shared_fields && key in p.shared_fields) { + return p.shared_fields[key] as string | null; + } + return p[key as keyof Person] as string | null | undefined; +} + const columns: ColumnDef[] = [ { key: 'name', @@ -92,7 +100,10 @@ const columns: ColumnDef[] = [ sortable: true, visibilityLevel: 'essential', render: (p) => { - const initialsName = getPersonInitialsName(p); + const firstName = sf(p, 'first_name') ?? p.first_name; + const lastName = sf(p, 'last_name') ?? p.last_name; + const liveName = [firstName, lastName].filter(Boolean).join(' ') || p.nickname || p.name; + const initialsName = liveName || getPersonInitialsName(p); return (
[] = [ > {getInitials(initialsName)}
- {p.nickname || p.name} + {liveName} {p.is_umbral_contact && ( )} @@ -113,18 +124,21 @@ const columns: ColumnDef[] = [ label: 'Number', sortable: false, visibilityLevel: 'essential', - render: (p) => ( - {p.mobile || p.phone || '—'} - ), + render: (p) => { + const mobile = sf(p, 'mobile') ?? p.mobile; + const phone = sf(p, 'phone') ?? p.phone; + return {mobile || phone || '—'}; + }, }, { key: 'email', label: 'Email', sortable: true, visibilityLevel: 'essential', - render: (p) => ( - {p.email || '—'} - ), + render: (p) => { + const email = sf(p, 'email') ?? p.email; + return {email || '—'}; + }, }, { key: 'job_title', @@ -132,10 +146,10 @@ const columns: ColumnDef[] = [ sortable: true, visibilityLevel: 'filtered', render: (p) => { - const parts = [p.job_title, p.company].filter(Boolean); - return ( - {parts.join(', ') || '—'} - ); + const jobTitle = sf(p, 'job_title') ?? p.job_title; + const company = sf(p, 'company') ?? p.company; + const parts = [jobTitle, company].filter(Boolean); + return {parts.join(', ') || '—'}; }, }, { @@ -143,12 +157,14 @@ const columns: ColumnDef[] = [ label: 'Birthday', sortable: true, visibilityLevel: 'filtered', - render: (p) => - p.birthday ? ( - {format(parseISO(p.birthday), 'MMM d')} + render: (p) => { + const birthday = sf(p, 'birthday') ?? p.birthday; + return birthday ? ( + {format(parseISO(birthday), 'MMM d')} ) : ( - ), + ); + }, }, { key: 'category',