Port para React — Fase 2: Clientes, Negativação, Contratos e Pagamentos

TLDR: portar as próximas 5 telas do protótipo — Clientes, Detalhe do cliente, Negativação, Contratos e Pagamentos — reaproveitando o design system e a arquitetura (services/mocks/hooks/pages) estabelecidos na Fase 1.

Contexto

A Fase 1 (fundação + Login + Painel + Lotes) está mergeada em main. Esta fase continua o port do Sistema de Cobrança.dc.html, substituindo os placeholders ComingSoonPage de 5 rotas por telas reais: Clientes, Detalhe do cliente, Negativação, Contratos e Pagamentos. Todas reaproveitam os componentes genéricos já construídos (DataTable, Pagination, SearchInput, StatusChip, Card, Button, PillGroup) e o padrão hooks+services+mocks.

Sem repositório remoto configurado ainda — como na Fase 1, o trabalho é commitado direto em main (sem branch nem PR), a pedido do usuário.

Descoberta: estado de Pagamentos é compartilhado entre duas telas

No protótipo original, tudo é um único componente com um único state — por isso, tanto a tela Pagamentos (duplicar pagamento) quanto a aba “Pagamentos” do Detalhe do cliente (pagamento avulso) leem e escrevem no mesmo array pagamentos. Uma cobrança avulsa criada no Detalhe do cliente aparece imediatamente na tela Pagamentos, e vice-versa.

Ao portar para hooks isolados por página, esse comportamento se perderia por padrão. Por isso a Fase 2 introduz o primeiro Context compartilhado entre páginas além da sessão: PagamentosProvider (em hooks/pagamentos/PagamentosContext.tsx), com o mesmo formato do SessionProvider da Fase 1. Ele expõe pagamentos, atualizarStatus(index, patch) e adicionarPagamento(pagamento); as duas telas consomem o mesmo contexto via hooks próprios.

mermaid graph TD PP["PagamentosPage<br/>(duplicar)"] --> CTX["PagamentosContext"] CD["ClienteDetalhePage<br/>aba Pagamentos<br/>(avulso)"] --> CTX CTX --> ST["pagamentos[]<br/>atualizarStatus · adicionarPagamento"] style CTX fill:#1f2937,color:#fff

Objetivos

  • Portar Negativação (fila de elegíveis + remoções pendentes) com paridade funcional.
  • Portar Contratos (esteira de assinatura, ciclo de status por clique).
  • Portar Pagamentos (busca + filtro de status, exportar CSV, menu de ações por linha, duplicar pagamento).
  • Portar Clientes (busca + drawer de filtros por status/curso, paginação 8/página).
  • Portar Detalhe do cliente (5 abas: Pessoais, Acadêmico, Pagamentos — com pagamento avulso —, Histórico, Auditoria).
  • Introduzir PagamentosProvider para o estado de pagamentos ser compartilhado entre as telas Pagamentos e Detalhe do cliente, igual ao protótipo original.
  • Atualizar hooks/nav (badge de Negativação e Contratos, hoje sempre vazios) para refletir a contagem real assim que os dados existirem.
  • Registrar em quirks do protótipo qualquer quirk novo encontrado ao implementar (ex.: duplicação do registro “Cléber Santana Farias” entre Negativação e Clientes, já antecipada na Fase 1).

Fora de escopo

  • Atendimento / Ficha Unificada (Fase 3).
  • Jurídico, Bots, Colaboradores, Meu perfil (Fase 4).
  • Correção do bug vencBase da Ficha Unificada (só ao portar essa tela).
  • Qualquer paginação na tela Pagamentos — o protótipo original não pagina essa lista, só filtra.

Mudanças

Novos arquivos, seguindo a mesma estrutura de pastas da Fase 1:

