Fix navigation and routing for client users

- Sidebar: Show proper navigation for client/employee roles
- App.tsx: Add HomeRedirect to route users based on role
- Client users now go directly to their company detail page
- Added AnalystRoute to protect ClientesList

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 23:49:18 -06:00
parent d2addbc1f6
commit 093570b7b2
2 changed files with 61 additions and 15 deletions

View File

@@ -41,6 +41,29 @@ function AdminRoute({ children }: { children: React.ReactNode }) {
return <>{children}</>; return <>{children}</>;
} }
function AnalystRoute({ children }: { children: React.ReactNode }) {
const { isAdmin, isAnalista } = useAuth();
if (!isAdmin && !isAnalista) {
return <Navigate to="/" replace />;
}
return <>{children}</>;
}
// Componente para redirigir a la página correcta según el rol
function HomeRedirect() {
const { user, isCliente, isEmpleado } = useAuth();
// Si es cliente o empleado, redirigir a su empresa
if ((isCliente || isEmpleado) && user?.cliente_id) {
return <Navigate to={`/clientes/${user.cliente_id}`} replace />;
}
// Si es admin o analista, ir a lista de clientes
return <Navigate to="/clientes" replace />;
}
function AppRoutes() { function AppRoutes() {
const { user, loading } = useAuth(); const { user, loading } = useAuth();
@@ -68,13 +91,24 @@ function AppRoutes() {
</ProtectedRoute> </ProtectedRoute>
} }
> >
<Route index element={<Navigate to="/clientes" replace />} /> <Route index element={<HomeRedirect />} />
<Route path="clientes" element={<ClientesList />} />
{/* Lista de clientes - solo admin/analista */}
<Route
path="clientes"
element={
<AnalystRoute>
<ClientesList />
</AnalystRoute>
}
/>
{/* Detalle de cliente - todos pueden ver (con restricciones en backend) */}
<Route path="clientes/:id" element={<ClienteDetail />} /> <Route path="clientes/:id" element={<ClienteDetail />} />
<Route path="dashboard/:clienteId/:reporteId" element={<Dashboard />} /> <Route path="dashboard/:clienteId/:reporteId" element={<Dashboard />} />
<Route path="reportes/:id" element={<ReporteView />} /> <Route path="reportes/:id" element={<ReporteView />} />
{/* Rutas de administración */} {/* Rutas de administración - solo admin */}
<Route path="admin" element={<AdminRoute><Navigate to="/admin/usuarios" replace /></AdminRoute>} /> <Route path="admin" element={<AdminRoute><Navigate to="/admin/usuarios" replace /></AdminRoute>} />
<Route path="admin/usuarios" element={<AdminRoute><AdminUsuarios /></AdminRoute>} /> <Route path="admin/usuarios" element={<AdminRoute><AdminUsuarios /></AdminRoute>} />
<Route path="admin/giros" element={<AdminRoute><AdminGiros /></AdminRoute>} /> <Route path="admin/giros" element={<AdminRoute><AdminGiros /></AdminRoute>} />

View File

@@ -2,11 +2,6 @@ import { NavLink } from 'react-router-dom';
import { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import clsx from 'clsx'; import clsx from 'clsx';
const navItems = [
{ name: 'Clientes', path: '/clientes', icon: '🏢', roles: ['admin', 'analista'] },
{ name: 'Mi Empresa', path: '/clientes', icon: '📊', roles: ['cliente', 'empleado'] },
];
const adminItems = [ const adminItems = [
{ name: 'Usuarios', path: '/admin/usuarios', icon: '👥' }, { name: 'Usuarios', path: '/admin/usuarios', icon: '👥' },
{ name: 'Giros', path: '/admin/giros', icon: '🏷️' }, { name: 'Giros', path: '/admin/giros', icon: '🏷️' },
@@ -15,11 +10,27 @@ const adminItems = [
]; ];
export default function Sidebar() { export default function Sidebar() {
const { user, isAdmin } = useAuth(); const { user, isAdmin, isAnalista, isCliente, isEmpleado } = useAuth();
const filteredNavItems = navItems.filter( // Determinar navegación principal según rol
(item) => item.roles.includes(user?.role || '') const getMainNavItems = () => {
); if (isAdmin || isAnalista) {
return [
{ name: 'Clientes', path: '/clientes', icon: '🏢' },
];
}
if ((isCliente || isEmpleado) && user?.cliente_id) {
return [
{ name: 'Mi Empresa', path: `/clientes/${user.cliente_id}`, icon: '🏢' },
{ name: 'Dashboard', path: `/clientes/${user.cliente_id}`, icon: '📊' },
];
}
return [];
};
const mainNavItems = getMainNavItems();
return ( return (
<aside className="fixed left-0 top-0 h-screen w-64 bg-horux-dark text-white flex flex-col z-50"> <aside className="fixed left-0 top-0 h-screen w-64 bg-horux-dark text-white flex flex-col z-50">
@@ -34,9 +45,9 @@ export default function Sidebar() {
<div className="text-xs uppercase text-gray-500 font-semibold mb-2 px-3"> <div className="text-xs uppercase text-gray-500 font-semibold mb-2 px-3">
Principal Principal
</div> </div>
{filteredNavItems.map((item) => ( {mainNavItems.map((item, index) => (
<NavLink <NavLink
key={item.path} key={`${item.path}-${index}`}
to={item.path} to={item.path}
className={({ isActive }) => className={({ isActive }) =>
clsx( clsx(
@@ -52,6 +63,7 @@ export default function Sidebar() {
</NavLink> </NavLink>
))} ))}
{/* Sección de administración - solo para admin */}
{isAdmin && ( {isAdmin && (
<> <>
<div className="text-xs uppercase text-gray-500 font-semibold mt-6 mb-2 px-3"> <div className="text-xs uppercase text-gray-500 font-semibold mt-6 mb-2 px-3">
@@ -82,7 +94,7 @@ export default function Sidebar() {
<div className="p-4 border-t border-gray-700"> <div className="p-4 border-t border-gray-700">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-horux-accent flex items-center justify-center text-lg"> <div className="w-10 h-10 rounded-full bg-horux-accent flex items-center justify-center text-lg">
{user?.nombre?.charAt(0).toUpperCase()} {user?.nombre?.charAt(0).toUpperCase() || '?'}
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{user?.nombre}</p> <p className="text-sm font-medium truncate">{user?.nombre}</p>