feat: add full project - backend, frontend, docker, specs and configs
This commit is contained in:
parent
b77c7d5a01
commit
e6cb06255b
24489 changed files with 61341 additions and 36 deletions
14
frontend/src/layouts/AdminLayout.tsx
Normal file
14
frontend/src/layouts/AdminLayout.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Outlet } from 'react-router-dom';
|
||||
import Navbar from '../components/Navbar';
|
||||
|
||||
export default function AdminLayout() {
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<main className="pt-14 min-h-screen bg-canvas">
|
||||
<Outlet />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
134
frontend/src/layouts/ClientLayout.tsx
Normal file
134
frontend/src/layouts/ClientLayout.tsx
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import { Outlet, NavLink, useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { ThemeToggle } from '../components/ThemeToggle';
|
||||
|
||||
|
||||
const navItems = [
|
||||
{ to: '/area-do-cliente', label: 'Painel', end: true, icon: '⊞' },
|
||||
{ to: '/area-do-cliente/favoritos', label: 'Favoritos', end: false, icon: '♡' },
|
||||
{ to: '/area-do-cliente/comparar', label: 'Comparar', end: false, icon: '⇄' },
|
||||
{ to: '/area-do-cliente/visitas', label: 'Visitas', end: false, icon: '📅' },
|
||||
{ to: '/area-do-cliente/boletos', label: 'Boletos', end: false, icon: '📄' },
|
||||
];
|
||||
|
||||
const adminNavItems = [
|
||||
{ to: '/admin', label: 'Admin', end: false, icon: '⚙️' },
|
||||
];
|
||||
|
||||
export default function ClientLayout() {
|
||||
const { user, logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = user?.role === 'admin';
|
||||
|
||||
function handleLogout() {
|
||||
logout();
|
||||
navigate('/');
|
||||
}
|
||||
|
||||
// Adiciona pt-14 para compensar o header fixo (Navbar)
|
||||
return (
|
||||
<div className="flex min-h-screen bg-canvas pt-14">
|
||||
{/* Sidebar */}
|
||||
<aside className="hidden lg:flex w-56 flex-col border-r border-borderSubtle bg-panel px-3 py-6">
|
||||
{/* Theme toggle */}
|
||||
<div className="flex items-center justify-between mb-6 px-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-brand text-sm font-medium text-white shrink-0">
|
||||
{user?.name?.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium text-textPrimary">{user?.name}</p>
|
||||
<p className="truncate text-xs text-textSecondary">{user?.email}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex flex-1 flex-col gap-0.5">
|
||||
{navItems.map(item => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
to={item.to}
|
||||
end={item.end}
|
||||
className={({ isActive }) =>
|
||||
`flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm transition ${isActive
|
||||
? 'bg-surface text-textPrimary font-medium'
|
||||
: 'text-textSecondary hover:text-textPrimary hover:bg-surface'
|
||||
}`
|
||||
}
|
||||
>
|
||||
<span className="text-base">{item.icon}</span>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
{isAdmin && adminNavItems.map(item => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
to={item.to}
|
||||
end={item.end}
|
||||
className={({ isActive }) =>
|
||||
`flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm transition ${isActive
|
||||
? 'bg-[#f5c518] text-black font-semibold'
|
||||
: 'text-[#f5c518] hover:text-black hover:bg-[#ffe066]'
|
||||
}`
|
||||
}
|
||||
>
|
||||
<span className="text-base">{item.icon}</span>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Logout */}
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-textTertiary hover:text-textPrimary hover:bg-surface transition mt-4"
|
||||
>
|
||||
<span>→</span>Sair
|
||||
</button>
|
||||
</aside>
|
||||
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 overflow-auto">
|
||||
{/* Mobile nav */}
|
||||
<div className="lg:hidden border-b border-borderSubtle bg-panel overflow-x-auto flex items-center justify-between px-2 py-2">
|
||||
<div className="flex gap-0.5">
|
||||
{navItems.map(item => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
to={item.to}
|
||||
end={item.end}
|
||||
className={({ isActive }) =>
|
||||
`shrink-0 rounded-lg px-3 py-1.5 text-xs transition ${isActive
|
||||
? 'bg-surface text-textPrimary font-medium'
|
||||
: 'text-textSecondary hover:text-textPrimary'
|
||||
}`
|
||||
}
|
||||
>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
{isAdmin && adminNavItems.map(item => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
to={item.to}
|
||||
end={item.end}
|
||||
className={({ isActive }) =>
|
||||
`shrink-0 rounded-lg px-3 py-1.5 text-xs font-semibold transition ${isActive
|
||||
? 'bg-[#f5c518] text-black'
|
||||
: 'text-[#f5c518] hover:text-black hover:bg-[#ffe066]'
|
||||
}`
|
||||
}
|
||||
>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue