[MVPTN-116]

This commit is contained in:
Keven Willian Pereira de Souza 2025-10-22 14:58:14 -03:00
parent 0e21ebfe5b
commit 2340cee82a
20 changed files with 614 additions and 0 deletions

View file

@ -0,0 +1,9 @@
import GEmolumentoPeriodoIndex from "@/packages/administrativo/components/GEmolumentoPeriodo/GEmolumentoPeriodoIndex";
export default function GEmolumentoPeriodoPage() {
return (
<GEmolumentoPeriodoIndex />
);
}

View file

@ -160,6 +160,10 @@ const data = {
{
title: "Cartório",
url: "/administrativo/cartorio",
},
{
title: "Financeiro/Periodo",
url: "/administrativo/financeiro/periodos",
}
],

View file

@ -0,0 +1,86 @@
import { ColumnDef } from '@tanstack/react-table';
import { EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
import { SortableHeader } from '@/shared/components/dataTable/SortableHeader';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
import { FormatDateTime } from '@/shared/actions/dateTime/FormatDateTime';
export default function GEmolumentoPeriodoColumns(
onEdit: (item: GEmolumentoPeriodoInterface, isEditingFormStatus: boolean) => void,
onDelete: (item: GEmolumentoPeriodoInterface, isEditingFormStatus: boolean) => void,
): ColumnDef<GEmolumentoPeriodoInterface>[] {
return [
// ID
{
accessorKey: 'emolumento_periodo_id',
header: ({ column }) => SortableHeader('ID', column),
cell: ({ row }) => Number(row.getValue('emolumento_periodo_id')),
enableSorting: true,
},
// Descrição
{
accessorKey: 'descricao',
header: ({ column }) => SortableHeader('Descrição', column),
cell: ({ row }) => GetCapitalize(String(row.getValue('descricao') || '')),
},
// Descrição
{
accessorKey: 'data_inicial',
header: ({ column }) => SortableHeader('Data Inicial', column),
cell: ({ row }) => FormatDateTime(String(row.getValue('data_inicial') || '')),
},
// Ações
{
id: 'actions',
header: 'Ações',
cell: ({ row }) => {
const natureza = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<EllipsisIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="left" align="start">
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => onEdit(natureza, true)}>
<PencilIcon className="mr-2 h-4 w-4" />
Editar
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-red-600"
onSelect={() => onDelete(natureza, true)}
>
<Trash2Icon className="mr-2 h-4 w-4" />
Remover
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
},
enableSorting: false,
enableHiding: false,
},
];
}

View file

@ -0,0 +1,110 @@
'use client';
import React, { useEffect } from 'react';
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 { ResetFormIfData } from '@/shared/actions/form/ResetFormIfData';
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
import { useGEmolumentoPeriodoFormHook } from '../../hooks/GEmolumentoPeriodo/useGEmolumentoPeriodoFormHook';
import { GEmolumentoPeriodoFormInterface } from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoFormInterface';
/**
* Formulário de cadastro/edição de Natureza
* Baseado nos campos da tabela G_NATUREZA
*/
export default function GEmolumentoPeriodoForm({
isOpen,
data,
onClose,
onSave,
buttonIsLoading,
}: GEmolumentoPeriodoFormInterface) {
const form = useGEmolumentoPeriodoFormHook({});
// Atualiza o formulário quando recebe dados para edição
useEffect(() => {
ResetFormIfData(form, data);
}, [data, form]);
function onError(error: any) {
console.log('Erro no formulário:', error);
}
return (
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) onClose(null, false);
}}
>
<DialogContent className="w-full max-w-full p-6 sm:max-w-3xl md:max-w-2xl lg:max-w-2xl">
<DialogHeader>
<DialogTitle className="text-lg sm:text-xl">Formulário de Gramática</DialogTitle>
<DialogDescription className="text-muted-foreground text-sm">
Formulário de Gramática
</DialogDescription>
</DialogHeader>
{/* Formulário principal */}
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-6">
{/* GRID MOBILE FIRST */}
<div className="grid w-full grid-cols-12 gap-4">
{/* Palavra */}
<div className="col-span-12 sm:col-span-6 md:col-span-12">
<FormField
control={form.control}
name="descricao"
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Palavra</FormLabel>
<FormControl>
<Input
{...field}
type="text"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
{/* Rodapé */}
<DialogFooter className="mt-6 flex flex-col justify-end gap-2 sm:flex-row">
<DialogClose asChild>
<Button variant="outline" type="button">
Cancelar
</Button>
</DialogClose>
<LoadingButton
text="Salvar"
textLoading="Salvando..."
type="submit"
loading={buttonIsLoading}
/>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
}

