[MVPTN-92] feat(SelectUF): Criado carregamento de estados de forma dinâmica

This commit is contained in:
Kenio 2025-09-30 08:20:50 -03:00
parent 13aea0e161
commit 175dff5ded
11 changed files with 157 additions and 23 deletions

View file

@ -27,6 +27,16 @@ import { Input } from "@/components/ui/input";
import { GCidadeSchema } from "../../_schemas/GCidadeSchema";
import { useEffect } from "react";
// Hook responsável em trazer todos os estados brasileiros
import { useGUfReadHook } from "../../_hooks/g_uf/useGUfReadHook";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from "@/components/ui/select";
// Define o tipo do formulário com base no schema Zod
type FormValues = z.infer<typeof GCidadeSchema>;
@ -41,6 +51,9 @@ interface Props {
// Componente principal do formulário
export default function GCidadeForm({ isOpen, data, onClose, onSave }: Props) {
//
const { gUf, fetchGUf } = useGUfReadHook();
// Inicializa o react-hook-form integrado ao Zod para validação
const form = useForm<FormValues>({
resolver: zodResolver(GCidadeSchema),
@ -55,7 +68,19 @@ export default function GCidadeForm({ isOpen, data, onClose, onSave }: Props) {
// Quando recebe dados para edição, atualiza os valores do formulário
useEffect(() => {
if (data) form.reset(data);
// Se existir dados, reseta o formulário com os dados informados
if (data) form.reset(data);
const loadData = async () => {
// Aguarda a busca terminar
await fetchGUf();
};
// Dispara a função
loadData();
}, [data, form]);
return (
@ -107,20 +132,38 @@ export default function GCidadeForm({ isOpen, data, onClose, onSave }: Props) {
)}
/>
{/* Campo: UF (Estado) */}
{/* Tipo */}
<FormField
name="uf"
control={form.control}
name="uf"
render={({ field }) => (
<FormItem>
<FormLabel>Estado</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a UF" />
</FormControl>
<FormLabel>
UF
</FormLabel>
<Select
value={String(field.value)}
// Carrega o valor selecionado
onValueChange={(val) => field.onChange(val)}
>
<FormControl className="w-full">
<SelectTrigger>
<SelectValue placeholder="Selecione o estado desejado" />
</SelectTrigger>
</FormControl>
<SelectContent>
{gUf.map((item) => (
<SelectItem key={item.g_uf_id} value={String(item.sigla)}>
{item.nome}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
/>
{/* Rodapé do diálogo com botões */}
<DialogFooter className="mt-4">

View file

@ -1,15 +1,32 @@
import API from "@/services/api/Api"; // Importa o serviço de API (ainda não utilizado aqui)
import { Methods } from "@/services/api/enums/ApiMethodEnum"; // Importa enum de métodos HTTP (também não usado neste trecho)
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from "@/services/api/Api";
// Função assíncrona responsável por salvar dados de cidades
export default async function GCidadeSaveData() {
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from "@/services/api/enums/ApiMethodEnum";
// Log para indicar que a função foi chamada
console.log("chegou");
// Importa a interface tipada que define a estrutura dos dados de uma cidade
import GCidadeInterface from "../../_interfaces/GCidadeInterface";
// Retorna uma Promise resolvida simulando resposta da API
return Promise.resolve({
status: 200, // Código de status fictício
message: "Dados salvos" // Mensagem de sucesso
});
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
// Função assíncrona que implementa a lógica de salvar (criar/atualizar) uma cidade
async function executeGcidadeSaveData(data: GCidadeInterface) {
// Verifica se existe ID da cidade para decidir se é atualização (PUT) ou criação (POST)
const isUpdate = Boolean(data.cidade_id);
// Instancia o cliente da API para enviar a requisição
const api = new API();
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
return await api.send({
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
endpoint: `administrativo/g_cidade/${data.cidade_id || ''}`, // endpoint dinâmico
body: data // payload enviado para a API
});
}
// Exporta a função de salvar cidade já encapsulada com tratamento de erros
export const GCidadeSaveData = withClientErrorHandler(executeGcidadeSaveData);

View file

@ -0,0 +1,19 @@
// Importa a classe API responsável por centralizar chamadas HTTP
import API from "@/services/api/Api";
// Importa o enum de métodos HTTP (GET, POST, PUT, DELETE, etc.)
import { Methods } from "@/services/api/enums/ApiMethodEnum";
// Exporta por padrão a função assíncrona GUfIndexData
export default async function GUfIndexData() {
// Cria uma instância da classe API para executar a requisição
const api = new API();
// Executa a chamada GET para o endpoint "administrativo/g_uf/" e retorna a resposta
return await api.send({
method: Methods.GET, // Define que o método HTTP é GET
endpoint: `administrativo/g_uf/` // Define o endpoint a ser acessado
});
}

View file

@ -18,6 +18,8 @@ export const useGCidadeSaveHook = () => {
// Guardar os dados localizados
setGCidade(response.data);
console.log(response)
// Manda a resposta para o verificador de resposta
setResponse(response);

View file

@ -0,0 +1,30 @@
'use client'
import { useResponse } from "@/app/_response/ResponseContext"
import { use, useState } from "react";
import GUfInterface from "../../_interfaces/GUfInterface";
import GUfIndexService from "../../_services/g_uf/GUfIndexService";
export const useGUfReadHook = () => {
const { setResponse } = useResponse();
// Controle dos dados obtidos via API
const [gUf, setGUf] = useState<GUfInterface[]>([]);
const fetchGUf = async () => {
// Realiza a requisição para a api
const response = await GUfIndexService();
// Armazena os dados da resposta
setGUf(response.data);
// Envia os dados da resposta para ser tratado
setResponse(response);
}
return { gUf, fetchGUf }
}

View file

@ -0,0 +1,8 @@
export default interface GUfInterface {
g_uf_id?: number,
sigla: string,
nome: string,
codigo_uf_ibge?: string,
}

View file

@ -7,5 +7,4 @@ export const GCidadeSchema = z.object({
cidade_nome: z.string().min(1, "O nome da cidade é obrigatório"),
codigo_ibge: z.string().optional(),
codigo_gyn: z.string().optional()
})

View file

@ -1,12 +1,16 @@
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
import GCidadeSaveData from "../../_data/GCidade/GCidadeSaveData";
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
// Função que salva os dados da cidade via API (ou mock)
import GCidadeInterface from "../../_interfaces/GCidadeInterface";
import { GCidadeSaveData } from "../../_data/GCidade/GCidadeSaveData";
// Interface tipada da cidade
import GCidadeInterface from "../../_interfaces/GCidadeInterface";
// Função assíncrona que executa o salvamento de uma cidade
async function executeGCidadeSaveService(data: GCidadeInterface) {
// Chama a função que salva os dados da cidade
const response = await GCidadeSaveData(data);

View file

@ -0,0 +1,9 @@
import GUfIndexData from "../../_data/GUf/GUfIndexData";
export default async function GUfIndexService() {
const response = await GUfIndexData();
return response;
}

View file

@ -32,6 +32,7 @@ export const ResponseProvider: React.FC<{ children: ReactNode }> = ({ children }
};
export const useResponse = () => {
const context = useContext(ResponseContext);
if (!context) throw new Error('useResponse must be used within ResponseProvider');
return context;

View file

@ -17,6 +17,8 @@ export default function Response() {
clearResponse
} = useResponse();
console.log(response)
useEffect(() => {
switch (Number(response?.status)) {