/* 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)
| Membro |
Status |
Progresso |
Último acesso |
Cadastro |
|
{list.map(u => (
))}
);
};
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 ? — : (
)}
|
{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}
)}
| Aprovado |
E-mail |
Token |
Criado |
Status |
|
{invites.map(inv => (
|
{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 => (
))}
| # |
Título |
Tipo |
Duração |
Materiais |
|
{lessons.map(l => (
| {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})}/>
)}
);
};
// ----- Activity tab -----
const ActivityTab = () => {
const acts = DB.activity(50);
const kinds = {
login: { label: 'Login', color: 'var(--blue-soft)' },
signup: { label: 'Cadastro novo', color: 'var(--gold-bright)' },
lesson_complete: { label: 'Concluiu aula', color: 'var(--success)' },
post: { label: 'Novo post', color: 'var(--blue-bright)' }
};
return (
| Quando | Membro | Evento | Detalhe |
{acts.map(a => {
const u = DB.userById(a.userId);
const k = kinds[a.kind] || { label: a.kind, color: 'var(--text-muted)' };
let detail = '';
if (a.kind === 'lesson_complete') {
const l = DB.lesson(a.payload.lessonId);
detail = l?.title || '—';
} else if (a.kind === 'post') {
detail = 'em Comunidade';
}
return (
| {timeAgo(a.createdAt)} atrás |
|
{k.label} |
{detail} |
);
})}
);
};
Object.assign(window, { AdminPanel });