feat(config): modulo Configuraciones admin + permisos por rol
- Tablas ConfiguracionSistema (7 configs) + RolConfiguracion (6 roles) - Endpoints: config/sistema GET/PATCH, config/roles GET/PATCH, config/usuarios GET/PATCH, config/reset-roles POST, config/acciones GET - modulosDeRol() async con fallback a MATRIZ estatica - auth/me devuelve acciones[] segun rol del usuario - saludMonday.estaDisponible() lee modo_local_forzado de DB (cache 30s) - Landing: vista Configuraciones con 4 tabs (Modo, Roles, Usuarios, Sistema) - Mi-dia: boton Descartar se deshabilita si !descartar_lead - 630 API tests + 24 landing tests + 20 mi-dia tests verdes Seed: npm run seed:config
This commit is contained in:
@@ -10,6 +10,8 @@ export interface UsuarioSesion {
|
||||
// Módulos del ecosistema visibles para el rol (matriz del API; presente en
|
||||
// /auth/me y /auth/login desde sep-2026)
|
||||
modulos?: string[]
|
||||
// Acciones permitidas por el rol (solo admin ve las de todos los roles)
|
||||
acciones?: string[]
|
||||
}
|
||||
|
||||
export interface Sesion {
|
||||
|
||||
119
apps/landing/src/services/config.ts
Normal file
119
apps/landing/src/services/config.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { API_URL, conAuth, manejar401 } from './auth'
|
||||
|
||||
// ─── Config Sistema ──────────────────────────────────────────────
|
||||
|
||||
export interface ConfigSistema {
|
||||
[clave: string]: string
|
||||
}
|
||||
|
||||
/** GET /config/sistema — todas las configuraciones del sistema */
|
||||
export async function getConfigSistema(): Promise<ConfigSistema> {
|
||||
const resp = await fetch(`${API_URL}/config/sistema`, conAuth())
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
return (await resp.json()) as ConfigSistema
|
||||
}
|
||||
|
||||
/** PATCH /config/sistema — actualiza configs (parcial) */
|
||||
export async function patchConfigSistema(data: Record<string, string>): Promise<void> {
|
||||
const resp = await fetch(
|
||||
`${API_URL}/config/sistema`,
|
||||
conAuth({
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
)
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
}
|
||||
|
||||
// ─── Roles ───────────────────────────────────────────────────────
|
||||
|
||||
export interface RolConfig {
|
||||
rol: string
|
||||
modulos: string // JSON array string
|
||||
acciones: string // JSON object string
|
||||
}
|
||||
|
||||
/** GET /config/roles — todas las configuraciones de rol */
|
||||
export async function getRolesConfig(): Promise<RolConfig[]> {
|
||||
const resp = await fetch(`${API_URL}/config/roles`, conAuth())
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
return (await resp.json()) as RolConfig[]
|
||||
}
|
||||
|
||||
/** PATCH /config/roles/:rol — actualiza módulos y acciones de un rol */
|
||||
export async function patchRolConfig(
|
||||
rol: string,
|
||||
data: { modulos: string[]; acciones: Record<string, boolean> },
|
||||
): Promise<void> {
|
||||
const resp = await fetch(
|
||||
`${API_URL}/config/roles/${encodeURIComponent(rol)}`,
|
||||
conAuth({
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
)
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
}
|
||||
|
||||
/** POST /config/reset-roles — restaura valores por defecto */
|
||||
export async function resetRoles(): Promise<void> {
|
||||
const resp = await fetch(
|
||||
`${API_URL}/config/reset-roles`,
|
||||
conAuth({ method: 'POST' }),
|
||||
)
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
}
|
||||
|
||||
// ─── Usuarios ────────────────────────────────────────────────────
|
||||
|
||||
export interface UsuarioConfig {
|
||||
id: string
|
||||
username: string
|
||||
nombre: string
|
||||
rol: string
|
||||
asignacion: string | null
|
||||
activo: boolean
|
||||
mondayUserId: number | null
|
||||
}
|
||||
|
||||
/** GET /config/usuarios — lista de usuarios con rol/asignación/activo */
|
||||
export async function getUsuariosConfig(): Promise<UsuarioConfig[]> {
|
||||
const resp = await fetch(`${API_URL}/config/usuarios`, conAuth())
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
return (await resp.json()) as UsuarioConfig[]
|
||||
}
|
||||
|
||||
/** PATCH /config/usuarios/:id — cambia rol/asignación/activo */
|
||||
export async function patchUsuarioConfig(
|
||||
id: string,
|
||||
data: { rol?: string; asignacion?: string | null; activo?: boolean },
|
||||
): Promise<void> {
|
||||
const resp = await fetch(
|
||||
`${API_URL}/config/usuarios/${encodeURIComponent(id)}`,
|
||||
conAuth({
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
)
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
}
|
||||
|
||||
// ─── Acciones ────────────────────────────────────────────────────
|
||||
|
||||
/** GET /config/acciones — acciones disponibles para el rol del usuario actual */
|
||||
export async function getAcciones(): Promise<Record<string, boolean>> {
|
||||
const resp = await fetch(`${API_URL}/config/acciones`, conAuth())
|
||||
manejar401(resp)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
return (await resp.json()) as Record<string, boolean>
|
||||
}
|
||||
Reference in New Issue
Block a user