[MVPTN-87] feat(CRUD): Cria crud de dados mocados da Imovel e da Unidade do Imóvel
This commit is contained in:
parent
8579387c53
commit
4eabe19ee3
36 changed files with 3504 additions and 35 deletions
20
src/actions/CEP/FormatCEP.ts
Normal file
20
src/actions/CEP/FormatCEP.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Formata um número de CEP no padrão 99999-999
|
||||
*
|
||||
* @param value - CEP em string ou number
|
||||
* @returns CEP formatado ou string vazia se inválido
|
||||
*/
|
||||
export function FormatCEP(value: string | number): string {
|
||||
if (!value) return '';
|
||||
|
||||
// Converte para string e remove tudo que não seja número
|
||||
const digits = String(value).replace(/\D/g, '');
|
||||
|
||||
// Garante que tenha no máximo 8 dígitos
|
||||
const cleanValue = digits.slice(0, 8);
|
||||
|
||||
// Retorna formatado ou valor limpo se não tiver tamanho suficiente
|
||||
if (cleanValue.length !== 8) return cleanValue;
|
||||
|
||||
return cleanValue.replace(/(\d{5})(\d{3})/, '$1-$2');
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
|
||||
import Loading from '@/app/_components/loading/loading';
|
||||
import TImovelTable from '../../../_components/t_imovel/TImovelTable';
|
||||
import TImovelForm from '../../../_components/t_imovel/TImovelForm';
|
||||
|
||||
import { useTImovelIndexHook } from '../../../_hooks/t_imovel/useTImovelIndexHook';
|
||||
import { useTImovelSaveHook } from '../../../_hooks/t_imovel/useTImovelSaveHook';
|
||||
import { useTImovelDeleteHook } from '../../../_hooks/t_imovel/useTImovelDeleteHook';
|
||||
|
||||
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
|
||||
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
|
||||
|
||||
import TImovelInterface from '../../../_interfaces/TImovelInterface';
|
||||
import Header from '@/app/_components/structure/Header';
|
||||
|
||||
export default function TTBAndamentoServico() {
|
||||
// Controle de estado do botão
|
||||
const [buttonIsLoading, setButtonIsLoading] = useState(false);
|
||||
|
||||
// Hooks para leitura e salvamento
|
||||
const { tImovel, indexTImovel } = useTImovelIndexHook();
|
||||
const { saveTImovel } = useTImovelSaveHook();
|
||||
const { deleteTImovel } = useTImovelDeleteHook();
|
||||
|
||||
// Estados
|
||||
const [selectedAndamento, setSelectedAndamento] = useState<TImovelInterface | null>(null);
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
|
||||
// Estado para saber qual item será deletado
|
||||
const [itemToDelete, setItemToDelete] = useState<TImovelInterface | 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: TImovelInterface | null) => {
|
||||
setSelectedAndamento(data);
|
||||
setIsFormOpen(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Fecha o formulário e limpa o andamento selecionado
|
||||
*/
|
||||
const handleCloseForm = useCallback(() => {
|
||||
setSelectedAndamento(null);
|
||||
setIsFormOpen(false);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Salva os dados do formulário
|
||||
*/
|
||||
const handleSave = useCallback(
|
||||
async (formData: TImovelInterface) => {
|
||||
// Coloca o botão em estado de loading
|
||||
setButtonIsLoading(true);
|
||||
|
||||
// Aguarda salvar o registro
|
||||
await saveTImovel(formData);
|
||||
|
||||
// Remove o botão em estado de loading
|
||||
setButtonIsLoading(false);
|
||||
|
||||
// Atualiza a lista de dados
|
||||
indexTImovel();
|
||||
},
|
||||
[saveTImovel, indexTImovel, handleCloseForm],
|
||||
);
|
||||
|
||||
/**
|
||||
* Quando o usuário clica em "remover" na tabela
|
||||
*/
|
||||
const handleConfirmDelete = useCallback(
|
||||
(item: TImovelInterface) => {
|
||||
// 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 deleteTImovel(itemToDelete);
|
||||
|
||||
// Atualiza a lista
|
||||
await indexTImovel();
|
||||
|
||||
// Limpa o item selecionado
|
||||
setItemToDelete(null);
|
||||
|
||||
// Fecha o modal
|
||||
handleCancel();
|
||||
}, [itemToDelete, indexTImovel, handleCancel]);
|
||||
|
||||
/**
|
||||
* Busca inicial dos dados
|
||||
*/
|
||||
useEffect(() => {
|
||||
indexTImovel();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Tela de loading enquanto carrega os dados
|
||||
*/
|
||||
if (tImovel?.length == 0) {
|
||||
return <Loading type={2} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Cabeçalho */}
|
||||
<Header
|
||||
title={'Imóveis Urbanos'}
|
||||
description={'Gerenciamento de imóveis urbanos'}
|
||||
buttonText={'Novo imóvel'}
|
||||
buttonAction={() => {
|
||||
handleOpenForm(null);
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Tabela de andamentos */}
|
||||
<TImovelTable
|
||||
data={tImovel}
|
||||
onEdit={handleOpenForm}
|
||||
onDelete={handleConfirmDelete} />
|
||||
|
||||
{/* Modal de confirmação */}
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmOpen}
|
||||
title="Confirmar exclusão"
|
||||
description="Atenção"
|
||||
message={`Deseja realmente excluir o imóvel "${itemToDelete?.cidade}"?`}
|
||||
confirmText="Sim, excluir"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleDelete}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
|
||||
{/* Formulário de criação/edição */}
|
||||
<TImovelForm
|
||||
isOpen={isFormOpen}
|
||||
data={selectedAndamento}
|
||||
onClose={handleCloseForm}
|
||||
onSave={handleSave}
|
||||
buttonIsLoading={buttonIsLoading}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
4;
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import TImovelInterface from "../../_interfaces/TImovelInterface";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
EllipsisIcon,
|
||||
PencilIcon,
|
||||
Trash2Icon,
|
||||
} from "lucide-react";
|
||||
import { FormatDateTime } from "@/actions/dateTime/FormatDateTime";
|
||||
import { FormatCEP } from "@/actions/CEP/FormatCEP";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { ImovelTipoRegistro } from "@/enums/ImovelTipoRegistro";
|
||||
import { SortableHeader } from "@/app/_components/dataTable/SortableHeader";
|
||||
|
||||
export default function TImovelColumns(
|
||||
onEdit: (item: TImovelInterface, isEditingFormStatus: boolean) => void,
|
||||
onDelete: (item: TImovelInterface, isEditingFormStatus: boolean) => void
|
||||
): ColumnDef<TImovelInterface>[] {
|
||||
return [
|
||||
// ID
|
||||
{
|
||||
accessorKey: "imovel_id",
|
||||
header: ({ column }) => SortableHeader("#", column),
|
||||
cell: ({ row }) => Number(row.getValue("imovel_id")),
|
||||
enableSorting: false,
|
||||
},
|
||||
|
||||
// Tipo Registro
|
||||
{
|
||||
accessorKey: "tipo_registro",
|
||||
header: ({ column }) => SortableHeader("Tipo Registro", column),
|
||||
cell: ({ row }) => {
|
||||
const value = row.getValue("tipo_registro") as keyof typeof ImovelTipoRegistro;
|
||||
return ImovelTipoRegistro[value] ?? value;
|
||||
},
|
||||
},
|
||||
|
||||
// Número
|
||||
{
|
||||
accessorKey: "numero",
|
||||
header: ({ column }) => SortableHeader("Número", column),
|
||||
cell: ({ row }) => row.getValue("numero"),
|
||||
},
|
||||
|
||||
// UF / Cidade / Bairro
|
||||
{
|
||||
id: "uf_cidade_bairro",
|
||||
accessorFn: (row) => row,
|
||||
header: ({ column }) => SortableHeader("Cidade / UF / Bairro", column),
|
||||
cell: ({ row }) => {
|
||||
const imovel = row.original;
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<span className="font-semibold text-gray-900 capitalize">
|
||||
{imovel.cidade}/{imovel.uf}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500">{imovel.gtb_descricao}</span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
sortingFn: (a, b) =>
|
||||
(a.original.cartorio?.toLowerCase() || "").localeCompare(
|
||||
b.original.cartorio?.toLowerCase() || ""
|
||||
),
|
||||
},
|
||||
|
||||
// CEP
|
||||
{
|
||||
accessorKey: "cep",
|
||||
header: ({ column }) => SortableHeader("CEP", column),
|
||||
cell: ({ row }) => FormatCEP(row.getValue("cep")),
|
||||
},
|
||||
|
||||
// Data de Registro
|
||||
{
|
||||
accessorKey: "data_registro",
|
||||
header: ({ column }) => SortableHeader("Cadastro", column),
|
||||
cell: ({ row }) => FormatDateTime(row.getValue("data_registro")),
|
||||
sortingFn: "datetime",
|
||||
},
|
||||
|
||||
// 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,304 @@
|
|||
'use client';
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { TImovelSchema } from '../../_schemas/TImovelSchema';
|
||||
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
|
||||
import { Select } from '@/components/ui/select';
|
||||
import TImovelUnidadePage from '../t_imovel_unidade/TImovelUnidadePage';
|
||||
|
||||
type FormValues = z.infer<typeof TImovelSchema>;
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
|
||||
export default function TCensecForm({ isOpen, data, onClose, onSave, buttonIsLoading }: Props) {
|
||||
// Inicializa o react-hook-form com schema zod
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(TImovelSchema),
|
||||
defaultValues: {},
|
||||
});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
if (data) form.reset(data);
|
||||
}, [data, form]);
|
||||
|
||||
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-4xl lg:max-w-5xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Imóvel Urbano
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Cadastro de imóvel urbano
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
|
||||
{/* Tabs */}
|
||||
<Tabs defaultValue="dadosDoImovel" className="space-y-4">
|
||||
<TabsList className="flex w-full">
|
||||
<TabsTrigger className="flex-1 text-center" value="dadosDoImovel">
|
||||
<UserIcon className="me-1 inline" />
|
||||
Dados do Imóvel
|
||||
</TabsTrigger>
|
||||
<TabsTrigger className="flex-1 text-center" value="unidades">
|
||||
<IdCardIcon className="inline" />
|
||||
Unidades
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
{/* Dados do Imóvel */}
|
||||
<TabsContent value="dadosDoImovel" className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{/* Tipo Classe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_classe"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Classe</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o tipo de classe" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Tipo Registro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_registro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Registro</FormLabel>
|
||||
<FormControl>
|
||||
<Select {...field}>
|
||||
<option value="M">Matrícula</option>
|
||||
<option value="T">Transcrição</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o número" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número Letra */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero_letra"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número Letra</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a letra" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cidade */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cidade"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cidade</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a cidade" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* UF */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="uf"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UF</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="UF" maxLength={2} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Bairro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tb_bairro_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bairro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o ID do bairro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CEP */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cep"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CEP</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o CEP" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cartório */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cartorio"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cartório</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o cartório" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Livro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="livro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Livro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o livro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CNS */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cns"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CNS</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o CNS" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* GTB Descrição */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="gtb_descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>GTB Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a descrição" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
{/* Unidades */}
|
||||
<TabsContent value="unidades" className="space-y-4">
|
||||
{/* Conteúdo das unidades */}
|
||||
< TImovelUnidadePage />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
{/* 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>
|
||||
{/* Campo oculto */}
|
||||
<input type="hidden" {...form.register("imovel_id")} />
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
'use client';
|
||||
|
||||
import { DataTable } from '@/app/_components/dataTable/DataTable';
|
||||
import TImovelColumns from './TImovelColumns';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
|
||||
interface TImovelTableProps {
|
||||
data: TImovelInterface[];
|
||||
onEdit: (item: TImovelInterface, isEditingFormStatus: boolean) => void;
|
||||
onDelete: (item: TImovelInterface, isEditingFormStatus: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Componente principal da tabela
|
||||
*/
|
||||
export default function TPessoaTable({ data, onEdit, onDelete }: TImovelTableProps) {
|
||||
const columns = TImovelColumns(onEdit, onDelete);
|
||||
return (
|
||||
<div>
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="numero"
|
||||
filterPlaceholder="Buscar pelo numero de transcrição, matricula etc..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import TImovelUnidadeInterface from "../../_interfaces/TImovelUnidadeInterface";
|
||||
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 "@/app/_components/dataTable/SortableHeader";
|
||||
|
||||
export default function TImovelUnidadeColumns(
|
||||
onEdit: (item: TImovelUnidadeInterface, isEditingFormStatus: boolean) => void,
|
||||
onDelete: (item: TImovelUnidadeInterface, isEditingFormStatus: boolean) => void
|
||||
): ColumnDef<TImovelUnidadeInterface>[] {
|
||||
return [
|
||||
// ID
|
||||
{
|
||||
accessorKey: "imovel_unidade_id",
|
||||
header: ({ column }) => SortableHeader("#", column),
|
||||
cell: ({ row }) => Number(row.getValue("imovel_unidade_id")),
|
||||
enableSorting: false,
|
||||
},
|
||||
// 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,306 @@
|
|||
'use client';
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { TImovelSchema } from '../../_schemas/TImovelSchema';
|
||||
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
|
||||
import { Select } from '@/components/ui/select';
|
||||
|
||||
type FormValues = z.infer<typeof TImovelSchema>;
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
|
||||
export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, buttonIsLoading }: Props) {
|
||||
// Inicializa o react-hook-form com schema zod
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(TImovelSchema),
|
||||
defaultValues: {},
|
||||
});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
if (data) form.reset(data);
|
||||
}, [data, form]);
|
||||
|
||||
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-4xl lg:max-w-5xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Imóvel Urbano
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Cadastro de imóvel urbano
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
|
||||
{/* Tabs */}
|
||||
<Tabs defaultValue="dadosDoImovel" className="space-y-4">
|
||||
<TabsList className="flex w-full">
|
||||
<TabsTrigger className="flex-1 text-center" value="dadosDoImovel">
|
||||
<UserIcon className="me-1 inline" />
|
||||
Dados do Imóvel
|
||||
</TabsTrigger>
|
||||
<TabsTrigger className="flex-1 text-center" value="unidades">
|
||||
<IdCardIcon className="inline" />
|
||||
Unidades
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* Dados do Imóvel */}
|
||||
<TabsContent value="dadosDoImovel" className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{/* Tipo Classe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_classe"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Classe</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o tipo de classe" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Tipo Registro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_registro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Registro</FormLabel>
|
||||
<FormControl>
|
||||
<Select {...field}>
|
||||
<option value="M">Matrícula</option>
|
||||
<option value="T">Transcrição</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o número" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número Letra */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero_letra"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número Letra</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a letra" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cidade */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cidade"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cidade</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a cidade" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* UF */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="uf"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UF</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="UF" maxLength={2} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Bairro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tb_bairro_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bairro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o ID do bairro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CEP */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cep"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CEP</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o CEP" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cartório */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cartorio"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cartório</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o cartório" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Livro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="livro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Livro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o livro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CNS */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cns"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CNS</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o CNS" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* GTB Descrição */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="gtb_descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>GTB Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a descrição" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Unidades */}
|
||||
<TabsContent value="unidades" className="space-y-4">
|
||||
{/* Conteúdo das unidades */}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* 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>
|
||||
|
||||
{/* Campo oculto */}
|
||||
<input type="hidden" {...form.register("imovel_id")} />
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
|
||||
import Loading from '@/app/_components/loading/loading';
|
||||
import TImovelUnidadeTable from './TImovelUnidadeTable';
|
||||
import TImovelUnidadeForm from './TImovelUnidadeForm';
|
||||
|
||||
import { useTImovelUnidadeIndexHook } from '../.././_hooks/t_imovel_unidade/useTImovelUnidadeIndexHook';
|
||||
import { useTImovelUnidadeSaveHook } from '../.././_hooks/t_imovel_unidade/useTImovelUnidadeSaveHook';
|
||||
import { useTImovelUnidadeDeleteHook } from '../.././_hooks/t_imovel_unidade/useTImovelUnidadeDeleteHook';
|
||||
|
||||
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
|
||||
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
|
||||
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import Header from '@/app/_components/structure/Header';
|
||||
|
||||
export default function TImovelUnidadePage() {
|
||||
// Controle de estado do botão
|
||||
const [buttonIsLoading, setButtonIsLoading] = useState(false);
|
||||
|
||||
// Hooks para leitura e salvamento
|
||||
const { tImovelUnidade, indexTImovelUnidade } = useTImovelUnidadeIndexHook();
|
||||
const { saveTImovelUnidade } = useTImovelUnidadeSaveHook();
|
||||
const { deleteTImovelUnidade } = useTImovelUnidadeDeleteHook();
|
||||
|
||||
// Estados
|
||||
const [selectedAndamento, setSelectedAndamento] = useState<TImovelUnidadeInterface | null>(null);
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
|
||||
// Estado para saber qual item será deletado
|
||||
const [itemToDelete, setItemToDelete] = useState<TImovelUnidadeInterface | 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: TImovelUnidadeInterface | null) => {
|
||||
setSelectedAndamento(data);
|
||||
setIsFormOpen(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Fecha o formulário e limpa o andamento selecionado
|
||||
*/
|
||||
const handleCloseForm = useCallback(() => {
|
||||
setSelectedAndamento(null);
|
||||
setIsFormOpen(false);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Salva os dados do formulário
|
||||
*/
|
||||
const handleSave = useCallback(
|
||||
async (formData: TImovelUnidadeInterface) => {
|
||||
// Coloca o botão em estado de loading
|
||||
setButtonIsLoading(true);
|
||||
|
||||
// Aguarda salvar o registro
|
||||
await saveTImovelUnidade(formData);
|
||||
|
||||
// Remove o botão em estado de loading
|
||||
setButtonIsLoading(false);
|
||||
|
||||
// Atualiza a lista de dados
|
||||
indexTImovelUnidade();
|
||||
},
|
||||
[saveTImovelUnidade, indexTImovelUnidade, handleCloseForm],
|
||||
);
|
||||
|
||||
/**
|
||||
* Quando o usuário clica em "remover" na tabela
|
||||
*/
|
||||
const handleConfirmDelete = useCallback(
|
||||
(item: TImovelUnidadeInterface) => {
|
||||
// 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 deleteTImovelUnidade(itemToDelete);
|
||||
|
||||
// Atualiza a lista
|
||||
await indexTImovelUnidade();
|
||||
|
||||
// Limpa o item selecionado
|
||||
setItemToDelete(null);
|
||||
|
||||
// Fecha o modal
|
||||
handleCancel();
|
||||
}, [itemToDelete, indexTImovelUnidade, handleCancel]);
|
||||
|
||||
/**
|
||||
* Busca inicial dos dados
|
||||
*/
|
||||
useEffect(() => {
|
||||
indexTImovelUnidade();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Tela de loading enquanto carrega os dados
|
||||
*/
|
||||
if (tImovelUnidade?.length == 0) {
|
||||
return <Loading type={2} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Cabeçalho */}
|
||||
<Header
|
||||
title={'Unidades'}
|
||||
description={'Gerenciamento de unidades'}
|
||||
buttonText={'Nova unidade'}
|
||||
buttonAction={() => {
|
||||
handleOpenForm(null);
|
||||
}}
|
||||
/>
|
||||
{/* Tabela de andamentos */}
|
||||
<TImovelUnidadeTable
|
||||
data={tImovelUnidade}
|
||||
onEdit={handleOpenForm}
|
||||
onDelete={handleConfirmDelete} />
|
||||
{/* Modal de confirmação */}
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmOpen}
|
||||
title="Confirmar exclusão"
|
||||
description="Atenção"
|
||||
message={`Deseja realmente excluir a unidade "${itemToDelete?.cidade}"?`}
|
||||
confirmText="Sim, excluir"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleDelete}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
{/* Formulário de criação/edição */}
|
||||
<TImovelUnidadeForm
|
||||
isOpen={isFormOpen}
|
||||
data={selectedAndamento}
|
||||
onClose={handleCloseForm}
|
||||
onSave={handleSave}
|
||||
buttonIsLoading={buttonIsLoading}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
'use client';
|
||||
|
||||
import { DataTable } from '@/app/_components/dataTable/DataTable';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import TImovelUnidadeColumns from './TImovelUnidadeColumns';
|
||||
|
||||
interface TImovelUnidadeTableProps {
|
||||
data: TImovelUnidadeInterface[];
|
||||
onEdit: (item: TImovelUnidadeInterface, isEditingFormStatus: boolean) => void;
|
||||
onDelete: (item: TImovelUnidadeInterface, isEditingFormStatus: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Componente principal da tabela
|
||||
*/
|
||||
export default function TImovelUnidadeTable({ data, onEdit, onDelete }: TImovelUnidadeTableProps) {
|
||||
const columns = TImovelUnidadeColumns(onEdit, onDelete);
|
||||
return (
|
||||
<div className="max-h-[40vh] overflow-y-auto">
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="numero"
|
||||
filterPlaceholder="Buscar pelo numero de transcrição, matricula etc..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -111,7 +111,6 @@ export default function TCensecForm({
|
|||
<DialogTitle>Pessoa</DialogTitle>
|
||||
<DialogDescription>Preencha os dados da pessoa</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
|
||||
{/* Tabs */}
|
||||
|
|
@ -128,7 +127,6 @@ export default function TCensecForm({
|
|||
<IdCardIcon /> Documentos
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* Dados Pessoais */}
|
||||
<TabsContent value="dadosPessoais" className="space-y-4">
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
|
|
@ -534,7 +532,6 @@ export default function TCensecForm({
|
|||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Endereço */}
|
||||
<TabsContent value="endereco" className="space-y-4">
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
|
|
@ -700,7 +697,6 @@ export default function TCensecForm({
|
|||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Documentos */}
|
||||
<TabsContent value="documentos" className="space-y-4">
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TImovelInterface from "../../_interfaces/TImovelInterface";
|
||||
|
||||
async function executeTImovelDeleteData(data: TImovelInterface) {
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
message: 'Dados Removidos'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelDeleteData = withClientErrorHandler(executeTImovelDeleteData);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,13 @@
|
|||
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TImovelInterface from "../../_interfaces/TImovelInterface";
|
||||
|
||||
async function executeTImovelSaveData(data: TImovelInterface) {
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
message: 'Dados salvos',
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelSaveData = withClientErrorHandler(executeTImovelSaveData);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TImovelUnidadeInterface from "../../_interfaces/TImovelUnidadeInterface";
|
||||
|
||||
async function executeTImovelUnidadeDeleteData(data: TImovelUnidadeInterface) {
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
message: 'Dados Removidos'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelUnidadeDeleteData = withClientErrorHandler(executeTImovelUnidadeDeleteData);
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
|
||||
async function executeTImovelUnidadeIndexData() {
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
message: 'Dados Salvos',
|
||||
data: [
|
||||
{
|
||||
"imovel_unidade_id": 3921.00,
|
||||
"imovel_id": 5459.00,
|
||||
"numero_unidade": "asdfasd",
|
||||
"quadra": null,
|
||||
"area": null,
|
||||
"superquadra": null,
|
||||
"conjunto": null,
|
||||
"bloco": null,
|
||||
"area_descritiva": null,
|
||||
"caracteristica": null,
|
||||
"reserva_florestal": null,
|
||||
"geo_referenciamento": null,
|
||||
"logradouro": null,
|
||||
"tb_tipologradouro_id": null,
|
||||
"selecionado": "S",
|
||||
"complemento": null,
|
||||
"tipo_imovel": 67.00,
|
||||
"tipo_construcao": 0.00,
|
||||
"texto": null,
|
||||
"numero_edificacao": null,
|
||||
"iptu": "",
|
||||
"ccir": null,
|
||||
"nirf": null,
|
||||
"lote": null,
|
||||
"torre": null,
|
||||
"nomeloteamento": null,
|
||||
"nomecondominio": null,
|
||||
"numero": null,
|
||||
"cnm_numero": null,
|
||||
"imovel_publico_uniao": null,
|
||||
"spu_rip": null,
|
||||
"cat": null,
|
||||
"inscricao_municipal": null,
|
||||
"cib": null,
|
||||
"area_construida": null
|
||||
},
|
||||
{
|
||||
"imovel_unidade_id": 3918.00,
|
||||
"imovel_id": 5456.00,
|
||||
"numero_unidade": null,
|
||||
"quadra": "45",
|
||||
"area": null,
|
||||
"superquadra": null,
|
||||
"conjunto": null,
|
||||
"bloco": null,
|
||||
"area_descritiva": null,
|
||||
"caracteristica": null,
|
||||
"reserva_florestal": null,
|
||||
"geo_referenciamento": null,
|
||||
"logradouro": null,
|
||||
"tb_tipologradouro_id": null,
|
||||
"selecionado": "S",
|
||||
"complemento": null,
|
||||
"tipo_imovel": 67.00,
|
||||
"tipo_construcao": 0.00,
|
||||
"texto": null,
|
||||
"numero_edificacao": null,
|
||||
"iptu": null,
|
||||
"ccir": null,
|
||||
"nirf": null,
|
||||
"lote": null,
|
||||
"torre": null,
|
||||
"nomeloteamento": null,
|
||||
"nomecondominio": null,
|
||||
"numero": null,
|
||||
"cnm_numero": null,
|
||||
"imovel_publico_uniao": null,
|
||||
"spu_rip": null,
|
||||
"cat": null,
|
||||
"inscricao_municipal": null,
|
||||
"cib": null,
|
||||
"area_construida": null
|
||||
},
|
||||
{
|
||||
"imovel_unidade_id": 3917.00,
|
||||
"imovel_id": 5454.00,
|
||||
"numero_unidade": null,
|
||||
"quadra": "45",
|
||||
"area": 160.00,
|
||||
"superquadra": null,
|
||||
"conjunto": null,
|
||||
"bloco": null,
|
||||
"area_descritiva": null,
|
||||
"caracteristica": null,
|
||||
"reserva_florestal": null,
|
||||
"geo_referenciamento": null,
|
||||
"logradouro": "RUA P 3",
|
||||
"tb_tipologradouro_id": 1.00,
|
||||
"selecionado": "",
|
||||
"complemento": null,
|
||||
"tipo_imovel": 67.00,
|
||||
"tipo_construcao": 0.00,
|
||||
"texto": null,
|
||||
"numero_edificacao": null,
|
||||
"iptu": "1200",
|
||||
"ccir": null,
|
||||
"nirf": null,
|
||||
"lote": "12",
|
||||
"torre": null,
|
||||
"nomeloteamento": null,
|
||||
"nomecondominio": null,
|
||||
"numero": 125.00,
|
||||
"cnm_numero": null,
|
||||
"imovel_publico_uniao": null,
|
||||
"spu_rip": null,
|
||||
"cat": null,
|
||||
"inscricao_municipal": null,
|
||||
"cib": null,
|
||||
"area_construida": null
|
||||
},
|
||||
{
|
||||
"imovel_unidade_id": 3916.00,
|
||||
"imovel_id": 5453.00,
|
||||
"numero_unidade": null,
|
||||
"quadra": "06",
|
||||
"area": 461.51,
|
||||
"superquadra": null,
|
||||
"conjunto": null,
|
||||
"bloco": null,
|
||||
"area_descritiva": null,
|
||||
"caracteristica": null,
|
||||
"reserva_florestal": null,
|
||||
"geo_referenciamento": null,
|
||||
"logradouro": "Mariana Vilela",
|
||||
"tb_tipologradouro_id": 3.00,
|
||||
"selecionado": "S",
|
||||
"complemento": null,
|
||||
"tipo_imovel": 71.00,
|
||||
"tipo_construcao": 2.00,
|
||||
"texto": "{...}",
|
||||
"numero_edificacao": null,
|
||||
"iptu": "001.211.0006.0012.0001",
|
||||
"ccir": null,
|
||||
"nirf": null,
|
||||
"lote": "12",
|
||||
"torre": null,
|
||||
"nomeloteamento": null,
|
||||
"nomecondominio": null,
|
||||
"numero": null,
|
||||
"cnm_numero": null,
|
||||
"imovel_publico_uniao": null,
|
||||
"spu_rip": null,
|
||||
"cat": null,
|
||||
"inscricao_municipal": null,
|
||||
"cib": null,
|
||||
"area_construida": null
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelUnidadeIndexData = withClientErrorHandler(executeTImovelUnidadeIndexData);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TImovelUnidadeInterface from "../../_interfaces/TImovelUnidadeInterface";
|
||||
|
||||
async function executeTImovelUnidadeSaveData(data: TImovelUnidadeInterface) {
|
||||
|
||||
return Promise.resolve({
|
||||
status: 200,
|
||||
message: 'Dados salvos',
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelUnidadeSaveData = withClientErrorHandler(executeTImovelUnidadeSaveData);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
import { TImovelDeleteService } from '../../_services/t_imovel/TImovelDeleteService';
|
||||
|
||||
export const useTImovelDeleteHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface>();
|
||||
|
||||
const deleteTImovel = async (data: TImovelInterface) => {
|
||||
const response = await TImovelDeleteService(data);
|
||||
|
||||
setTImovel(data);
|
||||
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return { tImovel, deleteTImovel };
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
import { TImovelIndexData } from '../../_data/TImovel/TImovelIndexData';
|
||||
|
||||
export const useTImovelIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<
|
||||
TImovelInterface[] | null
|
||||
>(null);
|
||||
|
||||
const indexTImovel = async () => {
|
||||
const response = await TImovelIndexData();
|
||||
|
||||
// Armazena os dados consultados
|
||||
setTImovel(response.data);
|
||||
|
||||
// Define os dados do componente de resposta (toast, modal, etc)
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return {
|
||||
tImovel,
|
||||
indexTImovel
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
import { TImovelSaveService } from '../../_services/t_imovel/TImovelSaveService';
|
||||
|
||||
export const useTImovelSaveHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface>();
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const saveTImovel = async (data: TImovelInterface) => {
|
||||
const response = await TImovelSaveService(data);
|
||||
|
||||
// Armazena os dados da repsota
|
||||
setTImovel(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 { tImovel, saveTImovel };
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import { TImovelDeleteService } from '../../_services/t_imovel/TImovelDeleteService';
|
||||
|
||||
export const useTImovelUnidadeDeleteHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovelUnidade, setTImovelUnidade] = useState<TImovelUnidadeInterface>();
|
||||
|
||||
const deleteTImovelUnidade = async (data: TImovelUnidadeInterface) => {
|
||||
const response = await TImovelDeleteService(data);
|
||||
|
||||
setTImovelUnidade(data);
|
||||
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return { tImovelUnidade, deleteTImovelUnidade };
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import { TImovelUnidadeIndexData } from '../../_data/TImovelUnidade/TImovelUnidadeIndexData';
|
||||
|
||||
export const useTImovelUnidadeIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovelUnidade, setTImovelUnidade] = useState<
|
||||
TImovelUnidadeInterface[] | null
|
||||
>(null);
|
||||
|
||||
const indexTImovelUnidade = async () => {
|
||||
const response = await TImovelUnidadeIndexData();
|
||||
|
||||
// Armazena os dados consultados
|
||||
setTImovelUnidade(response.data);
|
||||
|
||||
// Define os dados do componente de resposta (toast, modal, etc)
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return {
|
||||
tImovelUnidade,
|
||||
indexTImovelUnidade
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/app/_response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import { TImovelUnidadeSaveService } from '../../_services/t_imovel_unidade/TImovelUnidadeSaveService';
|
||||
|
||||
export const useTImovelUnidadeSaveHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovelUnidade, setTImovelUnidade] = useState<TImovelUnidadeInterface>();
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const saveTImovelUnidade = async (data: TImovelUnidadeInterface) => {
|
||||
const response = await TImovelUnidadeSaveService(data);
|
||||
|
||||
// Armazena os dados da repsota
|
||||
setTImovelUnidade(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 { tImovelUnidade, saveTImovelUnidade };
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
export default interface TImovelInterface {
|
||||
imovel_id?: number,
|
||||
tipo_classe?: string,
|
||||
tipo_registro?: string,
|
||||
data_registro?: string,
|
||||
numero?: number,
|
||||
numero_letra?: string,
|
||||
cidade?: string,
|
||||
cep?: string,
|
||||
uf?: string,
|
||||
tb_bairro_id?: number,
|
||||
cartorio?: string,
|
||||
livro?: string,
|
||||
cns?: number,
|
||||
gtb_descricao?: string,
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
export default interface TImovelUnidadeInterface {
|
||||
imovel_unidade_id?: number;
|
||||
imovel_id?: number;
|
||||
numero_unidade?: string;
|
||||
quadra?: string;
|
||||
area?: number;
|
||||
superquadra?: string;
|
||||
conjunto?: string;
|
||||
bloco?: string;
|
||||
area_descritiva?: string;
|
||||
caracteristica?: string;
|
||||
reserva_florestal?: string;
|
||||
geo_referenciamento?: string;
|
||||
logradouro?: string;
|
||||
tb_tipologradouro_id?: number;
|
||||
selecionado?: string;
|
||||
complemento?: string;
|
||||
tipo_imovel?: number;
|
||||
tipo_construcao?: number;
|
||||
texto?: string;
|
||||
numero_edificacao?: string;
|
||||
iptu?: string;
|
||||
ccir?: string;
|
||||
nirf?: string;
|
||||
lote?: string;
|
||||
torre?: string;
|
||||
nomeloteamento?: string;
|
||||
nomecondominio?: string;
|
||||
numero?: number;
|
||||
cnm_numero?: string;
|
||||
imovel_publico_uniao?: string;
|
||||
spu_rip?: string;
|
||||
cat?: string;
|
||||
inscricao_municipal?: string;
|
||||
cib?: string;
|
||||
area_construida?: number;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import z from "zod";
|
||||
|
||||
export const TImovelSchema = z.object({
|
||||
imovel_id: z.number().optional,
|
||||
tipo_classe: z.string().optional,
|
||||
tipo_registro: z.string().optional,
|
||||
data_registro: z.string().optional,
|
||||
numero: z.number().optional,
|
||||
numero_letra: z.string().optional,
|
||||
cidade: z.string().optional,
|
||||
cep: z.string().optional,
|
||||
uf: z.string().optional,
|
||||
tb_bairro_id: z.number().optional,
|
||||
cartorio: z.string().optional,
|
||||
livro: z.string().optional,
|
||||
cns: z.number().optional,
|
||||
});
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import z from "zod";
|
||||
|
||||
export const TImovelUnidadeSchema = z.object({
|
||||
imovel_unidade_id: z.number().optional(),
|
||||
imovel_id: z.number().optional(),
|
||||
numero_unidade: z.string().optional(),
|
||||
quadra: z.string().optional(),
|
||||
area: z.number().optional(),
|
||||
superquadra: z.string().optional(),
|
||||
conjunto: z.string().optional(),
|
||||
bloco: z.string().optional(),
|
||||
area_descritiva: z.string().optional(),
|
||||
caracteristica: z.string().optional(),
|
||||
reserva_florestal: z.string().optional(),
|
||||
geo_referenciamento: z.string().optional(),
|
||||
logradouro: z.string().optional(),
|
||||
tb_tipologradouro_id: z.number().optional(),
|
||||
selecionado: z.string().optional(),
|
||||
complemento: z.string().optional(),
|
||||
tipo_imovel: z.number().optional(),
|
||||
tipo_construcao: z.number().optional(),
|
||||
texto: z.string().optional(),
|
||||
numero_edificacao: z.string().optional(),
|
||||
iptu: z.string().optional(),
|
||||
ccir: z.string().optional(),
|
||||
nirf: z.string().optional(),
|
||||
lote: z.string().optional(),
|
||||
torre: z.string().optional(),
|
||||
nomeloteamento: z.string().optional(),
|
||||
nomecondominio: z.string().optional(),
|
||||
numero: z.number().optional(),
|
||||
cnm_numero: z.string().optional(),
|
||||
imovel_publico_uniao: z.string().optional(),
|
||||
spu_rip: z.string().optional(),
|
||||
cat: z.string().optional(),
|
||||
inscricao_municipal: z.string().optional(),
|
||||
cib: z.string().optional(),
|
||||
area_construida: z.number().optional(),
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelDeleteData } from '../../_data/TImovel/TImovelDeleteData';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
|
||||
async function executeTImovelDeleteService(data: TImovelInterface) {
|
||||
const response = await TImovelDeleteData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelDeleteService = withClientErrorHandler(executeTImovelDeleteService);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelIndexData } from '../../_data/TImovel/TImovelIndexData';
|
||||
|
||||
export default async function executeTImovelIndexService() {
|
||||
const response = await TImovelIndexData();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelIndexService = withClientErrorHandler(executeTImovelIndexService);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelSaveData } from '../../_data/TImovel/TImovelSaveData';
|
||||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
|
||||
async function executeTImovelSaveService(data: TImovelInterface) {
|
||||
const response = await TImovelSaveData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelSaveService = withClientErrorHandler(executeTImovelSaveService);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import { TImovelUnidadeDeleteData } from '../../_data/TImovelUnidade/TImovelUnidadeDeleteData';
|
||||
|
||||
async function executeTImovelUnidadeDeleteService(data: TImovelUnidadeInterface) {
|
||||
const response = await TImovelUnidadeDeleteData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelUnidadeDeleteService = withClientErrorHandler(executeTImovelUnidadeDeleteService);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelUnidadeIndexData } from '../../_data/TImovelUnidade/TImovelUnidadeIndexData';
|
||||
|
||||
export default async function executeTImovelUnidadeIndexService() {
|
||||
const response = await TImovelUnidadeIndexData();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelUnidadeIndexService = withClientErrorHandler(executeTImovelUnidadeIndexService);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import TImovelUnidadeInterface from '../../_interfaces/TImovelUnidadeInterface';
|
||||
import { TImovelUnidadeSaveData } from '../../_data/TImovelUnidade/TImovelUnidadeSaveData';
|
||||
|
||||
async function executeTImovelUnidadeSaveService(data: TImovelUnidadeInterface) {
|
||||
const response = await TImovelUnidadeSaveData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelUnidadeSaveService = withClientErrorHandler(executeTImovelUnidadeSaveService);
|
||||
12
src/app/_components/dataTable/SortableHeader.tsx
Normal file
12
src/app/_components/dataTable/SortableHeader.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { ArrowUpDownIcon } from "lucide-react";
|
||||
|
||||
export const SortableHeader = (label: string, column: any) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
{label}
|
||||
<ArrowUpDownIcon className="ml-1 h-4 w-4" />
|
||||
</Button>
|
||||
);
|
||||
|
|
@ -31,16 +31,21 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { ChevronLeftIcon, ChevronRightIcon, EyeIcon } from 'lucide-react';
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
EyeIcon,
|
||||
} from 'lucide-react';
|
||||
|
||||
// Tipagem genérica
|
||||
export interface DataTableProps<TData> {
|
||||
data: TData[];
|
||||
data?: TData[] | null;
|
||||
columns: ColumnDef<TData, any>[];
|
||||
filterColumn?: string; // Define qual coluna será usada para filtro
|
||||
filterPlaceholder?: string;
|
||||
onEdit?: (item: TData) => void;
|
||||
onDelete?: (item: TData) => void;
|
||||
onRowClick?: (item: TData) => void;
|
||||
}
|
||||
|
||||
export function DataTable<TData>({
|
||||
|
|
@ -50,7 +55,11 @@ export function DataTable<TData>({
|
|||
filterPlaceholder = 'Buscar...',
|
||||
onEdit,
|
||||
onDelete,
|
||||
onRowClick,
|
||||
}: DataTableProps<TData>) {
|
||||
// Garante que data sempre seja array
|
||||
const safeData = Array.isArray(data) ? data : [];
|
||||
|
||||
// Estados internos da tabela
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]);
|
||||
|
|
@ -59,8 +68,40 @@ export function DataTable<TData>({
|
|||
|
||||
// Configuração da tabela
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
data: safeData,
|
||||
columns: [
|
||||
...columns,
|
||||
...(onEdit || onDelete
|
||||
? [
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Ações',
|
||||
cell: ({ row }: any) => (
|
||||
<div className="flex gap-2">
|
||||
{onEdit && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => onEdit(row.original)}
|
||||
>
|
||||
Editar
|
||||
</Button>
|
||||
)}
|
||||
{onDelete && (
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => onDelete(row.original)}
|
||||
>
|
||||
Excluir
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
} as ColumnDef<TData, any>,
|
||||
]
|
||||
: []),
|
||||
],
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
|
|
@ -84,9 +125,9 @@ export function DataTable<TData>({
|
|||
{filterColumn && (
|
||||
<Input
|
||||
placeholder={filterPlaceholder}
|
||||
value={(table.getColumn(filterColumn as string)?.getFilterValue() as string) ?? ''}
|
||||
value={(table.getColumn(filterColumn)?.getFilterValue() as string) ?? ''}
|
||||
onChange={(e) =>
|
||||
table.getColumn(filterColumn as string)?.setFilterValue(e.target.value)
|
||||
table.getColumn(filterColumn)?.setFilterValue(e.target.value)
|
||||
}
|
||||
className="w-full"
|
||||
/>
|
||||
|
|
@ -95,7 +136,8 @@ export function DataTable<TData>({
|
|||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="ml-auto cursor-pointer">
|
||||
<EyeIcon /> Colunas visíveis
|
||||
<EyeIcon className="mr-2 h-4 w-4" />
|
||||
Colunas visíveis
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
|
|
@ -133,9 +175,13 @@ export function DataTable<TData>({
|
|||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows.length ? (
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow key={row.id} className="cursor-pointer">
|
||||
<TableRow
|
||||
key={row.id}
|
||||
className={onRowClick ? 'cursor-pointer hover:bg-muted/50' : ''}
|
||||
onClick={() => onRowClick?.(row.original)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
|
|
@ -145,7 +191,10 @@ export function DataTable<TData>({
|
|||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
<TableCell
|
||||
colSpan={table.getAllColumns().length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
Nenhum resultado encontrado.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
@ -155,27 +204,51 @@ export function DataTable<TData>({
|
|||
</div>
|
||||
|
||||
{/* Paginação */}
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Button
|
||||
className="cursor-pointer"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
<ChevronLeftIcon />
|
||||
Anterior
|
||||
</Button>
|
||||
<Button
|
||||
className="cursor-pointer"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
Próxima
|
||||
<ChevronRightIcon />
|
||||
</Button>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Página {table.getState().pagination.pageIndex + 1} de {table.getPageCount()}
|
||||
</span>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.setPageIndex(0)}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
aria-label="Primeira página"
|
||||
>
|
||||
Primeira
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
aria-label="Página anterior"
|
||||
>
|
||||
<ChevronLeftIcon className="h-4 w-4" />
|
||||
Anterior
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
aria-label="Próxima página"
|
||||
>
|
||||
Próxima
|
||||
<ChevronRightIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||
disabled={!table.getCanNextPage()}
|
||||
aria-label="Última página"
|
||||
>
|
||||
Última
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ const data = {
|
|||
title: 'Pessoas/Jurídica',
|
||||
url: '/cadastros/pessoa/juridica',
|
||||
},
|
||||
{
|
||||
title: 'Imovel/Urbano',
|
||||
url: '/cadastros/imoveis/urbanos',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
4
src/enums/ImovelTipoRegistro.ts
Normal file
4
src/enums/ImovelTipoRegistro.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export enum ImovelTipoRegistro {
|
||||
M = 'Matrícula',
|
||||
T = 'Transcrição'
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue