// Tela: Minha Equipe const EQUIPE = [ { id: 0, avatar: 0, nome: "Letícia Andrade", cargo: "Head Comercial", role: "Admin", status: "online", meta: 132, fechado: 982, deals: 14, you: true }, { id: 1, avatar: 3, nome: "Rodrigo Cavalcanti", cargo: "Senior Account", role: "Membro", status: "online", meta: 108, fechado: 614, deals: 11 }, { id: 2, avatar: 5, nome: "Patrícia Moreira", cargo: "Account Executive", role: "Membro", status: "ocupado", meta: 92, fechado: 482, deals: 9 }, { id: 3, avatar: 7, nome: "Henrique Lima", cargo: "Account Executive", role: "Membro", status: "offline", meta: 78, fechado: 388, deals: 8 }, { id: 4, avatar: 14, nome: "Mariana Tavares", cargo: "SDR Lead", role: "Admin", status: "online", meta: 64, fechado: 224, deals: 6 }, ]; const PENDENTES = [ { email: "joao.almeida@ezza.com.br", role: "SDR", enviado: "ontem" }, { email: "carla.viana@ezza.com.br", role: "Membro", enviado: "há 3 dias" }, ]; const eqHeaders = () => { const t = localStorage.getItem('ezza_token'); return { 'Content-Type':'application/json', ...(t?{'Authorization':`Bearer ${t}`}:{}) }; }; function Equipe({ onBack, onOpenContact }) { const [tab, setTab] = React.useState('todos'); const [pendentes, setPendentes] = React.useState(PENDENTES.map(p => ({...p}))); const [showConvite, setShowConvite] = React.useState(false); const [membrosReais, setMembrosReais] = React.useState(null); const [meuEmail, setMeuEmail] = React.useState(null); const toast = useToast(); React.useEffect(() => { fetch('/auth/me', { headers: eqHeaders() }).then(r=>r.json()).then(d=>{ if(d.ok) setMeuEmail(d.usuario.email); }).catch(()=>{}); fetch('/api/equipe', { headers: eqHeaders() }) .then(r=>r.json()) .then(d=>{ if(d.ok) setMembrosReais(d.equipe); }) .catch(()=>{}); }, []); // Lista em uso: real (mapeada pro formato do card) ou demo const EQUIPE_VIEW = (membrosReais !== null) ? membrosReais.map((m,i) => ({ id: m.id, avatar: i % 12, nome: m.nome, cargo: m.papel === 'admin' ? 'Administrador' : 'Membro da equipe', role: m.papel === 'admin' ? 'Admin' : 'Membro', status: m.ativo ? 'online' : 'offline', you: m.email === meuEmail, real: true, })) : EQUIPE; const reenviar = (email) => toast(`Convite reenviado para ${email}`); const cancelar = (email) => { setPendentes(prev => prev.filter(p => p.email !== email)); toast(`Convite para ${email} cancelado`); }; return ( <> Minha equipe} subtitle={`${EQUIPE_VIEW.length} pessoa${EQUIPE_VIEW.length!==1?'s':''}`} back onBack={onBack} right={
} />
{[ { id: 'todos', label: 'Todos', count: EQUIPE_VIEW.length }, { id: 'admin', label: 'Admins', count: EQUIPE_VIEW.filter(p => p.role === 'Admin').length }, { id: 'membro', label: 'Membros', count: EQUIPE_VIEW.filter(p => p.role === 'Membro').length }, { id: 'pend', label: 'Convites pendentes', count: pendentes.length }, ].map(t => (
setTab(t.id)}> {t.label} {t.count}
))}
{tab !== 'pend' && (
{EQUIPE_VIEW.filter(p => tab === 'todos' || (tab === 'admin' && p.role === 'Admin') || (tab === 'membro' && p.role === 'Membro')).map(p => (
!p.you && !p.real && onOpenContact && onOpenContact(p.id + 1)}>
{p.you && Você} {p.role} onBack && onBack('perfil')) : undefined }, { ic: ICN.users, label: 'Mudar função', onClick: () => toast(`Função de ${p.nome.split(' ')[0]} atualizada ✓`) }, { ic: ICN.mail, label: 'Enviar mensagem', onClick: () => { const slug = p.nome.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g,'').replace(/\s+/g,'.'); window.open(`mailto:${slug}@ezza.com.br?subject=Olá, ${p.nome.split(' ')[0]}!`); } }, { divider: true }, { ic: ICN.trash, label: 'Desativar conta', danger: true, toast: `${p.nome} desativado(a)` }, ]} />
{p.nome}
{p.cargo}
{!p.real && <>
R$ {p.fechado}k
Fechado
{p.deals}
Negócios
{p.meta}%
Meta
= 100 ? 'eq-bar-good' : 'eq-bar-warn'}`} style={{width: `${Math.min(100, p.meta)}%`}} />
}
))}
)} {tab === 'pend' && (
Convites pendentes
{pendentes.length === 0 &&
Nenhum convite pendente.
} {pendentes.length > 0 && ( {pendentes.map((p, i) => ( ))}
E-mailCargoEnviado
{p.email} {p.role} {p.enviado}
)}
)}
{membrosReais === null &&
Ranking do mês
{[...EQUIPE].sort((a,b) => b.fechado - a.fechado).map((p, i) => (
{i+1}
{p.nome}
R$ {p.fechado}k
))}
}
Permissões & Funções
{[ { label: 'Admin', desc: 'Acesso total à conta', color: 'dark', n: 2 }, { label: 'Gerente', desc: 'Gerencia pipeline e equipe', color: 'lav', n: 0 }, { label: 'Membro', desc: 'Cria e gerencia próprios leads', color: 'blue', n: 3 }, { label: 'SDR', desc: 'Qualificação de leads', color: 'mint', n: 0 }, { label: 'Somente leitura',desc: 'Visualiza dados sem editar', color: 'yellow',n: 0 }, ].map((r,i) => (
{r.label} {r.n} pessoas
{r.desc}
toast(`Permissões de "${r.label}" abertas para edição`)} />
))}
{showConvite && setShowConvite(false)} onSend={async (email, role) => { setShowConvite(false); // Se autenticado, cria membro real no banco if (membrosReais !== null) { const nome = email.split('@')[0].replace(/[._]/g,' ').replace(/\b\w/g, c => c.toUpperCase()); const senha = 'ezza' + Math.floor(1000 + Math.random()*9000); try { const r = await fetch('/api/equipe', { method: 'POST', headers: eqHeaders(), body: JSON.stringify({ nome, email, senha, papel: role === 'Admin' ? 'admin' : 'vendedor' }), }); const d = await r.json(); if (d.ok) { setMembrosReais(prev => [...prev, { id: d.membro.id, nome, email, papel: d.membro.papel, ativo: 1 }]); toast(`${nome} adicionado! Senha inicial: ${senha}`); } else { toast('Erro: ' + d.error); } } catch (e) { toast('Erro de conexão'); } } else { setPendentes(prev => [...prev, { email, role, enviado: 'agora' }]); toast(`Convite enviado para ${email}`); } }} />} ); } function ConviteModal({ onClose, onSend }) { const [email, setEmail] = React.useState(''); const [role, setRole] = React.useState('Membro'); const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); return (
e.stopPropagation()} style={{width: 460}}>
Convidar pessoa
O convite chegará por e-mail
{ICN.x}
setEmail(e.target.value)} />
); } window.Equipe = Equipe;