From 0407483d2300523ff2fec06568ec4e75e6d12e2b Mon Sep 17 00:00:00 2001 From: keven Date: Sat, 13 Sep 2025 13:14:00 -0300 Subject: [PATCH 1/2] =?UTF-8?q?[MVPTN-2]=20refacto(AndamentoServico):=20Re?= =?UTF-8?q?faz=20o=20CRUD=20de=20AndamentoServico=20implementando=20compon?= =?UTF-8?q?eiza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 24 ++ package.json | 2 + src/actions/json/Json.ts | 16 +- .../andamentos/page.tsx | 174 +++++++---- .../TTBAndamentoServicoAlert.tsx | 38 --- .../TTBAndamentoServicoForm.tsx | 273 ++++++++++-------- .../TTBAndamentoServicoTable.tsx | 169 +++++++---- .../TTBAndamentoServicoIndexData.ts | 145 +--------- .../TTBAndamentoServicoSaveData.ts | 25 +- .../useTTBAndamentoServicoReadHook.ts | 1 + .../useTTBAndamentoServicoSaveHook.ts | 8 +- .../confirm_dialog/ConfirmDialog.tsx | 83 ++++++ .../confirm_dialog/useConfirmDialog.ts | 51 ++++ src/config/app.json | 2 +- src/services/api/Api.ts | 5 +- 15 files changed, 580 insertions(+), 436 deletions(-) delete mode 100644 src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoAlert.tsx create mode 100644 src/app/_components/confirm_dialog/ConfirmDialog.tsx create mode 100644 src/app/_components/confirm_dialog/useConfirmDialog.ts diff --git a/package-lock.json b/package-lock.json index db55039..9e77c45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "app", "version": "0.1.0", "dependencies": { + "@faker-js/faker": "^10.0.0", "@hookform/resolvers": "^5.2.1", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.10", @@ -24,6 +25,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cookies-next": "^6.1.0", + "faker-js": "^1.0.0", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.540.0", "next": "15.4.6", @@ -69,6 +71,22 @@ "tslib": "^2.4.0" } }, + "node_modules/@faker-js/faker": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.0.0.tgz", + "integrity": "sha512-UollFEUkVXutsaP+Vndjxar40Gs5JL2HeLcl8xO1QAjJgOdhc3OmBFWyEylS+RddWaaBiAzH+5/17PLQJwDiLw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" + } + }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -2167,6 +2185,12 @@ "node": ">=10.13.0" } }, + "node_modules/faker-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/faker-js/-/faker-js-1.0.0.tgz", + "integrity": "sha512-kaToadbN63LWhHjl69pqG+YHlxAK0aZAPhQDUpVP7v7+RG//ZpK0OzXjCwaAQq98awOii0WSHxtJmIz0X7/UqQ==", + "license": "ISC" + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", diff --git a/package.json b/package.json index 7d867a7..0111c7f 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@faker-js/faker": "^10.0.0", "@hookform/resolvers": "^5.2.1", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.10", @@ -25,6 +26,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cookies-next": "^6.1.0", + "faker-js": "^1.0.0", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.540.0", "next": "15.4.6", diff --git a/src/actions/json/Json.ts b/src/actions/json/Json.ts index 92a1a18..b075b64 100644 --- a/src/actions/json/Json.ts +++ b/src/actions/json/Json.ts @@ -1,16 +1,6 @@ +import appConfig from '../../config/app.json'; export default class Json { - - static execute(path: string) { - - return { - "state": "go", - "api": { - "url": "http://localhost:8000/", - "prefix": "api/v1", - "content_type": "application/json" - } - } - + static execute() { + return appConfig; } - } \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx index 0338ae2..7fe708a 100644 --- a/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx @@ -1,92 +1,154 @@ -'use client' +'use client'; +import { useEffect, useState, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; -import { useEffect, useState } from "react"; -import { useTTBAndamentoServicoReadHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook"; -import Loading from "@/app/_components/loading/loading"; -import TTBAndamentoServicoInteface, { tipoEnum } from "../../_interfaces/TTBAndamentoServicoInterface"; -import { TTBAndamentoServicoSchema } from "../../_schemas/TTBAndamentoServicoSchema"; -import z from "zod"; -import { useTTBAndamentoServicoSaveHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook"; -import TTBAndamentoServicoTable from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoTable"; -import TTBAndamentoServicoForm from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoForm"; -import TTBAndamentoServicoAlert from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoAlert"; import { PlusIcon } from "lucide-react"; -type FormValues = z.infer +import Loading from "@/app/_components/loading/loading"; +import TTBAndamentoServicoTable from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoTable"; +import TTBAndamentoServicoForm from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoForm"; + +import { useTTBAndamentoServicoReadHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook"; +import { useTTBAndamentoServicoSaveHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook"; + +import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog"; +import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog"; + +import TTBAndamentoServicoInterface from "../../_interfaces/TTBAndamentoServicoInterface"; export default function TTBAndamentoServico() { + // Hooks para leitura e salvamento + const { tTBAndamentosServicos, fetchTTBAndamentoServico } = useTTBAndamentoServicoReadHook(); + const { saveTTBAndamentoServico } = useTTBAndamentoServicoSaveHook(); - const { tTBAndamentosServicos, fetchTTBAndamentoServico, addTTBAndamentoServico } = useTTBAndamentoServicoReadHook(); - const { tTBAndamentoServico, saveTTBAndamentoServico } = useTTBAndamentoServicoSaveHook(); + // Estados + const [selectedAndamento, setSelectedAndamento] = useState(null); + const [isFormOpen, setIsFormOpen] = useState(false); - const [dialogOpen, setDialogOpen] = useState(false); - const [alertDialogOpen, setAlertDialogOpen] = useState(false); - const [item, setItem] = useState(null); + // Estado para saber qual item será deletado + const [itemToDelete, setItemToDelete] = useState(null); - const [formOpen, setFormOpen] = useState(false); - const [editingItem, setEditingItem] = useState(null); + /** + * Hook do modal de confirmação + */ + const { + isOpen: isConfirmOpen, + openDialog: openConfirmDialog, + handleConfirm, + handleCancel, + } = useConfirmDialog(); - const [deleteOpen, setDeleteOpen] = useState(false) - const [deleteItem, setDeleteItem] = useState(null) + /** + * Abre o formulário no modo de edição ou criação + */ + const handleOpenForm = useCallback((data: TTBAndamentoServicoInterface | null) => { + setSelectedAndamento(data); + setIsFormOpen(true); + }, []); - const emptyForm: FormValues = { - tb_andamentoservico_id: 0, - descricao: "", - situacao: "I", - tipo: "", - usa_email: "", - }; + /** + * 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: TTBAndamentoServicoInterface) => { + await saveTTBAndamentoServico(formData); + handleCloseForm(); + fetchTTBAndamentoServico(); // Atualiza a lista após salvar + }, + [saveTTBAndamentoServico, fetchTTBAndamentoServico, handleCloseForm] + ); + + /** + * Quando o usuário clica em "remover" na tabela + */ + const handleConfirmDelete = useCallback((item: TTBAndamentoServicoInterface) => { + setItemToDelete(item); + openConfirmDialog(); // Abre o modal de confirmação + }, [openConfirmDialog]); + + /** + * Executa a exclusão de fato quando o usuário confirma + */ + const handleDelete = useCallback(() => { + if (!itemToDelete) return; + console.log("Deletando andamento:", itemToDelete); + + // TODO: Implementar lógica de exclusão na API + fetchTTBAndamentoServico(); // Atualiza a lista + setItemToDelete(null); // Limpa o item selecionado + handleCancel(); // Fecha o modal + }, [itemToDelete, fetchTTBAndamentoServico, handleCancel]); + + /** + * Busca inicial dos dados + */ useEffect(() => { fetchTTBAndamentoServico(); }, []); - const handleSave = async (values: FormValues) => { - const saved = await saveTTBAndamentoServico(values); - addTTBAndamentoServico(saved); - setFormOpen(false); + /** + * Tela de loading enquanto carrega os dados + */ + if (!tTBAndamentosServicos) { + return ; } - if (!tTBAndamentosServicos) return ; return (
-
-
-
+ {/* Cabeçalho */} +
+
+

