Add CEP autocompletion by ViaCEP/ECT

Signed-off-by: Rodrigo Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
rodrigo committed 2025-04-11 21:17:00 -03:00
1 parent 5559eb98b8
commit afcef9749e
1 file changed
+100 -8
+100 -8
View File
@@ -175,6 +175,7 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
initialTab = 0, initialTab = 0,
}) => { }) => {
const [activeTab, setActiveTab] = useState(initialTab); const [activeTab, setActiveTab] = useState(initialTab);
const [isLoadingCep, setIsLoadingCep] = useState(false);
const { const {
register, register,
handleSubmit, handleSubmit,
@@ -186,6 +187,51 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
const { createCliente, updateCliente } = useClientes(); const { createCliente, updateCliente } = useClientes();
const formPopulated = useRef(false); const formPopulated = useRef(false);
// Monitorar o valor do CEP para autopreenchimento
const cepValue = watch("cep");
// Função para buscar dados do CEP
const fetchAddressByCep = useCallback(async (cep: string) => {
if (!cep || cep.length !== 8) return;
try {
setIsLoadingCep(true);
const formattedCep = cep.replace(/\D/g, ""); // Remove caracteres não numéricos
const response = await axios.get(
`https://viacep.com.br/ws/${formattedCep}/json/`,
);
if (response.data && !response.data.erro) {
// Preencher os campos do formulário com os dados retornados
setValue("endereco", response.data.logradouro);
setValue("bairro", response.data.bairro);
setValue("cidade", response.data.localidade);
setValue("estado", response.data.uf);
// Focar no campo número após o preenchimento automático
const numeroInput = document.querySelector(
'input[name="numero"]',
) as HTMLInputElement;
if (numeroInput) numeroInput.focus();
} else {
console.error("CEP não encontrado");
}
} catch (error) {
console.error("Erro ao buscar CEP:", error);
} finally {
setIsLoadingCep(false);
}
}, [setValue]);
// Efeito para monitorar mudanças no CEP
useEffect(() => {
// Verificar se o CEP tem 8 dígitos (sem formatação)
const cleanCep = cepValue?.replace(/\D/g, "");
if (cleanCep && cleanCep.length === 8) {
fetchAddressByCep(cleanCep);
}
}, [cepValue, fetchAddressByCep]);
// Função para preencher o formulário com os dados do cliente // Função para preencher o formulário com os dados do cliente
const populateForm = useCallback( const populateForm = useCallback(
(clienteData: Cliente) => { (clienteData: Cliente) => {
@@ -372,7 +418,10 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
</div> </div>
{/* Formulário */} {/* Formulário */}
<form onSubmit={handleSubmit(onSubmit)} className="p-6 bg-white dark:bg-gray-800"> <form
onSubmit={handleSubmit(onSubmit)}
className="p-6 bg-white dark:bg-gray-800"
>
<div className="space-y-8 mb-8"> <div className="space-y-8 mb-8">
{/* Conteúdo das abas */} {/* Conteúdo das abas */}
{activeTab === 0 && ( {activeTab === 0 && (
@@ -459,13 +508,56 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
{activeTab === 1 && ( {activeTab === 1 && (
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<FormInput <div className="relative">
label="CEP" <FormInput
{...register("cep", { label="CEP"
required: "CEP é obrigatório", {...register("cep", {
})} required: "CEP é obrigatório",
error={errors.cep?.message} pattern: {
/> value: /^[0-9]{5}-?[0-9]{3}$/,
message: "CEP inválido",
},
})}
error={errors.cep?.message}
placeholder="00000-000"
maxLength={9}
onChange={(e) => {
// Formatação automática do CEP (00000-000)
let value = e.target.value.replace(/\D/g, "");
if (value.length > 5) {
value =
value.substring(0, 5) +
"-" +
value.substring(5, 8);
}
e.target.value = value;
}}
/>
{isLoadingCep && (
<div className="absolute right-3 top-9">
<svg
className="animate-spin h-5 w-5 text-blue-500"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
</div>
)}
</div>
<FormInput <FormInput
className="md:col-span-2" className="md:col-span-2"
label="Endereço" label="Endereço"