fix: Sidebar focus on some items

This commit is contained in:
charlesgauthereau
2026-01-17 21:13:54 +01:00
parent 53f82792d8
commit e63e62d3e0
3 changed files with 44 additions and 59 deletions
@@ -0,0 +1,28 @@
import {PageParams} from "@/types/next";
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
import {db} from "@/db";
import {notFound} from "next/navigation";
export default async function RoutePage(props: PageParams<{}>) {
const settings = await db.query.setting.findFirst({
where: (fields, {eq}) => eq(fields.name, "system"),
});
if (!settings) {
notFound()
}
return (
<Page>
<PageHeader className="flex flex-col">
<div className="flex justify-between">
<PageTitle className="mb-3">System settings</PageTitle>
</div>
</PageHeader>
<PageContent className="flex flex-col gap-5">
</PageContent>
</Page>
);
}
@@ -22,7 +22,6 @@ export const SidebarMenuCustomMain = () => {
const {data: session, isPending, error} = authClient.useSession(); const {data: session, isPending, error} = authClient.useSession();
const member = authClient.useActiveMember(); const member = authClient.useActiveMember();
if (isPending) return null; if (isPending) return null;
if (error || !session) { if (error || !session) {
@@ -39,9 +38,6 @@ export const SidebarMenuCustomMain = () => {
{title: "Settings", url: "/settings", icon: Settings, details: true, type: "item"} {title: "Settings", url: "/settings", icon: Settings, details: true, type: "item"}
]; ];
// if (activeOrganization && (member?.data?.role === "admin" || member?.data?.role === "owner")) {
// groupContent.push({ title: "Settings", url: "/settings", icon: Settings, details:true });
// }
const items: SidebarGroupItem[] = [ const items: SidebarGroupItem[] = [
{ {
@@ -98,19 +94,14 @@ export const SidebarMenuCustomMain = () => {
type: "collapse", type: "collapse",
submenu: [ submenu: [
{title: "Users", url: "/admin/users", icon: Users, type: "item"}, {title: "Users", url: "/admin/users", icon: Users, type: "item"},
{title: "Organizations", url: "/admin/organizations", icon: Building, type: "item"}, {title: "Organizations", url: "/admin/organizations", icon: Building, type: "item", details: true},
], ],
}, },
{ {
title: "Settings", title: "Settings",
url: "/admin/settings", url: "/admin/settings",
icon: Settings, icon: Settings,
details: true, type: "item",
type: "collapse",
submenu: [
{title: "Email", url: "/admin/settings/email", icon: Mail, type: "item"},
{title: "Storage", url: "/admin/settings/storage", icon: PackageOpen, type: "item"},
],
}, },
], ],
}); });
@@ -14,7 +14,7 @@ import {
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { ChevronRight, ChevronDown, MoreHorizontal } from "lucide-react"; import { ChevronRight, ChevronDown, MoreHorizontal } from "lucide-react";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
import React, { useEffect, useState } from "react"; import React from "react";
import Link from "next/link"; import Link from "next/link";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
@@ -46,43 +46,18 @@ type SidebarMenuCustomBaseProps = {
export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseProps) => { export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseProps) => {
const pathname = usePathname(); const pathname = usePathname();
const [activeItem, setActiveItem] = useState("");
useEffect(() => { const normalize = (url: string) => url.split("?")[0].replace(/\/$/, "");
const normalize = (url: string) => url.split("?")[0].replace(/\/$/, "");
const findActiveUrl = () => { const isItemActive = (item: SidebarItem) => {
const normalizedPathname = normalize(pathname); const fullUrl = item.not_from_base_url ? normalize(item.url) : normalize(`${baseUrl}${item.url}`);
for (const group of items) { if (item.details) return normalize(pathname).startsWith(fullUrl);
for (const item of group.group_content) { return normalize(pathname) === fullUrl;
if (item.submenu) { };
for (const subItem of item.submenu) {
const subItemUrl = normalize(subItem.url);
const subFullUrl = normalize(`${baseUrl}${subItemUrl}`);
if (normalizedPathname === subFullUrl || (subItem.details && normalizedPathname.startsWith(`${subFullUrl}/`))) {
return subItemUrl;
}
}
}
const itemUrl = normalize(item.url);
const fullUrl = item.not_from_base_url ? itemUrl : normalize(`${baseUrl}${itemUrl}`);
if (normalizedPathname === fullUrl || (item.details && normalizedPathname.startsWith(`${fullUrl}/`))) {
return itemUrl;
}
}
}
return "";
};
setActiveItem(findActiveUrl());
}, [pathname, baseUrl, items]);
const isSubActive = (item: SidebarItem) => { const isSubActive = (item: SidebarItem) => {
if (!item.submenu) return false; if (!item.submenu) return false;
return item.submenu.some((sub) => sub.url === activeItem); return item.submenu.some((sub) => isItemActive(sub));
}; };
return ( return (
@@ -91,7 +66,7 @@ export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseP
<Collapsible key={index} defaultOpen className="group/group-collapsible"> <Collapsible key={index} defaultOpen className="group/group-collapsible">
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel asChild> <SidebarGroupLabel asChild>
<CollapsibleTrigger disabled={group.type == "list"} className="flex w-full items-center text-sm font-medium text-sidebar-foreground/70"> <CollapsibleTrigger disabled={group.type === "list"} className="flex w-full items-center text-sm font-medium text-sidebar-foreground/70">
{group.label} {group.label}
{group.type === "collapse" && ( {group.type === "collapse" && (
<ChevronDown className="ml-auto h-4 w-4 transition-transform group-data-[state=open]/group-collapsible:rotate-180" /> <ChevronDown className="ml-auto h-4 w-4 transition-transform group-data-[state=open]/group-collapsible:rotate-180" />
@@ -118,14 +93,10 @@ export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseP
<SidebarMenuSub> <SidebarMenuSub>
{item.submenu.map((sub, subIdx) => ( {item.submenu.map((sub, subIdx) => (
<SidebarMenuSubItem key={subIdx}> <SidebarMenuSubItem key={subIdx}>
<SidebarMenuSubButton asChild isActive={activeItem === sub.url}> <SidebarMenuSubButton asChild isActive={isItemActive(sub)}>
<Link <Link
className={cn( href={sub.not_from_base_url ? sub.url : `${baseUrl}${sub.url}`}
buttonVariants({ variant: "ghost", size: "sm" }), className={cn(buttonVariants({ variant: "ghost", size: "sm" }), "w-full justify-start")}
"w-full justify-start"
)}
href={`${baseUrl}${sub.url}`}
onClick={() => setActiveItem(sub.url)}
> >
<sub.icon /> <sub.icon />
<span>{sub.title}</span> <span>{sub.title}</span>
@@ -142,11 +113,10 @@ export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseP
return ( return (
<SidebarMenuItem key={idx}> <SidebarMenuItem key={idx}>
<SidebarMenuButton asChild isActive={activeItem === item.url} tooltip={item.title}> <SidebarMenuButton asChild isActive={isItemActive(item)} tooltip={item.title}>
<Link <Link
href={item.redirect || item.not_from_base_url ? item.url : `${baseUrl}${item.url}`} href={item.redirect || item.not_from_base_url ? item.url : `${baseUrl}${item.url}`}
target={item.redirect ? "_blank" : ""} target={item.redirect ? "_blank" : ""}
onClick={() => setActiveItem(item.url)}
className={cn(buttonVariants({ variant: "ghost", size: "lg" }), "justify-start")} className={cn(buttonVariants({ variant: "ghost", size: "lg" }), "justify-start")}
> >
<item.icon /> <item.icon />
@@ -163,11 +133,7 @@ export const SidebarMenuCustomBase = ({ baseUrl, items }: SidebarMenuCustomBaseP
{item.dropdown.map((dropdown, dIdx) => ( {item.dropdown.map((dropdown, dIdx) => (
<DropdownMenuItem key={dIdx} asChild> <DropdownMenuItem key={dIdx} asChild>
<Link <Link
href={ href={dropdown.redirect || dropdown.not_from_base_url ? dropdown.url : `${baseUrl}${dropdown.url}`}
dropdown.redirect || dropdown.not_from_base_url
? dropdown.url
: `${baseUrl}${dropdown.url}`
}
target={dropdown.redirect ? "_blank" : ""} target={dropdown.redirect ? "_blank" : ""}
> >
<span>{dropdown.title}</span> <span>{dropdown.title}</span>