// admin-users.jsx — Gestión de usuarios (solo admin) y bandeja de leads const { useState, useEffect, useMemo } = React; // ════════════════════════════════════════════════════════════════════ // USUARIOS // ════════════════════════════════════════════════════════════════════ const UsersScreen = ({ profile, onTab, onLogout }) => { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [form, setForm] = useState({ email: '', password: '', nombre: '', role: 'vendedor' }); const [submitting, setSubmitting] = useState(false); const load = async () => { setLoading(true); try { const list = await window.OMEGA_STORE.listUsers(); setUsers(list || []); } catch (e) { window.__adm_toast({ msg: 'Error al cargar usuarios: ' + e.message, type: 'error' }); } finally { setLoading(false); } }; useEffect(() => { load(); }, []); const submit = async (e) => { e.preventDefault(); setSubmitting(true); try { await window.OMEGA_STORE.createUser(form.email, form.password, form.role, form.nombre); window.__adm_toast({ msg: 'Usuario creado · revisá tu email si Supabase pide confirmación', type:'success' }); setShowForm(false); setForm({ email: '', password: '', nombre: '', role: 'vendedor' }); await load(); } catch (e) { window.__adm_toast({ msg: e.message || 'No pude crear el usuario', type: 'error' }); } finally { setSubmitting(false); } }; const changeRole = async (userId, newRole) => { try { await window.OMEGA_STORE.updateUserRole(userId, newRole); window.__adm_toast({ msg: 'Rol actualizado', type:'success' }); await load(); } catch (e) { window.__adm_toast({ msg: 'No pude cambiar el rol: ' + e.message, type: 'error' }); } }; return (
Equipo OMEGA

Usuarios del panel

{loading ? (
CARGANDO USUARIOS...
) : ( {users.map(u => ( ))}
Nombre / Email Rol Creado
{u.nombre || '—'}
{u.email}
{u.role} {new Date(u.created_at).toLocaleDateString('es-AR')} {u.id !== profile.id && ( )}
)}
{showForm && (
setShowForm(false)}>
e.stopPropagation()} style={{maxWidth:520}}>

Nuevo usuario

setForm({...form, nombre: e.target.value})}/>
setForm({...form, email: e.target.value})}/>
setForm({...form, password: e.target.value})}/>
Mínimo 8 caracteres · el usuario podrá cambiarla después
{['vendedor', 'admin'].map(r => ( ))}
)}
); }; // ════════════════════════════════════════════════════════════════════ // LEADS / CONSULTAS // ════════════════════════════════════════════════════════════════════ const LeadsScreen = ({ profile, onTab, onLogout, vehicles }) => { const [leads, setLeads] = useState([]); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState('todos'); // todos / pendientes / contactados / busquedas const load = async () => { setLoading(true); try { const list = await window.OMEGA_STORE.listLeads(); setLeads(list || []); } catch (e) { window.__adm_toast({ msg: 'Error al cargar leads: ' + e.message, type: 'error' }); } finally { setLoading(false); } }; useEffect(() => { load(); }, []); const filtered = useMemo(() => { return leads.filter(l => { if (filter === 'pendientes' && l.contactado) return false; if (filter === 'contactados' && !l.contactado) return false; if (filter === 'busquedas' && l.tipo !== 'busqueda') return false; if (filter === 'consultas' && l.tipo === 'busqueda') return false; return true; }); }, [leads, filter]); const stats = useMemo(() => ({ total: leads.length, pendientes: leads.filter(l => !l.contactado).length, busquedas: leads.filter(l => l.tipo === 'busqueda').length }), [leads]); const toggleContactado = async (id, contactado) => { try { await window.OMEGA_STORE.updateLead(id, { contactado: !contactado }); await load(); } catch (e) { window.__adm_toast({ msg: 'Error: ' + e.message, type:'error' }); } }; const fmtDate = (s) => { const d = new Date(s); return d.toLocaleDateString('es-AR') + ' ' + d.toLocaleTimeString('es-AR', { hour: '2-digit', minute: '2-digit' }); }; const vehicleOf = (id) => vehicles?.find(v => v.id === id); return (
Bandeja de entrada

Consultas y pedidos

Total recibidos
{stats.total}
Pendientes
{stats.pendientes}
Búsquedas (red de agencias)
{stats.busquedas}
Tasa de respuesta
{stats.total ? Math.round((stats.total - stats.pendientes) / stats.total * 100) : 0}%
{loading ? (
CARGANDO LEADS...
) : filtered.length === 0 ? (
Sin consultas

Bandeja vacía

Cuando el sitio reciba consultas, aparecen acá.

) : (
{filtered.map(l => { const v = vehicleOf(l.vehicle_id); return (
{l.tipo === 'busqueda' ? '🔍 Búsqueda' : l.tipo === 'contacto' ? '📩 Contacto' : '🚗 Vehículo'} {fmtDate(l.created_at)}
{l.nombre || 'Sin nombre'}
{l.telefono && 📞 {l.telefono}} {l.email && ✉ {l.email}}
{v && (
Vehículo: {v.marca} {v.modelo} ({v.anio}) — {fmtPriceARS(v.precio)}
)} {l.tipo === 'busqueda' && (
Busca:{' '} {[l.marca_buscada, l.modelo_buscado, l.carroceria_buscada, l.anio_desde && `desde ${l.anio_desde}`, l.presupuesto && `hasta ${fmtPriceARS(l.presupuesto)}`] .filter(Boolean).join(' · ')}
)} {l.mensaje &&
"{l.mensaje}"
}
{l.telefono && (
WhatsApp {l.email && Email}
)}
); })}
)}
); }; Object.assign(window, { UsersScreen, LeadsScreen });