import { useState } from 'react'; import { Alert, App, Button, Card, Col, Form, Input, InputNumber, Row, Segmented, Select, Spin, Switch, Typography, } from 'antd'; import { ArrowLeftOutlined, BankOutlined, CheckCircleOutlined, EnvironmentOutlined, PhoneOutlined, ShopOutlined, UserOutlined, } from '@ant-design/icons'; import { useNavigate } from '@tanstack/react-router'; import type { CreateClientNovo } from '@sar/api-interface'; import { useMunicipios, usePautas, useFormasPagamento } from '../../lib/queries/catalog'; import { useCreateClientNovo } from '../../lib/queries/clients'; const { Title, Text } = Typography; type Pessoa = 'PJ' | 'PF'; function Section({ icon, title, children, }: { icon: React.ReactNode; title: string; children: React.ReactNode; }) { return (
{icon} {title}
{children}
); } export function NewClientPage() { const navigate = useNavigate(); const { message } = App.useApp(); const [form] = Form.useForm(); const [pessoa, setPessoa] = useState('PJ'); const [municipioSearch, setMunicipioSearch] = useState(''); const [syncError, setSyncError] = useState(null); const { data: municipios = [], isFetching: loadingMun } = useMunicipios( municipioSearch || undefined, ); const { data: pautas = [] } = usePautas(); const { data: formas = [] } = useFormasPagamento(); const createMutation = useCreateClientNovo(); async function handleCepBlur(cep: string) { const digits = cep.replace(/\D/g, ''); if (digits.length !== 8) return; try { const res = await fetch(`https://viacep.com.br/ws/${digits}/json/`); const data = (await res.json()) as { erro?: boolean; logradouro?: string; bairro?: string; localidade?: string; uf?: string; }; if (data.erro) return; if (data.logradouro) form.setFieldValue('endereco', data.logradouro); if (data.bairro) form.setFieldValue('bairro', data.bairro); if (data.localidade && data.uf) { setMunicipioSearch(data.localidade); } } catch { // silencioso — CEP inválido não bloqueia } } async function onFinish(values: Record) { setSyncError(null); const payload: CreateClientNovo = { pesso: pessoa === 'PJ' ? 0 : 1, consfinal: values.consfinal ? 1 : 0, nome: String(values.nome ?? '').slice(0, 40), razao: String(values.razao ?? values.nome ?? '').slice(0, 65), cgcpf: values.cgcpf ? String(values.cgcpf) : undefined, sufCgcpf: '', inscr: values.inscr ? String(values.inscr) : '', indicadorIe: values.indicadorIe as 1 | 2 | 9 | undefined, endereco: String(values.endereco ?? '').slice(0, 60), numEndereco: String(values.numEndereco ?? '').slice(0, 10), bairro: String(values.bairro ?? '').slice(0, 60), idMunicipio: Number(values.idMunicipio), cep: String(values.cep ?? '') .replace(/\D/g, '') .slice(0, 9), ddd: String(values.ddd ?? '').slice(0, 4), telefone: String(values.telefone ?? '').slice(0, 35), email: String(values.email ?? '').slice(0, 80), limiteCredito: Number(values.limiteCredito ?? 0), codFormapag: values.codFormapag ? Number(values.codFormapag) : undefined, codPauta: values.codPauta ? Number(values.codPauta) : undefined, }; let result: Awaited>; try { result = await createMutation.mutateAsync(payload); } catch { return; // erro já notificado pelo handler global do QueryClient } if (!result.sincronizado && result.erroSync) { setSyncError(result.erroSync); void message.warning('Cliente cadastrado, mas houve erro na sincronização com o ERP.'); } else { void message.success( `Cliente cadastrado com sucesso! Código ERP: ${result.idCorrentErp ?? '—'}`, ); void navigate({ to: '/clientes' }); } } const isPJ = pessoa === 'PJ'; return (
{/* Cabeçalho */}
Cadastrar Cliente Após salvar, o cliente é criado automaticamente no ERP.
{/* Seletor PJ / PF */}
{ setPessoa(v as Pessoa); form.resetFields(['cgcpf', 'inscr', 'indicadorIe', 'consfinal', 'razao']); }} options={[ { value: 'PJ', icon: , label: 'CNPJ — Pessoa Jurídica' }, { value: 'PF', icon: , label: 'CPF — Pessoa Física' }, ]} style={{ borderRadius: 10 }} />
void onFinish(v as Record)} requiredMark="optional" initialValues={{ consfinal: false, limiteCredito: 0 }} > {/* ── Identificação ─────────────────────────────────────────── */}
: } title="Identificação"> {isPJ ? ( <> ) : ( <> )}
{/* ── Endereço ──────────────────────────────────────────────── */}
} title="Endereço"> void handleCepBlur(e.target.value)} />
{/* ── Contato ───────────────────────────────────────────────── */}
} title="Contato">
{/* ── Comercial ─────────────────────────────────────────────── */}
} title="Comercial"> `R$ ${v ?? 0}`.replace(/\B(?=(\d{3})+(?!\d))/g, '.')} parser={(v) => Number((v ?? '').replace(/R\$\s?\.*/g, '').replace(',', '.'))} placeholder="0,00" />
{syncError && ( )}
{/* Rodapé sticky */}
); }