'use client'; import { ChevronLeft, Plus } from 'lucide-react'; import { useRouter, usePathname } from 'next/navigation'; import type { Route } from 'next'; import { useUIStore } from '@/stores/ui-store'; import { useMobileChrome } from '@/components/layout/mobile/mobile-layout-provider'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Separator } from '@/components/ui/separator'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Breadcrumbs } from '@/components/layout/breadcrumbs'; import { CommandSearch } from '@/components/search/command-search'; import { Inbox } from '@/components/layout/inbox'; import { UserMenu } from '@/components/layout/user-menu'; import type { Port } from '@/lib/db/schema/ports'; interface TopbarProps { ports: Port[]; user?: { name: string; email: string }; } export function Topbar({ ports, user }: TopbarProps) { const router = useRouter(); const pathname = usePathname(); const currentPortSlug = useUIStore((s) => s.currentPortSlug); const base = currentPortSlug ? `/${currentPortSlug}` : ''; // Reuse the existing per-page chrome state (originally built for the // mobile topbar) so any detail page that already declares // `showBackButton: true` automatically gets the back affordance on // desktop too. Saves duplicating the wiring across N detail headers. const { showBackButton: mobileShowBack } = useMobileChrome(); // Auto-show on entity-detail pages: `/[portSlug]/[section]/[id]` and // deeper. Top-level lists like `/[portSlug]/clients` stay clean. // The mobile-chrome flag still wins when a page explicitly opts in. // Pages that already render their own "back to X" link inline // (residential interest detail, expense scan flow, etc.) opt OUT // by setting the chrome flag to false on mount — the flag override // path here lets them suppress this auto-show. const segments = pathname.split('/').filter(Boolean); const isDeepPage = segments.length > 2; const showBackButton = mobileShowBack || isDeepPage; return ( // Three-column grid: breadcrumbs left, search center, actions right. // The brand logo lives in the sidebar header (per design feedback) so the // topbar center is dedicated to the global search bar.
{/* LEFT: optional back button + breadcrumbs / page title */}
{showBackButton && ( )}
{/* CENTER: global search - capped width and horizontally centered inside its grid slot so it sits visually in the middle of the topbar regardless of breadcrumb / action-row width. */}
{/* RIGHT: action row */}
{/* + New dropdown */} Create {/* Each item routes to the list page with ?create=1 so the relevant create sheet pops automatically (see useCreateFromUrl). The legacy `/clients/new`-style routes this menu used to push to landed on the dynamic detail page with id="new" and silently 404'd. */} {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} router.push(`${base}/clients?create=1` as any)}> New Client {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} router.push(`${base}/yachts?create=1` as any)}> New Yacht {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} router.push(`${base}/companies?create=1` as any)}> New Company {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} router.push(`${base}/interests?create=1` as any)}> New Interest {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} router.push(`${base}/expenses?create=1` as any)}> New Expense {/* /reminders 301s to /inbox#reminders (the merged page) and the server redirect strips the query string, so point straight at the new path. The Reminders section's useCreateFromUrl handler still picks up ?create=1. */} router.push(`${base}/inbox?create=1#reminders` as unknown as Route)} > New Reminder {/* Unified inbox - combines system alerts (operational) and personal notifications (user-targeted) into a single bell with two tabs. Replaces the previous AlertBell + NotificationBell pair. */} {/* User menu - single source of truth for the profile dropdown. Same component is mounted in the sidebar footer so the menu items (incl. port switcher) stay consistent across triggers. */} {(user?.name ?? 'U').slice(0, 1).toUpperCase()} } />
); }