import { type MenuModule, isPathAllowed } from '@basic-erp/sap-types'; /** Lo que el administrador marca en pantalla para un usuario. */ export interface Selection { /** Acceso total (`*`). */ all: boolean; /** Rutas de menú marcadas (incluye las cubiertas por un patrón `/modulo/*`). */ paths: ReadonlySet; /** Patrones que no corresponden a ninguna pantalla actual (ej. de una versión futura): se conservan tal cual. */ extras: readonly string[]; } /** Módulos que se otorgan con casillas; "Administración" solo llega con acceso total. */ export const grantableModules = (menu: readonly MenuModule[]): readonly MenuModule[] => menu.filter((m) => m.id !== 'admin'); export function toSelection(patterns: readonly string[], menu: readonly MenuModule[]): Selection { const all = patterns.includes('*'); const known = menu.flatMap((m) => m.items.map((i) => i.path)); const paths = new Set(known.filter((p) => !all && isPathAllowed(patterns, p))); const extras = patterns.filter((p) => p !== '*' && !known.some((k) => isPathAllowed([p], k))); return { all, paths, extras }; } /** * Patrones a guardar: `*` si es acceso total; si no, `/modulo/*` cuando están todas las pantallas * del módulo y rutas sueltas en otro caso, más los patrones desconocidos conservados. */ export function toPatterns(sel: Selection, menu: readonly MenuModule[]): string[] { if (sel.all) return ['*']; const out: string[] = []; for (const m of grantableModules(menu)) { const checked = m.items.filter((i) => sel.paths.has(i.path)); if (checked.length === m.items.length && m.items.length > 0) out.push(`/${m.id}/*`); else out.push(...checked.map((i) => i.path)); } return [...out, ...sel.extras]; } export function togglePath(sel: Selection, path: string, on: boolean): Selection { const paths = new Set(sel.paths); if (on) paths.add(path); else paths.delete(path); return { ...sel, paths }; } export function toggleModule(sel: Selection, module: MenuModule, on: boolean): Selection { const paths = new Set(sel.paths); for (const i of module.items) { if (on) paths.add(i.path); else paths.delete(i.path); } return { ...sel, paths }; } export const samePatterns = (a: readonly string[], b: readonly string[]): boolean => a.length === b.length && [...a].sort().every((p, i) => p === [...b].sort()[i]);