const { useState, useMemo } = React; window.AdminRoles = function({ actions = [], roles = [], showToast, refreshData }) { // Estado para Botones (Marcajes) const [editingActionId, setEditingActionId] = useState(null); const [actionLabel, setActionLabel] = useState(''); // Estado para Roles const [editingRoleOriginalName, setEditingRoleOriginalName] = useState(null); const [roleName, setRoleName] = useState(''); const [accessLevel, setAccessLevel] = useState('full'); // 'full' (Total), 'readonly' (Sólo Lectura), 'app_only' (App) const [permissions, setPermissions] = useState([]); const [cameraActions, setCameraActions] = useState([]); // Botones disponibles en el sistema (por defecto + personalizados) const availableActions = useMemo(() => { return actions.length > 0 ? actions : [ { id: 'almuerzo', label: 'Almuerzo' }, { id: 'break', label: 'Break / Merienda' }, { id: 'visita_in', label: 'Visita Cliente' }, { id: 'reunion', label: 'Reunión' }, { id: 'capacitacion', label: 'Capacitación' }, { id: 'gestiones', label: 'Gestiones de Campo' } ]; }, [actions]); // Combinar roles de la BD con los predeterminados const allCombinedRoles = useMemo(() => { const defaultRoles = [ { name: 'propietario', label: 'PROPIETARIO / ADMIN', accessLevel: 'full', permissions: availableActions.map(a => a.id), cameraActions: ['entrada', 'salida'] }, { name: 'empleado', label: 'EMPLEADO DE CAMPO / OFICINA', accessLevel: 'app_only', permissions: availableActions.map(a => a.id), cameraActions: ['entrada', 'salida'] } ]; const customMapped = (roles || []).map(r => ({ ...r, name: (r.name || '').toLowerCase().trim(), label: (r.name || '').toUpperCase().trim(), permissions: Array.isArray(r.permissions) ? r.permissions : (r.permissions ? JSON.parse(r.permissions) : []), cameraActions: Array.isArray(r.cameraActions) ? r.cameraActions : (r.cameraActions ? JSON.parse(r.cameraActions) : []), accessLevel: r.accessLevel || r.access_level || 'full' })); const list = []; const seen = new Set(); // Primero los personalizados / editados customMapped.forEach(r => { if (!seen.has(r.name)) { seen.add(r.name); list.push(r); } }); // Luego los defaults si no han sido personalizados defaultRoles.forEach(r => { if (!seen.has(r.name)) { seen.add(r.name); list.push(r); } }); return list; }, [roles, availableActions]); // --- ACCIONES DE BOTONES (MARCAJES) --- const handleSaveAction = async () => { if (!actionLabel.trim()) { if (showToast) showToast("Escribe un nombre para el botón."); return; } const newId = editingActionId || actionLabel.toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '') + '_' + Date.now().toString().slice(-4); const res = await window.apiCall('save_action', { action_id: newId, label: actionLabel.trim() }); if (res && res.success) { setEditingActionId(null); setActionLabel(''); if (showToast) showToast("Botón guardado exitosamente."); if (refreshData) await refreshData(); } else { if (showToast) showToast("Error al guardar botón."); } }; const handleDeleteAction = async (act) => { if (['entrada', 'salida'].includes(act.id)) return alert("No puedes eliminar los botones base de Entrada y Salida."); if (!confirm(`¿Estás seguro de eliminar el botón "${act.label}"?`)) return; const res = await window.apiCall('delete_action', { action_id: act.id }); if (res && res.success) { if (showToast) showToast("Botón eliminado."); if (refreshData) await refreshData(); } }; // --- ACCIONES DE ROLES --- const handleEditRoleClick = (r) => { setEditingRoleOriginalName(r.name); setRoleName(r.name.toUpperCase()); setAccessLevel(r.accessLevel || 'full'); setPermissions(r.permissions && r.permissions.length > 0 ? r.permissions : availableActions.map(a => a.id)); setCameraActions(r.cameraActions || ['entrada', 'salida']); }; const handleCancelRoleEdit = () => { setEditingRoleOriginalName(null); setRoleName(''); setAccessLevel('full'); setPermissions([]); setCameraActions([]); }; const handleSaveRole = async () => { if (!roleName.trim()) { if (showToast) showToast("El nombre del rol es obligatorio."); return; } const res = await window.apiCall('save_role', { name: roleName.toLowerCase().trim(), oldName: editingRoleOriginalName ? editingRoleOriginalName.toLowerCase().trim() : null, permissions: permissions, cameraActions: cameraActions, accessLevel: accessLevel }); if (res && res.success) { if (showToast) showToast("Rol guardado exitosamente."); handleCancelRoleEdit(); if (refreshData) await refreshData(); } else { if (showToast) showToast("Error al guardar rol: " + (res?.error || "")); } }; const togglePermission = (actionId) => { setPermissions(prev => prev.includes(actionId) ? prev.filter(p => p !== actionId) : [...prev, actionId]); }; const toggleCamera = (actionId) => { setCameraActions(prev => prev.includes(actionId) ? prev.filter(p => p !== actionId) : [...prev, actionId]); }; return (
Crea o renombra los botones que ven los usuarios en la aplicación. Puedes modificar su nombre visible sin romper el historial de registros.
Permisos: {permLabels.join(' • ') || 'Ninguno'}