Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { useKycStore } from "@/store/kycStore";
import Link from "next/link";
import { TransactionSecuritySettings } from "@/components/security/TransactionSecuritySettings";
import { Skeleton } from "@/components/ui/skeleton";
import { Sidebar } from "@/components/dashboard/Sidebar";
import { Menu } from "lucide-react";
import { Button } from "@/components/ui/button";

const StakingPanel = dynamic(
() => import("@/components/dashboard/StakingPanel").then((m) => m.StakingPanel),
Expand Down Expand Up @@ -62,17 +65,33 @@ const DataRefreshWrapper = dynamic(

const Index = () => {
const [sidebarOpen, setSidebarOpen] = useState(false);
const [activeItem, setActiveItem] = useState("dashboard");
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const { profile } = useKycStore();

return (
<div className="min-h-screen bg-background flex w-full">
<Sidebar
isOpen={sidebarOpen}
isCollapsed={sidebarCollapsed}
onClose={() => setSidebarOpen(false)}
onToggleCollapse={() => setSidebarCollapsed((c) => !c)}
/>
<div className="flex-1 flex flex-col min-w-0">
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800">
<header className="bg-white dark:bg-gray-800 shadow-sm border-b border-gray-200 dark:border-gray-700">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center gap-3">
{/* Mobile menu toggle */}
<Button
variant="ghost"
size="icon"
className="lg:hidden"
onClick={() => setSidebarOpen(true)}
aria-label="Open sidebar"
>
<Menu className="w-5 h-5" />
</Button>
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
<span className="text-white font-bold text-sm">PC</span>
</div>
Expand Down
322 changes: 192 additions & 130 deletions src/components/dashboard/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,140 +1,202 @@
// 'use client';
'use client';

// import { motion, AnimatePresence } from "framer-motion";
// import {
// LayoutDashboard,
// Building2,
// BarChart3,
// Wallet,
// FileText,
// Settings,
// HelpCircle,
// ChevronLeft,
// X
// } from "lucide-react";
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import {
LayoutDashboard,
Building2,
BarChart3,
Wallet,
FileText,
Settings,
HelpCircle,
X,
ChevronLeft,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';

// interface SidebarProps {
// isOpen: boolean;
// onClose: () => void;
// activeItem?: string;
// onItemClick?: (item: string) => void;
// }
const navItems = [
{ href: '/dashboard', label: 'Dashboard', icon: LayoutDashboard },
{ href: '/properties', label: 'Properties', icon: Building2 },
{ href: '/dashboard?tab=analytics', label: 'Analytics', icon: BarChart3 },
{ href: '/dashboard?tab=wallet', label: 'Wallet', icon: Wallet },
{ href: '/tax-report', label: 'Reports', icon: FileText },
];

// const menuItems = [
// { id: "dashboard", label: "Dashboard", icon: LayoutDashboard },
// { id: "properties", label: "Properties", icon: Building2 },
// { id: "analytics", label: "Analytics", icon: BarChart3 },
// { id: "wallet", label: "Wallet", icon: Wallet },
// { id: "reports", label: "Reports", icon: FileText },
// ];
const bottomItems = [
{ href: '/dashboard?tab=settings', label: 'Settings', icon: Settings },
{ href: '/dashboard?tab=help', label: 'Help & Support', icon: HelpCircle },
];

// const bottomItems = [
// { id: "settings", label: "Settings", icon: Settings },
// { id: "help", label: "Help & Support", icon: HelpCircle },
// ];
interface SidebarProps {
isOpen: boolean;
isCollapsed: boolean;
onClose: () => void;
onToggleCollapse: () => void;
}

// export const Sidebar = ({ isOpen, onClose, activeItem = "dashboard", onItemClick }: SidebarProps) => {
// const SidebarContent = () => (
// <div className="flex flex-col h-full">
// {/* Logo section for mobile */}
// <div className="lg:hidden flex items-center justify-between p-4 border-b border-border">
// <div className="flex items-center gap-3">
// <div className="w-10 h-10 rounded-xl bg-gradient-primary flex items-center justify-center">
// <span className="text-lg font-bold text-primary-foreground">M</span>
// </div>
// <div>
// <h1 className="text-lg font-bold gradient-text">MettaChain</h1>
// </div>
// </div>
// <button
// onClick={onClose}
// className="p-2 text-muted-foreground hover:text-foreground transition-colors"
// >
// <X className="w-5 h-5" />
// </button>
// </div>
function NavLink({
href,
label,
icon: Icon,
isActive,
isCollapsed,
onClick,
}: {
href: string;
label: string;
icon: React.ElementType;
isActive: boolean;
isCollapsed: boolean;
onClick?: () => void;
}) {
return (
<Link
href={href}
onClick={onClick}
title={isCollapsed ? label : undefined}
className={cn(
'flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all',
isCollapsed && 'justify-center px-2',
isActive
? 'bg-primary/10 text-primary border border-primary/20'
: 'text-muted-foreground hover:text-foreground hover:bg-secondary'
)}
aria-current={isActive ? 'page' : undefined}
>
<Icon className="w-5 h-5 shrink-0" />
{!isCollapsed && (
<>
<span>{label}</span>
{isActive && <div className="ml-auto w-1.5 h-1.5 rounded-full bg-primary" />}
</>
)}
</Link>
);
}

// {/* Navigation */}
// <nav className="flex-1 p-4 space-y-1">
// <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-4 px-3">
// Main Menu
// </p>
// {menuItems.map((item) => (
// <button
// key={item.id}
// onClick={() => onItemClick?.(item.id)}
// className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all ${
// activeItem === item.id
// ? "bg-primary/10 text-primary border border-primary/20"
// : "text-muted-foreground hover:text-foreground hover:bg-secondary"
// }`}
// >
// <item.icon className="w-5 h-5" />
// {item.label}
// {activeItem === item.id && (
// <div className="ml-auto w-1.5 h-1.5 rounded-full bg-primary" />
// )}
// </button>
// ))}
// </nav>
function SidebarContent({
isCollapsed,
onClose,
onToggleCollapse,
isMobileDrawer,
}: {
isCollapsed: boolean;
onClose: () => void;
onToggleCollapse: () => void;
isMobileDrawer?: boolean;
}) {
const pathname = usePathname();

// {/* Bottom section */}
// <div className="p-4 border-t border-border space-y-1">
// {bottomItems.map((item) => (
// <button
// key={item.id}
// onClick={() => onItemClick?.(item.id)}
// className="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary transition-all"
// >
// <item.icon className="w-5 h-5" />
// {item.label}
// </button>
// ))}
// </div>
return (
<div className="flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-border">
{(!isCollapsed || isMobileDrawer) && (
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center shrink-0">
<span className="text-white font-bold text-sm">PC</span>
</div>
<span className="font-bold text-base">PropChain</span>
</div>
)}
{isMobileDrawer ? (
<Button variant="ghost" size="icon" onClick={onClose} aria-label="Close sidebar">
<X className="w-5 h-5" />
</Button>
) : (
<Button
variant="ghost"
size="icon"
onClick={onToggleCollapse}
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
className={cn(isCollapsed && 'mx-auto')}
>
<ChevronLeft className={cn('w-5 h-5 transition-transform', isCollapsed && 'rotate-180')} />
</Button>
)}
</div>

// {/* Upgrade card */}
// <div className="p-4">
// <div className="bg-gradient-primary rounded-xl p-4 text-primary-foreground">
// <p className="font-semibold text-sm">Upgrade to Pro</p>
// <p className="text-xs mt-1 opacity-90">Unlock advanced analytics and premium features</p>
// <button className="mt-3 w-full bg-background/20 hover:bg-background/30 rounded-lg py-2 text-xs font-medium transition-colors">
// Upgrade Now
// </button>
// </div>
// </div>
// </div>
// );
{/* Main nav */}
<nav className="flex-1 p-3 space-y-1" aria-label="Dashboard navigation">
{!isCollapsed && (
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3 px-3">
Main Menu
</p>
)}
{navItems.map((item) => (
<NavLink
key={item.href}
{...item}
isActive={pathname === item.href.split('?')[0] && item.href === '/dashboard'
? pathname === '/dashboard'
: pathname === item.href.split('?')[0]}
isCollapsed={isCollapsed && !isMobileDrawer}
onClick={isMobileDrawer ? onClose : undefined}
/>
))}
</nav>

// return (
// <>
// {/* Desktop sidebar */}
// <aside className="hidden lg:block w-64 border-r border-border bg-card h-screen sticky top-0 shrink-0">
// <SidebarContent />
// </aside>
{/* Bottom nav */}
<div className="p-3 border-t border-border space-y-1">
{bottomItems.map((item) => (
<NavLink
key={item.href}
{...item}
isActive={false}
isCollapsed={isCollapsed && !isMobileDrawer}
onClick={isMobileDrawer ? onClose : undefined}
/>
))}
</div>
</div>
);
}

// {/* Mobile sidebar overlay */}
// <AnimatePresence>
// {isOpen && (
// <>
// <motion.div
// initial={{ opacity: 0 }}
// animate={{ opacity: 1 }}
// exit={{ opacity: 0 }}
// onClick={onClose}
// className="lg:hidden fixed inset-0 bg-background/80 backdrop-blur-sm z-40"
// />
// <motion.aside
// initial={{ x: -280 }}
// animate={{ x: 0 }}
// exit={{ x: -280 }}
// transition={{ type: "spring", damping: 25, stiffness: 200 }}
// className="lg:hidden fixed left-0 top-0 w-[280px] h-screen bg-card border-r border-border z-50"
// >
// <SidebarContent />
// </motion.aside>
// </>
// )}
// </AnimatePresence>
// </>
// );
// };
export function Sidebar({ isOpen, isCollapsed, onClose, onToggleCollapse }: SidebarProps) {
return (
<>
{/* Desktop sidebar */}
<aside
className={cn(
'hidden lg:flex flex-col border-r border-border bg-card h-screen sticky top-0 shrink-0 transition-all duration-300',
isCollapsed ? 'w-14' : 'w-64'
)}
aria-label="Sidebar"
>
<SidebarContent
isCollapsed={isCollapsed}
onClose={onClose}
onToggleCollapse={onToggleCollapse}
/>
</aside>

{/* Mobile overlay */}
{isOpen && (
<div
className="lg:hidden fixed inset-0 bg-black/50 z-40"
onClick={onClose}
aria-hidden="true"
/>
)}

{/* Mobile drawer */}
<aside
className={cn(
'lg:hidden fixed left-0 top-0 w-72 h-screen bg-card border-r border-border z-50 transition-transform duration-300',
isOpen ? 'translate-x-0' : '-translate-x-full'
)}
aria-label="Sidebar"
aria-hidden={!isOpen}
>
<SidebarContent
isCollapsed={false}
onClose={onClose}
onToggleCollapse={onToggleCollapse}
isMobileDrawer
/>
</aside>
</>
);
}
Loading