// Spreadsheet Table View
const Spreadsheet = ({ leads, setLeads, onOpenLead, onNewLead }) => {
const [sort, setSort] = React.useState({ col: 'entrada', dir: 'desc' });
const [filter, setFilter] = React.useState('');
const [stageFilter, setStageFilter] = React.useState('Todos');
const handleSort = (col) => {
setSort(prev => ({ col, dir: prev.col === col && prev.dir === 'asc' ? 'desc' : 'asc' }));
};
const filtered = leads
.filter(l => stageFilter === 'Todos' || l.stage === stageFilter)
.filter(l => !filter || [l.empresa, l.contato, l.responsavel, l.segmento, l.origem]
.some(v => v && v.toLowerCase().includes(filter.toLowerCase())))
.sort((a, b) => {
let va = a[sort.col], vb = b[sort.col];
if (sort.col === 'valor') { va = +va; vb = +vb; }
if (va < vb) return sort.dir === 'asc' ? -1 : 1;
if (va > vb) return sort.dir === 'asc' ? 1 : -1;
return 0;
});
const hoje = new Date().toISOString().split('T')[0];
const cols = [
{ key: 'empresa', label: 'Empresa / Contato', w: 200 },
{ key: 'responsavel', label: 'Responsável', w: 120 },
{ key: 'stage', label: 'Etapa', w: 120 },
{ key: 'valor', label: 'Valor', w: 110 },
{ key: 'origem', label: 'Origem', w: 100 },
{ key: 'segmento', label: 'Segmento', w: 100 },
{ key: 'entrada', label: 'Entrada', w: 90 },
{ key: 'followup', label: 'Follow-up', w: 90 },
];
const SortIcon = ({ col }) => {
if (sort.col !== col) return ↕;
return {sort.dir === 'asc' ? '↑' : '↓'};
};
return (
Planilha
{filtered.length} leads encontrados
{cols.map(c => (
| handleSort(c.key)}>
{c.label}
|
))}
% |
{filtered.map((lead, i) => {
const done = lead.checklist.filter(c => c.done).length;
const pct = Math.round((done / lead.checklist.length) * 100);
const isLate = lead.followup && lead.followup <= hoje && lead.stage !== 'Fechado';
return (
onOpenLead(lead)}>
|
{lead.empresa}
{lead.contato}
|
{lead.responsavel}
|
{lead.stage}
|
{formatCurrency(lead.valor)}
|
{lead.origem} |
{lead.segmento} |
{formatDate(lead.entrada)} |
{formatDate(lead.followup)}
{isLate && ⚠}
|
|
);
})}
{filtered.length === 0 && (
Nenhum lead encontrado com esses filtros.
)}
);
};
const ss = {
page: { flex: 1, display: 'flex', flexDirection: 'column', background: '#0d1020', overflow: 'hidden' },
header: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '20px 24px 12px', flexShrink: 0 },
pageTitle: { fontSize: 22, fontWeight: 700, color: '#e8eaf0' },
pageSubtitle: { fontSize: 12, color: '#4a4f6a', marginTop: 2 },
addBtn: { background: '#4f7cff', color: '#fff', border: 'none', borderRadius: 8, padding: '9px 18px', fontSize: 13, fontWeight: 600, cursor: 'pointer' },
toolbar: { display: 'flex', gap: 12, padding: '0 24px 12px', alignItems: 'center', flexWrap: 'wrap', flexShrink: 0 },
search: {
flex: 1, minWidth: 200, background: '#151828', border: '1px solid #1e2235', borderRadius: 8,
padding: '9px 14px', fontSize: 12, color: '#c7d2ff', outline: 'none',
},
stageFilters: { display: 'flex', gap: 6, flexWrap: 'wrap' },
stageBtn: {
background: 'none', border: '1px solid #1e2235', borderRadius: 20,
padding: '5px 12px', fontSize: 11, color: '#4a4f6a', cursor: 'pointer', transition: 'all 0.15s', fontWeight: 600,
},
tableWrap: { flex: 1, overflowY: 'auto', overflowX: 'auto', padding: '0 24px 24px' },
table: { width: '100%', borderCollapse: 'collapse', minWidth: 900 },
th: {
fontSize: 10, color: '#4a4f6a', fontWeight: 700, letterSpacing: 0.8,
padding: '10px 12px', textAlign: 'left', background: '#151828',
borderBottom: '1px solid #1e2235', position: 'sticky', top: 0, zIndex: 1, userSelect: 'none',
},
tr: { cursor: 'pointer', transition: 'background 0.1s' },
td: { fontSize: 12, color: '#8b90a7', padding: '11px 12px', borderBottom: '1px solid #111525', verticalAlign: 'middle' },
empresa: { fontWeight: 700, color: '#c7d2ff', fontSize: 13 },
contato: { color: '#4a4f6a', fontSize: 11, marginTop: 2 },
resp: { color: '#8b90a7', fontSize: 12 },
badge: { fontSize: 10, fontWeight: 700, padding: '3px 9px', borderRadius: 20, display: 'inline-block', whiteSpace: 'nowrap' },
tag: { background: '#1e2235', color: '#6b7194', borderRadius: 5, padding: '2px 7px', fontSize: 11 },
empty: { textAlign: 'center', color: '#2a2d3e', padding: '40px', fontSize: 14 },
};
Object.assign(window, { Spreadsheet });