// Tela: Meu Perfil
/* ── Modal: Adicionar Conexão ────────────────────────────── */
function ConexoesModal({ onClose }) {
const toast = useToast();
const plataformas = [
{ color: 'blue', label: 'Slack', desc: 'Notificações e alertas', icon: 'SL' },
{ color: 'pink', label: 'Zapier', desc: 'Automações personalizadas', icon: 'ZP' },
{ color: 'lav', label: 'GitHub', desc: 'Rastrear issues e commits', icon: 'GH' },
{ color: 'mint', label: 'Google Calendar', desc: 'Sincronizar agenda', icon: 'GC' },
{ color: 'yellow',label: 'Pipedrive', desc: 'Migrar histórico de CRM', icon: 'PD' },
];
return (
e.target === e.currentTarget && onClose()}>
Escolha uma plataforma para integrar ao seu perfil:
{plataformas.map(p => (
{ toast(`Conectando com ${p.label}…`); onClose(); }}
style={{
display:'flex', alignItems:'center', gap:12, padding:'10px 12px',
borderRadius:10, background:'var(--bg-soft)', cursor:'pointer',
transition:'background .15s',
}}
onMouseEnter={e => e.currentTarget.style.background='var(--acc-blue-faint,oklch(0.97 0.02 250))'}
onMouseLeave={e => e.currentTarget.style.background='var(--bg-soft)'}
>
{p.icon}
›
))}
);
}
/* ── Modal: Trocar Senha ─────────────────────────────────── */
function TrocarSenhaModal({ onClose }) {
const [atual, setAtual] = React.useState('');
const [nova, setNova] = React.useState('');
const [conf, setConf] = React.useState('');
const toast = useToast();
const valid = atual.length >= 6 && nova.length >= 8 && nova === conf;
const submit = () => {
if (!valid) return;
toast('Senha atualizada com sucesso ✓');
onClose();
};
const strength = nova.length === 0 ? 0 : nova.length < 8 ? 1 : /[A-Z]/.test(nova) && /[0-9]/.test(nova) ? 3 : 2;
const strengthLabel = ['', 'Fraca', 'Média', 'Forte'][strength];
const strengthColor = ['', 'var(--danger)', 'oklch(0.68 0.18 70)', 'var(--ok)'][strength];
return (
e.stopPropagation()} style={{width: 440}}>
Trocar senha
Mínimo 8 caracteres · maiúsculas e números
{ICN.x}
setAtual(e.target.value)} autoFocus />
setNova(e.target.value)} />
{nova.length > 0 &&
{[1,2,3].map(i =>
)}
{strengthLabel}
}
setConf(e.target.value)}
style={{borderColor: conf.length > 0 && conf !== nova ? 'var(--danger)' : ''}} />
{conf.length > 0 && conf !== nova &&
As senhas não coincidem
}
);
}
/* ── Modal: Sessões Ativas ───────────────────────────────── */
function SessoesModal({ onClose }) {
const [sessions, setSessions] = React.useState([
{ id: 1, device: 'Chrome · macOS', local: 'São Paulo, SP', time: 'Agora', current: true },
{ id: 2, device: 'Safari · iPhone 15', local: 'São Paulo, SP', time: 'há 2 horas' },
{ id: 3, device: 'Chrome · Windows 11', local: 'Campinas, SP', time: 'há 1 dia' },
]);
const toast = useToast();
const encerrar = (id) => { setSessions(s => s.filter(x => x.id !== id)); toast('Sessão encerrada ✓'); };
const encerrarTodas = () => { setSessions(s => s.filter(x => x.current)); toast('Todas as outras sessões encerradas ✓'); };
return (
e.stopPropagation()} style={{width: 480}}>
Sessões ativas
{sessions.length} dispositivo{sessions.length !== 1 ? 's' : ''} conectado{sessions.length !== 1 ? 's' : ''}
{ICN.x}
{sessions.map((s, i) => (
{s.device.includes('iPhone') ?
: }
{s.device} {s.current && Esta sessão}
{s.local} · {s.time}
{!s.current &&
}
))}
{sessions.length > 1 && }
);
}
function Perfil({ onBack }) {
const [editing, setEditing] = React.useState(false);
const [showSenha, setShowSenha] = React.useState(false);
const [showSessoes, setShowSessoes] = React.useState(false);
const [editingPrefs, setEditingPrefs] = React.useState(false);
const [showConexoes, setShowConexoes] = React.useState(false);
const [avatar, setAvatar] = React.useState('https://i.pravatar.cc/240?img=47');
const avatarRef = React.useRef(null);
const toast = useToast();
const handleAvatarFile = (file) => {
if (!file || !file.type.startsWith('image/')) return;
setAvatar(URL.createObjectURL(file));
toast('Foto atualizada ✓');
};
const [vals, setVals] = React.useState({
nome: 'Letícia Andrade Borges',
cargo: 'Head Comercial',
dept: 'Vendas',
bio: 'Lidero o time comercial da Ezza desde 2023. Foco em vendas consultivas para indústria e construção.',
email: 'leticia.andrade@ezza.com.br',
emailAlt: 'leticia.borges@gmail.com',
tel: '+55 11 9 9412-7782',
ramal: '2204',
});
const [saved, setSaved] = React.useState({...vals});
const [savedAvatar, setSavedAvatar] = React.useState(avatar);
const save = () => { setSaved({...vals}); setSavedAvatar(avatar); setEditing(false); toast('Perfil salvo com sucesso!'); };
const revert = () => { setVals({...saved}); setAvatar(savedAvatar); setEditing(false); };
const setV = (key) => (e) => setVals(prev => ({...prev, [key]: e.target.value}));
return (
<>
{showSenha && setShowSenha(false)} />}
{showSessoes && setShowSessoes(false)} />}
{showConexoes && setShowConexoes(false)} />}
Meu perfil>}
subtitle="Dados pessoais, preferências e segurança"
back onBack={onBack}
right={
{editing
? <>
>
:
}
}
/>
Foto e identidade
avatarRef.current?.click() },
{ ic: ICN.trash, label: 'Remover foto', danger: true, onClick: () => { setAvatar('https://i.pravatar.cc/240?img=47'); toast('Foto removida'); } },
]} />
handleAvatarFile(e.target.files?.[0])} />
setEditing(true)} />
setEditing(true)} />
setEditing(true)} />
setEditing(true)} />
Preferências
setEditingPrefs(e => !e)} />
{editingPrefs &&
Editando preferências
}
Atividade desta semana
↑ +12% vs semana anterior
R$ 482k
Receita fechada
↑ +R$ 48k
Segurança
setShowSenha(true) },
{ ic: ICN.bolt, label: 'Reconfigurar 2FA', toast: 'Redirecionando para app autenticador…' },
{ ic: ICN.users, label: 'Encerrar sessões', onClick: () => setShowSessoes(true) },
]} />
setShowSenha(true)} />
setShowSessoes(true)} />
{
const data = JSON.stringify({ nome: vals.nome, email: vals.email, exportadoEm: new Date().toISOString() }, null, 2);
const a = Object.assign(document.createElement('a'), { href: URL.createObjectURL(new Blob([data], {type:'application/json'})), download: 'meus-dados-ezza.json' });
a.click(); URL.revokeObjectURL(a.href); toast('Dados exportados ✓');
}} />
Conexões sociais
setShowConexoes(true)} />
>
);
}
function FieldRow({ label, value, badge, textarea, editing, onChange, onActivateEdit }) {
return (
{label}
{badge && {badge}}
{editing
? textarea
?
:
:
{value}
{ICN.edit}
}
);
}
function PrefRow({ label, value, editing, options }) {
const [val, setVal] = React.useState(value);
return (
{label}
{editing && options
?
:
{val}
{ICN.chevron}
}
);
}
function SecRow({ icon, icColor, label, hint, pill, pillColor, onClick }) {
const bgMap = { blue:'oklch(0.93 0.06 250)', mint:'oklch(0.92 0.07 160)', lav:'oklch(0.93 0.06 295)', yellow:'oklch(0.94 0.08 80)', pink:'oklch(0.93 0.06 18)' };
const fgMap = { blue:'oklch(0.38 0.16 250)', mint:'oklch(0.34 0.14 160)', lav:'oklch(0.38 0.14 295)', yellow:'oklch(0.40 0.14 80)', pink:'oklch(0.40 0.16 18)' };
return (
{ if(onClick) e.currentTarget.style.background='oklch(0.97 0.01 250)'; e.currentTarget.style.borderRadius='12px'; }}
onMouseLeave={e => { e.currentTarget.style.background=''; e.currentTarget.style.borderRadius=''; }}>
{icon}
{pill
?
{pill}
: onClick &&
{ICN.arrowRight}}
);
}
/* Logos SVG inline das redes sociais */
function BrandLogo({ logo }) {
if (logo === 'linkedin') return (
);
if (logo === 'google') return (
);
if (logo === 'whatsapp') return (
);
if (logo === 'instagram') return (
);
return null;
}
function ConRow({ logo, label, handle, connected }) {
const toast = useToast();
const [isConnected, setIsConnected] = React.useState(connected);
const bgMap = { linkedin:'#EBF3FB', google:'#FEF3EC', whatsapp:'#EDFBF2', instagram:'#FDF0F8' };
return (
{label}
{isConnected ? handle : 'Não conectado'}
{isConnected
?
Conectado
:
}
);
}
window.Perfil = Perfil;