feat(frontend): Discador > Campanhas — wizard de 7 passos, ciclo de vida, leads
Tela completa de campanhas do discador preditivo: listagem com busca/
filtro/status, wizard de criacao em 7 passos exatamente como a
especificacao nomeia (Geral -> Telefonia -> Discagem -> Horarios ->
Gravacao e IA -> Leads -> Revisao, agente.md secao 170) — nada e criado
ate confirmar na revisao, upload de CSV de leads na mesma acao de
criacao — e detalhe com acoes de ciclo de vida (iniciar/pausar/drenar/
parar, cada botao so aparece quando a transicao e valida pro status
atual), pacing ao vivo, previa de leads com import adicional, e remover.
Corrige de quebra um erro real de build: Server Actions exportadas como
arrow function que so repassam argumentos pra outra funcao quebram
("Server Actions must be async functions") — precisam ser declaradas
como async function de verdade.
Testado ponta a ponta com fila+tronco reais: os 7 passos preenchidos e
revisados, campanha criada com CSV de 3 leads importado, ciclo de vida
completo start->pause->drain->stop->delete via API, e confirmado que uma
campanha iniciada de verdade e pega pelo PredictiveDialerEngine real
rodando em Docker (stats deixam de ser null depois de alguns segundos).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EWHKmcVJtstQFErbZ1AanY
This commit is contained in:
56
TODO.md
56
TODO.md
@@ -812,7 +812,61 @@ app do Tenant + Dashboard (agente.md secao 162, 169)
|
||||
a PHASE 14, mas a UI não mostra consumo/limite antes de tentar
|
||||
criar — o erro 403 apareceria só depois do submit
|
||||
|
||||
## PHASE 26+ — ver `agente.md` seções 140 em diante (resto do Frontend,
|
||||
## PHASE 26 — Frontend: Discador > Campanhas (agente.md secao 63-86, 170)
|
||||
- [x] Tela `/app/discador/campanhas`: listagem com busca + filtro de
|
||||
status + ordenação, `StatusBadge` (já existia desde o design
|
||||
system da Tarifas, criado exatamente pra status de campanha —
|
||||
só faltava `WAITING_SCHEDULE`, adicionado). Nomes de fila/tronco
|
||||
resolvidos client-side (a lista busca `/queues`+`/trunks` junto,
|
||||
sem precisar mudar o backend). Aviso explícito quando o tenant
|
||||
ainda não tem fila+tronco (pré-requisito real pra criar
|
||||
qualquer campanha).
|
||||
- [x] Wizard de criação em 7 passos, exatamente como a especificação
|
||||
nomeia (secao 170): Geral → Telefonia → Discagem → Horários →
|
||||
Gravação e IA → Leads → Revisão. Nada é criado até confirmar na
|
||||
Revisão (`POST /campaigns` e, se um CSV foi anexado no passo
|
||||
Leads, `POST /campaigns/:id/leads/import` na mesma ação — a
|
||||
campanha nunca fica "meio criada" se o import falhar, só reporta
|
||||
o problema). Upload de CSV lido no browser via `FileReader`
|
||||
(endpoint espera o CSV cru no body, não multipart).
|
||||
- [x] Detalhe da campanha: `StatusBadge` + ações de ciclo de vida
|
||||
(Iniciar/Pausar/Drenar/Parar, cada botão só aparece quando a
|
||||
transição é válida pro status atual — mesma tabela
|
||||
`ALLOWED_TRANSITIONS` do backend, duplicada no client só pra
|
||||
UI, o backend segue sendo a autoridade), pacing ao vivo (`GET
|
||||
/campaigns/:id/stats`), configuração completa, prévia de leads
|
||||
(até 20, com import adicional) e remover (zona de risco, só
|
||||
quando parada).
|
||||
- [x] **Bug real, achado nesta fase**: `startCampaign`/`pauseCampaign`/
|
||||
`drainCampaign`/`stopCampaign` eram `const x = (id) =>
|
||||
transition(...)` — Next.js exige que toda Server Action exportada
|
||||
seja uma `async function` de verdade, não uma arrow function que
|
||||
apenas retorna uma Promise (erro de build: "Server Actions must
|
||||
be async functions"). Corrigido; útil lembrar em qualquer ação
|
||||
futura que só repassa argumentos pra outra função.
|
||||
- [x] **Achado sistêmico, não é bug novo**: `@@unique([tenantId, name])`
|
||||
em `Campaign` não exclui `deletedAt` — não dá pra reusar o nome
|
||||
de uma campanha apagada, mesma classe de problema já documentada
|
||||
pra Agent/Extension/Trunk/Queue/PauseReason na PHASE 12.
|
||||
- [x] Testado ponta a ponta contra a API real com fila+tronco reais
|
||||
(semeados via API pro tenant Acme): os 7 passos do wizard
|
||||
preenchidos e revisados (screenshot da Revisão confere cada
|
||||
valor), campanha criada com CSV de 3 leads importado (`imported:
|
||||
3, total: 3` batendo), ciclo de vida completo start→pause→
|
||||
drain→stop→delete confirmado via API, e confirmado que uma
|
||||
campanha iniciada de verdade é pega pelo `PredictiveDialerEngine`
|
||||
real rodando em Docker (stats deixam de ser null depois de
|
||||
alguns segundos — `answerProbability`/`pacingFactor` reais
|
||||
aparecem na tela, não só o placeholder "sem tentativas ainda").
|
||||
- [ ] `Discador > Leads` (tela dedicada, fora do wizard/detalhe) e
|
||||
`Importações` continuam "em breve" — a prévia de leads no
|
||||
detalhe da campanha cobre o básico, mas não pagina nem edita
|
||||
leads individualmente
|
||||
- [ ] O detalhe da campanha não escuta o WebSocket de monitoramento
|
||||
(secao 161) — `stats`/`callsInFlight` só atualizam ao recarregar
|
||||
a página, não em tempo real
|
||||
|
||||
## PHASE 27+ — ver `agente.md` seções 140 em diante (resto do Frontend,
|
||||
Security, Tests)
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user