const { useState, useEffect, useMemo } = React; window.AdminSaaS = function({ activeViewTab = 'saas_clients', refreshData }) { const [saasData, setSaasData] = useState({ clients: [], invoices: [], masterGeminiApiKey: '' }); const [selectedClient, setSelectedClient] = useState(null); const [showModuleModal, setShowModuleModal] = useState(false); const [showInvoiceModal, setShowInvoiceModal] = useState(false); // Modal de Nueva / Editar Empresa const [showCompanyModal, setShowCompanyModal] = useState(false); const [editingCompany, setEditingCompany] = useState(null); const [masterKeyInput, setMasterKeyInput] = useState(''); const [isSaving, setIsSaving] = useState(false); const [showKey, setShowKey] = useState(false); const [saveFeedback, setSaveFeedback] = useState(''); const loadMasterData = async () => { const res = await window.apiCall('get_master_dashboard_data', {}, 0); if (res && res.success) { setSaasData(res); setMasterKeyInput(res.masterGeminiApiKey || ''); } }; useEffect(() => { loadMasterData(); }, []); const metrics = useMemo(() => { const totalClients = saasData.clients.length; const activeClients = saasData.clients.filter(c => c.service_status === 'active').length; const suspendedClients = saasData.clients.filter(c => c.service_status === 'suspended').length; let mrrUSD = 0; saasData.clients.forEach(c => { if (c.service_status === 'active') { mrrUSD += parseFloat(c.monthly_fee || 0); } }); const today = new Date().toISOString().split('T')[0]; const overdueInvoices = saasData.invoices.filter(inv => { if (inv.status !== 'unpaid') return false; const diffDays = Math.floor((new Date(today) - new Date(inv.due_date)) / (1000 * 60 * 60 * 24)); return diffDays >= 5; }); return { totalClients, activeClients, suspendedClients, mrrUSD, overdueInvoices }; }, [saasData]); const handleSaveMasterKey = async () => { if (!masterKeyInput.trim()) return alert("Ingresa la API Key Maestra de Google Gemini."); setIsSaving(true); setSaveFeedback(''); try { const res = await window.apiCall('save_master_gemini_key', { gemini_api_key: masterKeyInput.trim() }, 0); if (res && res.success) { setSaveFeedback('API Key Maestra guardada correctamente en el servidor.'); await loadMasterData(); } else { setSaveFeedback('Error: ' + (res?.error || 'No se pudo guardar')); } } catch (err) { setSaveFeedback('Error de conexión: ' + err.message); } finally { setIsSaving(false); } }; const handleOpenNewCompany = () => { setEditingCompany(null); setShowCompanyModal(true); }; const handleOpenEditCompany = (cl) => { setEditingCompany(cl); setShowCompanyModal(true); }; const handleSaveCompanySubmit = async (e) => { e.preventDefault(); const fd = new FormData(e.target); const payload = { id: editingCompany ? editingCompany.id : null, company_name: fd.get('company_name'), shift_subdomain: fd.get('shift_subdomain'), contact_name: fd.get('contact_name'), contact_email: fd.get('contact_email'), contact_phone: fd.get('contact_phone'), admin_password: fd.get('admin_password'), tax_regime: fd.get('tax_regime'), ruc_number: fd.get('ruc_number'), owner_name: fd.get('owner_name'), legal_rep_id: fd.get('legal_rep_id'), business_address: fd.get('business_address'), municipality: fd.get('municipality'), module_shift: 1 }; setIsSaving(true); const res = await window.apiCall('save_master_client', payload, 0); setIsSaving(false); if (res && res.success) { setShowCompanyModal(false); await loadMasterData(); if (refreshData) await refreshData(0); } else { alert("Error al guardar empresa: " + (res?.error || "")); } }; const handleOpenModules = (cl) => { setSelectedClient(cl); setShowModuleModal(true); }; const handleSaveModulesAndBilling = async (e) => { e.preventDefault(); const fd = new FormData(e.target); const payload = { id: selectedClient.id, account_type: fd.get('account_type'), monthly_fee: fd.get('monthly_fee'), currency: fd.get('currency'), billing_day: fd.get('billing_day'), service_status: fd.get('service_status'), service_paid_until: fd.get('service_paid_until'), module_asistencia: fd.get('module_asistencia') ? 1 : 0, module_personal: fd.get('module_personal') ? 1 : 0, module_contratos: fd.get('module_contratos') ? 1 : 0, module_planilla: fd.get('module_planilla') ? 1 : 0, module_vacaciones: fd.get('module_vacaciones') ? 1 : 0, module_ausencias: fd.get('module_ausencias') ? 1 : 0, module_ai: fd.get('module_ai') ? 1 : 0, module_facial: fd.get('module_facial') ? 1 : 0 }; setIsSaving(true); const res = await window.apiCall('save_client_modules_and_billing', payload, 0); setIsSaving(false); if (res && res.success) { setShowModuleModal(false); await loadMasterData(); if (refreshData) await refreshData(0); } }; const handleToggleSuspension = async (client, currentStatus) => { const nextStatus = currentStatus === 'suspended' ? 'active' : 'suspended'; const msg = nextStatus === 'suspended' ? `¿Deseas SUSPENDER el acceso al portal de ${client.company_name}?` : `¿Deseas REACTIVAR el acceso al portal de ${client.company_name}?`; if (!confirm(msg)) return; const res = await window.apiCall('toggle_service_suspension', { client_id: client.id, status: nextStatus }, 0); if (res && res.success) { await loadMasterData(); if (refreshData) await refreshData(0); } }; const handleMarkPaid = async (inv) => { const ref = prompt("Referencia bancaria o método de pago (ej. Transferencia BAC #9482):", "Transferencia BAC"); if (ref === null) return; const res = await window.apiCall('mark_invoice_paid', { invoice_id: inv.id, payment_method: 'Transferencia Bancaria', payment_reference: ref }, 0); if (res && res.success) { alert(`Factura ${inv.invoice_number} marcada como PAGADA.`); await loadMasterData(); } }; const handleCreateInvoice = async (e) => { e.preventDefault(); const fd = new FormData(e.target); const clId = fd.get('client_id'); const cl = saasData.clients.find(c => Number(c.id) === Number(clId)); const payload = { client_id: clId, company_name: cl ? cl.company_name : 'Empresa Cliente', amount: fd.get('amount'), currency: fd.get('currency'), issue_date: fd.get('issue_date'), due_date: fd.get('due_date'), period_start: fd.get('period_start'), period_end: fd.get('period_end'), status: 'unpaid' }; setIsSaving(true); const res = await window.apiCall('create_client_invoice', payload, 0); setIsSaving(false); if (res && res.success) { setShowInvoiceModal(false); await loadMasterData(); } }; return (
{/* ENCABEZADO */}

Centro de Control SaaS • Shift Master

Administración central de empresas, cobros recurrentes y motor de Inteligencia Artificial

MRR Activo: ${metrics.mrrUSD.toLocaleString('en-US', { minimumFractionDigits: 2 })} USD
{/* ALERTA DE MORAS */} {metrics.overdueInvoices.length > 0 && (

Atención: {metrics.overdueInvoices.length} Factura(s) con más de 5 días de mora

Aplica suspensión o registra el cobro de estas empresas.

{metrics.overdueInvoices.map(inv => (
{inv.company_name} ({inv.currency} ${parseFloat(inv.amount).toFixed(2)})
))}
)} {/* SECCIÓN 1: EMPRESAS & PLANES */} {activeViewTab === 'saas_clients' && (

Total Empresas

{metrics.totalClients}

Empresas Activas

{metrics.activeClients}

Suspendidas

{metrics.suspendedClients}

Facturación Proyectada

${metrics.mrrUSD.toFixed(2)} USD

Directorio de Empresas SaaS

Gestión de portales, subdominios y planes

{saasData.clients.map(c => { const isSuspended = c.service_status === 'suspended'; const isDemo = c.account_type === 'demo'; const hasFacial = Boolean(c.module_facial); return (

{c.company_name}

{isDemo ? 'DEMO' : 'CLIENTE PAGO'} {hasFacial && ( BIOMETRÍA FACIAL ACTIVA )} {isSuspended ? 'SUSPENDIDO' : 'ACTIVO'}

{c.shift_subdomain}.shift.marcasnicaragua.com • Contacto: {c.contact_name} ({c.contact_email})

Tarifa: {c.currency} ${parseFloat(c.monthly_fee || 0).toFixed(2)}/mes • Día de Cobro: {c.billing_day} • Pagado hasta: {c.service_paid_until || 'Sin registrar'}

); })}
)} {/* SECCIÓN 2: COBROS & FACTURACIÓN */} {activeViewTab === 'saas_invoices' && (

Historial de Facturación y Cobros

Control mensual de facturas generadas a las empresas clientes

{saasData.invoices.length === 0 ? (

No hay facturas emitidas aún.

) : ( saasData.invoices.map(inv => { const isPaid = inv.status === 'paid'; return (

{inv.invoice_number} • {inv.company_name}

{isPaid ? 'PAGADA' : 'PENDIENTE'}

Periodo: {inv.period_start} al {inv.period_end} • Vence: {inv.due_date}

{isPaid &&

Pagado con: {inv.payment_method} ({inv.payment_reference})

}
{inv.currency} ${parseFloat(inv.amount).toFixed(2)} {!isPaid && ( )}
); }) )}
)} {/* SECCIÓN 3: MOTOR IA MAESTRO */} {activeViewTab === 'saas_ai' && (

API Key Maestra de Google Gemini

Esta clave central abastece el asistente de inteligencia artificial para todas las empresas de tu SaaS con aislamiento de datos.

setMasterKeyInput(e.target.value)} placeholder="Pega tu clave maestra: AIzaSy..." className="w-full p-4 bg-white/10 border border-white/20 rounded-2xl text-xs font-mono font-bold text-white outline-none focus:border-indigo-400" />
{saveFeedback && (

{saveFeedback}

)}
)} {/* MODAL COMPLETO DE ALTA / EDICIÓN DE EMPRESA */} {showCompanyModal && (
setShowCompanyModal(false)}>
e.stopPropagation()}>

