From 02ae936c879c49c8f1334765db35d345c2f27ab3 Mon Sep 17 00:00:00 2001 From: keven Date: Wed, 10 Sep 2025 16:59:00 -0300 Subject: [PATCH] =?UTF-8?q?[MVPTN]=20feat(dialog):=20Implementado=20formul?= =?UTF-8?q?=C3=A1rio=20em=20dialog=20e=20confirma=C3=A7=C3=A3o=20de=20excl?= =?UTF-8?q?us=C3=A3o=20de=20registro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 75 +++++ package.json | 2 + .../reconhecimentos/page.tsx | 276 +++++++++++++++--- .../TTBReconhecimentoTipoSaveData.ts | 14 + .../useTTBReconhecimentoTipoReadHooks.ts | 8 +- .../useTTBReconhecimentoTipoSaveHooks.ts | 29 ++ .../_schemas/TTTBReconhecimentoTipo.ts | 4 +- src/components/ui/alert-dialog.tsx | 157 ++++++++++ src/components/ui/checkbox.tsx | 32 ++ src/components/ui/dialog.tsx | 143 +++++++++ 10 files changed, 699 insertions(+), 41 deletions(-) create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoSaveHooks.ts create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/dialog.tsx diff --git a/package-lock.json b/package-lock.json index 0f7ae39..10555ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,9 @@ "version": "0.1.0", "dependencies": { "@hookform/resolvers": "^5.2.1", + "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", @@ -736,6 +738,34 @@ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", @@ -786,6 +816,36 @@ } } }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collapsible": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", @@ -1412,6 +1472,21 @@ } } }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-rect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", diff --git a/package.json b/package.json index 9ab3d66..22ea23d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ }, "dependencies": { "@hookform/resolvers": "^5.2.1", + "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", diff --git a/src/app/(protected)/(cadastros)/cadastros/(t_tb_reconhecimentotipo)/reconhecimentos/page.tsx b/src/app/(protected)/(cadastros)/cadastros/(t_tb_reconhecimentotipo)/reconhecimentos/page.tsx index 1147a6b..c944264 100644 --- a/src/app/(protected)/(cadastros)/cadastros/(t_tb_reconhecimentotipo)/reconhecimentos/page.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/(t_tb_reconhecimentotipo)/reconhecimentos/page.tsx @@ -1,37 +1,123 @@ 'use client' -import { Card, CardContent } from "@/components/ui/card"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog" + +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" + +import { Input } from "@/components/ui/input" +import { Card, CardContent } from "@/components/ui/card" import { Table, TableBody, - TableCaption, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" -import { useTTBReconhecimentoTipoReadHooks } from "../../_hooks/useTTBReconhecimentoTipoReadHooks"; -import { useEffect } from "react"; -import ITTTBReconhecimentoTipo from '../../_interfaces/ITTTBReconhecimentoTipo' -import Loading from "@/app/_components/loading/loading"; -import { Button } from "@/components/ui/button"; -import Link from "next/link"; +import { useTTBReconhecimentoTipoReadHooks } from "../../_hooks/useTTBReconhecimentoTipoReadHooks" +import { useEffect, useState } from "react" +import ITTTBReconhecimentoTipo from "../../_interfaces/ITTTBReconhecimentoTipo" +import Loading from "@/app/_components/loading/loading" +import { Button } from "@/components/ui/button" +import { useTTBReconhecimentoTipoSaveHooks } from "../../_hooks/useTTBReconhecimentoTipoSaveHooks" +import { Controller, useForm } from "react-hook-form" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { zodResolver } from "@hookform/resolvers/zod" +import { TTBReconhecimentoTipoSchema } from "../../_schemas/TTTBReconhecimentoTipo" +import z from "zod" +import { Label } from "@/components/ui/label" +import { Checkbox } from "@/components/ui/checkbox" +import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" +import { DropdownMenuLabel } from "@radix-ui/react-dropdown-menu" +import { EllipsisIcon, PencilIcon, PlusIcon, Trash2 } from "lucide-react" + +type FormValues = z.infer export default function TTBReconhecimentoTipoPage() { + const { reconhecimentosTipos, fetchReconhecimentosTipos, addReconhecimentoTipo } = useTTBReconhecimentoTipoReadHooks() + const { reconhecimentoTipo, saveReconhecimentoTipo } = useTTBReconhecimentoTipoSaveHooks() - const { reconhecimentosTipos, fetchReconhecimentosTipos } = useTTBReconhecimentoTipoReadHooks(); + const [dialogOpen, setDialogOpen] = useState(false); + const [editingItem, setEditingItem] = useState(null); + + const [alertDialogOpen, setAlertDialogOpen] = useState(false); + const [item, setItem] = useState(null); useEffect(() => { - fetchReconhecimentosTipos(); - }, []); + fetchReconhecimentosTipos() + }, []) + + const form = useForm({ + resolver: zodResolver(TTBReconhecimentoTipoSchema), + defaultValues: { + tb_reconhecimentotipo_id: 0, + descricao: "", + situacao: "I", + }, + }) + + async function onSubmit(values: FormValues) { + const saved = await saveReconhecimentoTipo(values); // aguarda o retorno + addReconhecimentoTipo(saved); // adiciona diretamente na lista + + // reinicia o formulário para o estado original + form.reset(); + } + + async function openForm(values: FormValues) { + setEditingItem(values); // guarda os valores do item + setDialogOpen(true); // abre o Dialog + form.reset({ + tb_reconhecimentotipo_id: values.tb_reconhecimentotipo_id, + descricao: values.descricao, + situacao: values.situacao, + }); + + } + + async function handlingConfirmation(visibility : boolean, item: null|any) { + setAlertDialogOpen(visibility); + setItem(item); + } + + const emptyForm: FormValues = { + tb_reconhecimentotipo_id: 0, + descricao: "", + situacao: "I", // padrão Inativo + }; if (!reconhecimentosTipos) return return (
- -
+
Tipos de Reconhecimentos @@ -40,14 +126,14 @@ export default function TTBReconhecimentoTipoPage() { Gerenciamento de tipos de reconhecimentos
+
-
+ @@ -56,36 +142,148 @@ export default function TTBReconhecimentoTipoPage() { # - - Descrição - Situação - Amount + + Descrição + + + - {reconhecimentosTipos.map((reconhecimentosTipos: ITTTBReconhecimentoTipo) => ( - - - {reconhecimentosTipos.tb_reconhecimentotipo_id} - - - {reconhecimentosTipos.descricao} - - - {reconhecimentosTipos.tb_reconhecimentotipo_id} - - $250.00 - - ))} + {reconhecimentosTipos.map( + (item: ITTTBReconhecimentoTipo) => ( + + + {item.tb_reconhecimentotipo_id} + + + {item.situacao === 'A' ? ( + + Ativo + + ) : ( + + Inativo + + )} + + + {item.descricao} + + + + + + + + + openForm(item)}> + Editar + + + handlingConfirmation(true, item)}> + Remover + + + + + + + ) + )}
+ + + {/* Formulário dentro do Dialog */} +
+ + + + + + Tipos de Reconhecimentos + + Tipos de reconhecimentos são usados na tela de balcão + + + ( + + Descrição + + + + + + )} + /> +
+ ( + field.onChange(checked ? "A" : "I")} + /> + )} + /> + +
+ + + + + + + + + +
+ + +
+ + + + + + #{item?.tb_reconhecimentotipo_id} - {item?.descricao} + + + Esta ação não pode ser desfeita. Isso excluirá permanentemente o registro e seus dados dos nossos servidores. + + + + handlingConfirmation(false, null)} className="cursor-pointer"> + Cancelar + + + Continuar + + + + +
- - ); - -} \ No newline at end of file + ) +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData.ts new file mode 100644 index 0000000..daf5964 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData.ts @@ -0,0 +1,14 @@ +import { faker } from "@faker-js/faker" + +export default async function TTBReconhecimentoTipoSaveData(reconhecimentoTipo: any) { + + return Promise.resolve({ + message: 'Dados salvos com sucesso', + data: { + tb_reconhecimentotipo_id: faker.number.int({ min: 1, max: 1000 }), + descricao: reconhecimentoTipo.tb_reconhecimentotipo_id + reconhecimentoTipo.descricao, + situacao: reconhecimentoTipo.situacao + }, + }); + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoReadHooks.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoReadHooks.ts index e626769..fb01797 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoReadHooks.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoReadHooks.ts @@ -21,6 +21,12 @@ export const useTTBReconhecimentoTipoReadHooks = () => { } - return { reconhecimentosTipos, fetchReconhecimentosTipos } + function addReconhecimentoTipo(reconhecimentoTipo: ITTTBReconhecimentoTipo) { + + setReconhecimenntosTipos(prev => [...(prev || []), reconhecimentoTipo]); + + } + + return { reconhecimentosTipos, fetchReconhecimentosTipos, addReconhecimentoTipo } } \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoSaveHooks.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoSaveHooks.ts new file mode 100644 index 0000000..8605a63 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/useTTBReconhecimentoTipoSaveHooks.ts @@ -0,0 +1,29 @@ +'use client' + +import { useResponse } from "@/app/_response/ResponseContext" +import { useState } from "react"; +import ITTTBReconhecimentoTipo from '../_interfaces/ITTTBReconhecimentoTipo' +import TTBReconhecimentoTipoSaveData from "../_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData"; + +export const useTTBReconhecimentoTipoSaveHooks = () => { + + const { setResponse } = useResponse(); + + const [reconhecimentoTipo, setReconhcimentoTipo] = useState(); + + const saveReconhecimentoTipo = async (reconhecimentoTipo: ITTTBReconhecimentoTipo) => { + + const response = await TTBReconhecimentoTipoSaveData(reconhecimentoTipo); + + setReconhcimentoTipo(response.data); + + setResponse(response); + + // Retorna os valores de forma imediata + return response.data; + + } + + return { reconhecimentoTipo, saveReconhecimentoTipo } + +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_schemas/TTTBReconhecimentoTipo.ts b/src/app/(protected)/(cadastros)/cadastros/_schemas/TTTBReconhecimentoTipo.ts index 18d493e..c8e73dc 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_schemas/TTTBReconhecimentoTipo.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_schemas/TTTBReconhecimentoTipo.ts @@ -3,5 +3,7 @@ import { z } from 'zod'; export const TTBReconhecimentoTipoSchema = z.object({ tb_reconhecimentotipo_id: z.number(), descricao: z.string().min(1), - situacao: z.string().min(1), + situacao: z.enum(["A", "I"], { + errorMap: () => ({ message: "Situação deve ser 'A' ou 'I'" }) + }), }); \ No newline at end of file diff --git a/src/components/ui/alert-dialog.tsx b/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..0863e40 --- /dev/null +++ b/src/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +"use client" + +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..fa0e4b5 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,32 @@ +"use client" + +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Checkbox({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + + ) +} + +export { Checkbox } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..d9ccec9 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}