feat(frontend): Discador > Leads (tela dedicada)

/app/discador/leads — seletor de campanha, busca por telefone/nome,
adicionar lead individual, remover com confirmação de 2 cliques. O
backend (GET/POST/DELETE /campaigns/:campaignId/leads) já existia desde a
PHASE 15; a prévia de leads no detalhe da campanha já apontava pra esta
tela ("a lista completa vive em Discador > Leads") desde a PHASE 26, só
faltava construir.

LEAD_STATUS_LABELS novo (16 valores) — badge própria, não reusa
StatusBadge (mesma cautela de gênero de AgentStateBadge/TenantStatusBadge:
READY/FAILED/COMPLETED colidiriam com rótulos de campanha).

Testado ponta a ponta: campanha de teste criada, 3 leads adicionados (2
via API, 1 via UI), busca filtrando corretamente, remoção confirmada via
API. Smoke test nas 19 telas do tenant + platform, todas 200.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
2026-08-30 00:44:09 -03:00
parent 4480e9265e
commit 52e1b4f3b7
10 changed files with 362 additions and 1 deletions

34
TODO.md
View File

@@ -1449,6 +1449,40 @@ systemd (fecha um risco documentado desde a PHASE 01)
(nginx, pendência original da PHASE 01) — o acesso de teste
continua direto na porta 3001 da VM
## PHASE 39 — Frontend: Discador > Leads (tela dedicada)
(agente.md secao 67-68, 170)
- [x] `/app/discador/leads` — seletor de campanha (o backend já era
`GET /campaigns/:campaignId/leads`, escopado por campanha desde a
PHASE 15, sem endpoint "todos os leads de todas as campanhas" — não
faz sentido ter um, `Lead.campaignId` é obrigatório), busca por
telefone/nome client-side, adicionar lead individual (mesmo `POST`
já usado pelo wizard), remover com confirmação de 2 cliques. A
prévia de 20 leads dentro do detalhe da campanha (PHASE 26) já
apontava pra cá ("a lista completa vive em Discador > Leads") — só
faltava a tela existir.
- [x] `LEAD_STATUS_LABELS` novo (16 valores do enum) — badge própria, sem
reusar `StatusBadge` (mesma cautela de gênero já aplicada em
`AgentStateBadge`/`TenantStatusBadge`: `READY`/`FAILED`/`COMPLETED`
colidiriam com rótulos de campanha que não fazem sentido pra um
lead individual).
- [x] Testado ponta a ponta contra a API real: criada uma campanha de
teste (`Campanha Teste Leads`, DRAFT) só pra ter um `campaignId`
válido, 3 leads adicionados (2 via API, 1 via UI), busca por nome
filtrando corretamente pra 1 resultado, remoção confirmada (3 → 2
leads, `DELETE` retornando 204). Smoke test de regressão nas 19
telas do tenant + platform, todas 200 — desta vez sem nenhum
timeout de navegação no meio do caminho (rotas já compiladas de
passadas anteriores, consistente com o achado da PHASE 38 sobre
compile-on-first-visit do modo dev).
- [ ] "Importações" e "Callbacks" continuam "em breve" — Importações é
CSV em lote, que já existe dentro do wizard/detalhe da campanha
(PHASE 26), uma tela separada só faria sentido com histórico de
importações persistido (não existe hoje, cada import é só um
resumo devolvido na hora, não uma linha salva); Callbacks depende
de `Lead.status = CALLBACK` + `nextAttemptAt`, que o
`PredictiveDialerEngine` já popula (PHASE 16) mas sem tela nenhuma
pra visualizar/gerenciar ainda
---
## Riscos conhecidos