Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProyectoFerretek/FerreMarket/llms.txt

Use this file to discover all available pages before exploring further.

src/utils/auth.ts provides server-side role checks and permission guards used across FerreMarket’s admin pages. These functions complement the session-based AuthContext with business-logic level access control: while AuthContext manages whether a user is authenticated at all, the utilities in this module determine what that authenticated user is allowed to do based on their role and active/inactive status stored in the usuarios table.

The usuarioActual Object

At the module level, auth.ts maintains a single shared state object that holds the currently authenticated worker’s role and status:
const usuarioActual = {
  id: '',
  rol: '',     // 'Admin' | 'Usuario' | 'Cliente'  (capitalised)
  estado: '',  // 'Activo' | 'Inactivo'             (capitalised)
  nombre: ''
};
This object starts with all fields set to empty strings. It is populated by calling cargarPermisosTrabajador() after a Supabase session has been established. All permission-guard functions read directly from this object, so they will return false (or their fallback) until the object has been loaded.
usuarioActual is empty at module initialisation. Always call cargarPermisosTrabajador() and await its resolution before invoking any permission-check function (esAdministrador, puedeGestionarUsuarios, puedeRealizarAccion). Calling them on a freshly imported module without loading data first will always return false because rol is still an empty string.

cargarPermisosTrabajador

export const cargarPermisosTrabajador = async (): Promise<void>
Retrieves the active Supabase Auth session, queries the usuarios table for the row whose uid matches the authenticated user’s UUID, and writes the returned rol, estado, and nombre fields into usuarioActual. Each value is normalised through capitalizeWords before storage, so raw lowercase database values like 'admin' become 'Admin'. If there is no active session, a warning is logged to the console and the function returns without modifying usuarioActual. If the Supabase query fails, the error is logged and the function returns early without mutating state. Parameters — none. Returns Promise<void>.
import { cargarPermisosTrabajador } from '@/utils/auth';

// Call once after confirming the user is logged in, e.g. in a top-level
// route guard or an AuthContext effect:
await cargarPermisosTrabajador();

// usuarioActual is now populated and permission checks are safe to call.
The best place to call this function is inside the same useEffect (or equivalent initialisation hook) that reads the Supabase session, immediately after verifying session.data.session is not null. Calling it in a shared layout component ensures it runs once per page load for every protected route.

obtenerUsuarioIdByUUID

export const obtenerUsuarioIdByUUID = async (uuid: string): Promise<number | null>
Resolves a Supabase Auth UUID to the internal numeric primary key used in the application’s usuarios table. Internally it runs:
const { data, error } = await supabase
  .from('usuarios')
  .select('id')
  .eq('uid', uuid)
  .single();
If the query succeeds and a row is found, data.id (a number) is returned. If the query fails or no matching row exists, the error is logged and the function returns null.
uuid
string
required
The UUID string from Supabase Auth (i.e. session.user.id). This is the value stored in the uid column of the usuarios table.
Returns Promise<number | null> — the internal numeric id of the user row, or null if the lookup fails.
import { obtenerUsuarioIdByUUID } from '@/utils/auth';

const session = await supabase.auth.getSession();
if (session.data.session) {
  const uuid = session.data.session.user.id;
  const internalId = await obtenerUsuarioIdByUUID(uuid);

  if (internalId !== null) {
    console.log('Internal user ID:', internalId); // e.g. 7
  }
}

esAdministrador

export const esAdministrador = (): boolean
Returns true when the loaded usuarioActual.rol is exactly 'Admin'. The comparison is case-sensitive — the value must be the capitalised form written by cargarPermisosTrabajador. This function is the foundation of every other permission guard; all other guards call esAdministrador() internally before applying their own additional conditions. Parameters — none. Returns booleantrue if and only if usuarioActual.rol === 'Admin'.
import { cargarPermisosTrabajador, esAdministrador } from '@/utils/auth';

await cargarPermisosTrabajador();

if (esAdministrador()) {
  // Show admin-only controls
}

puedeGestionarUsuarios

export const puedeGestionarUsuarios = (): boolean
A compound guard that requires both administrator role and an active account status. It returns true only when esAdministrador() is true and usuarioActual.estado === 'Activo'. This is used as the entry guard for the User Management page to prevent suspended administrators from making changes to user accounts. Parameters — none. Returns booleantrue if the current user is an active administrator.
import { cargarPermisosTrabajador, puedeGestionarUsuarios } from '@/utils/auth';

await cargarPermisosTrabajador();

if (!puedeGestionarUsuarios()) {
  navigate('/unauthorized');
}

puedeRealizarAccion

export const puedeRealizarAccion = (
  accion: 'crear' | 'editar' | 'eliminar' | 'ver' | 'recuperar'
): boolean
A granular action-level permission check. All recognised actions first require administrator role — non-admins always receive false regardless of the action requested. For admins, most actions are permitted freely, but 'eliminar' carries an extra constraint: the administrator’s account must also be in 'Activo' status.
accion
'crear' | 'editar' | 'eliminar' | 'ver' | 'recuperar'
required
The operation being attempted. Must be one of the five literal string values listed in the union type.
Returns boolean — whether the current user may perform the requested action.
accionAdmin 'Activo'Admin 'Inactivo'Non-admin
'ver'truetruefalse
'crear'truetruefalse
'editar'truetruefalse
'recuperar'truetruefalse
'eliminar'truefalsefalse
import { cargarPermisosTrabajador, puedeRealizarAccion } from '@/utils/auth';

await cargarPermisosTrabajador();

// Conditionally render a delete button
{puedeRealizarAccion('eliminar') && (
  <button onClick={() => handleEliminar(id)}>
    Eliminar
  </button>
)}

// Guard a create action before submitting a form
if (!puedeRealizarAccion('crear')) {
  toast.error('No tienes permisos para crear registros.');
  return;
}

obtenerUsuarioActual

export const obtenerUsuarioActual = () => {
  return usuarioActual;
}
Returns a direct reference to the usuarioActual module-level object. This is the recommended way to read the logged-in user’s name and role in UI components — for example to display "Bienvenido, {nombre}" in a navbar or to show a role badge in the profile dropdown. Parameters — none. Returns typeof usuarioActual — the shared object with id, rol, estado, and nombre fields.
import { cargarPermisosTrabajador, obtenerUsuarioActual } from '@/utils/auth';

await cargarPermisosTrabajador();

const usuario = obtenerUsuarioActual();

console.log(usuario.nombre); // 'Ana Torres'
console.log(usuario.rol);    // 'Admin'
console.log(usuario.estado); // 'Activo'

Important Notes

usuarioActual starts with all fields as empty strings. Call cargarPermisosTrabajador() and await its completion before invoking any permission-check function. Permission guards (esAdministrador, puedeGestionarUsuarios, puedeRealizarAccion) read directly from usuarioActual — if that object has not been populated, they will all return false because rol is '', which does not equal 'Admin'.
Role and status values inside usuarioActual are capitalised'Admin', 'Usuario', 'Cliente', 'Activo', 'Inactivo' — because cargarPermisosTrabajador passes every value through capitalizeWords before writing it to the object. The raw values in the Supabase usuarios table are stored in lowercase ('admin', 'usuario', 'activo', etc.). Keep this distinction in mind if you ever compare usuarioActual.rol directly against a value you have read from the database: normalise both sides first, or rely on the exported guard functions which already handle this correctly.

Build docs developers (and LLMs) love