Fix sidebar bug

main
Deardo Satria 2 days ago
parent 54dfbd2691
commit 1ab0c2e321

@ -1,5 +1,6 @@
"use client"; "use client";
import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { ChevronRightIcon } from "lucide-react"; import { ChevronRightIcon } from "lucide-react";
@ -21,7 +22,9 @@ import {
SidebarMenuSubButton, SidebarMenuSubButton,
SidebarMenuSubItem, SidebarMenuSubItem,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { navItems } from "./nav-items"; import { navItems, type NavItem } from "./nav-items";
type NavGroupItem = Extract<NavItem, { items: unknown }>;
export function AppSidebar({ footer }: { footer: React.ReactNode }) { export function AppSidebar({ footer }: { footer: React.ReactNode }) {
const pathname = usePathname(); const pathname = usePathname();
@ -36,33 +39,7 @@ export function AppSidebar({ footer }: { footer: React.ReactNode }) {
<SidebarMenu className="gap-0.5"> <SidebarMenu className="gap-0.5">
{navItems.map((item) => {navItems.map((item) =>
"items" in item ? ( "items" in item ? (
<Collapsible <NavGroup key={item.title} item={item} pathname={pathname} />
key={item.title}
defaultOpen={item.items.some((sub) =>
pathname.startsWith(sub.href),
)}
render={<SidebarMenuItem />}
>
<CollapsibleTrigger render={<SidebarMenuButton />}>
<item.icon />
<span>{item.title}</span>
<ChevronRightIcon className="ml-auto transition-transform group-data-panel-open/menu-button:rotate-90" />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((sub) => (
<SidebarMenuSubItem key={sub.href}>
<SidebarMenuSubButton
render={<Link href={sub.href} />}
isActive={pathname.startsWith(sub.href)}
>
<span>{sub.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</Collapsible>
) : ( ) : (
<SidebarMenuItem key={item.href}> <SidebarMenuItem key={item.href}>
<SidebarMenuButton <SidebarMenuButton
@ -82,3 +59,50 @@ export function AppSidebar({ footer }: { footer: React.ReactNode }) {
</Sidebar> </Sidebar>
); );
} }
// Controlled karena sidebar tetap ter-mount antar navigasi; defaultOpen yang berubah memicu warning Base UI.
function NavGroup({
item,
pathname,
}: {
item: NavGroupItem;
pathname: string;
}) {
const isActive = item.items.some((sub) => pathname.startsWith(sub.href));
const [open, setOpen] = useState(isActive);
const [prevActive, setPrevActive] = useState(isActive);
// Buka otomatis saat navigasi masuk ke grup ini, tanpa menutup grup yang dibuka manual.
if (isActive !== prevActive) {
setPrevActive(isActive);
if (isActive) setOpen(true);
}
return (
<Collapsible
open={open}
onOpenChange={setOpen}
render={<SidebarMenuItem />}
>
<CollapsibleTrigger render={<SidebarMenuButton />}>
<item.icon />
<span>{item.title}</span>
<ChevronRightIcon className="ml-auto transition-transform group-data-panel-open/menu-button:rotate-90" />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((sub) => (
<SidebarMenuSubItem key={sub.href}>
<SidebarMenuSubButton
render={<Link href={sub.href} />}
isActive={pathname.startsWith(sub.href)}
>
<span>{sub.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</Collapsible>
);
}

@ -0,0 +1,34 @@
"use client";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { useRouter } from "next/navigation";
export default function NotFoundPage() {
const router = useRouter();
return (
<div className="grid min-h-svh place-items-center bg-background px-6 text-foreground">
<div className="w-full max-w-sm text-center">
<p className="font-mono text-xs tracking-[0.3em] text-muted-foreground uppercase">
Cleo Minimarket
</p>
<h1 className="mt-4 text-7xl font-semibold tracking-tighter tabular-nums">
404
</h1>
<p className="mt-3 text-lg font-medium">Halaman tidak ditemukan</p>
<p className="mt-2 text-sm text-muted-foreground">
Alamat yang dibuka tidak ada atau sudah dipindah.
</p>
<div className="mt-8 border-t border-dashed pt-6">
<Button
className="inline-flex h-10 items-center rounded-md bg-primary px-5 text-sm font-medium text-primary-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring"
onClick={() => {
router.back();
}}
>
Kembali
</Button>
</div>
</div>
</div>
);
}
Loading…
Cancel
Save