Files
pn-new-crm/src/components/layout/mobile/more-sheet.tsx

153 lines
5.2 KiB
TypeScript

'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import {
Bookmark,
Building2,
FileSignature,
MailQuestion,
FileText,
Globe,
Home,
Inbox,
Receipt,
Settings,
Shield,
Ship,
} from 'lucide-react';
import {
Drawer,
DrawerContent,
DrawerHeader,
DrawerTitle,
DrawerClose,
} from '@/components/shared/drawer';
import { useUmamiActive } from '@/components/website-analytics/use-website-analytics';
type MoreItem = {
label: string;
icon: typeof Building2;
segment: string;
};
type MoreGroup = {
label: string;
items: MoreItem[];
};
// Logical grouping (vs alphabetical or frequency-ranked): keeps a stable
// spatial layout - reps' muscle memory survives - while making the
// "kind of thing" each tile is explicit. Three sections:
// - Records: entity lists (people, vessels, properties)
// - Operations: daily-use action surfaces
// - Configuration: port-level setup, hidden from most reps
//
// Interests stays here (not bottom nav) to dodge the Clients-vs-
// Interests UX confusion. Inbox replaces the previously-separate
// Alerts + Reminders entries (merged 2026-05-11). Website analytics
// is filtered out below when Umami isn't wired up for this port.
const MORE_GROUPS: MoreGroup[] = [
{
label: 'Records',
items: [
{ label: 'Documents', icon: FileSignature, segment: 'documents' },
{ label: 'Interests', icon: Bookmark, segment: 'interests' },
{ label: 'Inquiries', icon: MailQuestion, segment: 'inquiries' },
{ label: 'Yachts', icon: Ship, segment: 'yachts' },
{ label: 'Companies', icon: Building2, segment: 'companies' },
{ label: 'Residential', icon: Home, segment: 'residential/clients' },
],
},
{
label: 'Operations',
items: [
{ label: 'Alerts & Reminders', icon: Inbox, segment: 'inbox' },
// M-U15: invoices was missing from the mobile nav - reps doing
// mobile follow-ups had to type the URL by hand.
{ label: 'Invoices', icon: FileText, segment: 'invoices' },
{ label: 'Expenses', icon: Receipt, segment: 'expenses' },
],
},
{
label: 'Configuration',
items: [
{ label: 'Website analytics', icon: Globe, segment: 'website-analytics' },
{ label: 'Settings', icon: Settings, segment: 'settings' },
{ label: 'Admin', icon: Shield, segment: 'admin' },
],
},
];
export function MoreSheet({
open,
onOpenChange,
residentialModuleEnabled = true,
}: {
open: boolean;
onOpenChange: (next: boolean) => void;
/** Per-port residential-module gate, resolved SSR-side in the shell.
* Hides the Residential tile when the module is off. Defaults to true
* so a missing value keeps the feature visible (registry default). */
residentialModuleEnabled?: boolean;
}) {
const pathname = usePathname();
const portSlug = pathname.split('/').filter(Boolean)[0] ?? 'port-nimara';
// Hide "Website analytics" if Umami isn't wired up for this port - the
// dedicated tile on the dashboard already does the same.
const umami = useUmamiActive('today');
const umamiConfigured = !umami.isLoading && umami.data?.notConfigured !== true;
// Per-group filter: keep only the items relevant to this port's state.
const groups = MORE_GROUPS.map((g) => ({
...g,
items: g.items.filter((item) => {
if (item.segment === 'website-analytics') return umamiConfigured;
if (item.segment === 'residential/clients') return residentialModuleEnabled;
return true;
}),
})).filter((g) => g.items.length > 0);
return (
<Drawer open={open} onOpenChange={onOpenChange}>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>More</DrawerTitle>
</DrawerHeader>
<div className="space-y-4 px-3 pb-4">
{groups.map((group) => (
<section key={group.label}>
<h3 className="mb-1.5 px-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
{group.label}
</h3>
<ul className="grid grid-cols-3 gap-2">
{group.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}
// min-h-[88px] guarantees a 44pt vertical touch
// target (Apple HIG); icon + label centered.
className="flex min-h-[88px] flex-col items-center justify-center gap-1.5 rounded-md py-3 px-2 text-center text-xs text-foreground hover:bg-accent active:bg-accent/80"
>
<Icon className="size-7 text-muted-foreground" aria-hidden />
<span className="font-medium leading-tight">{item.label}</span>
</Link>
</DrawerClose>
</li>
);
})}
</ul>
</section>
))}
</div>
</DrawerContent>
</Drawer>
);
}