Add CEP autocompletion by ViaCEP/ECT
Signed-off-by: Rodrigo Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
5559eb98b8
commit
afcef9749e
1 file changed
+93
-1
@@ -175,6 +175,7 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
|
||||
initialTab = 0,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState(initialTab);
|
||||
const [isLoadingCep, setIsLoadingCep] = useState(false);
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
@@ -186,6 +187,51 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
|
||||
const { createCliente, updateCliente } = useClientes();
|
||||
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
|
||||
const populateForm = useCallback(
|
||||
(clienteData: Cliente) => {
|
||||
@@ -372,7 +418,10 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 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">
|
||||
{/* Conteúdo das abas */}
|
||||
{activeTab === 0 && (
|
||||
@@ -459,13 +508,56 @@ export const ClienteModal: React.FC<ClienteModalProps> = ({
|
||||
|
||||
{activeTab === 1 && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="relative">
|
||||
<FormInput
|
||||
label="CEP"
|
||||
{...register("cep", {
|
||||
required: "CEP é obrigatório",
|
||||
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
|
||||
className="md:col-span-2"
|
||||
label="Endereço"
|
||||
|
||||
Reference in new issue
Block a user