import { Breadcrumbs } from '@/components/breadcrumbs'; import { Icon } from '@/components/icon'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { NavigationMenu, NavigationMenuItem, NavigationMenuList, navigationMenuTriggerStyle, } from '@/components/ui/navigation-menu'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, } from '@/components/ui/sheet'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { UserMenuContent } from '@/components/user-menu-content'; import { useInitials } from '@/hooks/use-initials'; import { cn, isSameUrl, resolveUrl } from '@/lib/utils'; import { dashboard } from '@/routes'; import { type BreadcrumbItem, type NavItem, type SharedData } from '@/types'; import { Link, usePage } from '@inertiajs/react'; import { Bell, BookOpen, Folder, LayoutGrid, Menu, Search, UserPlus } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import AppLogo from './app-logo'; import AppLogoIcon from './app-logo-icon'; const mainNavItems: NavItem[] = [ { title: 'Dashboard', href: dashboard(), icon: LayoutGrid, }, ]; const rightNavItems: NavItem[] = [ { title: 'Repository', href: 'https://github.com/laravel/react-starter-kit', icon: Folder, }, { title: 'Documentation', href: 'https://laravel.com/docs/starter-kits#react', icon: BookOpen, }, ]; const activeItemStyles = 'text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100'; interface AppHeaderProps { breadcrumbs?: BreadcrumbItem[]; } interface PendingInvoiceNotification { id: number; client_id: number | null; invoice_no: string; pending_sql_acc_code?: string | null; pending_client_name?: string | null; requires_client?: boolean; start_date: string | null; end_date: string | null; management_fee: string | number | null; media_fee: string | number | null; nett_amount: string | number | null; total_spending: string | number | null; client?: { name: string | null; customer_id: string | null; } | null; } function InvoiceNotifications() { const [invoices, setInvoices] = useState([]); const [count, setCount] = useState(0); const [isLoading, setIsLoading] = useState(true); const currencyFormatter = useMemo( () => new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }), [], ); useEffect(() => { let isMounted = true; const loadPendingInvoices = async () => { try { const response = await fetch('/api/customer-invoices/pending', { headers: { Accept: 'application/json', }, credentials: 'same-origin', }); if (!response.ok) { throw new Error('Unable to load pending invoices.'); } const data = await response.json(); if (isMounted) { setInvoices(data.invoices ?? []); setCount(data.count ?? 0); } } catch { if (isMounted) { setInvoices([]); setCount(0); } } finally { if (isMounted) { setIsLoading(false); } } }; loadPendingInvoices(); return () => { isMounted = false; }; }, []); const formatAmount = (amount: string | number | null) => { const value = Number(amount ?? 0); return currencyFormatter.format(Number.isFinite(value) ? value : 0); }; return (
Pending invoice approvals
{count} invoice{count === 1 ? '' : 's'} waiting for approval
{isLoading ? (
Loading pending invoices...
) : invoices.length === 0 ? (
No invoices are waiting for approval.
) : ( {invoices.map((invoice) => ( ))}
Invoice Client SQL Acc Media Nett Period Action
{invoice.invoice_no} {invoice.client?.name ?? invoice.pending_client_name ?? '-'} {invoice.pending_sql_acc_code ?? '-'} {formatAmount(invoice.media_fee)} {formatAmount(invoice.nett_amount)} {invoice.start_date ?? '-'} to{' '} {invoice.end_date ?? '-'} {invoice.requires_client ? ( Link client ) : null}
)}
); } export function AppHeader({ breadcrumbs = [] }: AppHeaderProps) { const page = usePage(); const { auth } = page.props; const getInitials = useInitials(); return ( <>
{/* Mobile Menu */}
Navigation Menu
{mainNavItems.map((item) => ( {item.icon && ( )} {item.title} ))}
{rightNavItems.map((item) => ( {item.icon && ( )} {item.title} ))}
{/* Desktop Navigation */}
{mainNavItems.map((item, index) => ( {item.icon && ( )} {item.title} {isSameUrl(page.url, item.href) && (
)}
))}
{rightNavItems.map((item) => ( {item.title} {item.icon && ( )}

{item.title}

))}
{/* {breadcrumbs.length > 1 && ( */}
{/* )} */} ); }