diff --git a/apps/console/src/components/AppSidebar.tsx b/apps/console/src/components/AppSidebar.tsx index 36cee0c3a..7a190ad8c 100644 --- a/apps/console/src/components/AppSidebar.tsx +++ b/apps/console/src/components/AppSidebar.tsx @@ -1,16 +1,5 @@ import * as React from "react"; import { Suspense, useEffect } from "react"; -import { useParams } from "react-router"; -import { - BookOpen, - Users, - ToyBrick, - LifeBuoy, - Send, - Settings, - Building, - FileText, -} from "lucide-react"; import { graphql, PreloadedQuery, @@ -18,82 +7,12 @@ import { useQueryLoader, } from "react-relay"; -import { NavMain } from "@/components/NavMain"; -import { NavSecondary } from "@/components/NavSecondary"; import { NavUser } from "@/components/NavUser"; -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarHeader, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from "@/components/ui/sidebar"; +import { Sidebar } from "@/components/ui/sidebar"; import type { AppSidebarQuery as AppSidebarQueryType } from "./__generated__/AppSidebarQuery.graphql"; import { OrganizationSwitcher } from "@/components/OrganizationSwitcher"; - -function getNavItems(organizationId?: string) { - // Always return the same structure, but with or without URLs depending on whether an organization is selected - return { - navMain: [ - { - title: "Frameworks", - url: organizationId - ? `/organizations/${organizationId}/frameworks` - : undefined, - icon: BookOpen, - }, - { - title: "Organizations", - icon: Building, - url: organizationId - ? `/organizations/${organizationId}/peoples` - : undefined, - items: organizationId - ? [ - { - title: "Peoples", - url: `/organizations/${organizationId}/peoples`, - icon: Users, - }, - { - title: "Vendors", - url: `/organizations/${organizationId}/vendors`, - icon: ToyBrick, - }, - ] - : [], - }, - { - title: "Policies", - url: organizationId - ? `/organizations/${organizationId}/policies` - : undefined, - icon: FileText, - }, - { - title: "Settings", - url: organizationId - ? `/organizations/${organizationId}/settings` - : undefined, - icon: Settings, - }, - ], - navSecondary: [ - { - title: "Support", - url: "#", - icon: LifeBuoy, - }, - { - title: "Feedback", - url: "#", - icon: Send, - }, - ], - }; -} +import { AppSidebarShell } from "./AppSidebarShell"; +import { AppSidebarSkeleton } from "./AppSidebarSkeleton"; const AppSidebarQuery = graphql` query AppSidebarQuery { @@ -111,68 +30,16 @@ function AppSidebarContent({ }: React.ComponentProps & { queryRef: PreloadedQuery; }) { - const { organizationId } = useParams(); const data = usePreloadedQuery(AppSidebarQuery, queryRef); - const navItems = getNavItems(organizationId); return ( - - + - - - - - - - - - - ); -} - -function AppSidebarFallback(props: React.ComponentProps) { - return ( - - - - - -
-
-
-
-
- - - - - - - {Array.from({ length: 3 }).map((_, i) => ( - - -
-
- - - ))} - - - - - - -
-
-
-
-
- - - - - + } + navUser={} + {...props} + /> ); } @@ -185,11 +52,11 @@ export function AppSidebar(props: React.ComponentProps) { }, [loadQuery]); if (!queryRef) { - return ; + return ; } return ( - }> + }> ); diff --git a/apps/console/src/components/AppSidebarShell.tsx b/apps/console/src/components/AppSidebarShell.tsx new file mode 100644 index 000000000..93ccf66d9 --- /dev/null +++ b/apps/console/src/components/AppSidebarShell.tsx @@ -0,0 +1,107 @@ +import { useParams } from "react-router"; +import { NavMain } from "./NavMain"; +import { NavSecondary } from "./NavSecondary"; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, +} from "./ui/sidebar"; +import { + BookOpen, + Users, + ToyBrick, + LifeBuoy, + Send, + Settings, + Building, + FileText, +} from "lucide-react"; +import { ReactNode } from "react"; + +interface AppSidebarShellProps extends React.ComponentProps { + navUser: ReactNode; + organizationSwitcher: ReactNode; +} + +export function AppSidebarShell({ + navUser, + organizationSwitcher, + ...props +}: AppSidebarShellProps) { + const { organizationId } = useParams(); + const navItems = getNavItems(organizationId); + + return ( + + {organizationSwitcher} + + + + + {navUser} + + ); +} + +function getNavItems(organizationId?: string) { + // Always return the same structure, but with or without URLs depending on whether an organization is selected + return { + navMain: [ + { + title: "Frameworks", + url: organizationId + ? `/organizations/${organizationId}/frameworks` + : undefined, + icon: BookOpen, + }, + { + title: "Organizations", + icon: Building, + url: organizationId + ? `/organizations/${organizationId}/peoples` + : undefined, + items: organizationId + ? [ + { + title: "Peoples", + url: `/organizations/${organizationId}/peoples`, + icon: Users, + }, + { + title: "Vendors", + url: `/organizations/${organizationId}/vendors`, + icon: ToyBrick, + }, + ] + : [], + }, + { + title: "Policies", + url: organizationId + ? `/organizations/${organizationId}/policies` + : undefined, + icon: FileText, + }, + { + title: "Settings", + url: organizationId + ? `/organizations/${organizationId}/settings` + : undefined, + icon: Settings, + }, + ], + navSecondary: [ + { + title: "Support", + url: "#", + icon: LifeBuoy, + }, + { + title: "Feedback", + url: "#", + icon: Send, + }, + ], + }; +} diff --git a/apps/console/src/components/AppSidebarSkeleton.tsx b/apps/console/src/components/AppSidebarSkeleton.tsx new file mode 100644 index 000000000..26b590884 --- /dev/null +++ b/apps/console/src/components/AppSidebarSkeleton.tsx @@ -0,0 +1,16 @@ +import { AppSidebarShell } from "./AppSidebarShell"; +import { NavUserSkeleton } from "./NavUserSkeleton"; +import { OrganizationSwitcherSkeleton } from "./OrganizationSwitcherSkeleton"; +import { Sidebar } from "./ui/sidebar"; + +export function AppSidebarSkeleton( + props: React.ComponentProps +) { + return ( + } + navUser={} + {...props} + /> + ); +} diff --git a/apps/console/src/components/NavUserShell.tsx b/apps/console/src/components/NavUserShell.tsx new file mode 100644 index 000000000..8f8e58543 --- /dev/null +++ b/apps/console/src/components/NavUserShell.tsx @@ -0,0 +1,120 @@ +"use client"; + +import { + BadgeCheck, + Bell, + ChevronsUpDown, + CreditCard, + LogOut, + Sparkles, +} from "lucide-react"; +import { useNavigate } from "react-router"; + +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar"; +import { useAuth } from "@/contexts/AuthContext"; + +export function NavUserSkeleton() { + const { isMobile } = useSidebar(); + const { logout } = useAuth(); + const navigate = useNavigate(); + + const handleLogout = async () => { + await logout(); + navigate("/login"); + }; + + return ( + + + + + + + + {currentUser.fullName.substring(0, 2).toUpperCase()} + + +
+ + {currentUser.fullName} + + + {currentUser.email} + +
+ +
+
+ + +
+ + + {currentUser.fullName.substring(0, 2).toUpperCase()} + + +
+ + {currentUser.fullName} + + {currentUser.email} +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
+ ); +} diff --git a/apps/console/src/components/NavUserSkeleton.tsx b/apps/console/src/components/NavUserSkeleton.tsx new file mode 100644 index 000000000..6a94b772d --- /dev/null +++ b/apps/console/src/components/NavUserSkeleton.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { ChevronsUpDown } from "lucide-react"; + +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar"; + +export function NavUserSkeleton() { + return ( + + + + + + +
+
+
+
+
+
+
+
+ + + + + ); +} diff --git a/apps/console/src/components/OrganizationSwitcher.tsx b/apps/console/src/components/OrganizationSwitcher.tsx index cf4678e4f..886c6cb48 100644 --- a/apps/console/src/components/OrganizationSwitcher.tsx +++ b/apps/console/src/components/OrganizationSwitcher.tsx @@ -61,6 +61,7 @@ const LogoComponent = ({ /> ); } + return org.name.substring(0, 2).toUpperCase(); }; @@ -144,11 +145,7 @@ export function OrganizationSwitcher({ {currentOrganization ? "Free" : "No organization selected"}
- + + + +
+
+
+
+
+
+
+
+
+ + + + + ); +}