/* global React, Icon, Avatar, Modal, ProgressBar, timeAgo, formatDate */ // ============================================================================ // Admin panel — gerenciar membros, convites, aulas, ver atividade // ============================================================================ const AdminPanel = ({ user, nav }) => { const [tab, setTab] = React.useState('membros'); const members = DB.users().filter(u => u.role === 'membro'); const admins = DB.users().filter(u => u.role === 'admin'); const allLessons = DB.phases().flatMap(p => DB.lessonsByPhase(p.id)); return (
Painel administrativo · Edson

Gestão do Núcleo

Visão completa do programa: membros, convites, conteúdo e atividade recente.

Mentorados ativos
{members.filter(m=>m.status==='ativo').length}
+2 nas últimas 4 semanas
Convites em aberto
{DB.invites().filter(i=>!i.used).length}
aguardando criação de conta
Aulas publicadas
{allLessons.length}
{allLessons.filter(l=>l.type==='live').length} lives · {allLessons.filter(l=>l.type==='video').length} gravadas
Engajamento médio
{(() => { const avg = members.reduce((s,m) => s + DB.overallProgress(m), 0) / Math.max(1, members.length); return Math.round(avg); })()}%
de progresso geral
{[ ['membros', 'Membros'], ['convites', 'Convites'], ['conteudo', 'Conteúdo'], ['atividade', 'Atividade'], ['lgpd', 'Auditoria & LGPD'] ].map(([k, label]) => ( ))}
{tab==='membros' && } {tab==='convites' && } {tab==='conteudo' && } {tab==='atividade' && } {tab==='lgpd' && }
); }; // ----- Members tab ----- const MembersTab = ({ members, admins, nav }) => { const [q, setQ] = React.useState(''); const [filter, setFilter] = React.useState('todos'); let list = [...admins, ...members]; if (filter === 'ativo') list = list.filter(u => u.status === 'ativo'); if (filter === 'inativo') list = list.filter(u => u.status === 'inativo'); if (q.trim()) { const term = q.toLowerCase(); list = list.filter(u => u.name.toLowerCase().includes(term) || u.email.toLowerCase().includes(term)); } return (
setQ(e.target.value)} style={{ width: '100%', background: 'rgba(16,36,72,0.5)', border: '1px solid var(--line-dark)', borderRadius: 6, padding: '11px 14px 11px 40px', color:'var(--text-light)', fontSize: 14 }} />
{list.length} resultado(s)
{list.map(u => ( ))}
Membro Status Progresso Último acesso Cadastro
); }; const MemberRow = ({ member }) => { const progress = DB.overallProgress(member); const [open, setOpen] = React.useState(false); const isAdmin = member.role === 'admin'; return ( <>
{member.name}
{member.email}
{isAdmin ? Admin : {member.status}} {isAdmin ? : (
{progress}%
)} {timeAgo(member.lastLogin)} atrás {formatDate(member.createdAt)} {open && setOpen(false)}/>} ); }; const MemberDetailModal = ({ member, onClose }) => { const phases = DB.phases(); const isAdmin = member.role === 'admin'; return (
e.stopPropagation()}>

{member.name}

{member.email} · {member.phone || 'sem telefone'}
{isAdmin ? Administrador : {member.status}}
{member.bio && (
{member.bio}
)} {member.declaracaoIntencao && (
Declaração de intenção
"{member.declaracaoIntencao}"
)} {!isAdmin && (
Progresso por fase
{phases.map(p => { const pr = DB.progressForPhase(member, p.id); return (
{p.pillar}
{p.title.split(':')[0]}
{pr.done}/{pr.total} ({pr.pct}%)
); })}
)}
{!isAdmin && ( <> )}
); }; // ----- Invites tab ----- const InvitesTab = () => { const [showInvite, setShowInvite] = React.useState(false); const [form, setForm] = React.useState({ name: '', email: '' }); const [lastToken, setLastToken] = React.useState(null); const [copied, setCopied] = React.useState(false); const invites = DB.invites(); const submit = () => { if (!form.name || !form.email) return; const token = DB.inviteMember(form); setLastToken({ token, ...form }); setForm({ name: '', email: '' }); setShowInvite(false); }; const copy = (token) => { navigator.clipboard?.writeText(token); setCopied(token); setTimeout(()=>setCopied(false), 2000); }; return (

Convites são pessoais e usados uma única vez. Envie o token para o aprovado junto do link da plataforma.

{lastToken && (
Convite criado para {lastToken.name} ({lastToken.email})
{lastToken.token}
)}
{invites.map(inv => ( ))}
Aprovado E-mail Token Criado Status
{inv.name || '—'}
{inv.email} {inv.token} {formatDate(inv.createdAt)} {inv.used ? Utilizado : Em aberto}
{showInvite && ( setShowInvite(false)} actions={ <> } >
setForm({...form, name:e.target.value})}/>
setForm({...form, email:e.target.value})}/>
)}
); }; // ----- Content tab ----- const ContentTab = () => { const phases = DB.phases(); const [activePhase, setActivePhase] = React.useState(phases[0].id); const [addModal, setAddModal] = React.useState(false); const [form, setForm] = React.useState({ title:'', type:'video', duration:'', description:'' }); const lessons = DB.lessonsByPhase(activePhase); const add = () => { if (!form.title) return; DB.addLesson({ phaseId: activePhase, ...form, order: lessons.length + 1 }); setForm({ title:'', type:'video', duration:'', description:'' }); setAddModal(false); }; return (
{phases.map(p => ( ))}
{lessons.map(l => ( ))}
# Título Tipo Duração Materiais
{String(l.order).padStart(2,'0')}
{l.title}
{l.description?.slice(0,90)}…
{l.type} {l.duration} {l.materials.length || '—'}
{addModal && ( setAddModal(false)} actions={<> }>
setForm({...form, title:e.target.value})}/>
setForm({...form, duration:e.target.value})} placeholder="ex: 28:14"/>