story-generator/src/pages/dashboard/DashboardLayout.tsx
Lucas Santana c422a6186e feat: implementa interesses do aluno e melhora responsividade dos menus
- Adiciona nova aba de Interesses nas configura����es do aluno

- Implementa sistema de notifica����es toast usando Radix UI

- Torna menus laterais responsivos e colaps��veis

- Adiciona colapso autom��tico dos menus ao clicar em um item

- Cria tabela interests no banco de dados com pol��ticas RLS
2025-01-10 21:41:41 -03:00

214 lines
6.3 KiB
TypeScript

import React from 'react';
import { Outlet, NavLink, useNavigate } from 'react-router-dom';
import {
LayoutDashboard,
Users,
GraduationCap,
BookOpen,
Settings,
LogOut,
School,
UserRound,
Menu,
X,
ChevronLeft,
ChevronRight
} from 'lucide-react';
import { useAuth } from '../../hooks/useAuth';
import * as Dialog from '@radix-ui/react-dialog';
export function DashboardLayout() {
const navigate = useNavigate();
const { signOut } = useAuth();
const [isCollapsed, setIsCollapsed] = React.useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
const handleLogout = async () => {
await signOut();
navigate('/');
};
const handleNavigation = () => {
setIsMobileMenuOpen(false);
};
const NavItems = () => (
<nav className="p-4 space-y-1">
<NavLink
to="/dashboard"
end
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<LayoutDashboard className="h-5 w-5" />
{!isCollapsed && <span>Visão Geral</span>}
</NavLink>
<NavLink
to="/dashboard/turmas"
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<Users className="h-5 w-5" />
{!isCollapsed && <span>Turmas</span>}
</NavLink>
<NavLink
to="/dashboard/professores"
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<GraduationCap className="h-5 w-5" />
{!isCollapsed && <span>Professores</span>}
</NavLink>
<NavLink
to="/dashboard/alunos"
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<UserRound className="h-5 w-5" />
{!isCollapsed && <span>Alunos</span>}
</NavLink>
<NavLink
to="/dashboard/historias"
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<BookOpen className="h-5 w-5" />
{!isCollapsed && <span>Histórias</span>}
</NavLink>
<NavLink
to="/dashboard/configuracoes"
onClick={handleNavigation}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm ${
isActive
? 'bg-purple-50 text-purple-700'
: 'text-gray-600 hover:bg-gray-50'
}`
}
>
<Settings className="h-5 w-5" />
{!isCollapsed && <span>Configurações</span>}
</NavLink>
<button
onClick={() => {
handleNavigation();
handleLogout();
}}
className="flex items-center gap-2 px-4 py-2 rounded-lg text-sm text-gray-600 hover:bg-gray-50 w-full mt-4"
>
<LogOut className="h-5 w-5" />
{!isCollapsed && <span>Sair</span>}
</button>
</nav>
);
return (
<div className="min-h-screen bg-gray-50">
{/* Mobile Menu Button */}
<button
onClick={() => setIsMobileMenuOpen(true)}
className="fixed top-4 left-4 p-2 bg-white rounded-lg shadow-sm border border-gray-200 lg:hidden z-50"
>
<Menu className="h-6 w-6 text-gray-600" />
</button>
{/* Desktop Sidebar */}
<aside
className={`fixed left-0 top-0 h-full bg-white border-r border-gray-200 transition-all duration-300 hidden lg:block ${
isCollapsed ? 'w-20' : 'w-64'
}`}
>
<div className="flex items-center gap-2 p-6 border-b border-gray-200">
<School className="h-8 w-8 text-purple-600" />
{!isCollapsed && (
<span className="font-semibold text-gray-900">Histórias Mágicas</span>
)}
</div>
<NavItems />
{/* Collapse Button */}
<button
onClick={() => setIsCollapsed(!isCollapsed)}
className="absolute bottom-4 -right-4 p-2 bg-white rounded-full shadow-sm border border-gray-200"
>
{isCollapsed ? (
<ChevronRight className="h-4 w-4 text-gray-600" />
) : (
<ChevronLeft className="h-4 w-4 text-gray-600" />
)}
</button>
</aside>
{/* Mobile Menu Dialog */}
<Dialog.Root open={isMobileMenuOpen} onOpenChange={setIsMobileMenuOpen}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
<Dialog.Content className="fixed inset-y-0 left-0 w-64 bg-white shadow-xl z-50 lg:hidden">
<div className="flex items-center justify-between p-6 border-b border-gray-200">
<div className="flex items-center gap-2">
<School className="h-8 w-8 text-purple-600" />
<span className="font-semibold text-gray-900">
Histórias Mágicas
</span>
</div>
<button
onClick={() => setIsMobileMenuOpen(false)}
className="p-2 hover:bg-gray-100 rounded-lg"
>
<X className="h-5 w-5 text-gray-600" />
</button>
</div>
<NavItems />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
{/* Main Content */}
<main
className={`transition-all duration-300 ${
isCollapsed ? 'lg:ml-20' : 'lg:ml-64'
} p-8`}
>
<Outlet />
</main>
</div>
);
}