71 lines
2.7 KiB
TypeScript
71 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { Bell } from "lucide-react";
|
|
import { usePathname } from "next/navigation";
|
|
|
|
/** Pages that render their own inline bell (see InlineNotificationBell) as part of a proper header — the shell's own floating bell steps aside there instead of sitting on top of it. */
|
|
const PAGES_WITH_INLINE_BELL = [
|
|
"/staff",
|
|
"/owner/calendar",
|
|
"/staff/current",
|
|
"/staff/clients",
|
|
"/staff/settings",
|
|
"/appointments",
|
|
"/loyalty",
|
|
"/settings",
|
|
"/owner",
|
|
];
|
|
|
|
function badge(unreadCount: number) {
|
|
if (unreadCount === 0) return null;
|
|
return (
|
|
<span className="bg-danger absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-[10px] font-bold text-white">
|
|
{unreadCount > 9 ? "9+" : unreadCount}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fixed top-right on every screen inside the shell that renders it (see
|
|
* StaffShell and (customer)/layout.tsx) — unread count is fetched
|
|
* server-side by the layout and passed in, not polled client-side, so it
|
|
* only ever reflects "as of this page load/navigation". Real-time badge
|
|
* updates without a reload would need a persistent connection this phase
|
|
* doesn't build (see docs/phase-7-summary.md, "Known limitations").
|
|
*
|
|
* Steps aside (renders nothing) on pages that build their own proper
|
|
* header — a fixed top-right bell has nowhere sensible to sit once a page
|
|
* already has its own top-right control (e.g. Calendar's "New" button) —
|
|
* see InlineNotificationBell below, used in exactly those pages' headers.
|
|
*/
|
|
export function NotificationBell({ href, unreadCount }: { href: string; unreadCount: number }) {
|
|
const pathname = usePathname();
|
|
if (PAGES_WITH_INLINE_BELL.includes(pathname)) return null;
|
|
|
|
return (
|
|
<Link
|
|
href={href}
|
|
aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : "Notifications"}
|
|
className="fixed top-4 right-4 z-40 flex h-10 w-10 items-center justify-center rounded-full border border-line bg-white shadow-sm"
|
|
>
|
|
<Bell className="h-4 w-4" aria-hidden="true" />
|
|
{badge(unreadCount)}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
/** Same look as the fixed bell above, but a normal in-flow element — for a page's own TopNav `leftAction`, not the shell's floating corner. */
|
|
export function InlineNotificationBell({ href, unreadCount }: { href: string; unreadCount: number }) {
|
|
return (
|
|
<Link
|
|
href={href}
|
|
aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : "Notifications"}
|
|
className="relative flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-line"
|
|
>
|
|
<Bell className="h-4 w-4" aria-hidden="true" />
|
|
{badge(unreadCount)}
|
|
</Link>
|
|
);
|
|
}
|