From f8fcb8d8ada7838d03654758f2ecfac57fb76d5f Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 10 May 2026 12:30:56 +0200 Subject: [PATCH] feat(documents): admin-configurable Expired tab visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New documents_show_expired_tab system setting (default true). Public read via GET /api/v1/documents/feature-flags (gated on documents.view so reps can read it without holding manage_settings). When off, the Expired tab is hidden from the documents hub — useful when expired EOIs are noise that distracts reps from active deals. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../api/v1/documents/feature-flags/route.ts | 20 +++++++++++++++++++ .../admin/settings/settings-manager.tsx | 8 ++++++++ src/components/documents/documents-hub.tsx | 9 ++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/app/api/v1/documents/feature-flags/route.ts diff --git a/src/app/api/v1/documents/feature-flags/route.ts b/src/app/api/v1/documents/feature-flags/route.ts new file mode 100644 index 00000000..9e5d9c60 --- /dev/null +++ b/src/app/api/v1/documents/feature-flags/route.ts @@ -0,0 +1,20 @@ +import { NextResponse } from 'next/server'; + +import { withAuth, withPermission } from '@/lib/api/helpers'; +import { errorResponse } from '@/lib/errors'; +import { getSetting } from '@/lib/services/settings.service'; + +export const GET = withAuth( + withPermission('documents', 'view', async (_req, ctx) => { + try { + const showExpired = await getSetting('documents_show_expired_tab', ctx.portId); + return NextResponse.json({ + data: { + showExpiredTab: showExpired?.value !== false, // default true + }, + }); + } catch (error) { + return errorResponse(error); + } + }), +); diff --git a/src/components/admin/settings/settings-manager.tsx b/src/components/admin/settings/settings-manager.tsx index ce2fd236..39f9e015 100644 --- a/src/components/admin/settings/settings-manager.tsx +++ b/src/components/admin/settings/settings-manager.tsx @@ -210,6 +210,14 @@ const KNOWN_SETTINGS: Array<{ type: 'boolean', defaultValue: true, }, + { + key: 'documents_show_expired_tab', + label: 'Documents — show Expired tab', + description: + 'When off, the Expired tab on the documents hub is hidden. Use this when expired EOIs are noise that distracts reps from active deals.', + type: 'boolean', + defaultValue: true, + }, ]; export function SettingsManager() { diff --git a/src/components/documents/documents-hub.tsx b/src/components/documents/documents-hub.tsx index ee270e93..616be8af 100644 --- a/src/components/documents/documents-hub.tsx +++ b/src/components/documents/documents-hub.tsx @@ -119,6 +119,13 @@ export function DocumentsHub({ portSlug, initialTab = 'all' }: DocumentsHubProps staleTime: 30_000, }); + const { data: flagsResp } = useQuery<{ data: { showExpiredTab: boolean } }>({ + queryKey: ['documents', 'feature-flags'], + queryFn: () => apiFetch('/api/v1/documents/feature-flags'), + staleTime: 5 * 60 * 1000, + }); + const showExpiredTab = flagsResp?.data.showExpiredTab ?? true; + useRealtimeInvalidation({ 'document:created': [['documents']], 'document:updated': [['documents']], @@ -275,7 +282,7 @@ export function DocumentsHub({ portSlug, initialTab = 'all' }: DocumentsHubProps }} > - {documentsHubTabs.map((t) => ( + {documentsHubTabs.filter((t) => t !== 'expired' || showExpiredTab).map((t) => ( {TAB_LABELS[t]} {t !== 'all' && counts[t] > 0 ? (