From 08889a914ae2a96f5adaad057c1c0322ec0d2dad Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 18 Sep 2025 17:55:01 -0300 Subject: [PATCH] [MVPTN-74] feat(CRUD): Implementando Tipo de Medida --- .../(g_medidatipo)/medida-tipo/page.tsx | 128 ++++++++++++++++++ .../g_medidatipo/GMedidaTipoForm.tsx | 125 +++++++++++++++++ .../g_medidatipo/GMedidaTipoTable.tsx | 96 +++++++++++++ .../_data/GMedidoTipo/GMedidaTipoIndexData.ts | 25 ++++ .../GMedidoTipo/GMedidaTipoRemoveData.ts | 14 ++ .../_data/GMedidoTipo/GMedidaTipoSaveData.ts | 17 +++ .../_data/GMedidoTipo/mockMedidaTipo.ts | 28 ++++ .../g_medidatipo/useGMedidaTipoReadHook.ts | 27 ++++ .../g_medidatipo/useGMedidaTipoRemoveHook.ts | 19 +++ .../g_medidatipo/useGMedidaTipoSaveHook.ts | 31 +++++ .../_interfaces/GMedidaTipoInterface.ts | 5 + .../cadastros/_schemas/GMedidaTipoSchema.ts | 7 + .../g_medidatipo/GMedidaTipoIndexService.ts | 12 ++ .../g_medidatipo/GMedidaTipoRemoveService.ts | 10 ++ .../g_medidatipo/GMedidaTipoSaveService.ts | 12 ++ src/components/app-sidebar.tsx | 4 + 16 files changed, 560 insertions(+) create mode 100644 src/app/(protected)/(cadastros)/cadastros/(g_medidatipo)/medida-tipo/page.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoForm.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoTable.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoIndexData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoRemoveData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoSaveData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/mockMedidaTipo.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoReadHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoRemoveHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoSaveHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/GMedidaTipoInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_schemas/GMedidaTipoSchema.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoIndexService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoRemoveService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoSaveService.ts diff --git a/src/app/(protected)/(cadastros)/cadastros/(g_medidatipo)/medida-tipo/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(g_medidatipo)/medida-tipo/page.tsx new file mode 100644 index 0000000..5b198ea --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/(g_medidatipo)/medida-tipo/page.tsx @@ -0,0 +1,128 @@ +'use client'; + +import { useEffect, useState, useCallback } from "react"; +import { Card, CardContent } from "@/components/ui/card"; +import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog"; + +import Header from "@/app/_components/structure/Header"; +import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog"; +import Loading from "@/app/_components/loading/loading"; +import GMedidaTipoTable from "../../_components/g_medidatipo/GMedidaTipoTable"; +import GMedidaTipoForm from "../../_components/g_medidatipo/GMedidaTipoForm"; + +import { useGMedidaTipoReadHook } from "../../_hooks/g_medidatipo/useGMedidaTipoReadHook"; +import { useGMedidaTipoSaveHook } from "../../_hooks/g_medidatipo/useGMedidaTipoSaveHook"; +import { useGMedidaTipoRemoveHook } from "../../_hooks/g_medidatipo/useGMedidaTipoRemoveHook"; + +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; + +const initialMedidaTipo: GMedidaTipoInterface = { + medida_tipo_id: 0, + sigla: '', + descricao: '' +} + +export default function GMedidaTipoPage() { + + // Hooks para leitura, salvamento e remoção + const { gMedidaTipo, fetchGMedidaTipo } = useGMedidaTipoReadHook(); + const { saveGMedidaTipo } = useGMedidaTipoSaveHook(); + const { removeGMedidaTipo } = useGMedidaTipoRemoveHook(); + + // Estado para controlar o formulário e o item selecionado + const [selectedMedidaTipo, setSelectedMedidaTipo] = useState(null); + const [isFormOpen, setIsFormOpen] = useState(false); + const [itemToDelete, setItemToDelete] = useState(null); + + // Hook para o modal de confirmação + const { + isOpen: isConfirmOpen, + openDialog: openConfirmDialog, + handleConfirm, + handleCancel, + } = useConfirmDialog(); + + // Ações do formulário + const handleOpenForm = useCallback((data: GMedidaTipoInterface | null) => { + setSelectedMedidaTipo(data); + setIsFormOpen(true); + }, []); + + const handleCloseForm = useCallback(() => { + setIsFormOpen(false); + setSelectedMedidaTipo(null); + }, []); + + const handleSave = useCallback(async (data: GMedidaTipoInterface) => { + await saveGMedidaTipo(data); + await fetchGMedidaTipo(); // Atualiza a tabela após salvar + handleCloseForm(); + }, [saveGMedidaTipo, fetchGMedidaTipo]); + + // Ações de deleção + const handleConfirmDelete = useCallback((item: GMedidaTipoInterface) => { + setItemToDelete(item); + openConfirmDialog(); + }, [openConfirmDialog]); + + const handleDelete = useCallback(async () => { + if (itemToDelete) { + await removeGMedidaTipo(itemToDelete); + await fetchGMedidaTipo(); // Atualiza a tabela após remover + } + handleCancel(); + }, [itemToDelete, fetchGMedidaTipo, handleCancel]); + + // Efeito para carregar os dados na montagem do componente + useEffect(() => { + fetchGMedidaTipo(); + }, []); + + // Mostra tela de loading enquanto os dados não são carregados + if (!gMedidaTipo) { + return ; + } + + return ( +
+ {/* Cabeçalho */} +
{ handleOpenForm(data = initialMedidaTipo) }} + /> + + {/* Tabela de Tipos de Medida */} + + + + + + + {/* Modal de confirmação */} + + + {/* Formulário de criação/edição */} + +
+ ); +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoForm.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoForm.tsx new file mode 100644 index 0000000..46b47a1 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoForm.tsx @@ -0,0 +1,125 @@ +'use client'; + +import z from "zod"; +import { useEffect } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from "@/components/ui/dialog"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +import { GMedidaTipoSchema } from "../../_schemas/GMedidaTipoSchema"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; + +type FormValues = z.infer; + +interface GMedidaTipoFormProps { + isOpen: boolean; + data: FormValues | null; + onClose: (item: null, isFormStatus: boolean) => void; + onSave: (data: FormValues) => void; +} + +export default function GMedidaTipoForm({ isOpen, data, onClose, onSave }: GMedidaTipoFormProps) { + // Inicializa o react-hook-form com o schema Zod + const form = useForm({ + resolver: zodResolver(GMedidaTipoSchema), + defaultValues: { + medida_tipo_id: 0, + sigla: "", + descricao: "", + }, + }); + + // Atualiza o formulário quando recebe dados para edição + useEffect(() => { + if (data) form.reset(data); + }, [data, form]); + + return ( + { + if (!open) onClose(null, false); + }} + > + + + + Tipo de Medida + + + Crie ou edite um tipo de medida + + + +
+ + + {/* Descrição */} + ( + + Descrição + + + + + + )} + /> + + {/* Sigla */} + ( + + Sigla + + + + + + )} + /> + + {/* Rodapé do Dialog */} + + + + + + + + {/* Campo oculto */} + + + +
+
+ ); +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoTable.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoTable.tsx new file mode 100644 index 0000000..6005b84 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_components/g_medidatipo/GMedidaTipoTable.tsx @@ -0,0 +1,96 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow +} from "@/components/ui/table"; +import { EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; + +interface GMedidaTipoTableProps { + data: GMedidaTipoInterface[]; + onEdit: (item: GMedidaTipoInterface, isEditingFormStatus: boolean) => void; + onDelete: (item: GMedidaTipoInterface, isEditingFormStatus: boolean) => void; +} + +export default function GMedidaTipoTable({ + data, + onEdit, + onDelete +}: GMedidaTipoTableProps) { + return ( + + + + # + Descrição + Sigla + Ações + + + + + {data.map((item) => ( + + + {item.medida_tipo_id} + + {item.descricao} + {item.sigla} + + + + + + + + + onEdit(item, true)} + > + + Editar + + + + + onDelete(item, true)} + > + + Remover + + + + + + + ))} + +
+ ); +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoIndexData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoIndexData.ts new file mode 100644 index 0000000..7767d4c --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoIndexData.ts @@ -0,0 +1,25 @@ +import API from "@/services/api/Api"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; +import MedidaTipoMockDeDados from "./mockMedidaTipo"; + +const useMock = true + +export default async function GMedidaTipoIndexData() { + if (useMock) { + console.log(MedidaTipoMockDeDados()) + return await MedidaTipoMockDeDados(); + } + + const api = new API(); + try { + const dados = await api.send({ + method: Methods.GET, + endpoint: `administrativo/g_medida_tipo/` + }); + return dados + } catch (error) { + console.log(error) + return error + } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoRemoveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoRemoveData.ts new file mode 100644 index 0000000..7e7f4d3 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoRemoveData.ts @@ -0,0 +1,14 @@ +import API from "@/services/api/Api"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; + +export default async function GMedidaTipoRemoveData(data: GMedidaTipoInterface) { + + const api = new API(); + + return await api.send({ + method: Methods.DELETE, + endpoint: `administrativo/g_medida_tipo/${data.medida_tipo_id}` + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoSaveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoSaveData.ts new file mode 100644 index 0000000..deff26e --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/GMedidaTipoSaveData.ts @@ -0,0 +1,17 @@ +import API from "@/services/api/Api"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; + +export default async function GMedidaTipoSaveData(data: GMedidaTipoInterface) { + + const isUpdate = Boolean(data.medida_tipo_id); + + const api = new API(); + + return await api.send({ + method: isUpdate ? Methods.PUT : Methods.POST, + endpoint: `administrativo/g_medida_tipo/${data.medida_tipo_id || ''}`, + body: data + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/mockMedidaTipo.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/mockMedidaTipo.ts new file mode 100644 index 0000000..ae1eabf --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GMedidoTipo/mockMedidaTipo.ts @@ -0,0 +1,28 @@ +export default async function MedidaTipoMockDeDados() { + return Promise.resolve({ + status: 200, + message: 'Dados localizados', + data: [ + { + medida_tipo_id: 1.00, + sigla: "Alqueire", + descricao: "Alqueire" + }, + { + medida_tipo_id: 2.00, + sigla: "ha", + descricao: "Hectare" + }, + { + medida_tipo_id: 3.00, + sigla: "m2", + descricao: "Metros Quadrados" + }, + { + medida_tipo_id: 4.00, + sigla: "braça", + descricao: "Braça" + } + ] + }); +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoReadHook.ts new file mode 100644 index 0000000..9ac7b2c --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoReadHook.ts @@ -0,0 +1,27 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import { useState } from "react"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; +import GMedidaTipoIndexService from "../../_services/g_medidatipo/GMedidaTipoIndexService"; + +export const useGMedidaTipoReadHook = () => { + + const { setResponse } = useResponse(); + const [gMedidaTipo, setGMedidaTipo] = useState([]); + + const fetchGMedidaTipo = async () => { + + try { + const response = await GMedidaTipoIndexService(); + + setGMedidaTipo(response.data); + + setResponse(response); + } catch (error) { + console.log(error) + } + + } + + return { gMedidaTipo, fetchGMedidaTipo } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoRemoveHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoRemoveHook.ts new file mode 100644 index 0000000..d19018a --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoRemoveHook.ts @@ -0,0 +1,19 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; +import GMedidaTipoRemoveService from "../../_services/g_medidatipo/GMedidaTipoRemoveService"; + +export const useGMedidaTipoRemoveHook = () => { + + const { setResponse } = useResponse(); + + const removeGMedidaTipo = async (data: GMedidaTipoInterface) => { + + const response = await GMedidaTipoRemoveService(data); + + setResponse(response); + + } + + return { removeGMedidaTipo } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoSaveHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoSaveHook.ts new file mode 100644 index 0000000..8f70843 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_medidatipo/useGMedidaTipoSaveHook.ts @@ -0,0 +1,31 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import { useState } from "react"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; +import GMedidaTipoSaveService from "../../_services/g_medidatipo/GMedidaTipoSaveService"; + +export const useGMedidaTipoSaveHook = () => { + + const { setResponse } = useResponse(); + const [gMedidaTipo, setGMedidaTipo] = useState(null); + // controla se o formulário está aberto ou fechado + const [isOpen, setIsOpen] = useState(false); + + const saveGMedidaTipo = async (data: GMedidaTipoInterface) => { + + const response = await GMedidaTipoSaveService(data); + + setGMedidaTipo(response.data); + + setResponse(response); + + // Fecha o formulário automaticamente após salvar + setIsOpen(false); + + // Retorna os dados imediatamente + return response; + + } + + return { gMedidaTipo, saveGMedidaTipo } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/GMedidaTipoInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GMedidaTipoInterface.ts new file mode 100644 index 0000000..f351f54 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GMedidaTipoInterface.ts @@ -0,0 +1,5 @@ +export interface GMedidaTipoInterface { + medida_tipo_id: number; + sigla: string; + descricao: string; +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_schemas/GMedidaTipoSchema.ts b/src/app/(protected)/(cadastros)/cadastros/_schemas/GMedidaTipoSchema.ts new file mode 100644 index 0000000..12bc46e --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_schemas/GMedidaTipoSchema.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; + +export const GMedidaTipoSchema = z.object({ + medida_tipo_id: z.number(), + sigla: z.string(), + descricao: z.string(), +}); \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoIndexService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoIndexService.ts new file mode 100644 index 0000000..e12ceba --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoIndexService.ts @@ -0,0 +1,12 @@ +import GMedidaTipoIndexData from "../../_data/GMedidoTipo/GMedidaTipoIndexData"; + +export default async function GMedidaTipoIndexService() { + + try { + const response = await GMedidaTipoIndexData(); + return response; + } catch (error) { + console.log(error) + return error + } +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoRemoveService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoRemoveService.ts new file mode 100644 index 0000000..2a98f69 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoRemoveService.ts @@ -0,0 +1,10 @@ +import GMedidaTipoRemoveData from "../../_data/GMedidoTipo/GMedidaTipoRemoveData"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; + +export default async function GMedidaTipoRemoveService(data: GMedidaTipoInterface) { + + const response = await GMedidaTipoRemoveData(data); + + return response; + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoSaveService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoSaveService.ts new file mode 100644 index 0000000..c6f3460 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/g_medidatipo/GMedidaTipoSaveService.ts @@ -0,0 +1,12 @@ +import GMedidaTipoSaveData from "../../_data/GMedidoTipo/GMedidaTipoSaveData"; +import { GMedidaTipoInterface } from "../../_interfaces/GMedidaTipoInterface"; + +export default async function GMedidaTipoSaveService(data: GMedidaTipoInterface) { + + const response = await GMedidaTipoSaveData(data); + + console.log('GTBRegimeComunhaoSaveData', response) + + return response; + +} \ No newline at end of file diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 35c881d..aa0bd20 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -108,6 +108,10 @@ const data = { { title: "Estado Civil", url: "/cadastros/estado-civil" + }, + { + title: "Tipo de Medida", + url: "/cadastros/medida-tipo" } ], },