Files
pn-new-crm/src/components/layout/mobile/more-sheet.tsx
Matt Ciaccio a792d9a182
Some checks failed
Build & Push Docker Images / lint (push) Successful in 1m11s
Build & Push Docker Images / build-and-push (push) Failing after 5m45s
fix(ux): pass-2 audit fixes — admin grouping, Duplicates entry, header tooltips
Three small but high-leverage fixes from the second audit pass on main:

Admin index (src/app/(dashboard)/[portSlug]/admin/page.tsx):
  - Grouped 21 sections into 7 categories: Access, Configuration, Content,
    Data Quality, Operations, Tenancy, Integrations. Each group has a
    one-line description so first-time admins can orient themselves
    without reading every card.
  - Added the missing Duplicates entry (links to /admin/duplicates from
    the dedup-migration work) under Data Quality.

More sheet (mobile bottom-drawer nav):
  - "Email" -> "Inbox". The page that opens is an email-inbox surface
    (Inbox + Accounts tabs), not a generic email composer. The previous
    label was ambiguous.

Interest detail header (Won / Lost outcome buttons):
  - Added title="Mark as won" / "Close as lost" so the icon-only buttons
    on mobile have a tooltip on long-press / desktop hover.
  - Tightened mobile padding (px-2 vs px-2.5) so the full-text desktop
    labels still fit on sm+ without re-introducing a regression where a
    visible mobile "Won"/"Lost" inline label crowded the right cluster
    enough to push Email/Call/WhatsApp action chips into a vertical
    stack.

Verification: 0 tsc errors, 926/926 vitest passing, lint clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 16:35:32 +02:00

91 lines
2.7 KiB
TypeScript

'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import {
BarChart3,
Bell,
Bookmark,
Building2,
FileText,
Mail,
Receipt,
Settings,
Shield,
ShieldAlert,
Ship,
} from 'lucide-react';
import {
Drawer,
DrawerContent,
DrawerHeader,
DrawerTitle,
DrawerClose,
} from '@/components/shared/drawer';
type MoreItem = {
label: string;
icon: typeof Building2;
segment: string;
};
// Order: most-likely overflow targets first. Interests is here (rather
// than the bottom row) to dodge the Clients-vs-Interests UX confusion;
// reps reach the active deals via the Interests tab on a client detail
// (or via the new bottom-sheet drawer). Yachts is asset-record traffic
// best reached contextually from inside an interest or client.
const MORE_ITEMS: MoreItem[] = [
{ label: 'Interests', icon: Bookmark, segment: 'interests' },
{ label: 'Yachts', icon: Ship, segment: 'yachts' },
{ label: 'Companies', icon: Building2, segment: 'companies' },
{ label: 'Invoices', icon: FileText, segment: 'invoices' },
{ label: 'Expenses', icon: Receipt, segment: 'expenses' },
{ label: 'Inbox', icon: Mail, segment: 'email' },
{ label: 'Alerts', icon: ShieldAlert, segment: 'alerts' },
{ label: 'Reports', icon: BarChart3, segment: 'reports' },
{ label: 'Reminders', icon: Bell, segment: 'reminders' },
{ label: 'Settings', icon: Settings, segment: 'settings' },
{ label: 'Admin', icon: Shield, segment: 'admin' },
];
export function MoreSheet({
open,
onOpenChange,
}: {
open: boolean;
onOpenChange: (next: boolean) => void;
}) {
const pathname = usePathname();
const portSlug = pathname.split('/').filter(Boolean)[0] ?? 'port-nimara';
return (
<Drawer open={open} onOpenChange={onOpenChange}>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>More</DrawerTitle>
</DrawerHeader>
<ul className="grid grid-cols-3 gap-1 px-3 pb-4">
{MORE_ITEMS.map((item) => {
const Icon = item.icon;
return (
<li key={item.segment}>
<DrawerClose asChild>
<Link
// eslint-disable-next-line @typescript-eslint/no-explicit-any
href={`/${portSlug}/${item.segment}` as any}
className="flex flex-col items-center justify-center gap-1.5 rounded-md py-4 text-xs text-foreground hover:bg-accent"
>
<Icon className="size-6 text-muted-foreground" aria-hidden />
<span className="font-medium">{item.label}</span>
</Link>
</DrawerClose>
</li>
);
})}
</ul>
</DrawerContent>
</Drawer>
);
}