feat(web): telas de Cadastro de Cliente e Contratos no EDEN Core

Continuação direta da leva anterior, sem parar para autorização (a
pedido do usuário). 2 subagentes eden-frontend em paralelo.

- Cadastro de Cliente: lista, criação direta (PF/PJ + portabilidade),
  detalhe rico editável por seção (status, endereço, contatos, dados
  PF/PJ com CPF/CNPJ sempre somente-leitura, portabilidade condicional)
  + sub-seção de Sócios para PJ. Fecha a pendência da leva anterior:
  QuoteDetailPage não pede mais UUID colado à mão para fechar negócio,
  agora é um select real com atalho para criar cadastro novo.
- Contratos: lista, criação (itens produto+quantidade, partes
  contratada/contratante), detalhe com resumo financeiro, aviso de
  fidelidade sem efeito legal quando não aprovada, histórico de status,
  e botões de transição limitados aos alvos válidos a partir do status
  atual (servidor continua sendo a única fonte de verdade real).
  QuoteDetailPage ganha link "Criar contrato a partir desta oferta"
  quando a oferta está fechada.

Reconciliação manual de App.tsx/AuthenticatedLayout.tsx/QuoteDetailPage.tsx
entre os 2 agentes (mais o de Empresas/CRM/Ofertas da leva anterior),
um de cada vez, confirmando typecheck/build limpo a cada mesclagem.

Verificado: pnpm turbo run typecheck build (28/28); containers
eden-api/eden-core reconstruídos; fluxo completo testado ao vivo
ATRAVÉS DO PROXY same-origin (porta 3001, não direto na API) — login,
criação de cadastro, criação de contrato, transição de status inválida
corretamente rejeitada com 409.

Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 22:51:40 -03:00
parent abe056c8b6
commit 19e67dbe63
14 changed files with 2732 additions and 16 deletions

View File

@@ -18,6 +18,12 @@ import { OpportunityFormPage } from "./routes/crm/OpportunityFormPage.js";
import { QuotesListPage } from "./routes/quotes/QuotesListPage.js";
import { QuoteFormPage } from "./routes/quotes/QuoteFormPage.js";
import { QuoteDetailPage } from "./routes/quotes/QuoteDetailPage.js";
import { ClientRegistrationsListPage } from "./routes/client-registrations/ClientRegistrationsListPage.js";
import { ClientRegistrationFormPage } from "./routes/client-registrations/ClientRegistrationFormPage.js";
import { ClientRegistrationDetailPage } from "./routes/client-registrations/ClientRegistrationDetailPage.js";
import { ContractsListPage } from "./routes/contracts/ContractsListPage.js";
import { ContractFormPage } from "./routes/contracts/ContractFormPage.js";
import { ContractDetailPage } from "./routes/contracts/ContractDetailPage.js";
export function App() {
return (
@@ -53,6 +59,14 @@ export function App() {
<Route path="/quotes" element={<QuotesListPage />} />
<Route path="/quotes/new" element={<QuoteFormPage />} />
<Route path="/quotes/:id" element={<QuoteDetailPage />} />
<Route path="/client-registrations" element={<ClientRegistrationsListPage />} />
<Route path="/client-registrations/new" element={<ClientRegistrationFormPage />} />
<Route path="/client-registrations/:id" element={<ClientRegistrationDetailPage />} />
<Route path="/contracts" element={<ContractsListPage />} />
<Route path="/contracts/new" element={<ContractFormPage />} />
<Route path="/contracts/:id" element={<ContractDetailPage />} />
</Route>
</Route>
</Routes>