From 16349852cc4511a32bdfd708be260d709de36a26 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Tue, 8 Sep 2026 04:59:25 -0700 Subject: [PATCH] feat: fix issue #381 by scoping the import and sheet-sync entry points on a segment's member list to that segment, so a CSV uploaded from inside a segment pins its rows in instead of creating contacts that are nowhere in it, and round the page out with an empty state offering Add contacts, Import file and New contact plus a pinned-contacts panel that says when it is showing only the newest slice of a large import --- .../app/app/contacts/segments/[id]/page.tsx | 12 +++++++- .../components/app/contacts/ContactsTable.tsx | 30 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/web/src/app/app/contacts/segments/[id]/page.tsx b/web/src/app/app/contacts/segments/[id]/page.tsx index 2e41856a..2f312085 100644 --- a/web/src/app/app/contacts/segments/[id]/page.tsx +++ b/web/src/app/app/contacts/segments/[id]/page.tsx @@ -127,7 +127,7 @@ function SegmentDetail() { {(s.included_count > 0 || s.excluded_count > 0) && } - + setEditorOpen(false)} segment={s} /> setCampaignOpen(false)} segment={s} /> @@ -190,6 +190,10 @@ function OverridesPanel({ segment }: { segment: Segment }) { } const list = overrides.data ?? []; + // The API caps one listing, so a segment a big import pinned into shows a + // slice of its overrides. Say so rather than implying this is all of them. + const pinned = segment.included_count + segment.excluded_count; + const truncated = pinned > list.length; return (
diff --git a/web/src/components/app/contacts/ContactsTable.tsx b/web/src/components/app/contacts/ContactsTable.tsx index bb35be32..0f85edc2 100644 --- a/web/src/components/app/contacts/ContactsTable.tsx +++ b/web/src/components/app/contacts/ContactsTable.tsx @@ -117,7 +117,7 @@ export default function ContactsTable({ }: { current_campaign?: MiniCampaign; // Scope the list to one segment's members (the segment detail page). - segment?: { id: string; name: string }; + segment?: { id: string; name: string; color?: string }; }) { const confirm = useConfirm(); const segmentMembers = useSetSegmentMembers(); @@ -487,7 +487,7 @@ export default function ContactsTable({ ? "Pick people from your contacts, import a file, or add one by hand. The linked segments could not be loaded." : "Pick people from your contacts, link a segment, import a file, or add one by hand." : segment - ? "Nobody matches its conditions yet. Adjust them or pin contacts in." + ? "Nothing matches it yet. Pin people in from your contacts, import a file, or add one by hand." : "Add or upload contacts to get started." } emptyCta={ @@ -532,6 +532,29 @@ export default function ContactsTable({ Import file + ) : segment ? ( +
+ } + onClick={() => setFromContactsOpen(true)} + > + Add contacts + + } + onClick={() => setImportOpen(true)} + > + Import file + + } + onClick={() => setNewOpen(true)} + > + New contact + +
) : ( } @@ -931,8 +954,9 @@ export default function ContactsTable({ setImportOpen(false)} + lockedSegment={segment} /> - setSyncOpen(false)} /> + setSyncOpen(false)} segment={segment} /> ); }