import { DevDatabaseLink } from "@agent-native/core/client/db-admin"; import { useActionQuery } from "@agent-native/core/client/hooks"; import { LanguagePicker, useT } from "@agent-native/core/client/i18n"; import { openCommandMenu } from "@agent-native/core/client/navigation"; import { OrgSwitcher } from "@agent-native/core/client/org"; import { FeedbackButton } from "@agent-native/core/client/ui"; import { SidebarFooterActions } from "@agent-native/toolkit/app-shell"; import { IconAlertTriangle, IconBuilding, IconChartBar, IconChecklist, IconLayoutBoard, IconLayoutDashboard, IconLayoutSidebarLeftCollapse, IconLayoutSidebarLeftExpand, IconList, IconMessageCircle, IconPencilCheck, IconRoute, IconSearch, IconSettings, IconStar, IconTable, IconUsers, } from "@tabler/icons-react"; import { useEffect, useState } from "react"; import { Link, NavLink, useLocation } from "react-router"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { getCollapseStorage, readSidebarCollapsed, writeSidebarCollapsed, } from "./sidebar-collapse"; import { normalizeCrmLists, normalizeCrmSavedViews, savedViewHref, type CrmSidebarList, type CrmSidebarSavedView, } from "./sidebar-lists"; const primaryNav = [ { to: "/", labelKey: "navigation.overview", icon: IconLayoutDashboard, end: true, }, { to: "/accounts", labelKey: "navigation.accounts", icon: IconBuilding }, { to: "/people", labelKey: "navigation.people", icon: IconUsers }, { to: "/opportunities", labelKey: "navigation.opportunities", icon: IconRoute, }, { to: "/lists", labelKey: "navigation.lists", icon: IconList }, { to: "/tasks", labelKey: "navigation.tasks", icon: IconChecklist }, { to: "/proposals", labelKey: "navigation.proposals", icon: IconPencilCheck }, { to: "/dashboard", labelKey: "navigation.dashboard", icon: IconChartBar }, ]; const footerNav = [ { to: "/ask", labelKey: "navigation.askCrm", icon: IconMessageCircle }, { to: "/settings/connections", labelKey: "navigation.connections", icon: IconSettings, }, ]; function itemClasses(isActive: boolean, collapsed: boolean) { return cn( "flex items-center rounded-md text-sm", collapsed ? "h-9 w-9 justify-center" : "h-8 gap-2 px-2", isActive ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground" : "text-sidebar-foreground/80 hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground", ); } function CollapsibleTooltip({ collapsed, label, children, }: { collapsed: boolean; label: string; children: React.ReactNode; }) { if (!collapsed) return <>{children}; return ( {children} {label} ); } function SidebarSection({ heading, children, }: { heading: string; children: React.ReactNode; }) { return (

{heading}

{children}
); } function ListRow({ to, label, icon: Icon, collapsed, onNavigate, }: { to: string; label: string; icon: typeof IconList; collapsed: boolean; onNavigate?: () => void; }) { return ( itemClasses(isActive, collapsed)} > {!collapsed && {label}} ); } export function CrmSidebar({ onNavigate }: { onNavigate?: () => void }) { const t = useT(); const location = useLocation(); const [collapsed, setCollapsed] = useState(() => readSidebarCollapsed(getCollapseStorage()), ); useEffect(() => { writeSidebarCollapsed(getCollapseStorage(), collapsed); }, [collapsed]); const listsQuery = useActionQuery( "list-crm-lists" as never, { limit: 50 } as never, { staleTime: 30_000, retry: false } as never, ); const viewsQuery = useActionQuery( "list-crm-saved-views" as never, { limit: 50 } as never, { staleTime: 30_000, retry: false } as never, ); const lists: CrmSidebarList[] = normalizeCrmLists(listsQuery.data); const views: CrmSidebarSavedView[] = normalizeCrmSavedViews(viewsQuery.data); const favorites = views.filter((view) => view.pinned); const unpinnedViews = views.filter((view) => !view.pinned); // An action that has not shipped yet and one that failed are the same 404 to // the browser, so surface the failure instead of rendering an empty section. const loadFailed = listsQuery.isError || viewsQuery.isError; const settled = !listsQuery.isPending && !viewsQuery.isPending; const collapseButton = ( {collapsed ? t("navigation.expandSidebar") : t("navigation.collapseSidebar")} ); const searchButton = ( {t("navigation.search")} ); return ( ); }