fix(layout): mobile UX cleanup + interest-stage legend popover

Mobile UX:
- Hide ColumnPicker on `< sm` viewports (cards, no columns to toggle).
- Hide kanban toggle in interest list on mobile and snap viewMode back
  to 'table' if the persisted choice was 'board'.
- Drop dead "Inbox" link from the More-sheet (email/IMAP feature is
  deferred per sidebar.tsx note).
- Repoint Notifications nav from `/notifications` (no page.tsx — 404)
  to `/notifications/preferences` and re-label as "Notification
  preferences" (the bell stays the surface for actual notifications).
- Hide Website Analytics on both desktop sidebar and mobile More-sheet
  when Umami isn't configured for the port (`useUmamiActive()`).

Interests:
- New `<StageLegend>` popover button in the filter row decodes the
  card stripe colours to pipeline stage names, kept in sync with
  `STAGE_DOT` automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 04:11:01 +02:00
parent 82fd75081a
commit 19622985b5
5 changed files with 99 additions and 9 deletions

View File

@@ -34,6 +34,7 @@ import { Separator } from '@/components/ui/separator';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { UserMenu } from '@/components/layout/user-menu';
import { useUmamiActive } from '@/components/website-analytics/use-website-analytics';
import type { UserPortRole } from '@/lib/db/schema/users';
import type { Role } from '@/lib/db/schema/users';
import type { Port } from '@/lib/db/schema/ports';
@@ -76,6 +77,8 @@ interface NavSection {
marinaRequired?: boolean;
/** When true, only render if the user has residential-side access. */
residentialRequired?: boolean;
/** When true, only render if Umami analytics is wired up for the port. */
umamiRequired?: boolean;
}
function buildNavSections(portSlug: string | undefined): NavSection[] {
@@ -140,10 +143,12 @@ function buildNavSections(portSlug: string | undefined): NavSection[] {
{
title: 'Insights',
marinaRequired: true,
umamiRequired: true,
items: [
// Marketing / Umami integration. Distinct from the main dashboard
// (which is sales-focused) so the audience and the metrics don't
// compete for visual real estate.
// compete for visual real estate. Whole section is hidden when
// Umami isn't wired up — see SidebarContent.
{
href: `${base}/website-analytics`,
label: 'Website analytics',
@@ -250,6 +255,8 @@ function SidebarContent({
const pathname = usePathname();
const [adminExpanded, setAdminExpanded] = useState(true);
const sections = buildNavSections(portSlug);
const umami = useUmamiActive('today');
const umamiConfigured = umami.data?.error !== 'umami_not_configured';
// Small label under the user identity when the user has access to more
// than one port — disambiguates which port is currently active without
@@ -324,6 +331,7 @@ function SidebarContent({
if (section.adminRequired && !hasAdminAccess) return null;
if (section.marinaRequired && !hasMarinaAccess) return null;
if (section.residentialRequired && !hasResidentialAccess) return null;
if (section.umamiRequired && !umamiConfigured) return null;
return (
<div key={section.title}>