Andamentos -

-
+ +

Gerenciamento de tipos de reconhecimentos -

-
-
- +

+
+ + {/* Tabela de andamentos */} { setEditingItem(item); setFormOpen(true) }} - onDelete={(item) => { setDeleteItem(item); setDeleteOpen(true) }} + onEdit={handleOpenForm} + onDelete={handleConfirmDelete} /> - setFormOpen(false)} - initialData={editingItem || emptyForm} - onSave={handleSave} + + {/* Modal de confirmação */} + - < TTBAndamentoServicoAlert - isOpen={deleteOpen} - item={deleteItem} - onClose={() => setDeleteOpen(false)} - onConfirm={() => { setDeleteOpen(false) }} + + {/* Formulário de criação/edição */} +
); diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoAlert.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoAlert.tsx deleted file mode 100644 index 1fc1667..0000000 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoAlert.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client' - -import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; -import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; - -interface Props { - isOpen: boolean, - item?: TTBAndamentoServicoInteface | null, - onClose: () => void - onConfirm: () => void -} - -export default function TTBAndamentoServicoAlert({ isOpen, item, onClose, onConfirm }: Props) { - return ( -
- - - - - #{item?.tb_andamentoservico_id} - {item?.descricao} - - - Esta ação não pode ser desfeita. Isso excluirá permanentemente o registro e seus dados dos nossos servidores. - - - - - Cancelar - - - Continuar - - - - -
- ); -} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx index dbb519f..bd85c25 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx @@ -1,36 +1,67 @@ -'use client' +'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 { + 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Controller, useForm } from "react-hook-form"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from "@/components/ui/select"; + import { TTBAndamentoServicoSchema } from "../../_schemas/TTBAndamentoServicoSchema"; import { tipoEnum } from "../../_interfaces/TTBAndamentoServicoInterface"; -type FormValues = z.infer +type FormValues = z.infer; interface Props { - isOpen: boolean - onClose: () => void - initialData?: FormValues - onSave: (data: FormValues) => void + isOpen: boolean; + data: FormValues | null; + onClose: (item: null, isFormStatus: boolean) => void; + onSave: (data: FormValues) => void; } -export default function TTBAndamentoServicoForm({ isOpen, onClose, initialData, onSave }: Props) { - +export default function TTBAndamentoServicoForm({ isOpen, data, onClose, onSave }: Props) { + // Inicializa o react-hook-form com schema zod const form = useForm({ - resolver: undefined, - defaultValues: initialData || { tb_andamentoservico_id: 0, descricao: "", situacao: "I" } - }) + resolver: zodResolver(TTBAndamentoServicoSchema), + defaultValues: { + descricao: "", + tipo: "", + situacao: "A", + usa_email: "I", + tb_andamentoservico_id: undefined, + }, + }); + // Opções do Select mapeadas a partir do enum const tipoOptions = Object.values(tipoEnum).map((value) => ({ value, - // Aqui você pode personalizar o label como quiser label: value === "C" ? "Cancelado" : value === "E" ? "Estornado" : @@ -40,113 +71,117 @@ export default function TTBAndamentoServicoForm({ isOpen, onClose, initialData, "Outros" })); + // Atualiza o formulário quando recebe dados para edição + useEffect(() => { + if (data) form.reset(data); + }, [data, form]); + return ( -
- + { + if (!open) onClose(null, false); + }} + > + + + + Andamentos + + + Controle de andamentos de atos + + +
- - - - - - - Andamentos - - - Controle de andamentos de atos - - - ( - - - Descrição - - - - - - - )} + + + {/* Descrição */} + ( + + Descrição + + + + + + )} + /> + + {/* Tipo */} + ( + + Tipo + + + + )} + /> + + {/* Situação */} + ( +
+ field.onChange(checked ? "A" : "I")} /> - ( - - - Tipo - - - - - )} + +
+ )} + /> + + {/* Usar e-mail */} + ( +
+ field.onChange(checked ? "A" : "I")} /> -
- ( - field.onChange(checked ? "A" : "I")} - /> - )} - /> - -
-
- ( - field.onChange(checked ? "A" : "I")} - /> - )} - /> - -
- - - - - - - - - - + +
+ )} + /> + + {/* Rodapé do Dialog */} + + + + + + + + {/* Campo oculto */} + -
-
+ + ); -} \ No newline at end of file +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoTable.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoTable.tsx index 9183f05..1eada8f 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoTable.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoTable.tsx @@ -1,79 +1,124 @@ -'use client' +'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 { + 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 TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; -interface Props { - data: TTBAndamentoServicoInteface[] - onEdit: (item: TTBAndamentoServicoInteface) => void - onDelete: (item: TTBAndamentoServicoInteface) => void +interface TTBAndamentoServicoTableProps { + data: TTBAndamentoServicoInteface[]; + onEdit: (item: TTBAndamentoServicoInteface, isEditingFormStatus: boolean) => void; + onDelete: (item: TTBAndamentoServicoInteface, isEditingFormStatus: boolean) => void; } -export default function TTBAndamentoServicoTable({ data, onEdit, onDelete }: Props) { +/** + * 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 TTBAndamentoServicoTable({ + data, + onEdit, + onDelete +}: TTBAndamentoServicoTableProps) { return ( - - # - - - Situação - - - Descrição - - + # + Situação + Descrição + Ações + - {data.map( - (item: TTBAndamentoServicoInteface) => ( - - - {item.tb_andamentoservico_id} - - - {item.situacao === 'A' ? ( - - Ativo - - ) : ( - - Inativo - - )} - - - {item.descricao} - - - - - - - - - onEdit(item)}> - Editar - - - onDelete(item)}> - Remover - - - - - - - ) - )} + {data.map((item) => ( + + + {item.tb_andamentoservico_id} + + + + + + + {item.descricao} + + + + + + + + + + onEdit(item, true)} + > + + Editar + + + + + onDelete(item, true)} + > + + Remover + + + + + + + ))}
); -} \ No newline at end of file +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoIndexData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoIndexData.ts index b91bb11..3865338 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoIndexData.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoIndexData.ts @@ -1,132 +1,17 @@ +'use server' + +import API from "@/services/api/Api"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; + export default async function TTBAndamentoServicoIndexData() { - return Promise.resolve({ - data: [ - { - tb_andamentoservico_id: 1, - descricao: "Recepção 1", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 2, - descricao: "Aguardando assinatura da Imobiliária", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 3, - descricao: "Esc. Impugnada (Falta Itbi, cert. ou documentos)", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 4, - descricao: "Aguardando Certtb_andamentoservico_idão de Registro", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 5, - descricao: "Conferencia", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 16, - descricao: "Mapa", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 6, - descricao: "Entregue", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 18, - descricao: "PROTOCOLADO", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 7, - descricao: "Protocolo", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 8, - descricao: "Cadastro", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 9, - descricao: "Registro/Espelho", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 10, - descricao: "Corrigtb_andamentoservico_ido Pronto", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 11, - descricao: "Aguardando Cliente", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 12, - descricao: "Cancelado a pedtb_andamentoservico_ido da parte", - status: "A", - tipo: "C" - }, - { - tb_andamentoservico_id: 13, - descricao: "Cancelado por determinação judicial", - status: "A", - tipo: "C" - }, - { - tb_andamentoservico_id: 14, - descricao: "Capas e Indicador", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 15, - descricao: "Falta assinatura", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 17, - descricao: "Impugnado", - status: "A", - tipo: "G" - }, - { - tb_andamentoservico_id: 19, - descricao: "Entregre/sem registro", - status: "A", - tipo: "C" - }, - { - tb_andamentoservico_id: 20, - descricao: "Corrigtb_andamentoservico_ido sem Registro", - status: "A", - tipo: "C" - }, - { - tb_andamentoservico_id: 21, - descricao: "Cancelamento de ofício", - status: "A", - tipo: "C" - } - ] + + const api = new API(); + + const response = await api.send({ + 'method': Methods.GET, + 'endpoint': `administrativo/t_tb_andamentoservico/` }); -} + + return response; + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts index ab8035d..fdc5943 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts @@ -1,16 +1,19 @@ -import { faker } from "@faker-js/faker"; +'use server' -export default async function name(andamentoServico: any) { +import API from "@/services/api/Api"; +import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; - return Promise.resolve({ - message: 'Dados salvos com sucesso', - data: { - tb_reconhecimentotipo_id: faker.number.int({ min: 1, max: 1000 }), - descricao: andamentoServico.tb_reconhecimentotipo_id + andamentoServico.descricao, - situacao: andamentoServico.situacao, - tipo: andamentoServico.tipo, - usa_email: andamentoServico.usa_email, - }, +export default async function TTBAndamentoServicoSaveData(andamentoServico: TTBAndamentoServicoInteface) { + + const api = new API(); + + const response = await api.send({ + method: Methods.POST, + endpoint: `administrativo/t_tb_andamentoservico/`, + body: andamentoServico }); + return response; + } \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook.ts index df69730..a1b0ac1 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook.ts @@ -15,6 +15,7 @@ export const useTTBAndamentoServicoReadHook = () => { const response = await TTBAndamentoServicoIndexData(); + // Armazena os dados consultados setTTBAndamentosServicos(response.data); // Define os dados do componente de resposta (toast, modal, etc) diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts index b854b0a..18f6c0d 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts @@ -1,9 +1,9 @@ 'use client' import { useResponse } from "@/app/_response/ResponseContext" -import { use, useState } from "react"; +import { useState } from "react"; import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; -import TTBReconhecimentoTipoSaveData from "../../_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData"; +import TTBAndamentoServicoSaveData from "../../_data/TTBAndamentoServico/TTBAndamentoServicoSaveData"; export const useTTBAndamentoServicoSaveHook = () => { @@ -13,10 +13,12 @@ export const useTTBAndamentoServicoSaveHook = () => { const saveTTBAndamentoServico = async (form: TTBAndamentoServicoInteface) => { - const response = await TTBReconhecimentoTipoSaveData(form); + const response = await TTBAndamentoServicoSaveData(form); + // Armazena os dados da repsota setTTBAndamentoServico(response.data); + // Define os dados da respota(toast, modal, etc) setResponse(response); // Retorna os valores de forma imediata diff --git a/src/app/_components/confirm_dialog/ConfirmDialog.tsx b/src/app/_components/confirm_dialog/ConfirmDialog.tsx new file mode 100644 index 0000000..f72a3eb --- /dev/null +++ b/src/app/_components/confirm_dialog/ConfirmDialog.tsx @@ -0,0 +1,83 @@ +'use client'; + +import React from 'react'; + +// Shadcn UI components +import { + AlertDialog, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogAction, +} from '@/components/ui/alert-dialog'; + +interface AlertProps { + /** Controla a abertura do modal */ + isOpen: boolean; + + /** Título principal do alerta */ + title: string; + + /** Descrição adicional do alerta */ + description?: string; + + /** Mensagem do corpo do alerta */ + message: string; + + /** Texto do botão de confirmação */ + confirmText?: string; + + /** Texto do botão de cancelamento */ + cancelText?: string; + + /** Função executada ao confirmar */ + onConfirm: () => void; + + /** Função executada ao cancelar */ + onCancel: () => void; +} + +/** + * Componente de alerta genérico e reutilizável. + * Baseado no Radix e Shadcn UI, com suporte a título, descrição, + * mensagem e botões de ação customizáveis. + */ +export default function ConfirmDialog({ + isOpen, + title, + description, + message, + confirmText = 'Confirmar', + cancelText = 'Cancelar', + onConfirm, + onCancel, +}: AlertProps) { + return ( + + + + {title} + {description && ( + {description} + )} + + +
+ {message} +
+ + + + {cancelText} + + + {confirmText} + + +
+
+ ); +} diff --git a/src/app/_components/confirm_dialog/useConfirmDialog.ts b/src/app/_components/confirm_dialog/useConfirmDialog.ts new file mode 100644 index 0000000..55afbc6 --- /dev/null +++ b/src/app/_components/confirm_dialog/useConfirmDialog.ts @@ -0,0 +1,51 @@ +// Importa os hooks useCallback e useState do React +import { useCallback, useState } from "react"; + +// Define a interface para opções do hook +// Permite que o usuário passe callbacks opcionais para confirmação e cancelamento +interface UseConfirmDialogOptions { + onConfirm?: () => void; // Função chamada quando o usuário confirma a ação + onCancel?: () => void; // Função chamada quando o usuário cancela a ação +} + +// Declara o hook customizado useConfirmDialog +// Recebe um objeto de opções que contém os callbacks onConfirm e onCancel +export function useConfirmDialog({ onConfirm, onCancel }: UseConfirmDialogOptions = {}) { + // Estado interno que controla se o diálogo de confirmação está aberto + const [isOpen, setIsOpen] = useState(false); + + // Função para abrir o diálogo + // useCallback memoriza a função para que não seja recriada em cada renderização + const openDialog = useCallback(() => setIsOpen(true), []); + + // Função para fechar o diálogo + const closeDialog = useCallback(() => setIsOpen(false), []); + + // Função chamada quando o usuário confirma a ação + // Executa o callback onConfirm, se fornecido, e fecha o diálogo + const handleConfirm = useCallback(() => { + onConfirm?.(); // Chama onConfirm somente se ele existir + closeDialog(); // Fecha o diálogo após a confirmação + }, [onConfirm, closeDialog]); + + // Função chamada quando o usuário cancela a ação + // Executa o callback onCancel, se fornecido, e fecha o diálogo + const handleCancel = useCallback(() => { + onCancel?.(); // Chama onCancel somente se ele existir + closeDialog(); // Fecha o diálogo após o cancelamento + }, [onCancel, closeDialog]); + + // Retorna os valores e funções que serão usados pelo componente + // isOpen -> estado do modal + // openDialog -> função para abrir o modal + // closeDialog -> função para fechar o modal + // handleConfirm -> função para confirmar a ação + // handleCancel -> função para cancelar a ação + return { + isOpen, + openDialog, + closeDialog, + handleConfirm, + handleCancel, + }; +} diff --git a/src/config/app.json b/src/config/app.json index 64ba493..d38e8d3 100644 --- a/src/config/app.json +++ b/src/config/app.json @@ -1,7 +1,7 @@ { "state": "go", "api": { - "url": "http://localhost:3000/", + "url": "http://localhost:8000/", "prefix": "api/v1/", "content_type": "application/json" } diff --git a/src/services/api/Api.ts b/src/services/api/Api.ts index 75e6173..dfa75f1 100644 --- a/src/services/api/Api.ts +++ b/src/services/api/Api.ts @@ -1,6 +1,5 @@ import Json from '@/actions/json/Json'; import ApiInterface from './interfaces/ApiInterface'; -import Response from '@/services/response/Response'; import TokenGet from '@/actions/token/TokenGet'; import ApiSchema from '@/services/api/schemas/ApiSchema'; @@ -17,7 +16,7 @@ export default class API { this.ApiSchema = new ApiSchema(); // Obtem as configurações da aplicação - this.config = Json.execute('config/app.json'); + this.config = Json.execute(); } @@ -46,7 +45,7 @@ export default class API { const filteredBody = _data.body ? Object.fromEntries(Object.entries(_data.body).filter(([_, v]) => v != null && v !== "")) : null; // Realiza a requisição - const response = await fetch(`${this.ApiSchema.url}${this.ApiSchema.prefix}/${this.ApiSchema.endpoint}`, { + const response = await fetch(`${this.ApiSchema.url}${this.ApiSchema.prefix}${this.ApiSchema.endpoint}`, { method: _data.method, headers: { "Accept": `${this.ApiSchema.contentType}`, From 44d20d6f81c08d93f1063113471b9e231609d4ce Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 14 Sep 2025 10:49:05 -0300 Subject: [PATCH 2/2] =?UTF-8?q?[MVPTN-2]=20feat(CRUD):=20Finaliza=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20a=C3=A7=C3=B5es=20do=20CRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../andamentos/page.tsx | 49 +++++++++++++------ .../TTBAndamentoServicoForm.tsx | 8 +-- .../TTBAndamentoServicoRemoveData.ts | 18 +++++++ .../TTBAndamentoServicoSaveData.ts | 8 +-- .../useTTBAndamentoServicoDeleteHook.ts | 24 +++++++++ .../useTTBAndamentoServicoSaveHook.ts | 4 +- .../_schemas/TTBAndamentoServicoSchema.ts | 10 ++-- 7 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoRemoveData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoDeleteHook.ts diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx index 7fe708a..2f9fb14 100644 --- a/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/(t_tb_andamentoservico)/andamentos/page.tsx @@ -16,11 +16,13 @@ import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog"; import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog"; import TTBAndamentoServicoInterface from "../../_interfaces/TTBAndamentoServicoInterface"; +import { useTTBAndamentoServicoDeleteHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoDeleteHook"; export default function TTBAndamentoServico() { // Hooks para leitura e salvamento const { tTBAndamentosServicos, fetchTTBAndamentoServico } = useTTBAndamentoServicoReadHook(); const { saveTTBAndamentoServico } = useTTBAndamentoServicoSaveHook(); + const { deleteTTBAndamentoServico } = useTTBAndamentoServicoDeleteHook(); // Estados const [selectedAndamento, setSelectedAndamento] = useState(null); @@ -58,34 +60,49 @@ export default function TTBAndamentoServico() { /** * Salva os dados do formulário */ - const handleSave = useCallback( - async (formData: TTBAndamentoServicoInterface) => { - await saveTTBAndamentoServico(formData); - handleCloseForm(); - fetchTTBAndamentoServico(); // Atualiza a lista após salvar - }, - [saveTTBAndamentoServico, fetchTTBAndamentoServico, handleCloseForm] - ); + const handleSave = useCallback(async (formData: TTBAndamentoServicoInterface) => { + + // Aguarda salvar o registro + await saveTTBAndamentoServico(formData); + + // Encerra o fomulário + handleCloseForm(); + + // Atualiza a lista de dados + fetchTTBAndamentoServico(); + + }, [saveTTBAndamentoServico, fetchTTBAndamentoServico, handleCloseForm]); /** * Quando o usuário clica em "remover" na tabela */ const handleConfirmDelete = useCallback((item: TTBAndamentoServicoInterface) => { + + // Define o item atual para remoção setItemToDelete(item); - openConfirmDialog(); // Abre o modal de confirmação + + // Abre o modal de confirmação + openConfirmDialog(); + }, [openConfirmDialog]); /** * Executa a exclusão de fato quando o usuário confirma */ - const handleDelete = useCallback(() => { - if (!itemToDelete) return; - console.log("Deletando andamento:", itemToDelete); + const handleDelete = useCallback(async () => { + + // Executa o Hook de remoção + await deleteTTBAndamentoServico(itemToDelete); + + // Atualiza a lista + await fetchTTBAndamentoServico(); + + // Limpa o item selecionado + setItemToDelete(null); + + // Fecha o modal + handleCancel(); - // TODO: Implementar lógica de exclusão na API - fetchTTBAndamentoServico(); // Atualiza a lista - setItemToDelete(null); // Limpa o item selecionado - handleCancel(); // Fecha o modal }, [itemToDelete, fetchTTBAndamentoServico, handleCancel]); /** diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx index bd85c25..f93cd52 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_tb_andamentoservico/TTBAndamentoServicoForm.tsx @@ -55,7 +55,7 @@ export default function TTBAndamentoServicoForm({ isOpen, data, onClose, onSave tipo: "", situacao: "A", usa_email: "I", - tb_andamentoservico_id: undefined, + tb_andamentoservico_id: 0, }, }); @@ -170,11 +170,13 @@ export default function TTBAndamentoServicoForm({ isOpen, data, onClose, onSave {/* Rodapé do Dialog */} - - + {/* Campo oculto */} diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoRemoveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoRemoveData.ts new file mode 100644 index 0000000..5ad8fc9 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoRemoveData.ts @@ -0,0 +1,18 @@ +'use server' + +import API from "@/services/api/Api"; +import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; +import { Methods } from "@/services/api/enums/ApiMethodEnum"; + +export default async function TTBAndamentoServicoRemoveData(tTBAndamentoServico: TTBAndamentoServicoInteface) { + + const api = new API(); + + const response = await api.send({ + method: Methods.DELETE, + endpoint: `administrativo/t_tb_andamentoservico/${tTBAndamentoServico.tb_andamentoservico_id}` + }); + + return response; + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts index fdc5943..c8ebd33 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TTBAndamentoServico/TTBAndamentoServicoSaveData.ts @@ -4,14 +4,14 @@ import API from "@/services/api/Api"; import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; import { Methods } from "@/services/api/enums/ApiMethodEnum"; -export default async function TTBAndamentoServicoSaveData(andamentoServico: TTBAndamentoServicoInteface) { +export default async function TTBAndamentoServicoSaveData(data: TTBAndamentoServicoInteface) { const api = new API(); const response = await api.send({ - method: Methods.POST, - endpoint: `administrativo/t_tb_andamentoservico/`, - body: andamentoServico + method: data.tb_andamentoservico_id ? Methods.PUT : Methods.POST, + endpoint: `administrativo/t_tb_andamentoservico/${data.tb_andamentoservico_id ? data.tb_andamentoservico_id : ''}`, + body: data }); return response; diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoDeleteHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoDeleteHook.ts new file mode 100644 index 0000000..c3407ee --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoDeleteHook.ts @@ -0,0 +1,24 @@ +import { useResponse } from "@/app/_response/ResponseContext" +import { useState } from "react"; +import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface"; +import TTBAndamentoServicoRemoveData from "../../_data/TTBAndamentoServico/TTBAndamentoServicoRemoveData"; + +export const useTTBAndamentoServicoDeleteHook = () => { + + const { setResponse } = useResponse(); + + const [tTBAndamentoServico, setTTBAndamentoServico] = useState(); + + const deleteTTBAndamentoServico = async (data: TTBAndamentoServicoInteface) => { + + const response = await TTBAndamentoServicoRemoveData(data); + + setTTBAndamentoServico(data); + + setResponse(response); + + } + + return { tTBAndamentoServico, deleteTTBAndamentoServico } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts index 18f6c0d..c5c1c37 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook.ts @@ -11,9 +11,9 @@ export const useTTBAndamentoServicoSaveHook = () => { const [tTBAndamentoServico, setTTBAndamentoServico] = useState(); - const saveTTBAndamentoServico = async (form: TTBAndamentoServicoInteface) => { + const saveTTBAndamentoServico = async (data: TTBAndamentoServicoInteface) => { - const response = await TTBAndamentoServicoSaveData(form); + const response = await TTBAndamentoServicoSaveData(data); // Armazena os dados da repsota setTTBAndamentoServico(response.data); diff --git a/src/app/(protected)/(cadastros)/cadastros/_schemas/TTBAndamentoServicoSchema.ts b/src/app/(protected)/(cadastros)/cadastros/_schemas/TTBAndamentoServicoSchema.ts index af713ff..7a326bc 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_schemas/TTBAndamentoServicoSchema.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_schemas/TTBAndamentoServicoSchema.ts @@ -2,10 +2,10 @@ import { z } from 'zod'; export const TTBAndamentoServicoSchema = z.object({ - tb_andamentoservico_id: z.number(), - descricao: z.string(), - situacao: z.string(), - tipo: z.string(), - usa_email: z.string() + tb_andamentoservico_id: z.number().optional(), + descricao: z.string().min(1, "Descrição Obrigatória"), + situacao: z.string().min(1, "Situação Obrigatória"), + tipo: z.string().min(1, "Tipo Obrigatória"), + usa_email: z.string().min(1, "Email Obrigatória"), }); \ No newline at end of file