website/app/(admin)/_components/side-nav.tsx

157 lines
6.1 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { usePathname } from "next/navigation";
import Link from "next/link";
import {
LayoutGrid,
Calendar,
Settings,
LogOut,
Menu,
X,
Heart,
} from "lucide-react";
const navItems = [
{ label: "Dashboard", icon: LayoutGrid, href: "/dashboard" },
{ label: "Book Appointment", icon: Calendar, href: "/booking" },
];
export default function SideNav() {
const [open, setOpen] = useState(false);
const pathname = usePathname();
const getActiveIndex = () => {
return navItems.findIndex((item) => pathname?.includes(item.href)) ?? -1;
};
// Handle body scroll when mobile menu is open
useEffect(() => {
if (open) {
document.body.classList.add("menu-open");
} else {
document.body.classList.remove("menu-open");
}
return () => {
document.body.classList.remove("menu-open");
};
}, [open]);
return (
<>
{/* Mobile Top Bar */}
<div className="flex md:hidden items-center justify-between px-4 py-3 border-b border-gray-200 bg-white z-30 fixed top-0 left-0 right-0">
<div className="flex items-center gap-3">
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-rose-100 to-pink-100">
<Heart className="w-5 h-5 text-rose-600" fill="currentColor" />
</div>
<span className="text-lg font-semibold text-gray-900">Attune Heart Therapy</span>
</div>
<button onClick={() => setOpen((v) => !v)} aria-label="Open menu">
{open ? <X size={28} /> : <Menu size={28} />}
</button>
</div>
{/* Mobile Drawer Overlay */}
<div
className={`fixed inset-0 z-40 bg-black/30 transition-opacity duration-200 md:hidden ${
open ? "opacity-100" : "opacity-0 pointer-events-none"
}`}
onClick={() => setOpen(false)}
/>
{/* Side Navigation */}
<aside
className={`fixed top-0 left-0 z-50 h-screen bg-white border-r border-gray-200 flex flex-col transition-transform duration-200 w-[85vw] max-w-[250px] min-w-[200px] md:translate-x-0 md:w-[250px] md:min-w-[250px] md:max-w-[250px] ${
open ? "translate-x-0" : "-translate-x-full"
} md:translate-x-0`}
>
{/* Logo Section */}
<div className="flex-shrink-0 px-4 pb-4 flex flex-col gap-1 md:block mb-5 pt-16 md:pt-4">
<div className="flex items-center gap-3 mb-1 ml-4 md:ml-6">
<div className="flex items-center justify-center w-10 h-10 rounded-lg bg-gradient-to-br from-rose-100 to-pink-100">
<Heart className="w-6 h-6 text-rose-600" fill="currentColor" />
</div>
<span className="text-lg font-semibold text-gray-900">Attune Heart</span>
</div>
</div>
<hr className="flex-shrink-0 -mt-10 mb-4 mx-4 border-gray-200 md:block hidden" />
{/* Navigation Items */}
<nav className="flex-1 overflow-y-auto flex flex-col gap-2 px-2 md:px-0">
{navItems.map((item, idx) => {
const Icon = item.icon;
const isActive = idx === getActiveIndex();
return (
<div className="relative flex items-center w-full" key={item.label}>
{isActive && (
<span
className="absolute left-0 top-0 h-[45px] w-[3px] bg-[#4A90A4]"
style={{ left: 0 }}
/>
)}
<Link
href={item.href}
onClick={() => setOpen(false)}
className={`group flex items-center gap-3 py-3 pl-4 md:pl-4 pr-4 md:pr-4 transition-colors duration-200 focus:outline-none w-[90%] md:w-[90%] ml-2 md:ml-4 cursor-pointer justify-start ${
isActive
? "bg-[#4A90A4] text-white border border-[#4A90A4] rounded-[5px] shadow-sm"
: "bg-transparent text-gray-600 hover:bg-[#4A90A4]/10 hover:text-[#4A90A4] rounded-lg"
}`}
style={isActive ? { height: 45 } : {}}
>
<Icon
size={20}
strokeWidth={isActive ? 2.2 : 1.5}
className={
isActive
? "text-white"
: "text-gray-700 group-hover:text-[#4A90A4]"
}
/>
<span
className="font-light leading-none text-[13px] md:text-[13px]"
style={{ fontWeight: 300 }}
>
{item.label}
</span>
</Link>
</div>
);
})}
{/* Bottom Actions */}
<div className="mt-auto pt-4 pb-4 border-t border-gray-200">
<Link
href="/settings"
onClick={() => setOpen(false)}
className="group flex items-center gap-3 py-3 pl-4 md:pl-4 pr-4 md:pr-4 transition-colors duration-200 w-[90%] md:w-[90%] ml-2 md:ml-4 cursor-pointer justify-start text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg"
>
<Settings size={20} strokeWidth={1.5} className="text-gray-700 group-hover:text-gray-900" />
<span className="font-light leading-none text-[13px]" style={{ fontWeight: 300 }}>
Settings
</span>
</Link>
<button
onClick={() => {
setOpen(false);
// Handle logout
}}
className="group flex items-center gap-3 py-3 pl-4 md:pl-4 pr-4 md:pr-4 transition-colors duration-200 w-[90%] md:w-[90%] ml-2 md:ml-4 cursor-pointer justify-start text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg"
>
<LogOut size={20} strokeWidth={1.5} className="text-gray-700 group-hover:text-gray-900" />
<span className="font-light leading-none text-[13px]" style={{ fontWeight: 300 }}>
Logout
</span>
</button>
</div>
</nav>
</aside>
</>
);
}