const { useState, useEffect, useMemo } = React; const ALL_DAYS = [ { code: 'lun', label: 'Lunes' }, { code: 'mar', label: 'Martes' }, { code: 'mie', label: 'Miércoles' }, { code: 'jue', label: 'Jueves' }, { code: 'vie', label: 'Viernes' }, { code: 'sab', label: 'Sábado' }, { code: 'dom', label: 'Domingo' } ]; window.AdminPersonal = function({ globalUsers = [], roles = [], logs = [], handleUserSubmit, editingUser, setEditingUser, deleteUser, toggleLock, confirmAction, isReadOnly = false }) { const [showModal, setShowModal] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [filterRole, setFilterRole] = useState('ALL'); const [isSubmittingUser, setIsSubmittingUser] = useState(false); // BLOQUEO ANTI DOBLE CLIC // Horarios e Identidad const [selectedScheduleDays, setSelectedScheduleDays] = useState(['lun', 'mar', 'mie', 'jue', 'vie']); const [scheduleCustom, setScheduleCustom] = useState({}); const [baseStart, setBaseStart] = useState('08:00'); const [baseEnd, setBaseEnd] = useState('17:00'); // INSS e Impuestos const [hasInss, setHasInss] = useState(false); const [inssNumber, setInssNumber] = useState(''); const [appliesInss, setAppliesInss] = useState(true); const [appliesIr, setAppliesIr] = useState(true); const [gpsTracking, setGpsTracking] = useState(false); const [avatarBase64, setAvatarBase64] = useState(''); const [avatarPreview, setAvatarPreview] = useState(''); const isUserLockedToday = (user) => { const todayLogs = (logs || []).filter(l => Number(l.userId) === Number(user.id) && l.date === window.getNICDate()); const hasSalida = todayLogs.some(l => l.type === 'salida'); return Boolean(user.manualLock) || (hasSalida && !user.overrideCheckOut); }; useEffect(() => { if (editingUser) { setSelectedScheduleDays(editingUser.scheduleDays || ['lun', 'mar', 'mie', 'jue', 'vie']); setScheduleCustom(editingUser.scheduleCustom || {}); setBaseStart(editingUser.scheduleStart || '08:00'); setBaseEnd(editingUser.scheduleEnd || '17:00'); setHasInss(Boolean(editingUser.hasInss)); setInssNumber(editingUser.inssNumber || ''); setAppliesInss(editingUser.appliesInss !== undefined ? Boolean(editingUser.appliesInss) : true); setAppliesIr(editingUser.appliesIr !== undefined ? Boolean(editingUser.appliesIr) : true); setGpsTracking(Boolean(editingUser.gpsTrackingEnabled)); setAvatarPreview(editingUser.avatarUrl || ''); setAvatarBase64(''); setIsSubmittingUser(false); setShowModal(true); } else { setSelectedScheduleDays(['lun', 'mar', 'mie', 'jue', 'vie']); setScheduleCustom({}); setBaseStart('08:00'); setBaseEnd('17:00'); setHasInss(false); setInssNumber(''); setAppliesInss(true); setAppliesIr(true); setGpsTracking(false); setAvatarPreview(''); setAvatarBase64(''); setIsSubmittingUser(false); } }, [editingUser]); const openNewUserModal = () => { if (isReadOnly) return alert("Modo supervisión: no tienes permisos para crear empleados."); setEditingUser(null); setSelectedScheduleDays(['lun', 'mar', 'mie', 'jue', 'vie']); setScheduleCustom({}); setBaseStart('08:00'); setBaseEnd('17:00'); setHasInss(false); setInssNumber(''); setAppliesInss(true); setAppliesIr(true); setGpsTracking(false); setAvatarPreview(''); setAvatarBase64(''); setIsSubmittingUser(false); setShowModal(true); }; const closeModal = () => { if (isSubmittingUser) return; // Evitar cerrar mientras se procesa setEditingUser(null); setShowModal(false); }; const handleAvatarFile = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (ev) => { setAvatarBase64(ev.target.result); setAvatarPreview(ev.target.result); }; reader.readAsDataURL(file); }; const handleToggleDay = (dayCode) => { setSelectedScheduleDays(prev => prev.includes(dayCode) ? prev.filter(d => d !== dayCode) : [...prev, dayCode] ); }; const handleToggleCustomDay = (dayCode) => { setScheduleCustom(prev => { const copy = { ...prev }; if (copy[dayCode]) { delete copy[dayCode]; } else { copy[dayCode] = { start: '08:00', end: '12:00', isHalfDay: true }; } return copy; }); }; const handleCustomDayChange = (dayCode, field, val) => { setScheduleCustom(prev => ({ ...prev, [dayCode]: { ...prev[dayCode], [field]: val } })); }; const dbRolesList = useMemo(() => { const roleSet = new Map(); roleSet.set('propietario', 'PROPIETARIO / ADMIN'); roleSet.set('empleado', 'EMPLEADO'); (roles || []).forEach(r => { const rawName = (typeof r === 'object' ? r.name : r) || ''; const key = rawName.toLowerCase().trim(); if (key) { if (key.includes('propietario') || key.includes('admin') || key.includes('dueño')) { roleSet.set('propietario', 'PROPIETARIO / ADMIN'); } else if (key === 'empleado') { roleSet.set('empleado', 'EMPLEADO'); } else { roleSet.set(key, rawName.toUpperCase()); } } }); return Array.from(roleSet.entries()).map(([key, label]) => ({ key, label })); }, [roles]); const filteredUsers = useMemo(() => { return (globalUsers || []).filter(u => { const matchText = (u.name || '').toLowerCase().includes(searchTerm.toLowerCase()) || (u.email || '').toLowerCase().includes(searchTerm.toLowerCase()) || (u.alias || '').toLowerCase().includes(searchTerm.toLowerCase()); const userRoleKey = (u.role || u.role_name || '').toLowerCase().trim(); const matchRole = filterRole === 'ALL' || userRoleKey === filterRole.toLowerCase().trim(); return matchText && matchRole; }); }, [globalUsers, searchTerm, filterRole]); const ownersAndAdmins = filteredUsers.filter(u => { const r = (u.role || u.role_name || '').toLowerCase().trim(); return r === 'propietario' || r === 'admin' || r === 'dueño' || r === 'owner'; }); const regularEmployees = filteredUsers.filter(u => { const r = (u.role || u.role_name || '').toLowerCase().trim(); return r !== 'propietario' && r !== 'admin' && r !== 'dueño' && r !== 'owner'; }); // Control seguro de envío con bloqueo de doble clic const onFormSubmit = async (e) => { e.preventDefault(); if (isSubmittingUser) return; setIsSubmittingUser(true); try { await handleUserSubmit(e); closeModal(); } catch (err) { console.error("Error al procesar usuario:", err); } finally { setIsSubmittingUser(false); } }; const renderUserRowCard = (u, isOwner = false) => { const isLocked = isUserLockedToday(u); const activeDaysStr = (u.scheduleDays || []).join(', ').toUpperCase(); const hasCustom = u.scheduleCustom && Object.keys(u.scheduleCustom).length > 0; return (
{u.avatarUrl ? ( {u.name} ) : (
{u.name ? u.name[0].toUpperCase() : 'U'}
)}

{u.name}

{u.gpsTrackingEnabled ? ( ) : null}

{u.email}

@{u.alias} {u.role} C$ {parseFloat(u.baseSalary || 0).toLocaleString('en-US', { minimumFractionDigits: 2 })} {u.hasInss && u.inssNumber ? ( INSS: {u.inssNumber} ) : null}
Jornada: {activeDaysStr || 'SIN DÍAS'} ({u.scheduleStart || '08:00'} - {u.scheduleEnd || '17:00'}) {hasCustom && • Con Horario Especial}
{!isReadOnly ? (
{isLocked ? ( ) : ( )}
) : (
👁️ Inspección
)}
); }; return (

Personal y Horarios

Gestión de colaboradores, salarios, turnos y emisión de contratos

{!isReadOnly && ( )}
setSearchTerm(e.target.value)} placeholder="Buscar por Nombre, Correo o Código (@)..." className="flex-1 p-3.5 bg-slate-50 border rounded-2xl font-bold outline-none text-xs focus:border-indigo-500 transition-colors" />
{/* SECCIÓN 1: ADMINISTRACIÓN */}