View file

@ -0,0 +1,161 @@
'use client';
import { useEffect, useState, useCallback } from 'react';
import { useGEmolumentoPeriodoDeleteHook } from '@/packages/administrativo/hooks/GEmolumentoPeriodo/useGEmolumentoPeriodoDeleteHook';
import { useGEmolumentoPeriodoIndexHook } from '@/packages/administrativo/hooks/GEmolumentoPeriodo/useGEmolumentoPeriodoIndexHook';
import { useGEmolumentoPeriodoSaveHook } from '@/packages/administrativo/hooks/GEmolumentoPeriodo/useGEmolumentoPeriodoSaveHook';
import GEmolumentoPeriodoInterface from '@/packages/administrativo/interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
import Loading from '@/shared/components/loading/loading';
import Header from '@/shared/components/structure/Header';
import GEmolumentoPeriodoForm from './GEmolumentoPeriodoForm';
import GEmolumentoPeriodoTable from './GEmolumentoPeriodoTable';
export default function GEmolumentoPeriodoIndex() {
// Controle de estado do botão
const [buttonIsLoading, setButtonIsLoading] = useState(false);
// Hooks para leitura e salvamento
const { gEmolumentoPeriodo, indexGEmolumentoPeriodo } = useGEmolumentoPeriodoIndexHook();
const { saveGEmolumentoPeriodo } = useGEmolumentoPeriodoSaveHook();
const { deleteGEmolumentoPeriodo } = useGEmolumentoPeriodoDeleteHook();
// Estados
const [selectedData, setSelectedData] = useState<GEmolumentoPeriodoInterface | null>(null);
const [isFormOpen, setIsFormOpen] = useState(false);
// Estado para saber qual item será deletado
const [itemToDelete, setItemToDelete] = useState<GEmolumentoPeriodoInterface | null>(null);
/**
* Hook do modal de confirmação
*/
const { isOpen: isConfirmOpen, openDialog: openConfirmDialog, handleCancel } = useConfirmDialog();
/**
* Abre o formulário no modo de edição ou criação
*/
const handleOpenForm = useCallback((data: GEmolumentoPeriodoInterface | null) => {
setSelectedData(data);
setIsFormOpen(true);
}, []);
/**
* Fecha o formulário e limpa o andamento selecionado
*/
const handleCloseForm = useCallback(() => {
setSelectedData(null);
setIsFormOpen(false);
}, []);
/**
* Salva os dados do formulário
*/
const handleSave = useCallback(
async (formData: GEmolumentoPeriodoInterface) => {
// Coloca o botão em estado de loading
setButtonIsLoading(true);
// Aguarda salvar o registro
await saveGEmolumentoPeriodo(formData);
// Remove o botão em estado de loading
setButtonIsLoading(false);
// Atualiza a lista de dados
indexGEmolumentoPeriodo();
},
[saveGEmolumentoPeriodo, indexGEmolumentoPeriodo, handleCloseForm],
);
/**
* Quando o usuário clica em "remover" na tabela
*/
const handleConfirmDelete = useCallback(
(item: GEmolumentoPeriodoInterface) => {
// 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 deleteGEmolumentoPeriodo(itemToDelete);
// Atualiza a lista
await indexGEmolumentoPeriodo();
// Limpa o item selecionado
setItemToDelete(null);
// Fecha o modal
handleCancel();
}, [itemToDelete, indexGEmolumentoPeriodo, handleCancel]);
/**
* Busca inicial dos dados
*/
useEffect(() => {
indexGEmolumentoPeriodo();
}, []);
/**
* Tela de loading enquanto carrega os dados
*/
if (gEmolumentoPeriodo?.length == 0) {
return <Loading type={2} />;
}
return (
<div>
{/* Cabeçalho */}
<Header
title={'Períodos de Emolumentos'}
description={'Períodos de Emolumentos'}
buttonText={'Novo período'}
buttonAction={() => {
handleOpenForm(null);
}}
/>
{/* Tabela de andamentos */}
<GEmolumentoPeriodoTable data={gEmolumentoPeriodo} onEdit={handleOpenForm} onDelete={handleConfirmDelete} />
{/* Modal de confirmação */}
{isConfirmOpen && (
<ConfirmDialog
isOpen={isConfirmOpen}
title="Confirmar exclusão"
description="Atenção"
message={`Deseja realmente excluir o periodo "${itemToDelete?.descricao}"?`}
confirmText="Sim, excluir"
cancelText="Cancelar"
onConfirm={handleDelete}
onCancel={handleCancel}
/>
)}
{/* Formulário de criação/edição */}
{isFormOpen && (
<GEmolumentoPeriodoForm
isOpen={isFormOpen}
data={selectedData}
onClose={handleCloseForm}
onSave={handleSave}
buttonIsLoading={buttonIsLoading}
/>
)}
</div>
);
}

