Fix pantalla en blanco al entrar: landing por rol cuando el Dashboard no es visible + matrices de menus coherentes
This commit is contained in:
@@ -39,7 +39,9 @@ const RequireAuth: FC<{ children: ReactNode; href: string }> = ({ children, href
|
||||
const { user, loading, canSee } = useAuth();
|
||||
if (loading) return <FullScreenLoader />;
|
||||
if (!user) return <Navigate to="/login" replace />;
|
||||
if (!canSee(href)) return <Navigate to="/" replace />;
|
||||
// La ruta "/" se maneja en HomeRoute (calcula landing por rol) para evitar
|
||||
// el bucle de redirecciones cuando el rol no tiene '/' en la matriz.
|
||||
if (!canSee(href) && href !== '/') return <Navigate to="/" replace />;
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -50,11 +52,30 @@ const LoginRoute: FC = () => {
|
||||
return <Login />;
|
||||
};
|
||||
|
||||
// Pantalla inicial por rol: el médico aterriza directo en su Agenda
|
||||
// Pantalla inicial por rol: el médico aterriza directo en su Agenda.
|
||||
// Si el rol no tiene acceso al Dashboard (matriz por rol), aterriza en la
|
||||
// primera sección visible; si no tiene ninguna, muestra "Sin acceso" en
|
||||
// lugar de redirigir a "/" en bucle (pantalla en blanco).
|
||||
const LANDING_CANDIDATOS = [
|
||||
'/agenda', '/mis-ventas', '/pacientes', '/pos', '/visitas', '/consultas',
|
||||
'/expedientes', '/medicos', '/servicios', '/ventas', '/pagos', '/monedero',
|
||||
'/inventario', '/cortes', '/reportes', '/cumpleanos', '/wacrm/messages',
|
||||
'/wacrm/leads', '/configuracion',
|
||||
];
|
||||
|
||||
const HomeRoute: FC = () => {
|
||||
const { user } = useAuth();
|
||||
const { user, canSee } = useAuth();
|
||||
if (user?.role === 'medico') return <Navigate to="/agenda" replace />;
|
||||
return <Dashboard />;
|
||||
if (canSee('/')) return <Dashboard />;
|
||||
for (const href of LANDING_CANDIDATOS) {
|
||||
if (canSee(href)) return <Navigate to={href} replace />;
|
||||
}
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col items-center justify-center gap-3">
|
||||
<p className="text-theme-heading font-semibold">Sin acceso a módulos</p>
|
||||
<p className="text-sm text-theme-muted">Tu usuario no tiene secciones habilitadas. Contacta al administrador.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const App: FC = () => {
|
||||
|
||||
@@ -23,7 +23,7 @@ const ROLE_RANK: Record<FrontendRole, number> = {
|
||||
// 'gerencia' (gerencia de la clínica) ve toda la operación excepto
|
||||
// /configuracion (solo admin del sistema), /mis-ventas, /cumpleanos y /wacrm/*.
|
||||
const MENU_ROLES: Record<string, FrontendRole[]> = {
|
||||
'/': ['admin', 'recepcion', 'medico', 'lectura', 'gerencia'],
|
||||
'/' : ['admin', 'medico', 'recepcion', 'enfermeria', 'cosmetologia', 'psicologa', 'farmacia', 'gerencia', 'marketing', 'lectura'],
|
||||
'/agenda': ['admin', 'recepcion', 'medico', 'gerencia'],
|
||||
'/mis-ventas': ['medico'],
|
||||
'/pacientes': ['admin', 'recepcion', 'medico', 'lectura', 'gerencia'],
|
||||
|
||||
@@ -94,10 +94,9 @@ class SkeenFrontendController(http.Controller):
|
||||
if not login or not password:
|
||||
return json_response({'status': 'error', 'message': 'Usuario y contraseña son obligatorios'}, 400)
|
||||
User = request.env['skeen.frontend.user'].sudo()
|
||||
# Login insensible a mayúsculas/minúsculas (la gente escribe "Andrea").
|
||||
# =ilike trata % y _ como comodines: se quitan para buscar literal.
|
||||
login_lookup = login.replace('%', '').replace('_', '')
|
||||
user = User.search([('login', '=ilike', login_lookup), ('active', '=', True)], limit=1)
|
||||
# Login insensible a mayúsculas/minúsculas: los logins guardados
|
||||
# están en minúsculas, se busca la forma exacta en minúsculas.
|
||||
user = User.search([('login', '=', login.lower()), ('active', '=', True)], limit=1)
|
||||
if not user or not user.check_password(password):
|
||||
return json_response({'status': 'error', 'message': 'Credenciales inválidas'}, 401)
|
||||
user.write({'last_login': fields.Datetime.now()})
|
||||
@@ -134,7 +133,7 @@ class SkeenFrontendController(http.Controller):
|
||||
def auth_users_create(self, **kw):
|
||||
try:
|
||||
data = _parse_json_body()
|
||||
login = (data.get('login') or '').strip()
|
||||
login = (data.get('login') or '').strip().lower()
|
||||
name = (data.get('name') or '').strip()
|
||||
password = data.get('password') or ''
|
||||
role = data.get('role') or 'recepcion'
|
||||
|
||||
@@ -47,7 +47,7 @@ MENU_ROLES_KEY = 'skeen.menu_roles'
|
||||
# operación EXCEPTO /configuracion (solo admin del sistema), /mis-ventas,
|
||||
# /cumpleanos y /wacrm/*.
|
||||
DEFAULT_MENU_ROLES = {
|
||||
'/': ['admin', 'recepcion', 'medico', 'lectura', 'gerencia'],
|
||||
'/' : ['admin', 'medico', 'recepcion', 'enfermeria', 'cosmetologia', 'psicologa', 'farmacia', 'gerencia', 'marketing', 'lectura'],
|
||||
'/agenda': ['admin', 'recepcion', 'medico', 'gerencia'],
|
||||
'/mis-ventas': ['medico'],
|
||||
'/pacientes': ['admin', 'recepcion', 'medico', 'lectura', 'gerencia'],
|
||||
|
||||
Reference in New Issue
Block a user