[MVPTN-89] feat(CRUD): conclusão do CRUD g_cidade

This commit is contained in:
Kenio 2025-10-02 18:06:44 -03:00
parent 13aea0e161
commit eed113590c
11 changed files with 209 additions and 205 deletions

View file

@ -52,7 +52,7 @@ export default function GCidadePage() {
/**
* Fecha o formulário e limpa o andamento selecionado
*/
const handleCloseForm = useCallback(() => {
const handleCloseForm = useCallback((_: null, __: boolean) => {
setSelectedCidade(null);
setIsFormOpen(false);
}, []);
@ -61,14 +61,16 @@ export default function GCidadePage() {
* Salva os dados do formulário
*/
const handleSave = useCallback(async (formData: GCidadeInterface) => {
// Aguarda salvar o registro
await saveGCidade(formData);
// Atualiza a lista de dados
fetchGCidade();
}, [saveGCidade, fetchGCidade]);
// Atualiza a lista de dados
fetchGCidade();
},
[saveGCidade, fetchGCidade],
);
/**
* Quando o usuário clica em "remover" na tabela

View file

@ -53,10 +53,40 @@ 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);
}, [data, form]);
// Quando recebe dados para edição, atualiza os valores do formulário
useEffect(() => {
if (data) {
// Se for edição, carrega os dados recebidos
form.reset({
cidade_id: data.cidade_id,
uf: data.uf ?? '',
cidade_nome: data.cidade_nome ?? '',
codigo_ibge: data.codigo_ibge ?? '',
codigo_gyn: data.codigo_gyn ?? '',
});
} else {
// Se for novo cadastro, limpa o formulário com valores padrão
form.reset({
cidade_id: 0,
uf: '',
cidade_nome: '',
codigo_ibge: '',
codigo_gyn: '',
});
}
// Carrega todos os estados
// brasileiros para o formulário
const loadData = async () => {
// Aguarda a busca terminar
await fetchGUf();
};
// Dispara a função
loadData();
}, [data, form]);
return (
<Dialog
@ -73,54 +103,67 @@ export default function GCidadeForm({ isOpen, data, onClose, onSave }: Props) {
<DialogDescription>Controle de Cidades</DialogDescription>
</DialogHeader>
{/* Estrutura do formulário */}
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Estrutura do formulário */}
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Campo: Nome da cidade */}
<FormField
control={form.control}
name="cidade_nome"
render={({ field }) => (
<FormItem>
<FormLabel>Descrição</FormLabel>
<FormControl>
<Input {...field} value={field.value ?? ''} placeholder="Digite a descrição" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Campo: Nome da cidade */}
<FormField
control={form.control}
name="cidade_nome"
render={({ field }) => (
<FormItem>
<FormLabel>Descrição</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a descrição" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Campo: Código IBGE */}
<FormField
name="codigo_ibge"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Código IBGE</FormLabel>
<FormControl>
<Input {...field} value={field.value ?? ''} placeholder="Digite o código" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Campo: Código IBGE */}
<FormField
name="codigo_ibge"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Código IBGE</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite o código" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Campo: UF (Estado) */}
<FormField
name="uf"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Estado</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a UF" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Tipo */}
<FormField
control={form.control}
name="uf"
render={({ field }) => (
<FormItem>
<FormLabel>UF</FormLabel>
<Select
value={field.value ?? ''} // garante que não será null
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,86 +1,24 @@
import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/services/api/Api';
export default async function GCidadeIndexData() {
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/services/api/enums/ApiMethodEnum';
return Promise.resolve({
status: 200,
message: "Dados localizados",
data: [
{
"cidade_id": 1,
"uf": "AC",
"cidade_nome": "Acrelândia",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 2,
"uf": "AC",
"cidade_nome": "Assis Brasil",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 3,
"uf": "AC",
"cidade_nome": "Brasiléia",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 4,
"uf": "AC",
"cidade_nome": "Bujari",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 5,
"uf": "AC",
"cidade_nome": "Capixaba",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 6,
"uf": "AC",
"cidade_nome": "Cruzeiro do Sul",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 7,
"uf": "AC",
"cidade_nome": "Epitaciolândia",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 8,
"uf": "AC",
"cidade_nome": "Feijó",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 9,
"uf": "AC",
"cidade_nome": "Jordão",
"codigo_ibge": null,
"codigo_gyn": null
},
{
"cidade_id": 10,
"uf": "AC",
"cidade_nome": "Mâncio Lima",
"codigo_ibge": null,
"codigo_gyn": null
}
]
// 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 executeGcidadeIndexData() {
// 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: Methods.GET, // GET listar todos os itens
endpoint: `administrativo/g_cidade/` // endpoint dinâmico
});
}
// Exporta a função de salvar cidade já encapsulada com tratamento de erros
export const GCidadeIndexData = withClientErrorHandler(executeGcidadeIndexData);

View file

@ -1,14 +1,27 @@
import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/services/api/Api';
export default async function GCidadeRemoveData() {
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/services/api/enums/ApiMethodEnum';
return Promise.resolve({
status: 200,
message: "Dados removidos",
data: null
});
// Importa a interface tipada que define a estrutura dos dados de uma cidade
import GCidadeInterface from '../../_interfaces/GCidadeInterface';
// 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 executeGcidadeRemoveData(data: GCidadeInterface) {
// 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: Methods.DELETE, // Verbo DELETE para exclusão
endpoint: `administrativo/g_cidade/${data.cidade_id}`, // endpoint dinâmico
});
}
// Exporta a função de salvar cidade já encapsulada com tratamento de erros
export const GCidadeRemoveData = withClientErrorHandler(executeGcidadeRemoveData);

View file

@ -1,15 +1,31 @@
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

@ -1,6 +1,6 @@
import { useResponse } from "@/app/_response/ResponseContext"; // Contexto global para gerenciar respostas da API
import GCidadeInterface from "../../_interfaces/GCidadeInterface"; // Interface tipada da cidade
import GCidadeRemoveData from "../../_data/GCidade/GCidadeRemoveData"; // Função que remove a cidade via API
import { GCidadeRemoveData } from "../../_data/GCidade/GCidadeRemoveData"; // Função que remove a cidade via API
// Hook customizado para remoção de cidades
export const useGCidadeRemoveHook = () => {

View file

@ -8,24 +8,18 @@ export const useGCidadeSaveHook = () => {
const { setResponse } = useResponse();
const [gCidade, setGCidade] = useState<GCidadeInterface | null>(null);
// controla se o formulário está aberto ou fechado
const [isOpen, setIsOpen] = useState(false);
// controla se o formulário está aberto ou fechado
// const [isOpen, setIsOpen] = useState(false);
const saveGCidade = async (data: GCidadeInterface) => {
const response = await GCidadeSaveService(data);
// Guardar os dados localizados
setGCidade(response.data);
// Guardar os dados localizados
setGCidade(response.data);
// Manda a resposta para o verificador de resposta
setResponse(response);
// Fecha o formulário automaticamente após salvar
setIsOpen(false);
// Retorna os dados imediatamente
return response;
// Manda a resposta para o verificador de resposta
setResponse(response);
}

View file

@ -1,6 +1,6 @@
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
import GCidadeIndexData from "../../_data/GCidade/GCidadeIndexData";
import { GCidadeIndexData } from '../../_data/GCidade/GCidadeIndexData';
// Função que retorna os dados da lista de cidades (chamada à API ou mock)
// Função assíncrona que executa a chamada para buscar os dados de cidades

View file

@ -37,37 +37,34 @@ export default function CadastrosPage() {
},
];
return (
return (
<div>
<div className="mb-4 flex items-center justify-between">
<div>
<div className="flex items-center justify-between mb-4">
<div>
<h1 className="text-4xl font-semibold mb-1">
Complementos de Cadastro pessoal
</h1>
<p className="text-base text-muted-foreground">
Gerencie os cadastros relacionados a regimes, como estado civil, regime de comunhão e outras informações complementares necessárias para o registro de pessoas.
</p>
</div>
</div>
<div className="grid grid-cols-5 gap-3">
{items.map((item, key) => (
<Link href={"/"}>
<Card key={key} className="cursor-pointer hover:bg-muted transition-colors">
<CardContent>
<span className="inline-flex shrink-0 rounded-md border border-blue-300 bg-blue-100 p-2 dark:border-blue-300/10 dark:bg-blue-400/10 mb-2">
<item.icon className="size-6 stroke-blue-700 dark:stroke-blue-500" />
</span>
<h3 className="text-gray-900 dark:text-white mt-3 text-2xl font-medium tracking-tight">
{item.title}
</h3>
<p className="text-gray-500 dark:text-gray-400 mt-1 text-sm ">
{item.description}
</p>
</CardContent>
</Card>
</Link>
))}
</div>
<h1 className="mb-1 text-4xl font-semibold">Complementos de Cadastro pessoal</h1>
<p className="text-muted-foreground text-base">
Gerencie os cadastros relacionados a regimes, como estado civil, regime de comunhão e
outras informações complementares necessárias para o registro de pessoas.
</p>
</div>
);
</div>
<div className="grid grid-cols-5 gap-3">
{items.map((item, key) => (
<Link key={key} href={'/'}>
<Card className="hover:bg-muted cursor-pointer transition-colors">
<CardContent>
<span className="mb-2 inline-flex shrink-0 rounded-md border border-blue-300 bg-blue-100 p-2 dark:border-blue-300/10 dark:bg-blue-400/10">
<item.icon className="size-6 stroke-blue-700 dark:stroke-blue-500" />
</span>
<h3 className="mt-3 text-2xl font-medium tracking-tight text-gray-900 dark:text-white">
{item.title}
</h3>
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">{item.description}</p>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
);
}

View file

@ -19,6 +19,7 @@ export default function Response() {
useEffect(() => {
switch (Number(response?.status)) {
case 201:
toast.success(response.message);

View file

@ -133,13 +133,13 @@ const data = {
url: "/cadastros/minuta/",
},
{
title: "Regimes/Comunhão",
url: "/cadastros/regime-comunhao/",
title: 'Pessoas/Físicas',
url: '/cadastros/pessoa/fisica',
},
{
title: "Censec/Centrais",
url: "/cadastros/censec/",
}
title: 'Pessoas/Jurídica',
url: '/cadastros/pessoa/juridica',
},
],
},
{