View file

@ -0,0 +1,23 @@
'use client';
import { DataTable } from '@/shared/components/dataTable/DataTable';
import GEmolumentoPeriodoColumns from './GEmolumentoPeriodoColumns';
import GEmolumentoPeriodoTableInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoTableInterface';
/**
* Componente principal da tabela de Naturezas
*/
export default function GEmolumentoPeriodoTable({ data, onEdit, onDelete }: GEmolumentoPeriodoTableInterface) {
const columns = GEmolumentoPeriodoColumns(onEdit, onDelete);
return (
<div>
<DataTable
data={data}
columns={columns}
filterColumn="descricao"
filterPlaceholder="Buscar por descrição da natureza..."
/>
</div>
);
}

View file

@ -0,0 +1,17 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import API from '@/shared/services/api/Api';
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
async function executeGEmolumentoPeriodoDeleteData(data: GEmolumentoPeriodoInterface): Promise<ApiResponseInterface> {
const api = new API();
return api.send({
method: Methods.DELETE,
endpoint: `administrativo/g_emolumento_periodo/${data.emolumento_periodo_id}`,
});
}
export const GEmolumentoPeriodoDeleteData = withClientErrorHandler(executeGEmolumentoPeriodoDeleteData);

View file

@ -0,0 +1,15 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import API from '@/shared/services/api/Api';
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
async function executeGEmolumentoPeriodoIndexData(): Promise<ApiResponseInterface> {
const api = new API();
return api.send({
method: Methods.GET,
endpoint: `administrativo/g_emolumento_periodo/`,
});
}
export const GEmolumentoPeriodoIndexData = withClientErrorHandler(executeGEmolumentoPeriodoIndexData);

View file

@ -0,0 +1,23 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import API from '@/shared/services/api/Api';
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
async function executeGEmolumentoPeriodoSaveData(data: GEmolumentoPeriodoInterface): Promise<ApiResponseInterface> {
// Verifica se existe ID para decidir se é atualização (PUT) ou criação (POST)
const isUpdate = Boolean(data.emolumento_periodo_id);
// Instancia o cliente da API
const api = new API();
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
return api.send({
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
endpoint: `administrativo/g_emolumento_periodo/${data.emolumento_periodo_id || ''}`, // endpoint dinâmico
body: data, // payload enviado para a API
});
}
export const GEmolumentoPeriodoSaveData = withClientErrorHandler(executeGEmolumentoPeriodoSaveData);

View file

@ -0,0 +1,21 @@
import { useState } from 'react';
import { useResponse } from '@/shared/components/response/ResponseContext';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
import { GEmolumentoPeriodoDeleteService } from '../../services/GEmolumentoPeriodo/GEmolumentoPeriodoDeleteService';
export const useGEmolumentoPeriodoDeleteHook = () => {
const { setResponse } = useResponse();
const [gGramatica, setGEmolumentoPeriodo] = useState<GEmolumentoPeriodoInterface>();
const deleteGEmolumentoPeriodo = async (data: GEmolumentoPeriodoInterface) => {
const response = await GEmolumentoPeriodoDeleteService(data);
setGEmolumentoPeriodo(data);
setResponse(response);
};
return { gGramatica, deleteGEmolumentoPeriodo };
};

View file

@ -0,0 +1,14 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { GEmolumentoPeriodoFormValues, GEmolumentoPeriodoSchema } from '../../schemas/GEmolumentoPeriodo/GEmolumentoPeriodoSchema';
export function useGEmolumentoPeriodoFormHook(defaults?: Partial<GEmolumentoPeriodoFormValues>) {
return useForm<GEmolumentoPeriodoFormValues>({
resolver: zodResolver(GEmolumentoPeriodoSchema),
defaultValues: {
emolumento_periodo_id: 0,
...defaults,
},
});
}

View file

