From 7eafc9439b97b1d37e0a7d2fc76f83793ff8c141 Mon Sep 17 00:00:00 2001 From: keven Date: Wed, 17 Sep 2025 15:57:26 -0300 Subject: [PATCH] [MVPTN-72] feat(CRUD): Cria CRUD para manipular as centrais do CENSEC --- .../cadastros/(t_censec)/censec/page.tsx | 163 ++++++++++++++++++ .../_components/t_censec/TCensecForm.tsx | 127 ++++++++++++++ .../_components/t_censec/TCensecTable.tsx | 125 ++++++++++++++ .../_data/TCensec/TCensecDeleteData.ts | 10 ++ .../_data/TCensec/TCensecIndexData.ts | 30 ++++ .../_data/TCensec/TCensecSaveData.ts | 15 ++ .../_hooks/t_censec/useTCensecDeleteHook.ts | 19 ++ .../_hooks/t_censec/useTCensecReadHook.ts | 26 +++ .../_hooks/t_censec/useTCensecSaveHook.ts | 37 ++++ .../cadastros/_interfaces/TCensecInterface.ts | 6 + .../cadastros/_schemas/TCensecSchema.ts | 7 + .../t_censec/TCensecDeleteService.ts | 10 ++ .../_services/t_censec/TCensecIndexService.ts | 9 + .../_services/t_censec/TCensecSaveService.ts | 10 ++ src/components/app-sidebar.tsx | 4 + 15 files changed, 598 insertions(+) create mode 100644 src/app/(protected)/(cadastros)/cadastros/(t_censec)/censec/page.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecForm.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecTable.tsx create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecDeleteData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecIndexData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecSaveData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecDeleteHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecReadHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecSaveHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/TCensecInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_schemas/TCensecSchema.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecIndexService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService.ts diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_censec)/censec/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_censec)/censec/page.tsx new file mode 100644 index 0000000..e4050c9 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/(t_censec)/censec/page.tsx @@ -0,0 +1,163 @@ +'use client'; + +import { useEffect, useState, useCallback } from "react"; +import { Card, CardContent } from "@/components/ui/card"; + +import Loading from "@/app/_components/loading/loading"; +import TCensecTable from "../../_components/t_censec/TCensecTable"; +import TCensecForm from "../../_components/t_censec/TCensecForm"; + +import { useTCensecReadHook } from "../../_hooks/t_censec/useTCensecReadHook"; +import { useTCensecSaveHook } from "../../_hooks/t_censec/useTCensecSaveHook"; +import { useTCensecDeleteHook } from "../../_hooks/t_censec/useTCensecDeleteHook"; + +import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog"; +import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog"; + +import TCensecInterface from "../../_interfaces/TCensecInterface"; +import Header from "@/app/_components/structure/Header"; + +export default function TTBAndamentoServico() { + // Hooks para leitura e salvamento + const { tCensec, fetchTCensec } = useTCensecReadHook(); + const { saveTCensec } = useTCensecSaveHook(); + const { deleteTCensec } = useTCensecDeleteHook(); + + // Estados + const [selectedAndamento, setSelectedAndamento] = useState(null); + const [isFormOpen, setIsFormOpen] = useState(false); + + // Estado para saber qual item será deletado + const [itemToDelete, setItemToDelete] = useState(null); + + /** + * Hook do modal de confirmação + */ + const { + isOpen: isConfirmOpen, + openDialog: openConfirmDialog, + handleConfirm, + handleCancel, + } = useConfirmDialog(); + + /** + * Abre o formulário no modo de edição ou criação + */ + const handleOpenForm = useCallback((data: TCensecInterface | null) => { + setSelectedAndamento(data); + setIsFormOpen(true); + }, []); + + /** + * Fecha o formulário e limpa o andamento selecionado + */ + const handleCloseForm = useCallback(() => { + setSelectedAndamento(null); + setIsFormOpen(false); + }, []); + + /** + * Salva os dados do formulário + */ + const handleSave = useCallback(async (formData: TCensecInterface) => { + + // Aguarda salvar o registro + await saveTCensec(formData); + + // Atualiza a lista de dados + fetchTCensec(); + + }, [saveTCensec, fetchTCensec, handleCloseForm]); + + /** + * Quando o usuário clica em "remover" na tabela + */ + const handleConfirmDelete = useCallback((item: TCensecInterface) => { + + // Define o item atual para remoção + setItemToDelete(item); + + // Abre o modal de confirmação + openConfirmDialog(); + + }, [openConfirmDialog]); + + /** + * Executa a exclusão de fato quando o usuário confirma + */ + const handleDelete = useCallback(async () => { + + // Protege contra null + if (!itemToDelete) return; + + // Executa o Hook de remoção + await deleteTCensec(itemToDelete); + + // Atualiza a lista + await fetchTCensec(); + + // Limpa o item selecionado + setItemToDelete(null); + + // Fecha o modal + handleCancel(); + + }, [itemToDelete, fetchTCensec, handleCancel]); + + /** + * Busca inicial dos dados + */ + useEffect(() => { + fetchTCensec(); + }, []); + + /** + * Tela de loading enquanto carrega os dados + */ + if (!tCensec) { + return ; + } + + return ( +
+ {/* Cabeçalho */} +
{ handleOpenForm(null) }} + /> + + {/* Tabela de andamentos */} + + + + + + + {/* Modal de confirmação */} + + + {/* Formulário de criação/edição */} + +
+ ); 4 +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecForm.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecForm.tsx new file mode 100644 index 0000000..93576d7 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecForm.tsx @@ -0,0 +1,127 @@ +'use client'; + +import z from "zod"; +import { useEffect } from "react"; +import { useForm, Controller } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; + +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +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 { Label } from "@/components/ui/label"; + +import { TCensecSchema } from "../../_schemas/TCensecSchema"; + +type FormValues = z.infer; + +interface Props { + isOpen: boolean; + data: FormValues | null; + onClose: (item: null, isFormStatus: boolean) => void; + onSave: (data: FormValues) => void; +} + +export default function TCensecForm({ isOpen, data, onClose, onSave }: Props) { + // Inicializa o react-hook-form com schema zod + const form = useForm({ + resolver: zodResolver(TCensecSchema), + defaultValues: { + descricao: "", + situacao: "A", + censec_id: 0, + }, + }); + + // Atualiza o formulário quando recebe dados para edição + useEffect(() => { + if (data) form.reset(data); + }, [data, form]); + + return ( + { + if (!open) onClose(null, false); + }} + > + + + + + Censec + + + Tipos de Centrais + + + +
+ + + {/* Descrição */} + ( + + Descrição + + + + + + )} + /> + + {/* Situação */} + ( +
+ field.onChange(checked ? "A" : "I")} + /> + +
+ )} + /> + + {/* Rodapé do Dialog */} + + + + + + + + {/* Campo oculto */} + + + +
+
+ ); +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecTable.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecTable.tsx new file mode 100644 index 0000000..37df466 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_censec/TCensecTable.tsx @@ -0,0 +1,125 @@ +'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 TCensecInterface from "../../_interfaces/TCensecInterface"; + +interface TCensecTableProps { + data: TCensecInterface[]; + onEdit: (item: TCensecInterface, isEditingFormStatus: boolean) => void; + onDelete: (item: TCensecInterface, isEditingFormStatus: boolean) => void; +} + +/** + * Renderiza o badge de situação + */ +function StatusBadge({ situacao }: { situacao: string }) { + const isActive = situacao === "A"; + + const baseClasses = + "text-xs font-medium px-2.5 py-0.5 rounded-sm me-2"; + + const activeClasses = + "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"; + + const inactiveClasses = + "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300"; + + return ( + + {isActive ? "Ativo" : "Inativo"} + + ); +} + +export default function TCensecTable({ + data, + onEdit, + onDelete +}: TCensecTableProps) { + return ( + + + + # + Situação + CBO + Descrição + Ações + + + + + {data.map((item) => ( + + + {item.censec_id} + + + + + + + {item.descricao} + + + + + + + + + + onEdit(item, true)} + > + + Editar + + + + + onDelete(item, true)} + > + + Remover + + + + + + + ))} + +
+ ); +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecDeleteData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecDeleteData.ts new file mode 100644 index 0000000..f3f367a --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecDeleteData.ts @@ -0,0 +1,10 @@ +import TCensecInterface from "../../_interfaces/TCensecInterface"; + +export default async function TCensecDeleteData(data: TCensecInterface) { + + return Promise.resolve({ + message: 'Dados removidos', + status: 200 + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecIndexData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecIndexData.ts new file mode 100644 index 0000000..d1747cf --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecIndexData.ts @@ -0,0 +1,30 @@ +export default async function TCensecIndexData() { + + return Promise.resolve({ + message: 'Dados localizados', + status: 200, + data: [ + { + censec_id: 1.00, + descricao: 'CEP - Escritura e Procurações Diversas', + situacao: 'A' + }, + { + censec_id: 2.00, + descricao: 'CESDI - Escrituras Lei 11.441', + situacao: 'A' + }, + { + censec_id: 3.00, + descricao: 'RCTO - Testamentos', + situacao: 'A' + }, + { + censec_id: 9.00, + descricao: 'Não Possui', + situacao: 'A' + } + ] + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecSaveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecSaveData.ts new file mode 100644 index 0000000..eefb0f8 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TCensec/TCensecSaveData.ts @@ -0,0 +1,15 @@ +import TCensecInterface from "../../_interfaces/TCensecInterface"; + +export default async function TCensecSaveData(data: TCensecInterface) { + + return Promise.resolve({ + message: 'Dados salvos', + status: 201, + data: { + censec_id: 9.00, + descricao: 'Não Possui', + situacao: 'A' + } + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecDeleteHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecDeleteHook.ts new file mode 100644 index 0000000..6542033 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecDeleteHook.ts @@ -0,0 +1,19 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import TCensecInterface from "../../_interfaces/TCensecInterface"; +import TCensecDeleteService from "../../_services/t_censec/TCensecDeleteService"; + +export const useTCensecDeleteHook = () => { + + const { setResponse } = useResponse(); + + const deleteTCensec = async (data: TCensecInterface) => { + + const response = await TCensecDeleteService(data); + + setResponse(response); + + } + + return { deleteTCensec } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecReadHook.ts new file mode 100644 index 0000000..b71e8c3 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecReadHook.ts @@ -0,0 +1,26 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import TCensecIndexService from "../../_services/t_censec/TCensecIndexService"; +import { useState } from "react"; +import TCensecInterface from "../../_interfaces/TCensecInterface"; + +export const useTCensecReadHook = () => { + + const { setResponse } = useResponse(); + + const [tCensec, setTCensec] = useState([]); + + const fetchTCensec = async () => { + + const response = await TCensecIndexService(); + + setTCensec(response.data); + + setResponse(response); + + return response + + } + + return { tCensec, fetchTCensec } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecSaveHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecSaveHook.ts new file mode 100644 index 0000000..a1412b7 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_censec/useTCensecSaveHook.ts @@ -0,0 +1,37 @@ +'use client' + +import { useResponse } from "@/app/_response/ResponseContext" +import { useState } from "react"; +import TCensecInterface from "../../_interfaces/TCensecInterface"; +import TCensecSaveService from "../../_services/t_censec/TCensecSaveService"; + +export const useTCensecSaveHook = () => { + + const { setResponse } = useResponse(); + + const [tCensec, setTCensec] = useState(); + + // controla se o formulário está aberto ou fechado + const [isOpen, setIsOpen] = useState(false); + + const saveTCensec = async (data: TCensecInterface) => { + + const response = await TCensecSaveService(data); + + // Armazena os dados da repsota + setTCensec(response.data); + + // Define os dados da respota(toast, modal, etc) + setResponse(response); + + // Fecha o formulário automaticamente após salvar + setIsOpen(false); + + // Retorna os valores de forma imediata + return response.data; + + } + + return { tCensec, saveTCensec } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/TCensecInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/TCensecInterface.ts new file mode 100644 index 0000000..2fbf58a --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/TCensecInterface.ts @@ -0,0 +1,6 @@ + +export default interface TCensecInterface { + censec_id?: number + descricao: string + situacao: string +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_schemas/TCensecSchema.ts b/src/app/(protected)/(cadastros)/cadastros/_schemas/TCensecSchema.ts new file mode 100644 index 0000000..a9d0aa4 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_schemas/TCensecSchema.ts @@ -0,0 +1,7 @@ +import z from "zod"; + +export const TCensecSchema = z.object({ + censec_id: z.number().optional(), + descricao: z.string().min(1, "O campo deve ser preenchido").max(60, "O campo excedeu o limite de 60 caracteres"), + situacao: z.string().min(1, "O campo deve ser preenchido").max(10, "O campo excedeu o limite de 10 caracteres"), +}); \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService.ts new file mode 100644 index 0000000..f70eea2 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService.ts @@ -0,0 +1,10 @@ +import TCensecDeleteData from "../../_data/TCensec/TCensecDeleteData"; +import TCensecInterface from "../../_interfaces/TCensecInterface"; + +export default async function TCensecDeleteService(data: TCensecInterface) { + + const response = await TCensecDeleteData(data); + + return response; + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecIndexService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecIndexService.ts new file mode 100644 index 0000000..1e37031 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecIndexService.ts @@ -0,0 +1,9 @@ +import TCensecIndexData from "../../_data/TCensec/TCensecIndexData"; + +export default async function TCensecIndexService() { + + const response = await TCensecIndexData(); + + return response; + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService.ts new file mode 100644 index 0000000..0240cb8 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService.ts @@ -0,0 +1,10 @@ +import TCensecSaveData from "../../_data/TCensec/TCensecSaveData"; +import TCensecInterface from "../../_interfaces/TCensecInterface"; + +export default async function TCensecSaveService(data: TCensecInterface) { + + const response = await TCensecSaveData(data); + + return response; + +} \ No newline at end of file diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index ed96420..a771867 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -96,6 +96,10 @@ const data = { { title: "Regimes/Comunhão", url: "/cadastros/regime-comunhao/", + }, + { + title: "Censec/Centrais", + url: "/cadastros/censec/", } ], },