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 */}
}
onClick={() => void navigate({ to: '/clientes' })}
style={{ borderRadius: 8 }}
>
Voltar
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 }}
/>
);
}