@ -0,0 +1,27 @@
'use client';
import { useState } from 'react';
import { useResponse } from '@/shared/components/response/ResponseContext';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
import { GEmolumentoPeriodoIndexService } from '../../services/GEmolumentoPeriodo/GEmolumentoPeriodoIndexService';
export const useGEmolumentoPeriodoIndexHook = () => {
const { setResponse } = useResponse();
const [gEmolumentoPeriodo, setGEmolumentoPeriodo] = useState<GEmolumentoPeriodoInterface[]>([]);
const indexGEmolumentoPeriodo = async () => {
const response = await GEmolumentoPeriodoIndexService();
// Armazena os dados consultados
setGEmolumentoPeriodo(response.data);
// Define a resposta (toast, modal, feedback, etc.)
setResponse(response);
};
return {
gEmolumentoPeriodo,
indexGEmolumentoPeriodo,
};
};

View file

@ -0,0 +1,35 @@
'use client';
import { useState } from 'react';
import { useResponse } from '@/shared/components/response/ResponseContext';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
import { GEmolumentoPeriodoSaveService } from '../../services/GEmolumentoPeriodo/GEmolumentoPeriodoSaveService';
export const useGEmolumentoPeriodoSaveHook = () => {
const { setResponse } = useResponse();
const [gGramatica, setGEmolumentoPeriodo] = useState<GEmolumentoPeriodoInterface | null>(null);
// controla se o formulário está aberto ou fechado
const [isOpen, setIsOpen] = useState(false);
const saveGEmolumentoPeriodo = async (data: GEmolumentoPeriodoInterface) => {
const response = await GEmolumentoPeriodoSaveService(data);
// Armazena os dados da resposta
setGEmolumentoPeriodo(response.data);
// Define os dados da resposta (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 { gGramatica, saveGEmolumentoPeriodo, isOpen, setIsOpen };
};

View file

@ -0,0 +1,9 @@
import { GEmolumentoPeriodoFormValues } from '../../schemas/GEmolumentoPeriodo/GEmolumentoPeriodoSchema';
export interface GEmolumentoPeriodoFormInterface {
isOpen: boolean;
data: GEmolumentoPeriodoFormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: GEmolumentoPeriodoFormValues) => void;
buttonIsLoading: boolean;
}

View file

@ -0,0 +1,6 @@
export default interface GEmolumentoPeriodoInterface {
emolumento_periodo_id?: number,
descricao?: string,
situacao?: string,
data_inicial?: string,
}

View file

@ -0,0 +1,7 @@
import GEmolumentoPeriodoInterface from './GEmolumentoPeriodoInterface';
export default interface GEmolumentoPeriodoTableInterface {
data?: GEmolumentoPeriodoInterface[];
onEdit: (item: GEmolumentoPeriodoInterface, isEditingFormStatus: boolean) => void;
onDelete: (item: GEmolumentoPeriodoInterface, isEditingFormStatus: boolean) => void;
}

View file

@ -0,0 +1,10 @@
import z from "zod";
export const GEmolumentoPeriodoSchema = z.object({
emolumento_periodo_id: z.number().optional(),
descricao: z.string().optional(),
situacao: z.string().optional(),
data_inicial: z.string().optional(),
});
export type GEmolumentoPeriodoFormValues = z.infer<typeof GEmolumentoPeriodoSchema>;

View file

@ -0,0 +1,14 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import { GEmolumentoPeriodoDeleteData } from '../../data/GEmolumentoPeriodo/GEmolumentoPeriodoDeleteData';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
async function executeGEmolumentoPeriodoDeleteService(data: GEmolumentoPeriodoInterface) {
const response = await GEmolumentoPeriodoDeleteData(data);
return response;
}
export const GEmolumentoPeriodoDeleteService = withClientErrorHandler(executeGEmolumentoPeriodoDeleteService);

View file

@ -0,0 +1,11 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import { GEmolumentoPeriodoIndexData } from '../../data/GEmolumentoPeriodo/GEmolumentoPeriodoIndexData';
export default async function executeGEmolumentoPeriodoIndexService() {
const response = await GEmolumentoPeriodoIndexData();
return response;
}
export const GEmolumentoPeriodoIndexService = withClientErrorHandler(executeGEmolumentoPeriodoIndexService);

View file

@ -0,0 +1,12 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
import { GEmolumentoPeriodoSaveData } from '../../data/GEmolumentoPeriodo/GEmolumentoPeriodoSaveData';
import GEmolumentoPeriodoInterface from '../../interfaces/GEmolumentoPeriodo/GEmolumentoPeriodoInterface';
async function executeGEmolumentoPeriodoSaveService(data: GEmolumentoPeriodoInterface) {
const response = await GEmolumentoPeriodoSaveData(data);
return response;
}
export const GEmolumentoPeriodoSaveService = withClientErrorHandler(executeGEmolumentoPeriodoSaveService);