{editingCompany ? "Editar Ficha de Empresa" : "Alta de Nueva Empresa SaaS"}

Información corporativa, fiscal y credenciales de acceso administrativo

.shift...
)} {/* MODAL CONFIGURACIÓN DE MÓDULOS (INCLUYE RECONOCIMIENTO FACIAL BIOMÉTRICO) */} {showModuleModal && selectedClient && (
setShowModuleModal(false)}>
e.stopPropagation()}>

Plan & Módulos: {selectedClient.company_name}

Activa o desactiva las secciones según el plan contratado

{[ { name: 'module_asistencia', label: 'Asistencia y Marcajes' }, { name: 'module_personal', label: 'Gestión de Personal' }, { name: 'module_contratos', label: 'Contratos Laborales' }, { name: 'module_planilla', label: 'Planilla de Sueldos (NI)' }, { name: 'module_vacaciones', label: 'Control de Vacaciones' }, { name: 'module_ausencias', label: 'Registro de Ausencias' }, { name: 'module_ai', label: 'Shift Copilot AI' }, { name: 'module_facial', label: 'Reconocimiento Facial Biométrico' } ].map(mod => ( ))}
)} {/* MODAL EMISIÓN DE FACTURA */} {showInvoiceModal && (
setShowInvoiceModal(false)}>
e.stopPropagation()}>

Nueva Factura de Servicio

)}
); };