[MVPTN-109] feat(CRUD): Cria o CRUD de T_CENSEC_TIPONATUREZA
This commit is contained in:
parent
aaaa04975e
commit
3bd3134d33
26 changed files with 998 additions and 1 deletions
|
|
@ -0,0 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import TCensecTipoNaturezaIndex from "@/packages/administrativo/components/TCensecTipoNatureza/TCensecTipoNaturezaIndex";
|
||||
|
||||
export default function TCensecTipoNaturezaPage() {
|
||||
return (
|
||||
< TCensecTipoNaturezaIndex />
|
||||
);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import TCensecQualidadeIndex from "@/packages/administrativo/components/TCensecQualidade/TCensecQualidadeIndex";
|
||||
|
||||
export default function TImovelRuralPage() {
|
||||
export default function TCensecQualidadePage() {
|
||||
return (
|
||||
< TCensecQualidadeIndex />
|
||||
);
|
||||
|
|
|
|||
|
|
@ -137,6 +137,10 @@ const data = {
|
|||
title: "Censec/Qualidades",
|
||||
url: "/administrativo/censec/qualidades"
|
||||
},
|
||||
{
|
||||
title: "Censec/Qualidades",
|
||||
url: "/administrativo/censec/naturezas"
|
||||
},
|
||||
{
|
||||
title: 'Censec/Centrais',
|
||||
url: '/cadastros/censec/',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
'use client';
|
||||
|
||||
import React from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command";
|
||||
import { FormControl } from "@/components/ui/form";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
||||
import GetCapitalize from "@/shared/actions/text/GetCapitalize";
|
||||
import { useTCensecTipoAtoReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/t_censec_tipoato/useTCensecTipoAtoReadHook";
|
||||
|
||||
export default function TCensecTipoAtoSelect({ field }: any) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const { tCensecTipoAto, fetchTCensecTipoAto } = useTCensecTipoAtoReadHook();
|
||||
// Busca os dados uma única vez ao montar
|
||||
React.useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (!tCensecTipoAto.length) {
|
||||
setIsLoading(true);
|
||||
await fetchTCensecTipoAto();
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
loadData();
|
||||
}, []);
|
||||
const selected = tCensecTipoAto.find(
|
||||
(item) => String(item.censec_tipoato_id) === String(field.value)
|
||||
);
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
disabled={isLoading}
|
||||
className="justify-between"
|
||||
>
|
||||
{isLoading
|
||||
? "Carregando..."
|
||||
: selected
|
||||
? GetCapitalize(selected.descricao)
|
||||
: "Selecione..."}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar tipo logradouro..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
{isLoading ? "Carregando..." : "Nenhum resultado encontrado."}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{tCensecTipoAto?.map((item) => (
|
||||
<CommandItem
|
||||
key={item.censec_tipoato_id}
|
||||
value={item.descricao?.toLowerCase() ?? ""}
|
||||
onSelect={() => {
|
||||
field.onChange(Number(item.censec_tipoato_id));
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
String(field.value) === String(item.censec_tipoato_id)
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{GetCapitalize(item.descricao)}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import TCensecTipoNaturezaInterface from "../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
EllipsisIcon,
|
||||
PencilIcon,
|
||||
Trash2Icon,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { SortableHeader } from "@/shared/components/dataTable/SortableHeader";
|
||||
import GetCapitalize from "@/shared/actions/text/GetCapitalize";
|
||||
import { ConfirmacaoEnum } from "@/shared/enums/ConfirmacaoEnum";
|
||||
import { TipoAtoAnteriorEnum } from "@/shared/enums/TipoAtoAnteriorEnum";
|
||||
|
||||
export default function TCensecTipoNaturezaColumns(
|
||||
onEdit: (item: TCensecTipoNaturezaInterface, isEditingFormStatus: boolean) => void,
|
||||
onDelete: (item: TCensecTipoNaturezaInterface, isEditingFormStatus: boolean) => void
|
||||
): ColumnDef<TCensecTipoNaturezaInterface>[] {
|
||||
return [
|
||||
// ID
|
||||
{
|
||||
accessorKey: "censec_tiponatureza_id",
|
||||
header: ({ column }) => SortableHeader("#", column),
|
||||
cell: ({ row }) => Number(row.getValue("censec_tiponatureza_id")),
|
||||
enableSorting: false,
|
||||
},
|
||||
// descricao
|
||||
{
|
||||
accessorKey: "descricao",
|
||||
header: ({ column }) => SortableHeader("Descrição", column),
|
||||
cell: ({ row }) => GetCapitalize(row.getValue("descricao")),
|
||||
},
|
||||
// possui_ato_anterior
|
||||
{
|
||||
accessorKey: "possui_ato_anterior",
|
||||
header: ({ column }) => SortableHeader("Possui Ato Anterior", column),
|
||||
cell: ({ row }) => {
|
||||
const value = row.getValue("possui_ato_anterior") as keyof typeof ConfirmacaoEnum;
|
||||
return ConfirmacaoEnum[value] ?? "-";
|
||||
},
|
||||
},
|
||||
// situacao_ato_anterior
|
||||
{
|
||||
accessorKey: "situacao_ato_anterior",
|
||||
header: ({ column }) => SortableHeader("Situação Ato Anterior", column),
|
||||
cell: ({ row }) => {
|
||||
const value = Number(row.getValue("situacao_ato_anterior"));
|
||||
const label = Object.prototype.hasOwnProperty.call(TipoAtoAnteriorEnum, value)
|
||||
? TipoAtoAnteriorEnum[value as keyof typeof TipoAtoAnteriorEnum]
|
||||
: "-";
|
||||
return label;
|
||||
},
|
||||
},
|
||||
// Ações
|
||||
{
|
||||
id: "actions",
|
||||
header: "Ações",
|
||||
cell: ({ row }) => {
|
||||
const imovel = row.original;
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<EllipsisIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="left" align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={() => onEdit(imovel, true)}>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
className="text-red-600"
|
||||
onSelect={() => onDelete(imovel, true)}
|
||||
>
|
||||
<Trash2Icon className="mr-2 h-4 w-4" />
|
||||
Remover
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
'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 LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
import { ResetFormIfData } from '@/shared/actions/form/ResetFormIfData';
|
||||
import { useTCensecTipoNaturezaFormHook } from '../../hooks/TCensecTipoNatureza/useTCensecTipoNaturezaFormHook';
|
||||
import { TCensecTipoNaturezaFormInterface } from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaFormInterface';
|
||||
import { parseNumberInput } from '@/shared/actions/form/parseNumberInput';
|
||||
import TCensecTipoAtoSelect from '../TCensecTipoAto/TCensecTipoAtoSelect';
|
||||
import ConfirmacaoSelect from '@/shared/components/confirmacao/ConfirmacaoSelect';
|
||||
import TipoAtoAnteriorSelect from '@/shared/components/tipoAtoAnterior/TipoAtoAnteriorSelect';
|
||||
import TipoNaturezaSelect from '@/shared/components/tipoNatureza/TipoNaturezaSelect';
|
||||
|
||||
export default function TCensecTipoNaturezaForm({ isOpen, data, onClose, onSave, buttonIsLoading }: TCensecTipoNaturezaFormInterface) {
|
||||
|
||||
// Inicializa o react-hook-form com schema zod
|
||||
const form = useTCensecTipoNaturezaFormHook({});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
|
||||
// Se existir dados, reseta o formulário com os mesmos
|
||||
ResetFormIfData(form, data);
|
||||
|
||||
}, [data, form]);
|
||||
|
||||
function onError(error: any) {
|
||||
console.log(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>
|
||||
Censec tipos de natureza
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Censec tipos de natureza
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-6">
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
{/* Descrição */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-12">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type='text' />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Tipo do Ato */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-12">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="censec_tipoato_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo do Ato</FormLabel>
|
||||
< TCensecTipoAtoSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Possui Ato Anterior */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="possui_ato_anterior"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Possui Ato Anterior</FormLabel>
|
||||
<FormControl>
|
||||
<ConfirmacaoSelect field={field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* tipo_ato_anterior */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_ato_anterior"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Natureza</FormLabel>
|
||||
<TipoNaturezaSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Situação */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="situacao_ato_anterior"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Situação</FormLabel>
|
||||
<TipoAtoAnteriorSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Código CENSEC */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="obrigatorio"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Código CENSEC</FormLabel>
|
||||
<FormControl>
|
||||
<ConfirmacaoSelect field={field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Código */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="codigo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Código</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type='number' onChange={e => field.onChange(parseNumberInput(e))} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Rodapé do Dialog */}
|
||||
<DialogFooter className="mt-4 flex flex-col sm:flex-row gap-2 justify-end">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline" type="button" onClick={() => onClose(null, false)}>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Aguarde..."
|
||||
type="submit"
|
||||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent >
|
||||
</Dialog >
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
|
||||
import Loading from '@/shared/components/loading/loading';
|
||||
|
||||
import { useTCensecTipoNaturezaIndexHook } from '@/packages/administrativo/hooks/TCensecTipoNatureza/useTCensecTipoNaturezaIndexHook';
|
||||
import { useTCensecTipoNaturezaSaveHook } from '@/packages/administrativo/hooks/TCensecTipoNatureza/useTCensecTipoNaturezaSaveHook';
|
||||
import { useTCensecTipoNaturezaDeleteHook } from '@/packages/administrativo/hooks/TCensecTipoNatureza/useTCensecTipoNaturezaDeleteHook';
|
||||
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
|
||||
|
||||
import TCensecTipoNaturezaInterface from '@/packages/administrativo/interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import Header from '@/shared/components/structure/Header';
|
||||
import TCensecTipoNaturezaTable from './TCensecTipoNaturezaTable';
|
||||
import TCensecTipoNaturezaForm from './TCensecTipoNaturezaForm';
|
||||
|
||||
export default function TCensecTipoNaturezaIndex() {
|
||||
|
||||
// Controle de estado do botão
|
||||
const [buttonIsLoading, setButtonIsLoading] = useState(false);
|
||||
|
||||
// Hooks para leitura e salvamento
|
||||
const { tCensecNaturezaTipo, indexTCensecTipoNatureza } = useTCensecTipoNaturezaIndexHook();
|
||||
const { saveTCensecTipoNatureza } = useTCensecTipoNaturezaSaveHook();
|
||||
const { deleteTCensecTipoNatureza } = useTCensecTipoNaturezaDeleteHook();
|
||||
|
||||
// Estados
|
||||
const [selectedData, setSelectedData] = useState<TCensecTipoNaturezaInterface | null>(null);
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
|
||||
// Estado para saber qual item será deletado
|
||||
const [itemToDelete, setItemToDelete] = useState<TCensecTipoNaturezaInterface | null>(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: TCensecTipoNaturezaInterface | null) => {
|
||||
// Se não houver dados (criação), cria um objeto inicial com pessoa_tipo
|
||||
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: TCensecTipoNaturezaInterface) => {
|
||||
// Coloca o botão em estado de loading
|
||||
setButtonIsLoading(true);
|
||||
|
||||
// Aguarda salvar o registro
|
||||
await saveTCensecTipoNatureza(formData);
|
||||
|
||||
// Remove o botão em estado de loading
|
||||
setButtonIsLoading(false);
|
||||
|
||||
// Atualiza a lista de dados
|
||||
indexTCensecTipoNatureza();
|
||||
},
|
||||
[saveTCensecTipoNatureza, indexTCensecTipoNatureza, handleCloseForm],
|
||||
);
|
||||
|
||||
/**
|
||||
* Quando o usuário clica em "remover" na tabela
|
||||
*/
|
||||
const handleConfirmDelete = useCallback(
|
||||
(item: TCensecTipoNaturezaInterface) => {
|
||||
// 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 deleteTCensecTipoNatureza(itemToDelete);
|
||||
|
||||
// Atualiza a lista
|
||||
await indexTCensecTipoNatureza();
|
||||
|
||||
// Limpa o item selecionado
|
||||
setItemToDelete(null);
|
||||
|
||||
// Fecha o modal
|
||||
handleCancel();
|
||||
}, [itemToDelete, indexTCensecTipoNatureza, handleCancel]);
|
||||
|
||||
/**
|
||||
* Busca inicial dos dados
|
||||
*/
|
||||
useEffect(() => {
|
||||
indexTCensecTipoNatureza();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Tela de loading enquanto carrega os dados
|
||||
*/
|
||||
if (tCensecNaturezaTipo?.length == 0) {
|
||||
return <Loading type={2} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Cabeçalho */}
|
||||
<Header
|
||||
title={"CENSEC Tipos de Natureza"}
|
||||
description={"CENSEC Tipos de Natureza"}
|
||||
buttonText={'Novo tipo de natureza'}
|
||||
buttonAction={() => {
|
||||
handleOpenForm(null);
|
||||
}}
|
||||
/>
|
||||
{/* Tabela de andamentos */}
|
||||
<TCensecTipoNaturezaTable
|
||||
data={tCensecNaturezaTipo}
|
||||
onEdit={handleOpenForm}
|
||||
onDelete={handleConfirmDelete}
|
||||
/>
|
||||
{/* Modal de confirmação */}
|
||||
{isConfirmOpen && (
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmOpen}
|
||||
title="Confirmar exclusão"
|
||||
description="Atenção"
|
||||
message={`Deseja realmente excluir o Tipo de Natureza "${itemToDelete?.descricao}"?`}
|
||||
confirmText="Sim, excluir"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleDelete}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
)}
|
||||
{/* Formulário de criação/edição */}
|
||||
{isFormOpen && (
|
||||
<TCensecTipoNaturezaForm
|
||||
isOpen={isFormOpen}
|
||||
data={selectedData}
|
||||
onClose={handleCloseForm}
|
||||
onSave={handleSave}
|
||||
buttonIsLoading={buttonIsLoading}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
'use client';
|
||||
|
||||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
import TCensecTipoNaturezaColumns from './TCensecTipoNaturezaColumns';
|
||||
import TCensecTipoNaturezaTableInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaTableInterface';
|
||||
|
||||
/**
|
||||
* Componente principal da tabela
|
||||
*/
|
||||
export default function TCensecTipoNaturezaTable({ data, onEdit, onDelete }: TCensecTipoNaturezaTableInterface) {
|
||||
const columns = TCensecTipoNaturezaColumns(onEdit, onDelete);
|
||||
return (
|
||||
<div>
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="descricao"
|
||||
filterPlaceholder="Busque pela descrição..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import ApiResponseInterface from "@/shared/services/api/interfaces/ApiResponseInterface";
|
||||
import API from "@/shared/services/api/Api";
|
||||
import { Methods } from "@/shared/services/api/enums/ApiMethodEnum";
|
||||
import TCensecTipoNaturezaInterface from "../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface";
|
||||
|
||||
async function executeTCensecTipoNaturezaDeleteData(data: TCensecTipoNaturezaInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return await api.send({
|
||||
method: Methods.DELETE,
|
||||
endpoint: `administrativo/t_censec_tiponatureza/${data.censec_tiponatureza_id}`
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaDeleteData = withClientErrorHandler(executeTCensecTipoNaturezaDeleteData);
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
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 executeTCensecTipoNaturezaIndexData(): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `administrativo/t_censec_tiponatureza`
|
||||
});
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaIndexData = withClientErrorHandler(executeTCensecTipoNaturezaIndexData);
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TCensecTipoNaturezaInterface from "../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface";
|
||||
import ApiResponseInterface from "@/shared/services/api/interfaces/ApiResponseInterface";
|
||||
import API from "@/shared/services/api/Api";
|
||||
import { Methods } from "@/shared/services/api/enums/ApiMethodEnum";
|
||||
|
||||
async function executeTCensecTipoNaturezaSaveData(data: TCensecTipoNaturezaInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
console.log('executeTCensecTipoNaturezaSaveData', data)
|
||||
|
||||
// Verifica se existe ID da cidade para decidir se é atualização (PUT) ou criação (POST)
|
||||
const isUpdate = Boolean(data.censec_tiponatureza_id);
|
||||
|
||||
// Instancia o cliente da API para enviar a requisição
|
||||
const api = new API();
|
||||
|
||||
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
|
||||
return await api.send({
|
||||
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
|
||||
endpoint: `administrativo/t_censec_tiponatureza/${data.censec_tiponatureza_id || ''}`, // endpoint dinâmico
|
||||
body: data, // payload enviado para a API
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaSaveData = withClientErrorHandler(executeTCensecTipoNaturezaSaveData);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TCensecTipoNaturezaInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import { TCensecTipoNaturezaDeleteService } from '../../services/TCensecTipoNatureza/TCensecTipoNaturezaDeleteService';
|
||||
|
||||
export const useTCensecTipoNaturezaDeleteHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tAtoParteTipo, setTCensecTipoNatureza] = useState<TCensecTipoNaturezaInterface>();
|
||||
|
||||
const deleteTCensecTipoNatureza = async (data: TCensecTipoNaturezaInterface) => {
|
||||
const response = await TCensecTipoNaturezaDeleteService(data);
|
||||
|
||||
setTCensecTipoNatureza(data);
|
||||
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return { tAtoParteTipo, deleteTCensecTipoNatureza };
|
||||
};
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { useForm } from "react-hook-form";
|
||||
import { TCensecTipoNaturezaFormValues, TCensecTipoNaturezaSchema } from "../../schemas/TCensecTipoNatureza/TCensecTipoNaturezaSchema";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
export function useTCensecTipoNaturezaFormHook(defaults?: Partial<TCensecTipoNaturezaFormValues>) {
|
||||
return useForm<TCensecTipoNaturezaFormValues>({
|
||||
resolver: zodResolver(TCensecTipoNaturezaSchema),
|
||||
defaultValues: {
|
||||
censec_tiponatureza_id: 0,
|
||||
...defaults,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TCensecTipoNaturezaInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import { TCensecTipoNaturezaIndexService } from '../../services/TCensecTipoNatureza/TCensecTipoNaturezaIndexService';
|
||||
|
||||
export const useTCensecTipoNaturezaIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tCensecNaturezaTipo, setTCensecTipoNatureza] = useState<TCensecTipoNaturezaInterface[]>([]);
|
||||
|
||||
const indexTCensecTipoNatureza = async () => {
|
||||
const response = await TCensecTipoNaturezaIndexService();
|
||||
// Armazena os dados consultados
|
||||
setTCensecTipoNatureza(response.data);
|
||||
// Define os dados do componente de resposta (toast, modal, etc)
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return {
|
||||
tCensecNaturezaTipo,
|
||||
indexTCensecTipoNatureza
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TCensecTipoNaturezaInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import { TCensecTipoNaturezaSaveService } from '../../services/TCensecTipoNatureza/TCensecTipoNaturezaSaveService';
|
||||
|
||||
export const useTCensecTipoNaturezaSaveHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tAtoParteTipo, setTCensecTipoNatureza] = useState<TCensecTipoNaturezaInterface>();
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const saveTCensecTipoNatureza = async (data: TCensecTipoNaturezaInterface) => {
|
||||
const response = await TCensecTipoNaturezaSaveService(data);
|
||||
|
||||
// Armazena os dados da repsota
|
||||
setTCensecTipoNatureza(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 { tAtoParteTipo, saveTCensecTipoNatureza };
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { TCensecTipoNaturezaFormValues } from "../../schemas/TCensecTipoNatureza/TCensecTipoNaturezaSchema";
|
||||
|
||||
export interface TCensecTipoNaturezaFormInterface {
|
||||
isOpen: boolean;
|
||||
data: TCensecTipoNaturezaFormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: TCensecTipoNaturezaFormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export default interface TCensecTipoNaturezaInterface {
|
||||
censec_tiponatureza_id?: number;
|
||||
censec_tipoato_id?: number;
|
||||
descricao?: string;
|
||||
possui_ato_anterior?: string;
|
||||
codigo?: number;
|
||||
obrigatorio?: string;
|
||||
tipo_ato_anterior?: string;
|
||||
situacao_ato_anterior?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import TCensecTipoNaturezaInterface from "./TCensecTipoNaturezaInterface";
|
||||
|
||||
export default interface TCensecTipoNaturezaTableInterface {
|
||||
data?: TCensecTipoNaturezaInterface[];
|
||||
onEdit: (item: TCensecTipoNaturezaInterface, isEditingFormStatus: boolean) => void;
|
||||
onDelete: (item: TCensecTipoNaturezaInterface, isEditingFormStatus: boolean) => void;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import z from "zod";
|
||||
|
||||
export const TCensecTipoNaturezaSchema = z.object({
|
||||
censec_tiponatureza_id: z.number().optional(),
|
||||
censec_tipoato_id: z.number().optional(),
|
||||
descricao: z.string().optional(),
|
||||
possui_ato_anterior: z.string().optional(),
|
||||
codigo: z.number().optional(),
|
||||
obrigatorio: z.string().optional(),
|
||||
tipo_ato_anterior: z.string().optional(),
|
||||
situacao_ato_anterior: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TCensecTipoNaturezaFormValues = z.infer<typeof TCensecTipoNaturezaSchema>;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import TCensecTipoNaturezaInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import { TCensecTipoNaturezaDeleteData } from '../../data/TCensecTipoNatureza/TCensecTipoNaturezaDeleteData';
|
||||
|
||||
async function executeTCensecTipoNaturezaDeleteService(data: TCensecTipoNaturezaInterface) {
|
||||
const response = await TCensecTipoNaturezaDeleteData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaDeleteService = withClientErrorHandler(executeTCensecTipoNaturezaDeleteService);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TCensecTipoNaturezaIndexData } from '../../data/TCensecTipoNatureza/TCensecTipoNaturezaIndexData';
|
||||
|
||||
export default async function executeTCensecTipoNaturezaIndexService() {
|
||||
const response = await TCensecTipoNaturezaIndexData();
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaIndexService = withClientErrorHandler(executeTCensecTipoNaturezaIndexService);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import TCensecTipoNaturezaInterface from '../../interfaces/TCensecTipoNatureza/TCensecTipoNaturezaInterface';
|
||||
import { TCensecTipoNaturezaSaveData } from '../../data/TCensecTipoNatureza/TCensecTipoNaturezaSaveData';
|
||||
|
||||
async function executeTCensecTipoNaturezaSaveService(data: TCensecTipoNaturezaInterface) {
|
||||
const response = await TCensecTipoNaturezaSaveData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TCensecTipoNaturezaSaveService = withClientErrorHandler(executeTCensecTipoNaturezaSaveService);
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
|
||||
import { FormControl } from "@/components/ui/form";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TipoAtoAnteriorEnum } from "@/shared/enums/TipoAtoAnteriorEnum";
|
||||
import { Command } from "cmdk";
|
||||
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
||||
import React from "react";
|
||||
|
||||
export default function TipoAtoAnteriorSelect({ field }: any) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const options = Object.entries(TipoAtoAnteriorEnum).map(([value, label]) => ({
|
||||
value,
|
||||
label,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button variant="outline" role="combobox" aria-expanded={open} className="justify-between">
|
||||
{field.value
|
||||
? options.find((item) => item.value === field.value)?.label
|
||||
: "Selecione..."}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar situação..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{options.map((item) => (
|
||||
<CommandItem
|
||||
key={item.value}
|
||||
value={item.label.toLowerCase()}
|
||||
onSelect={() => {
|
||||
field.onChange(item.value);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
field.value === item.value ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{item.label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
107
src/shared/components/tipoNatureza/TipoNaturezaSelect.tsx
Normal file
107
src/shared/components/tipoNatureza/TipoNaturezaSelect.tsx
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command";
|
||||
import { FormControl } from "@/components/ui/form";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TipoNaturezaEnum } from "@/shared/enums/TipoNaturezaEnum";
|
||||
import { Command } from "cmdk";
|
||||
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
||||
import React from "react";
|
||||
|
||||
export default function TipoNaturezaSelect({ field }: any) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
// Gera opções a partir do Enum
|
||||
const options = Object.entries(TipoNaturezaEnum).map(([id, label]) => ({
|
||||
value: Number(id),
|
||||
label,
|
||||
}));
|
||||
|
||||
// 🔹 Converte valor recebido (string tipo ";0,1,2,3") para array de números
|
||||
const parseToArray = (value: any): number[] => {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value.map(Number);
|
||||
if (typeof value === "string") {
|
||||
return value
|
||||
.replace(/^;/, "") // remove o primeiro ";"
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((v) => Number(v.trim()));
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
// Array de valores selecionados
|
||||
const selectedValues: number[] = parseToArray(field.value);
|
||||
|
||||
// Atualiza valor selecionado (e reenvia como string ";0,1,2,3")
|
||||
const toggleSelect = (value: number) => {
|
||||
let newValues;
|
||||
if (selectedValues.includes(value)) {
|
||||
newValues = selectedValues.filter((v) => v !== value);
|
||||
} else {
|
||||
newValues = [...selectedValues, value];
|
||||
}
|
||||
// Converte para formato ";0,1,2,3"
|
||||
const formatted = ";" + newValues.join(",");
|
||||
field.onChange(formatted);
|
||||
};
|
||||
|
||||
// Label do botão (nomes selecionados)
|
||||
const selectedLabels = options
|
||||
.filter((opt) => selectedValues.includes(opt.value))
|
||||
.map((opt) => opt.label)
|
||||
.join(", ");
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="justify-between"
|
||||
>
|
||||
{selectedLabels || "Selecione..."}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar tipo natureza..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{options.map((item) => (
|
||||
<CommandItem
|
||||
key={item.value}
|
||||
value={item.label.toLowerCase()}
|
||||
onSelect={() => toggleSelect(item.value)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
selectedValues.includes(item.value)
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{item.label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
8
src/shared/enums/TipoAtoAnteriorEnum.ts
Normal file
8
src/shared/enums/TipoAtoAnteriorEnum.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const TipoAtoAnteriorEnum = {
|
||||
1: 'Substabelecido',
|
||||
2: 'Revogado',
|
||||
3: 'Reratificado',
|
||||
4: 'Renunciado',
|
||||
5: 'Renúncia',
|
||||
6: 'Renúncia Parcial'
|
||||
} as const;
|
||||
6
src/shared/enums/TipoNaturezaEnum.ts
Normal file
6
src/shared/enums/TipoNaturezaEnum.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const TipoNaturezaEnum = {
|
||||
1: 'Escritura',
|
||||
2: 'Procuração',
|
||||
3: 'Substabelecimento',
|
||||
4: 'Testamento',
|
||||
} as const;
|
||||
Loading…
Add table
Reference in a new issue