wulf-pulse/components/mobile/MoreDrawer.tsx
lorentz 9658640c04 fix(04-01): restore phase 2/3 work lost by worktree soft-reset
The soft reset to 77073ba inadvertently staged deletions of all phase 2
and 3 artifacts. This commit restores them from their source commits so
subsequent task commits build on the complete prior-phase foundation:
- components/mobile/{BottomNav,HeaderBar,KpiCardMobile,MoreDrawer,NeedsAttentionStrip,WorkerStatusRow}
- app/mobile/layout.tsx, dashboard/page.tsx, analyzer/page.tsx
- app/api/mobile/dashboard/route.ts
- All .planning/** files from phases 01-04
- CLAUDE.md, app/layout.tsx, app/styles/brand.css, public/manifest.json
2026-05-03 18:01:14 -04:00

166 lines
5.7 KiB
TypeScript

'use client';
/* MoreDrawer — phase 02 (DRAWER-01..05).
*
* shadcn Sheet (side="right") with three top-to-bottom sections:
* 1. Mobile sections — Engagement (in-shell route, no ExternalLink hint)
* 2. Full site — desktop-only routes, each with ExternalLink hint
* 3. Account — current user (read-only) + Sign out
*
* Open state is controlled by the parent so the header avatar AND the
* bottom-nav More cell can both trigger this single drawer. */
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import {
ExternalLink,
FileText,
Server,
HardDrive,
BarChart3,
Settings,
Users,
LogOut,
} from 'lucide-react';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetClose,
} from '@/components/ui/sheet';
import { useSession, signOut } from '@/lib/auth-client';
import { toast } from 'sonner';
const MOBILE_SECTIONS = [
{ href: '/mobile/engagement', label: 'Engagement', icon: Users },
];
const DESKTOP_LINKS = [
{ href: '/quotes', label: 'Quotes', icon: FileText },
{ href: '/configuration-items', label: 'Configuration Items', icon: Server },
{ href: '/backup-status', label: 'Backup Status', icon: HardDrive },
{ href: '/admin/ticket-digest', label: 'Ticket Digest', icon: BarChart3 },
{ href: '/admin/sync', label: 'Admin / Sync', icon: Settings },
];
interface MoreDrawerProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function MoreDrawer({ open, onOpenChange }: MoreDrawerProps) {
const router = useRouter();
const { data: session } = useSession();
const user = session?.user as
| { name?: string; email?: string; image?: string | null }
| undefined;
const initials = (user?.name ?? user?.email ?? '?')
.split(/[\s@]/)
.filter(Boolean)
.slice(0, 2)
.map((p) => p[0]?.toUpperCase())
.join('');
async function handleSignOut() {
try {
await signOut();
router.push('/auth/sign-in');
} catch (e) {
toast.error('Sign out failed');
console.error('Sign out failed:', e);
}
}
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent side="right" className="w-80 sm:max-w-sm flex flex-col">
<SheetHeader>
<SheetTitle>Menu</SheetTitle>
<SheetDescription className="sr-only">
Navigation, full-site links, and account actions.
</SheetDescription>
</SheetHeader>
{/* Section 1: Mobile sections (DRAWER-03) */}
<div className="px-4">
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
Mobile sections
</p>
<div className="rounded-2xl border divide-y overflow-hidden">
{MOBILE_SECTIONS.map(({ href, label, icon: Icon }) => (
<SheetClose asChild key={href}>
<Link
href={href}
className="flex items-center gap-3 px-4 py-3 hover:bg-accent transition-colors"
>
<Icon className="w-4 h-4 text-muted-foreground shrink-0" />
<span className="text-sm flex-1">{label}</span>
</Link>
</SheetClose>
))}
</div>
</div>
{/* Section 2: Full site (DRAWER-04) */}
<div className="px-4">
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
Full site
</p>
<div className="rounded-2xl border divide-y overflow-hidden">
{DESKTOP_LINKS.map(({ href, label, icon: Icon }) => (
<SheetClose asChild key={href}>
<Link
href={href}
className="flex items-center gap-3 px-4 py-3 hover:bg-accent transition-colors"
>
<Icon className="w-4 h-4 text-muted-foreground shrink-0" />
<span className="text-sm flex-1">{label}</span>
<ExternalLink className="w-3.5 h-3.5 text-muted-foreground shrink-0" />
</Link>
</SheetClose>
))}
</div>
</div>
{/* Section 3: Account (DRAWER-05) */}
<div className="px-4 mt-auto pb-safe">
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
Account
</p>
<div className="rounded-2xl border overflow-hidden">
{user && (
<div className="flex items-center gap-3 px-4 py-3 border-b">
<span className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-primary/15 text-primary text-xs font-semibold shrink-0">
{initials}
</span>
<div className="flex-1 min-w-0">
{user.name && (
<p className="text-sm font-medium leading-tight truncate">
{user.name}
</p>
)}
{user.email && (
<p className="text-xs text-muted-foreground truncate" title={user.email}>
{user.email}
</p>
)}
</div>
</div>
)}
<button
type="button"
onClick={handleSignOut}
className="w-full flex items-center gap-3 px-4 py-3 text-destructive hover:bg-destructive/10 transition-colors"
>
<LogOut className="w-4 h-4 shrink-0" />
<span className="text-sm">Sign out</span>
</button>
</div>
</div>
</SheetContent>
</Sheet>
);
}