import { Search, Bell, Plus, Menu, RefreshCw } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useSidebarStore } from "@/lib/stores/use-sidebar-store"; import { useApiDomain } from "@/lib/stores/use-active-domain-store"; import { useAuthStore } from "@/lib/stores/use-auth-store"; import { useApiQuery } from "@/lib/api"; import { useNavigate } from "@tanstack/react-router"; import { useQueryClient } from "@tanstack/react-query"; import { DomainPicker } from "@/components/shell/domain-picker"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { formatDistanceToNow } from "date-fns"; import type { NotificationsResponse } from "@/lib/types"; const ACTION_LABELS: Record = { created: "created", updated: "updated", deleted: "deleted", completed: "completed", }; function readableEntityType(entityType: string): string { return entityType .replace(/_/g, " ") .replace(/\b\w/g, (ch) => ch.toUpperCase()); } export function Topbar() { const { setMobileOpen } = useSidebarStore(); const queryClient = useQueryClient(); const navigate = useNavigate(); const domainId = useApiDomain(); const user = useAuthStore((s) => s.user); const userName = user?.name || "User"; const userEmail = user?.email || ""; const userInitials = (user?.name || user?.email || "U").slice(0, 2).toUpperCase(); const openPalette = () => { document.dispatchEvent(new CustomEvent("open-command-palette")); }; const { data: notificationsData } = useApiQuery( ["notifications", domainId], "/notifications?workspace_id=" + encodeURIComponent(domainId), { enabled: !!domainId, refetchInterval: 60_000 } ); const notifications = notificationsData?.items || []; const count = notificationsData?.count || 0; const badgeLabel = count > 99 ? "99+" : String(count); const tooltipText = count === 0 ? "No notifications" : `${count} unread notification${count === 1 ? "" : "s"}`; return (
{/* Mobile menu */} {/* Search input */}
{/* Domain picker */} {/* Right side */}
{/* Quick add */} Quick add (Cmd+K) {/* Notifications bell */} {tooltipText}
Notifications
{notifications.length === 0 ? (
No notifications
) : ( notifications.slice(0, 10).map((n) => ( {readableEntityType(n.entityType)}{" "} {ACTION_LABELS[n.action] || n.action} {n.actor} · {formatDistanceToNow(new Date(n.createdAt), { addSuffix: true })} )) )}
{/* User avatar */}
{userInitials}
{userName} {userEmail}
navigate({ to: "/settings" })}> Profile { document.dispatchEvent(new CustomEvent("open-command-palette")); }}> Command palette { fetch("/api/auth/logout", { method: "POST" }).then(() => { window.location.href = "/login"; }); }}> Log out
); }