``` types/negativacao.ts, types/contratos.ts, types/pagamentos.ts, types/clientes.ts

mocks/negativacao.ts → fila (3 registros) + registro de remoção pendente mocks/contratos.ts → 3 contratos mocks/pagamentos.ts → 6 pagamentos mocks/clientes.ts → 6 clientes (cada um com cursos[], hist[], aud[])

services/negativacao.ts, services/contratos.ts, services/pagamentos.ts, services/clientes.ts

hooks/negativacao/useFilaNegativacao.ts → fetch + negativar(i) hooks/negativacao/useRemocaoPendente.ts → fetch + removerNeg() hooks/contratos/useContratos.ts → fetch + ciclo de status por clique hooks/pagamentos/PagamentosContext.tsx → provider compartilhado hooks/pagamentos/usePagamentosFiltro.ts → busca + filtro de status (view local, lê do contexto) hooks/pagamentos/usePagamentoAcoes.ts → menu aberto/copiado, ações por linha hooks/pagamentos/useDuplicarPagamento.ts → estado do painel de duplicação + gerar hooks/clientes/useClientes.ts → fetch + busca + filtro status/curso + drawer + usePagination hooks/clienteDetalhe/useClienteDetalhe.ts → cliente por rota, abas, dados derivados hooks/clienteDetalhe/usePagamentoAvulso.ts → formulário de cobrança avulsa, escreve no PagamentosContext

components/negativacao/{FilaNegativacaoTable,RemocaoPendenteCard} components/contratos/ContratosTable components/pagamentos/{PagamentosTable,DuplicarPagamentoPanel,RowActionsMenu} components/clientes/{ClientesTable,FiltrosDrawer} components/clienteDetalhe/{ClienteHeader,PessoaisTab,AcademicoTab,PagamentosTab,HistoricoTab,AuditoriaTab}

pages/NegativacaoPage, pages/ContratosPage, pages/PagamentosPage, pages/ClientesPage, pages/ClienteDetalhePage ```

RowActionsMenu e FiltrosDrawer vão para components/ui se, ao implementar, não houver nada específico do domínio — decisão tomada durante a implementação, não travada aqui.

Rotas atualizadas em App.tsx: /negativacao, /contratos, /pagamentos, /clientes, /clientes/:clienteId. Esta última é nova — o protótipo usa um índice em memória; portamos para um id de rota, com clSel virando “cliente encontrado por id” via service. RequireRole roles={['gestor']} continua em Negativação e Contratos (gestor-only); Pagamentos, Clientes e Detalhe do cliente continuam acessíveis a ambos os papéis, como no protótipo.

Sequência de implementação

# Tipo Entrega
1 feat Tipos + mocks + services das 5 telas (dados 1:1 com o protótipo)
2 test useContratos — ciclo PENDENTE→ASSINADO→FINALIZADO, ação some quando FINALIZADO
3 feat useContratos + ContratosTable + ContratosPage
4 test useFilaNegativacao (marcar não afeta outras linhas), useRemocaoPendente
5 feat Negativação completa
6 test PagamentosContext/usePagamentosFiltro (busca, filtro, combinação) e useDuplicarPagamento (novo pendente + original regerado, parcelas 1–12, parse BRL)
7 feat Pagamentos completo (contexto, tabela, menu de ações, painel de duplicar, export CSV)
8 test useClientes — busca + filtro status + filtro curso combinados, paginação 8/página, limpar filtros
9 feat Clientes completo
10 test useClienteDetalhe (troca de aba, clCobrancas cruzando o PagamentosContext pelo nome) e usePagamentoAvulso
11 feat Detalhe do cliente completo (5 abas)
12 refactor Revisão de duplicação entre as 5 telas novas e as já existentes

Como verificar

  • npm run build, npm run lint, npm test passam sem erros.
  • Manual (npm run dev), comparando com o protótipo aberto localmente:
    • Negativação: negativar um aluno da fila remove o botão de ação e mostra o chip “NEGATIVADO HOJE”; remover a negativação pendente troca o chip/texto e some o botão.
    • Contratos: clicar na ação avança PENDENTE→ASSINADO→FINALIZADO; ao chegar em FINALIZADO, mostra “Arquivado” sem botão.
    • Pagamentos: busca e filtro de status combinam; menu “⋯” mostra as ações certas por status; duplicar um pagamento pago/pendente cria um novo PENDENTE e marca o original como CANCELADO/RE-GERADO; exportar CSV baixa o arquivo.
    • Clientes: busca por nome/CPF/e-mail; drawer de filtros por status e curso (com badge “ · 1” quando algum filtro ativo); paginação 8/página; “Ver detalhes” abre o cliente certo.
    • Detalhe do cliente: 5 abas trocam corretamente; gerar um pagamento avulso aparece imediatamente na tela Pagamentos (mesmo Context); “Levar para atendimento” navega para /atendimento (ainda placeholder).

Documentação

  • Camadas do app React — seção sobre PagamentosContext: por que existe, quando usar Context compartilhado vs. service+hook local.
  • Quirks do protótipo dc-runtime — o registro duplicado “Cléber Santana Farias” entre Negativação e Clientes já está documentado; validar se há outros ao portar.