Administración del Portal ({ownersAndAdmins.length})

{ownersAndAdmins.map(u => renderUserRowCard(u, true))}
{/* SECCIÓN 2: PERSONAL */}

Personal de Campo y Oficina ({regularEmployees.length})

{regularEmployees.map(u => renderUserRowCard(u, false))}
{/* MODAL EDITAR FICHA DE EMPLEADO (PROTECCIÓN DOBLE CLIC + PLACEHOLDERS EN GRIS) */} {showModal && (
e.stopPropagation()}>

{editingUser ? "Editar Ficha de Empleado" : "Alta de Nuevo Colaborador"}

Configuración de rol de acceso, permisos y datos laborales

{/* COLUMNA 1: IDENTIDAD & PERSONAL */}

1. Identidad & Personal

{avatarPreview ? ( ) : (
{editingUser?.name ? editingUser.name[0] : '+'}
)}
{/* CAMPO DINÁMICO NÚMERO INSS */}
{hasInss && (
setInssNumber(e.target.value)} placeholder="Ej. 1234567-8" className="w-full p-2 bg-white rounded-xl border text-xs font-bold outline-none focus:border-indigo-500 placeholder:text-slate-300" required={hasInss} />
)}
{/* COLUMNA 2: JORNADA Y HORARIOS */}

2. Jornada y Horarios

setBaseStart(e.target.value)} className="w-full p-2 bg-white rounded-xl font-bold text-xs border" />
setBaseEnd(e.target.value)} className="w-full p-2 bg-white rounded-xl font-bold text-xs border" />
{ALL_DAYS.map(d => { const isActive = selectedScheduleDays.includes(d.code); const custom = scheduleCustom[d.code]; return (
{isActive && ( )}
{isActive && custom && (
handleCustomDayChange(d.code, 'start', e.target.value)} className="p-1 bg-white rounded-md text-[9px] font-bold border" /> - handleCustomDayChange(d.code, 'end', e.target.value)} className="p-1 bg-white rounded-md text-[9px] font-bold border" />
)}
); })}
{/* COLUMNA 3: CONTRATO Y SALARIO */}

3. Contrato y Salario

{/* DEDUCCIONES DE LEY */}
{/* COLUMNA 4: ACCESO Y CAMPO */}

4. Acceso y Campo

)}
); };