// ── PANEL DE ADMIN ────────────────────────────────────────────
const AdminScreen = () => {
const[tab,setTab]=React.useState('usuarios');
const[stats,setStats]=React.useState({});
const[users,setUsers]=React.useState([]);
const[invites,setInvites]=React.useState([]);
const[events,setEvents]=React.useState([]);
const[modal,setModal]=React.useState(false);
const[invForm,setInvForm]=React.useState({email:'',plan:'v1',name:''});
const[copied,setCopied]=React.useState('');
const[sending,setSending]=React.useState(false);
const load=()=>{
API.get('/admin/stats').then(r=>r&&setStats(r));
API.get('/admin/users').then(r=>r&&setUsers(r));
API.get('/admin/invitations').then(r=>r&&setInvites(r));
API.get('/admin/hotmart-events').then(r=>r&&setEvents(r));
};
React.useEffect(()=>{load();},[]);
const sendInvite=async()=>{
if(!invForm.email){showToast('Email requerido','error');return;}
setSending(true);
const res=await API.post('/admin/invite',invForm);
setSending(false);
if(res.error){showToast(res.error,'error');return;}
setModal(false);
setInvForm({email:'',plan:'v1',name:''});
showToast(res.email_sent?'Invitación enviada por email ✓':'Invitación creada (email no configurado)');
load();
// Copiar link al portapapeles
if(res.invite_url) { try{navigator.clipboard.writeText(res.invite_url);}catch{} }
};
const copyLink=async(url)=>{
try{await navigator.clipboard.writeText(url); setCopied(url); setTimeout(()=>setCopied(''),2000);}catch{}
};
const updateUser=async(id,field,val)=>{
const u=users.find(x=>x.id===id);
await API.put(`/admin/users/${id}`,{...u,[field]:val});
showToast('Actualizado ✓');
load();
};
const deleteInvite=async(id)=>{
if(!confirm('¿Cancelar esta invitación?'))return;
await API.del(`/admin/invitations/${id}`);
showToast('Invitación cancelada');
load();
};
const statusColor={active:EJ.green,suspended:EJ.pink,pending:'#F59E0B'};
const statusLabel={active:'Activa',suspended:'Suspendida',pending:'Pendiente'};
const planLabel={v1:'Esencial ($3)',v2:'Pro IA ($6)'};
const hotmartColor={'active':EJ.green,'canceled':'#F59E0B','payment_failed':EJ.pink,'suspended':EJ.pink};
return (
Panel de Admin
Gestión de usuarias, invitaciones y Hotmart
setModal(true)}>+ Enviar invitación
{/* Stats */}
{[
{label:'Usuarias totales',value:stats.total_users||0,color:EJ.navy},
{label:'Activas',value:stats.active_users||0,color:EJ.green},
{label:'Suspendidas',value:stats.suspended_users||0,color:EJ.pink},
{label:'Invitaciones pendientes',value:stats.pending_invites||0,color:EJ.violet},
{label:'Eventos Hotmart hoy',value:stats.events_today||0,color:EJ.cyan},
].map((s,i)=>
{s.label}
{s.value}
)}
{/* Tabs */}
{[{id:'usuarios',label:'👥 Usuarias'},{id:'invitaciones',label:'✉️ Invitaciones'},{id:'hotmart',label:'🔗 Hotmart'}].map(t=>(
setTab(t.id)} style={{padding:'8px 18px',borderRadius:50,border:'none',cursor:'pointer',fontFamily:'Nunito, sans-serif',fontWeight:700,fontSize:13,background:tab===t.id?EJ.navy:'transparent',color:tab===t.id?'#fff':EJ.muted,transition:'all .2s'}}>
{t.label}
))}
{/* USUARIOS */}
{tab==='usuarios'&&
{['Email','Nombre','Plan','Estado Cuenta','Estado Hotmart','Registro','Último acceso','Acciones'].map(h=>{h} )}
{users.length===0?Sin usuarias registradas :
users.map(u=>
{u.email}
{u.name||'—'}
updateUser(u.id,'plan',e.target.value)} style={{fontSize:12,border:`1px solid ${EJ.border}`,borderRadius:8,padding:'3px 8px',background:'#fff',cursor:'pointer'}}>
Esencial
Pro IA
updateUser(u.id,'status',e.target.value)} style={{fontSize:12,border:`1px solid ${EJ.border}`,borderRadius:8,padding:'3px 8px',background:'#fff',cursor:'pointer',color:statusColor[u.status]||EJ.muted}}>
Activa
Suspendida
{u.hotmart_subscription_status||'—'}
{u.created_at?.slice(0,10)||'—'}
{u.last_login?.slice(0,10)||'Nunca'}
updateUser(u.id,'status',u.status==='active'?'suspended':'active')} style={{background:'none',border:`1px solid ${u.status==='active'?EJ.pink:EJ.green}`,borderRadius:8,padding:'4px 10px',cursor:'pointer',fontSize:11,color:u.status==='active'?EJ.pink:EJ.green,fontWeight:600}}>
{u.status==='active'?'Suspender':'Reactivar'}
)}
}
{/* INVITACIONES */}
{tab==='invitaciones'&&
💡 Cómo funciona: Cuando envías una invitación, la usuaria recibe un email con un link único.
Al hacer clic, puede registrarse y el link se marca como usado.
Si no tienes email configurado, copia el link manualmente y envíalo por WhatsApp.
{['Email','Plan','Estado','Expira','Link de invitación','Transacción Hotmart',''].map(h=>{h} )}
{invites.length===0?Sin invitaciones :
invites.map(inv=>{
const expired=new Date(inv.expires_at)
{inv.email}
{inv.plan==='v2'?'Pro':'Esencial'}
{inv.status==='used'?'✓ Usada':expired?'Expirada':'Pendiente'}
{inv.expires_at?.slice(0,10)}
{inv.status==='pending'&&!expired&&
{invUrl}
copyLink(invUrl)} style={{background:copied===invUrl?EJ.green:EJ.cyan,color:'#fff',border:'none',borderRadius:8,padding:'4px 10px',cursor:'pointer',fontSize:11,fontWeight:600,whiteSpace:'nowrap'}}>
{copied===invUrl?'✓ Copiado':'Copiar'}
}
{inv.hotmart_transaction||'Manual'}
{inv.status==='pending'&&deleteInvite(inv.id)} style={{background:'none',border:'none',cursor:'pointer',color:EJ.pink,fontSize:16}}>✕ }
;
})}
}
{/* HOTMART EVENTOS */}
{tab==='hotmart'&&
🔗 URL del Webhook para Hotmart
{window.location.origin}/api/webhook/hotmart
copyLink(window.location.origin+'/api/webhook/hotmart')} style={{background:EJ.navy,color:'#fff',border:'none',borderRadius:12,padding:'12px 20px',cursor:'pointer',fontFamily:'Nunito, sans-serif',fontWeight:700,fontSize:13,whiteSpace:'nowrap'}}>
{copied===window.location.origin+'/api/webhook/hotmart'?'✓ Copiado':'Copiar URL'}
Configura en Hotmart: Panel → Herramientas → Webhook → + Registrar → Pega esta URL.
Eventos recomendados: PURCHASE_APPROVED · SUBSCRIPTION_CANCELLATION · PURCHASE_REFUNDED · SUBSCRIPTION_PAYMENT_FAILED
Variable de entorno: Agrega HOTMART_HOTTOK con el token de seguridad de Hotmart para mayor seguridad.
📋 Log de eventos recientes
{events.length===0?🔗
Sin eventos. Cuando Hotmart envíe notificaciones, aparecerán aquí.
:(
{['Evento','Email','Transacción','Plan','Estado','Fecha'].map(h=>{h} )}
{events.map(e=>
{e.event||'—'}
{e.email||'—'}
{e.transaction?.slice(0,16)||'—'}
{e.plan}
{e.processed?'✓ Procesado':'Pendiente'}
{e.created_at?.slice(0,16)}
)}
)}
}
{/* MODAL INVITACIÓN */}
setModal(false)} title="✉️ Enviar invitación" width={440}>
La usuaria recibirá un email con link de activación. Si SMTP no está configurado, se generará un link que puedes copiar y enviar manualmente.
setInvForm(f=>({...f,email:e.target.value}))}/>
setInvForm(f=>({...f,name:e.target.value}))}/>
setInvForm(f=>({...f,plan:e.target.value}))} options={[{value:'v1',label:'V1 — Esencial ($3/mes)'},{value:'v2',label:'V2 — Pro con IA ($6/mes)'}]}/>
setModal(false)}>Cancelar
{sending?'Enviando...':'Enviar invitación'}
);
};
Object.assign(window, { AdminScreen });