feat(client-registrations): reordena tela — Dados PJ, Sócios, Endereço, Contatos
Ordem pedida pelo usuário. O <form> único virou dois (Sócios renderiza seu próprio <form> interno entre eles, e form aninhado é inválido em HTML) — ambos chamam o mesmo handleSubmit, que sempre lê o estado React completo, então salvar continua gravando tudo de uma vez independente de qual dos dois disparou. Testado ao vivo. pnpm turbo run typecheck build: 28/28. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,10 +21,14 @@ import { PartnersSection } from "./PartnersSection.js";
|
||||
* (breadcrumb + title/status header, grouped info blocks) and `customers.tsx`
|
||||
* (status badge) — rebuilt with `@eden/ui` Card sections, one per group of
|
||||
* fields, same pattern as QuoteDetailPage/CompanyFormPage. Unlike those two
|
||||
* (pure display or pure form), this screen mixes both: everything below the
|
||||
* header is one editable form (single PATCH on submit, matching how the
|
||||
* API accepts a fully partial `UpdateClientRegistrationDto`), plus a
|
||||
* separate Sócios sub-section with its own independent list/add/edit calls.
|
||||
* (pure display or pure form), this screen mixes both: one editable form
|
||||
* (single PATCH on submit, matching how the API accepts a fully partial
|
||||
* `UpdateClientRegistrationDto`) split across two `<form>` elements —
|
||||
* Status/Dados PF-PJ, then (after the non-form Sócios sub-section) Endereço/
|
||||
* Contatos/Portabilidade — both calling the same `handleSubmit`, which
|
||||
* always reads the complete React `form` state regardless of which one
|
||||
* triggered it, so the split is purely visual (see the JSX comment above
|
||||
* the first `<form>`). Sócios has its own independent list/add/edit calls.
|
||||
*/
|
||||
const STATUS_LABEL: Record<RegistrationStatus, string> = {
|
||||
rascunho: "Rascunho",
|
||||
@@ -350,6 +354,15 @@ export function ClientRegistrationDetailPage() {
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{/*
|
||||
Ordem pedida pelo usuário: Dados PJ/PF -> Sócios -> Endereço ->
|
||||
Contatos. `Status` fica primeiro (não mencionado, posição natural) e
|
||||
`Portabilidade`/botão de salvar ficam no final (idem). `PartnersSection`
|
||||
renderiza seu próprio <form> interno (form aninhado é inválido em
|
||||
HTML), então o form único original virou dois — ambos chamam o mesmo
|
||||
`handleSubmit`, que sempre lê o estado React completo (`form`), não o
|
||||
DOM, então dividir em dois <form> não muda o que é salvo.
|
||||
*/}
|
||||
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||
<Card title="Status">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
@@ -381,113 +394,6 @@ export function ClientRegistrationDetailPage() {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card title="Endereço">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Input label="CEP" value={form.addressZip} onChange={(e) => updateField("addressZip", e.target.value)} />
|
||||
<div className="sm:col-span-2">
|
||||
<Input
|
||||
label="Logradouro"
|
||||
value={form.addressStreet}
|
||||
onChange={(e) => updateField("addressStreet", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
label="Número"
|
||||
value={form.addressNumber}
|
||||
onChange={(e) => updateField("addressNumber", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Complemento"
|
||||
value={form.addressComplement}
|
||||
onChange={(e) => updateField("addressComplement", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Bairro"
|
||||
value={form.addressNeighborhood}
|
||||
onChange={(e) => updateField("addressNeighborhood", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Cidade"
|
||||
value={form.addressCity}
|
||||
onChange={(e) => updateField("addressCity", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="UF"
|
||||
maxLength={2}
|
||||
value={form.addressState}
|
||||
onChange={(e) => updateField("addressState", e.target.value.toUpperCase())}
|
||||
/>
|
||||
<Input
|
||||
label="País"
|
||||
value={form.addressCountry}
|
||||
onChange={(e) => updateField("addressCountry", e.target.value)}
|
||||
placeholder="Brasil"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card title="Contatos">
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Principal</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactPrincipalName}
|
||||
onChange={(e) => updateField("contactPrincipalName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactPrincipalEmail}
|
||||
onChange={(e) => updateField("contactPrincipalEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactPrincipalPhone}
|
||||
onChange={(e) => updateField("contactPrincipalPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Financeiro</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactFinancialName}
|
||||
onChange={(e) => updateField("contactFinancialName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactFinancialEmail}
|
||||
onChange={(e) => updateField("contactFinancialEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactFinancialPhone}
|
||||
onChange={(e) => updateField("contactFinancialPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Técnico</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactTechnicalName}
|
||||
onChange={(e) => updateField("contactTechnicalName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactTechnicalEmail}
|
||||
onChange={(e) => updateField("contactTechnicalEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactTechnicalPhone}
|
||||
onChange={(e) => updateField("contactTechnicalPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{registration.person_type === "pf" ? (
|
||||
<Card title="Dados PF">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@@ -666,6 +572,125 @@ export function ClientRegistrationDetailPage() {
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</form>
|
||||
|
||||
{registration.person_type === "pj" ? (
|
||||
<div className="mt-4">
|
||||
<PartnersSection
|
||||
registrationId={registration.id}
|
||||
accessToken={accessToken}
|
||||
refreshKey={partnersRefreshKey}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<form className="mt-4 space-y-4" onSubmit={handleSubmit}>
|
||||
<Card title="Endereço">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Input label="CEP" value={form.addressZip} onChange={(e) => updateField("addressZip", e.target.value)} />
|
||||
<div className="sm:col-span-2">
|
||||
<Input
|
||||
label="Logradouro"
|
||||
value={form.addressStreet}
|
||||
onChange={(e) => updateField("addressStreet", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
label="Número"
|
||||
value={form.addressNumber}
|
||||
onChange={(e) => updateField("addressNumber", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Complemento"
|
||||
value={form.addressComplement}
|
||||
onChange={(e) => updateField("addressComplement", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Bairro"
|
||||
value={form.addressNeighborhood}
|
||||
onChange={(e) => updateField("addressNeighborhood", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Cidade"
|
||||
value={form.addressCity}
|
||||
onChange={(e) => updateField("addressCity", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="UF"
|
||||
maxLength={2}
|
||||
value={form.addressState}
|
||||
onChange={(e) => updateField("addressState", e.target.value.toUpperCase())}
|
||||
/>
|
||||
<Input
|
||||
label="País"
|
||||
value={form.addressCountry}
|
||||
onChange={(e) => updateField("addressCountry", e.target.value)}
|
||||
placeholder="Brasil"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card title="Contatos">
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Principal</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactPrincipalName}
|
||||
onChange={(e) => updateField("contactPrincipalName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactPrincipalEmail}
|
||||
onChange={(e) => updateField("contactPrincipalEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactPrincipalPhone}
|
||||
onChange={(e) => updateField("contactPrincipalPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Financeiro</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactFinancialName}
|
||||
onChange={(e) => updateField("contactFinancialName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactFinancialEmail}
|
||||
onChange={(e) => updateField("contactFinancialEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactFinancialPhone}
|
||||
onChange={(e) => updateField("contactFinancialPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold uppercase text-default">Técnico</p>
|
||||
<Input
|
||||
label="Nome"
|
||||
value={form.contactTechnicalName}
|
||||
onChange={(e) => updateField("contactTechnicalName", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.contactTechnicalEmail}
|
||||
onChange={(e) => updateField("contactTechnicalEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Telefone"
|
||||
value={form.contactTechnicalPhone}
|
||||
onChange={(e) => updateField("contactTechnicalPhone", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{registration.is_portability ? (
|
||||
<Card title="Portabilidade" bodyClassName="p-5">
|
||||
@@ -686,16 +711,6 @@ export function ClientRegistrationDetailPage() {
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{registration.person_type === "pj" ? (
|
||||
<div className="mt-4">
|
||||
<PartnersSection
|
||||
registrationId={registration.id}
|
||||
accessToken={accessToken}
|
||||
refreshKey={partnersRefreshKey}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user