5.4 KiB
Plan: Etapa 4.1 — Navbar con menú lateral para Dashboard
Contexto
El Dashboard de Ro-ut actualmente es un <h1>Dashboard</h1> sin navegación. La tarea 4.1 del plan de Etapa 4 ("Frontend: Dashboard funcional y gestión de usuarios") requiere integrar el componente Navbar del design system @aleleba/ro-ut-ui para dar al usuario una barra de navegación funcional con sidebar lateral.
El Navbar del UI kit es chrome-only: no envuelve el contenido de la página, sino que se coloca fuera y publica variables CSS (--ro-ut-sidebar-width, --ro-ut-topbar-height) para que el contenido reserve el espacio adecuado.
Archivos a crear
1. src/frontend/components/Dashboard/DashboardLayout/components/DashboardLayout.tsx
Componente layout que envuelve el Dashboard con el Navbar. Sigue el patrón connect de Redux del proyecto:
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { useNavigate } from 'react-router';
import { Navbar, TopNavbar, LeftNavbar, NavList, NavItem, IconNames } from '@aleleba/ro-ut-ui';
import { logInActions, ILogInPayload } from '@actions';
const { logInAction } = logInActions;
export type TDashboardLayoutProps = {
children: React.ReactNode;
setLogIn: ({ payload }: { payload: ILogInPayload }) => void;
connection: boolean;
token: string;
user: string | null;
};
const DashboardLayout = (props: TDashboardLayoutProps) => {
const { children, setLogIn, connection, token, user } = props;
const navigate = useNavigate();
// Auth redirect — mismo patrón que el Dashboard actual
useEffect(() => {
if ((connection === false) && (token === null)) {
navigate('/login');
}
}, [connection, token]);
const handleLogout = () => {
setLogIn({ payload: { connection: false, token: null, user: null } });
};
const navItems = [
{ label: 'Dashboard', to: '/dashboard', icon: IconNames.dashboard, active: true }
];
return (
<Navbar defaultExpanded>
<TopNavbar
brand={<img src="/assets/img/logo-ro-ut.svg" alt="RO-UT Logo" style={{ height: '32px' }} />}
actions={
<NavItem label={user || 'Usuario'} onClick={handleLogout} icon={IconNames.usuarioDentroApp} />
}
/>
<LeftNavbar>
<NavList>
{navItems.map(item => (
<NavItem key={item.to} label={item.label} to={item.to} icon={item.icon} active={item.active} />
))}
</NavList>
</LeftNavbar>
<div className="dashboard-content">{children}</div>
</Navbar>
);
};
const mapStateToProps = (state) => ({
connection: state.logIn.connection,
token: state.logIn.token,
user: state.logIn.user
});
const mapDispatchToProps = (dispatch) => ({
setLogIn: ({ payload }) => dispatch(logInAction(payload))
});
export default connect(mapStateToProps, mapDispatchToProps)(DashboardLayout);
Decisiones clave:
childrencomo prop hace el layout composable — cualquier vista futura se envuelve igual.- El logout es local (dispatch Redux con
connection: false, token: null). Si en el futuro se necesita invalidar sesión en el servidor, se crea un container con GraphQL mutation siguiendo el patrón deLogIn/containers/queryGraphQLLogOut.ts. - El auth redirect se mueve del Dashboard al layout, centralizando la lógica de protección.
Archivos a modificar
2. src/frontend/components/Dashboard/Dashboard/components/Dashboard.tsx
Simplificar a componente de contenido puro — sin Redux, sin useEffect, sin useNavigate:
import React from 'react';
const Dashboard = () => (
<div className="container">
<div className="row">
<h1 style={{ color: '#000' }}>Dashboard</h1>
</div>
</div>
);
export default Dashboard;
3. src/routes/index.tsx
Envolver el Dashboard con el layout:
import DashboardLayout from '../frontend/components/Dashboard/DashboardLayout/components/DashboardLayout';
const DASHBOARD = {
path: '/dashboard',
element: (
<DashboardLayout>
<Dashboard />
</DashboardLayout>
),
};
CSS para el offset del contenido
El Navbar publica variables CSS en document.documentElement (runtime, vía JS). El .dashboard-content debe usarlas:
.dashboard-content {
margin-left: var(--ro-ut-sidebar-width, 0px);
margin-top: var(--ro-ut-topbar-height, 0px);
padding: 1rem;
}
Esto asegura que el contenido se ajuste automáticamente cuando el sidebar se colapsa/expande, sin valores hardcodeados.
Comportamiento responsive
El Navbar maneja la responsividad internamente:
- Desktop: sidebar visible (expandido o colapsado), topbar fija arriba.
- Móvil: menú hamburguesa en la topbar; sidebar se superpone como acordeón.
No se necesita CSS responsive adicional del layout.
Items de navegación
Por ahora solo Dashboard (/dashboard). El array navItems en el componente es el lugar central para agregar nuevos items cuando se construyan las vistas de usuarios, empresas, etc. (tareas 4.2–4.5).
Verificación
npm run build— compilar sin errores.- Navegar a
/dashboard— ver Navbar con sidebar izquierdo y topbar con logo + nombre de usuario. - Click en logout — redirigir a
/login. - Sidebar colapsar/expandir — el contenido se ajusta con las variables CSS.
- Navegar a
/logincon sesión activa — redirigir a/dashboard. - Navegar directamente a
/dashboardsin autenticar — redirigir a/login.