107 lines
3.2 KiB
JavaScript
107 lines
3.2 KiB
JavaScript
// src/lib/auth.jsx
|
|
import { createContext, useContext, useEffect, useState, useCallback } from "react";
|
|
import { supabase } from "./supabase";
|
|
|
|
const AuthContext = createContext(null);
|
|
|
|
export function AuthProvider({ children }) {
|
|
const [session, setSession] = useState(null);
|
|
const [perfil, setPerfil] = useState(null); // { nombre, rol }
|
|
const [permisos, setPermisos] = useState([]); // ["ocupabilidad", "cobranza", ...]
|
|
const [cargando, setCargando] = useState(true);
|
|
|
|
// Cargar perfil (rol) y permisos del usuario logueado
|
|
const cargarPerfil = useCallback(async (userId) => {
|
|
// 1) Traer el rol del usuario desde la tabla "perfiles"
|
|
const { data: perf, error: e1 } = await supabase
|
|
.from("perfiles")
|
|
.select("nombre, rol, activo")
|
|
.eq("id", userId)
|
|
.single();
|
|
|
|
if (e1 || !perf || perf.activo === false) {
|
|
setPerfil(null);
|
|
setPermisos([]);
|
|
return false;
|
|
}
|
|
|
|
// 2) Traer los módulos permitidos para ese rol desde "permisos"
|
|
const { data: perms } = await supabase
|
|
.from("permisos")
|
|
.select("modulo, puede_ver")
|
|
.eq("rol", perf.rol);
|
|
|
|
const modulos = (perms || [])
|
|
.filter((p) => p.puede_ver)
|
|
.map((p) => p.modulo);
|
|
|
|
setPerfil({ nombre: perf.nombre, rol: perf.rol });
|
|
setPermisos(modulos);
|
|
return true;
|
|
}, []);
|
|
|
|
// Al iniciar: revisar si ya hay sesión activa
|
|
useEffect(() => {
|
|
let activo = true;
|
|
supabase.auth.getSession().then(async ({ data }) => {
|
|
if (!activo) return;
|
|
const s = data?.session || null;
|
|
setSession(s);
|
|
if (s?.user) await cargarPerfil(s.user.id);
|
|
setCargando(false);
|
|
});
|
|
|
|
// Escuchar cambios de sesión (login/logout)
|
|
const { data: sub } = supabase.auth.onAuthStateChange(async (_evt, s) => {
|
|
setSession(s);
|
|
if (s?.user) await cargarPerfil(s.user.id);
|
|
else { setPerfil(null); setPermisos([]); }
|
|
});
|
|
|
|
return () => { activo = false; sub?.subscription?.unsubscribe(); };
|
|
}, [cargarPerfil]);
|
|
|
|
const login = async (email, password) => {
|
|
const { data, error } = await supabase.auth.signInWithPassword({ email, password });
|
|
if (error) return { ok: false, msg: traducirError(error.message) };
|
|
// Verificar que tenga perfil/rol válido
|
|
const ok = await cargarPerfil(data.user.id);
|
|
if (!ok) {
|
|
await supabase.auth.signOut();
|
|
return { ok: false, msg: "Tu usuario no tiene un perfil asignado. Contacta al administrador." };
|
|
}
|
|
return { ok: true };
|
|
};
|
|
|
|
const logout = async () => {
|
|
await supabase.auth.signOut();
|
|
setPerfil(null);
|
|
setPermisos([]);
|
|
};
|
|
|
|
const value = {
|
|
session,
|
|
perfil,
|
|
permisos,
|
|
cargando,
|
|
login,
|
|
logout,
|
|
autenticado: !!session && !!perfil,
|
|
puedeVer: (modulo) => permisos.includes(modulo),
|
|
};
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
}
|
|
|
|
export function useAuth() {
|
|
const ctx = useContext(AuthContext);
|
|
if (!ctx) throw new Error("useAuth debe usarse dentro de AuthProvider");
|
|
return ctx;
|
|
}
|
|
|
|
function traducirError(msg) {
|
|
if (/invalid login credentials/i.test(msg)) return "Correo o contraseña incorrectos.";
|
|
if (/email not confirmed/i.test(msg)) return "El correo no está confirmado.";
|
|
return msg || "Error al iniciar sesión.";
|
|
}
|