Merge branch 'MVPTN-99' into release(MVP/Sprint6)

This commit is contained in:
Keven Willian Pereira de Souza 2025-10-03 10:36:09 -03:00
commit b3dc6c87f2
90 changed files with 4487 additions and 614 deletions

BIN
public/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/images/logo-abb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View 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');
}

View file

@ -0,0 +1,15 @@
import { UseFormReturn, FieldValues } from "react-hook-form";
/**
* Reseta o formulário com os dados recebidos (se existirem)
* @param form - Instância do react-hook-form
* @param data - Dados para popular o formulário
*/
export function ResetFormIfData<T extends FieldValues>(
form: UseFormReturn<T>,
data: T | null
) {
if (data) {
form.reset(data);
}
}

View file

@ -0,0 +1,6 @@
/**
* Converte o valor do input para número, enviando undefined se estiver vazio
*/
export function parseNumberInput(e: React.ChangeEvent<HTMLInputElement>): number | undefined {
return e.target.value ? Number(e.target.value) : undefined;
}

View file

@ -3,17 +3,17 @@
import React, { useEffect, useState, useCallback } from 'react';
import Loading from '@/app/_components/loading/loading';
import TPessoaTable from '../../../_components/t_pessoa/TPessoaTable';
import TPessoaForm from '../../../_components/t_pessoa/TPessoaForm';
import TPessoaTable from '@/packages/administrativo/components/TPessoa/TPessoaFisica/TPessoaFisicaTable';
import TPessoaForm from '@/packages/administrativo/components/TPessoa/TPessoaFisica/TPessoaFisicaForm';
import { useTPessoaIndexHook } from '../../../_hooks/t_pessoa/useTPessoaIndexHook';
import { useTPessoaSaveHook } from '../../../_hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '../../../_hooks/t_pessoa/useTPessoaDeleteHook';
import { useTPessoaIndexHook } from '@/packages/administrativo/hooks/t_pessoa/useTPessoaIndexHook';
import { useTPessoaSaveHook } from '@/packages/administrativo/hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '@/packages/administrativo/hooks/t_pessoa/useTPessoaDeleteHook';
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
import TPessoaInterface from '../../../_interfaces/TPessoaInterface';
import TPessoaInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaInterface';
import Header from '@/app/_components/structure/Header';
export default function TPessoaFisica() {

View file

@ -4,17 +4,17 @@ import React, { useEffect, useState, useCallback } from 'react';
import Loading from '@/app/_components/loading/loading';
import { useTPessoaSaveHook } from '../../../_hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '../../../_hooks/t_pessoa/useTPessoaDeleteHook';
import { useTPessoaSaveHook } from '@/packages/administrativo/hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '@/packages/administrativo/hooks/t_pessoa/useTPessoaDeleteHook';
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
import TPessoaInterface from '../../../_interfaces/TPessoaInterface';
import TPessoaInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaInterface';
import Header from '@/app/_components/structure/Header';
import TPessoaJuridicaTable from '../../../_components/t_pessoa/juridica/TPessoaJuridicaTable';
import { useTPessoaJuridicaIndexHook } from '../../../_hooks/t_pessoa/juridica/useTPessoaJuridicaIndexHook';
import TPessoaJuridicaForm from '../../../_components/t_pessoa/juridica/TPessoaJuridicaForm';
import TPessoaJuridicaTable from '@/packages/administrativo/components/TPessoa/TPessoaJuridica/TPessoaJuridicaTable';
import { useTPessoaJuridicaIndexHook } from '@/packages/administrativo/hooks/t_pessoa/juridica/useTPessoaJuridicaIndexHook';
import TPessoaJuridicaForm from '@/packages/administrativo/components/TPessoa/TPessoaJuridica/TPessoaJuridicaForm';
export default function TPessoaFisica() {
// Controle de estado do botão

View file

@ -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 '@/packages/administrativo/components/t_imovel/TImovelTable';
import TImovelForm from '@/packages/administrativo/components/t_imovel/TImovelForm';
import { useTImovelIndexHook } from '@/packages/administrativo/hooks/t_imovel/useTImovelIndexHook';
import { useTImovelSaveHook } from '@/packages/administrativo/hooks/t_imovel/useTImovelSaveHook';
import { useTImovelDeleteHook } from '@/packages/administrativo/hooks/t_imovel/useTImovelDeleteHook';
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
import TImovelInterface from '@/packages/administrativo/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;
}

View file

@ -1,7 +1,7 @@
'use client';
import z from 'zod';
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
@ -73,10 +73,13 @@ export default function GTBBairroForm({
>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Bairro</DialogTitle>
<DialogDescription>Crie ou edite um bairro</DialogDescription>
<DialogTitle>
Bairro
</DialogTitle>
<DialogDescription>
Crie ou edite um bairro
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Descrição */}
@ -93,7 +96,6 @@ export default function GTBBairroForm({
</FormItem>
)}
/>
{/* Situação */}
<Controller
name="situacao"
@ -108,7 +110,6 @@ export default function GTBBairroForm({
</div>
)}
/>
{/* Rodapé do Dialog */}
<DialogFooter className="mt-4">
<DialogClose asChild>

View file

@ -1,205 +0,0 @@
'use client';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { ArrowUpDownIcon, EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
import { ColumnDef } from '@tanstack/react-table';
import GetNameInitials from '@/actions/text/GetNameInitials';
import { DataTable } from '@/app/_components/dataTable/DataTable';
import TPessoaInterface from '../../../_interfaces/TPessoaInterface';
import { FormatCPF } from '@/actions/CPF/FormatCPF';
import { FormatPhone } from '@/actions/phone/FormatPhone';
import { FormatDateTime } from '@/actions/dateTime/FormatDateTime';
import empty from '@/actions/validations/empty';
import { FormatCNPJ } from '@/actions/CNPJ/FormatCNPJ';
// Tipagem das props
interface TPessoaJuridicaTableProps {
data: TPessoaInterface[];
onEdit: (item: TPessoaInterface, isEditingFormStatus: boolean) => void;
onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void;
}
/**
* Função para criar a definição das colunas da tabela
*/
function createPessoaColumns(
onEdit: (item: TPessoaInterface, isEditingFormStatus: boolean) => void,
onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void,
): ColumnDef<TPessoaInterface>[] {
return [
// ID
{
accessorKey: 'pessoa_id',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
# <ArrowUpDownIcon className="ml-1 h-4 w-4" />
</Button>
),
cell: ({ row }) => Number(row.getValue('pessoa_id')),
enableSorting: false,
},
// Nome / Email / Foto
{
id: 'nome_completo',
accessorFn: (row) => row,
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Nome / Email <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => {
const pessoa = row.original;
return (
<div className="flex items-center gap-3">
{/* Nome e Email */}
<div>
<div className="font-semibold text-gray-900 capitalize">{pessoa.nome || '-'}</div>
<div className="text-sm text-gray-500">
{empty(pessoa.email) ? 'Email não informado' : pessoa.email}
</div>
</div>
</div>
);
},
sortingFn: (a, b) =>
(a.original.nome?.toLowerCase() || '').localeCompare(b.original.nome?.toLowerCase() || ''),
},
// CPF
{
accessorKey: 'cpf_cnpj',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
CNPJ <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatCNPJ(row.getValue('cpf_cnpj')),
},
// Telefone
{
accessorKey: 'telefone',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Telefone <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatPhone(row.getValue('telefone')),
},
// Cidade / UF
{
id: 'cidade_uf',
accessorFn: (row) => `${row.cidade}/${row.uf}`,
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Cidade/UF <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => <span>{row.getValue('cidade_uf') || '-'}</span>,
sortingFn: (a, b) =>
`${a.original.cidade}/${a.original.uf}`
.toLowerCase()
.localeCompare(`${b.original.cidade}/${b.original.uf}`.toLowerCase()),
},
// Data de cadastro
{
accessorKey: 'data_cadastro',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Cadastro <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatDateTime(row.getValue('data_cadastro')),
sortingFn: 'datetime',
},
// Ações
{
id: 'actions',
header: 'Ações',
cell: ({ row }) => {
const pessoa = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="cursor-pointer">
<EllipsisIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="left" align="start">
<DropdownMenuGroup>
<DropdownMenuItem className="cursor-pointer" onSelect={() => onEdit(pessoa, true)}>
<PencilIcon className="mr-2 h-4 w-4" />
Editar
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="cursor-pointer text-red-600"
onSelect={() => onDelete(pessoa, true)}
>
<Trash2Icon className="mr-2 h-4 w-4" />
Remover
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
},
enableSorting: false,
enableHiding: false,
},
];
}
/**
* Componente principal da tabela
*/
export default function TPessoaJuridicaTable({
data,
onEdit,
onDelete,
}: TPessoaJuridicaTableProps) {
const columns = createPessoaColumns(onEdit, onDelete);
return (
<div>
<DataTable
data={data}
columns={columns}
filterColumn="nome_completo"
filterPlaceholder="Buscar por nome ou email..."
/>
</div>
);
}

View file

@ -1,63 +0,0 @@
export default interface TPessoaInterface {
pessoa_id?: number;
pessoa_tipo?: string;
nome?: string;
nacionalidade?: string;
documento?: string;
tb_documentotipo_id?: number;
tb_profissao_id?: number;
tb_estadocivil_id?: number;
nome_pai?: string;
nome_mae?: string;
data_cadastro?: string; // ou Date
naturalidade?: string;
telefone?: string;
endereco?: string;
cidade?: string;
uf?: string;
data_nascimento?: string; // ou Date
sexo?: string;
tb_regimecomunhao_id?: number;
pessoa_conjuge_id?: number;
email?: string;
documento_numero?: string;
bairro?: string;
cep?: string;
documento_expedicao?: string; // ou Date
documento_validade?: string; // ou Date
observacao?: string;
cpf_cnpj?: string;
cpf_terceiro?: string;
nome_fantasia?: string;
texto?: string;
ddd?: number;
cert_casamento_numero?: string;
cert_casamento_folha?: string;
cert_casamento_livro?: string;
cert_casamento_cartorio?: string;
cert_casamento_data?: string; // ou Date
cert_casamento_lei?: string;
pessoa_conjuge_nome?: string;
estrangeiro_nat?: string;
estrangeiro_nat_tb_pais_id?: number;
estrangeiro_res_tb_pais_id?: number;
estrangeiro_res?: string;
municipio_id?: number;
documento_orgao?: string;
documento_uf?: string;
uf_residencia?: string;
inscricao_municipal?: string;
enviado_cnncnb?: boolean;
data_auteracao?: string; // ou Date
data_envioccn?: string; // ou Date
ccnregistros_id?: number;
observacao_envioccn?: string;
observacao_envio_ccn?: string;
deficiencias?: string;
grau_instrucao?: string;
cidade_nat_id?: number;
tb_tipologradouro_id?: number;
unidade?: string;
numero_end?: string;
foto?: string;
}

View file

@ -1,63 +0,0 @@
export default interface TPessoaJuridicaInterface {
pessoa_id?: number;
pessoa_tipo?: string;
nome?: string;
nacionalidade?: string;
documento?: string;
tb_documentotipo_id?: number;
tb_profissao_id?: number;
tb_estadocivil_id?: number;
nome_pai?: string;
nome_mae?: string;
data_cadastro?: string; // ou Date
naturalidade?: string;
telefone?: string;
endereco?: string;
cidade?: string;
uf?: string;
data_nascimento?: string; // ou Date
sexo?: string;
tb_regimecomunhao_id?: number;
pessoa_conjuge_id?: number;
email?: string;
documento_numero?: string;
bairro?: string;
cep?: string;
documento_expedicao?: string; // ou Date
documento_validade?: string; // ou Date
observacao?: string;
cpf_cnpj?: string;
cpf_terceiro?: string;
nome_fantasia?: string;
texto?: string;
ddd?: number;
cert_casamento_numero?: string;
cert_casamento_folha?: string;
cert_casamento_livro?: string;
cert_casamento_cartorio?: string;
cert_casamento_data?: string; // ou Date
cert_casamento_lei?: string;
pessoa_conjuge_nome?: string;
estrangeiro_nat?: string;
estrangeiro_nat_tb_pais_id?: number;
estrangeiro_res_tb_pais_id?: number;
estrangeiro_res?: string;
municipio_id?: number;
documento_orgao?: string;
documento_uf?: string;
uf_residencia?: string;
inscricao_municipal?: string;
enviado_cnncnb?: boolean;
data_auteracao?: string; // ou Date
data_envioccn?: string; // ou Date
ccnregistros_id?: number;
observacao_envioccn?: string;
observacao_envio_ccn?: string;
deficiencias?: string;
grau_instrucao?: string;
cidade_nat_id?: number;
tb_tipologradouro_id?: number;
unidade?: string;
numero_end?: string;
foto?: string;
}

View file

@ -1,5 +0,0 @@
export default interface TPessoaJuridicaInterface {
pessoa_representante_id: number;
nome: string;
tipo: string;
}

View file

@ -1,64 +0,0 @@
import z from 'zod';
export const TPessoaSchema = z.object({
pessoa_id: z.number().optional(),
pessoa_tipo: z.string().optional(),
nome: z.string().min(1, 'O campo deve ser preenchido').max(120, 'O nome excede 120 caracteres'),
nacionalidade: z.string().optional(),
documento: z.string().optional(),
tb_documentotipo_id: z.number().optional(),
tb_profissao_id: z.number().optional(),
tb_estadocivil_id: z.number().optional(),
nome_pai: z.string().optional(),
nome_mae: z.string().optional(),
data_cadastro: z.string().optional(), // ou z.string().datetime()
naturalidade: z.string().optional(),
telefone: z.string().optional(),
endereco: z.string().optional(),
cidade: z.string().optional(),
uf: z.string().optional(),
data_nascimento: z.string().optional(), // ou z.string().datetime()
sexo: z.string().optional(),
tb_regimecomunhao_id: z.number().optional(),
pessoa_conjuge_id: z.number().optional(),
email: z.string().email().optional(),
documento_numero: z.string().optional(),
bairro: z.string().optional(),
cep: z.string().optional(),
documento_expedicao: z.string().optional(), // ou z.string().datetime()
documento_validade: z.string().optional(), // ou z.string().datetime()
observacao: z.string().optional(),
cpf_cnpj: z.string().optional(),
cpf_terceiro: z.string().optional(),
nome_fantasia: z.string().optional(),
texto: z.string().optional(),
ddd: z.number().optional(),
cert_casamento_numero: z.string().optional(),
cert_casamento_folha: z.string().optional(),
cert_casamento_livro: z.string().optional(),
cert_casamento_cartorio: z.string().optional(),
cert_casamento_data: z.string().optional(), // ou z.string().datetime()
cert_casamento_lei: z.string().optional(),
pessoa_conjuge_nome: z.string().optional(),
estrangeiro_nat: z.string().optional(),
estrangeiro_nat_tb_pais_id: z.number().optional(),
estrangeiro_res_tb_pais_id: z.number().optional(),
estrangeiro_res: z.string().optional(),
municipio_id: z.number().optional(),
documento_orgao: z.string().optional(),
documento_uf: z.string().optional(),
uf_residencia: z.string().optional(),
inscricao_municipal: z.string().optional(),
enviado_cnncnb: z.boolean().optional(),
data_auteracao: z.string().optional(), // ou z.string().datetime()
data_envioccn: z.string().optional(), // ou z.string().datetime()
ccnregistros_id: z.number().optional(),
observacao_envioccn: z.string().optional(),
observacao_envio_ccn: z.string().optional(),
deficiencias: z.string().optional(),
grau_instrucao: z.string().optional(),
cidade_nat_id: z.number().optional(),
tb_tipologradouro_id: z.number().optional(),
unidade: z.string().optional(),
numero_end: z.string().optional(),
});

View file

@ -28,8 +28,11 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: 'SAAS - Orius Tecnologia',
description: 'Evolução tecnológica com toque humano',
icons: {
icon: '/images/favicon.ico',
},
};
export default function RootLayout({
@ -53,11 +56,15 @@ export default function RootLayout({
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem className="hidden md:block">
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
<BreadcrumbLink href="#">
Building Your Application
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className="hidden md:block" />
<BreadcrumbItem>
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
<BreadcrumbPage>
Data Fetching
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>

View 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>
);

View file

@ -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,55 @@ 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"
className='cursor-pointer'
>
Primeira
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
aria-label="Página anterior"
className='cursor-pointer'
>
<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"
className='cursor-pointer'
>
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"
className='cursor-pointer'
>
Última
</Button>
</div>
</div>
</div>
);

View file

@ -30,6 +30,7 @@ import {
} from '@/components/ui/sidebar';
import useGUsuarioGetJWTHook from '@/hooks/auth/useGUsuarioGetJWTHook';
import Image from 'next/image';
// This is sample data.
const data = {
@ -75,6 +76,22 @@ const data = {
},
],
},
{
title: 'Pessoas',
url: '#',
icon: SquareTerminal,
isActive: false,
items: [
{
title: 'Físicas',
url: '/administrativo/pessoas/fisicas',
},
{
title: 'Jurídicas',
url: '/administrativo/pessoas/fisicas',
},
],
},
{
title: 'Cadastros',
url: '#',
@ -149,12 +166,8 @@ const data = {
url: '/cadastros/censec/',
},
{
title: 'Pessoas/Físicas',
url: '/cadastros/pessoa/fisica',
},
{
title: 'Pessoas/Jurídica',
url: '/cadastros/pessoa/juridica',
title: 'Imovel/Urbano',
url: '/cadastros/imoveis/urbanos',
},
],
},
@ -226,7 +239,6 @@ const data = {
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const { userAuthenticated } = useGUsuarioGetJWTHook();
return (
<Sidebar collapsible="icon" {...props}>
<SidebarHeader>
@ -236,28 +248,34 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<a href="#">
<div className="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
<GalleryVerticalEnd className="size-4" />
<Image
src="/images/logo-abb.png"
alt="Logo do site"
width={100}
height={100}
className='rounded-lg'
/>
</div>
<div className="flex flex-col gap-0.5 leading-none">
<span className="font-semibold">Orius Tecnologia</span>
<span className="">25.9.1</span>
<span className="font-semibold">
Orius Tecnologia
</span>
<span className="">
25.9.1
</span>
</div>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<NavMain items={data.navMain} />
<NavProjects projects={data.projects} />
</SidebarContent>
<SidebarFooter>
{userAuthenticated?.data ? <NavUser user={userAuthenticated.data} /> : 'Carregando...'}
</SidebarFooter>
<SidebarRail />
</Sidebar>
);

View file

@ -0,0 +1,5 @@
export const ImovelConstrucaoEnum: { [key: number]: string } = {
0: 'Construção averbada',
1: 'Em construção',
2: 'Não se aplica',
};

View file

@ -0,0 +1,4 @@
export const ImovelTipoClasseEnum: { [key: number]: string } = {
1: 'Urbano',
3: 'Rural',
};

View file

@ -0,0 +1,22 @@
export const ImovelTipoEnum: { [key: number]: string } = {
15: 'Loja',
31: 'Galpão',
65: 'Apartamento',
67: 'Casa',
69: 'Fazenda / Sítio / Chácara',
71: 'Terreno / Fração',
89: 'Outros',
90: 'Sala',
91: 'Conjunto de salas',
92: 'Sobreloja',
17: 'Sala / Conjunto',
33: 'Prédio Comercial',
35: 'Prédio Residencial',
73: 'Sala ou Loja',
85: 'Construções',
87: 'Desmembramento',
93: 'Vaga de Garagem',
94: 'Laje',
95: 'Estacionamento',
96: 'Barraco'
};

View file

@ -0,0 +1,5 @@
export enum ImovelTipoRegistro {
M = 'Matrícula',
T = 'Transcrição',
I = 'Inscrição',
}

View file

@ -1,41 +1,21 @@
'use client';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { ArrowUpDownIcon, EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
import { ColumnDef } from '@tanstack/react-table';
import GetNameInitials from '@/actions/text/GetNameInitials';
import { DataTable } from '@/app/_components/dataTable/DataTable';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { FormatCPF } from '@/actions/CPF/FormatCPF';
import { FormatPhone } from '@/actions/phone/FormatPhone';
import { FormatDateTime } from '@/actions/dateTime/FormatDateTime';
import empty from '@/actions/validations/empty';
// Tipagem das props
interface TPessoaTableProps {
data: TPessoaInterface[];
onEdit: (item: TPessoaInterface, isEditingFormStatus: boolean) => void;
onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void;
}
import { FormatCPF } from "@/actions/CPF/FormatCPF";
import { FormatDateTime } from "@/actions/dateTime/FormatDateTime";
import { FormatPhone } from "@/actions/phone/FormatPhone";
import GetNameInitials from "@/actions/text/GetNameInitials";
import empty from "@/actions/validations/empty";
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import TPessoaFisicaInterface from "@/packages/administrativo/interfaces/TPessoa/TPessoaFisica/TPessoaFisicaInterface";
import { ColumnDef } from "@tanstack/react-table";
import { ArrowUpDownIcon, EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react";
/**
* Função para criar a definição das colunas da tabela
*/
function createPessoaColumns(
onEdit: (item: TPessoaInterface, isEditingFormStatus: boolean) => void,
onDelete: (item: TPessoaInterface, isEditingFormStatus: boolean) => void,
): ColumnDef<TPessoaInterface>[] {
export function TPessoaFisicaColumns(
onEdit: (item: TPessoaFisicaInterface, isEditingFormStatus: boolean) => void,
onDelete: (item: TPessoaFisicaInterface, isEditingFormStatus: boolean) => void,
): ColumnDef<TPessoaFisicaInterface>[] {
return [
// ID
{
@ -197,20 +177,3 @@ function createPessoaColumns(
},
];
}
/**
* Componente principal da tabela
*/
export default function TPessoaTable({ data, onEdit, onDelete }: TPessoaTableProps) {
const columns = createPessoaColumns(onEdit, onDelete);
return (
<div>
<DataTable
data={data}
columns={columns}
filterColumn="nome_completo"
filterPlaceholder="Buscar por nome ou email..."
/>
</div>
);
}

View file

@ -1,9 +1,6 @@
'use client';
import z from 'zod';
import React, { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@/components/ui/button';
import {
@ -25,7 +22,6 @@ import {
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { TPessoaSchema } from '../../_schemas/TPessoaSchema';
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
@ -33,14 +29,13 @@ import {
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { CheckIcon, ChevronsUpDownIcon, HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
import { Sexo } from '@/enums/SexoEnum';
import { useGTBEstadoCivilReadHook } from '../../_hooks/g_tb_estadocivil/useGTBEstadoCivilReadHook';
import { useGTBEstadoCivilReadHook } from '../../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_estadocivil/useGTBEstadoCivilReadHook';
import GetCapitalize from '@/actions/text/GetCapitalize';
import { useGTBRegimeComunhaoReadHook } from '../../_hooks/g_tb_regimecomunhao/useGTBRegimeComunhaoReadHook';
import { useGTBProfissaoReadHook } from '../../_hooks/g_tb_profissao/useGTBProfissaoReadHook';
import { useGTBRegimeComunhaoReadHook } from '../../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_regimecomunhao/useGTBRegimeComunhaoReadHook';
import { useGTBProfissaoReadHook } from '../../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_profissao/useGTBProfissaoReadHook';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import {
Command,
@ -51,50 +46,36 @@ import {
CommandList,
} from '@/components/ui/command';
import { cn } from '@/lib/utils';
import TPessoaFisicaFormInterface from '../../../interfaces/TPessoa/TPessoaFisica/TPessoaFisicaFormInterface';
import { ResetFormIfData } from '@/actions/form/ResetFormIfData';
import { useTPessoaForm } from '@/packages/administrativo/hooks/t_pessoa/fisica/usetTPessoaFormHook';
type FormValues = z.infer<typeof TPessoaSchema>;
interface TPessoaFormProps {
isOpen: boolean;
data: FormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: FormValues) => void;
buttonIsLoading: boolean;
}
export default function TCensecForm({
export default function TPessoaFisicaForm({
isOpen,
data,
onClose,
onSave,
buttonIsLoading,
}: TPessoaFormProps) {
}: TPessoaFisicaFormInterface) {
const { gTBProfissao, fetchGTBProfissao } = useGTBProfissaoReadHook();
const { gTBEstadoCivil, fetchGTBEstadoCivil } = useGTBEstadoCivilReadHook();
const { gTBRegimeComunhao, fetchGTBRegimeComunhao } = useGTBRegimeComunhaoReadHook();
// Inicializa o react-hook-form com schema zod
const form = useForm<FormValues>({
resolver: zodResolver(TPessoaSchema),
defaultValues: {
nome: '',
pessoa_id: 0,
},
});
const form = useTPessoaForm({});
// Atualiza o formulário quando recebe dados para edição
useEffect(() => {
// Função para carregar os dados de forma sincrona
const loadData = async () => {
// Se existir dados, reseta o formulário com os dados informados
if (data) form.reset(data);
ResetFormIfData(form, data)
// Aguarda a busca terminar
await fetchGTBProfissao();
await fetchGTBEstadoCivil();
await fetchGTBRegimeComunhao();
};
// Dispara a função
loadData();
}, [data, form]);
@ -108,10 +89,13 @@ export default function TCensecForm({
>
<DialogContent className="w-full max-w-full p-6 sm:max-w-3xl md:max-w-4xl lg:max-w-5xl">
<DialogHeader>
<DialogTitle>Pessoa</DialogTitle>
<DialogDescription>Preencha os dados da pessoa</DialogDescription>
<DialogTitle>
Pessoa Física
</DialogTitle>
<DialogDescription>
Preencha os dados da pessoa
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Tabs */}
@ -128,7 +112,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">
@ -312,10 +295,10 @@ export default function TCensecForm({
className="justify-between"
>
{field.value
? gTBEstadoCivil.find(
(item) =>
String(item.tb_estadocivil_id) === String(field.value),
)?.descricao
? gTBEstadoCivil?.find(
(item) =>
String(item.tb_estadocivil_id) === String(field.value),
)?.descricao
: 'Escolha o estado civil'}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
@ -378,11 +361,11 @@ export default function TCensecForm({
className="justify-between"
>
{field.value
? gTBRegimeComunhao.find(
(item) =>
String(item.tb_regimecomunhao_id) ===
String(field.value),
)?.descricao
? gTBRegimeComunhao?.find(
(item) =>
String(item.tb_regimecomunhao_id) ===
String(field.value),
)?.descricao
: 'Escolha o regime'}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
@ -446,10 +429,10 @@ export default function TCensecForm({
className="justify-between"
>
{field.value
? gTBProfissao.find(
(item) =>
String(item.tb_profissao_id) === String(field.value),
)?.descricao
? gTBProfissao?.find(
(item) =>
String(item.tb_profissao_id) === String(field.value),
)?.descricao
: 'Escolha a profissão'}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
@ -534,7 +517,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 +682,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">
@ -720,7 +701,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* Número */}
<div className="col-span-12 sm:col-span-12 md:col-span-5">
<FormField
@ -737,7 +717,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* CPF */}
<div className="col-span-12 sm:col-span-12 md:col-span-4">
<FormField
@ -754,7 +733,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* Órgão Emissor */}
<div className="col-span-12 sm:col-span-12 md:col-span-4">
<FormField
@ -775,7 +753,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* UF */}
<div className="col-span-12 sm:col-span-12 md:col-span-2">
<FormField
@ -792,7 +769,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* Data de Expedição */}
<div className="col-span-12 sm:col-span-12 md:col-span-3">
<FormField
@ -809,7 +785,6 @@ export default function TCensecForm({
)}
/>
</div>
{/* Validade */}
<div className="col-span-12 sm:col-span-12 md:col-span-3">
<FormField
@ -829,7 +804,6 @@ export default function TCensecForm({
</div>
</TabsContent>
</Tabs>
{/* Rodapé do Dialog */}
<DialogFooter className="mt-4">
<DialogClose asChild>
@ -849,7 +823,6 @@ export default function TCensecForm({
loading={buttonIsLoading}
/>
</DialogFooter>
{/* Campo oculto */}
<input type="hidden" {...form.register('pessoa_id')} />
</form>

View file

@ -0,0 +1,22 @@
'use client';
import { DataTable } from '@/app/_components/dataTable/DataTable';
import TPessoaFisicaTableInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaFisica/TPessoaFisicaTableInterface';
import { TPessoaFisicaColumns } from './TPessoaFisicaColumns';
/**
* Componente principal da tabela
*/
export default function TPessoaFisicaTable({ data, onEdit, onDelete }: TPessoaFisicaTableInterface) {
const columns = TPessoaFisicaColumns(onEdit, onDelete);
return (
<div>
<DataTable
data={data}
columns={columns}
filterColumn="nome_completo"
filterPlaceholder="Buscar por nome ou email..."
/>
</div>
);
}

View file

@ -0,0 +1,159 @@
import { FormatCNPJ } from "@/actions/CNPJ/FormatCNPJ";
import { FormatDateTime } from "@/actions/dateTime/FormatDateTime";
import { FormatPhone } from "@/actions/phone/FormatPhone";
import empty from "@/actions/validations/empty";
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import TPessoaJuridicaInterface from "@/packages/administrativo/interfaces/TPessoa/TPessoaJuridica/TPessoaJuridicaInterface";
import { ColumnDef } from "@tanstack/react-table";
import { ArrowUpDownIcon, EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react";
export default function TPessoaJuridicaColumns(
onEdit: (item: TPessoaJuridicaInterface, isEditingFormStatus: boolean) => void,
onDelete: (item: TPessoaJuridicaInterface, isEditingFormStatus: boolean) => void,
): ColumnDef<TPessoaJuridicaInterface>[] {
return [
// ID
{
accessorKey: 'pessoa_id',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
# <ArrowUpDownIcon className="ml-1 h-4 w-4" />
</Button>
),
cell: ({ row }) => Number(row.getValue('pessoa_id')),
enableSorting: false,
},
// Nome / Email / Foto
{
id: 'nome_completo',
accessorFn: (row) => row,
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Nome / Email <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => {
const pessoa = row.original;
return (
<div className="flex items-center gap-3">
{/* Nome e Email */}
<div>
<div className="font-semibold text-gray-900 capitalize">{pessoa.nome || '-'}</div>
<div className="text-sm text-gray-500">
{empty(pessoa.email) ? 'Email não informado' : pessoa.email}
</div>
</div>
</div>
);
},
sortingFn: (a, b) =>
(a.original.nome?.toLowerCase() || '').localeCompare(b.original.nome?.toLowerCase() || ''),
},
// CPF
{
accessorKey: 'cpf_cnpj',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
CNPJ <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatCNPJ(row.getValue('cpf_cnpj')),
},
// Telefone
{
accessorKey: 'telefone',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Telefone <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatPhone(row.getValue('telefone')),
},
// Cidade / UF
{
id: 'cidade_uf',
accessorFn: (row) => `${row.cidade}/${row.uf}`,
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Cidade/UF <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => <span>{row.getValue('cidade_uf') || '-'}</span>,
sortingFn: (a, b) =>
`${a.original.cidade}/${a.original.uf}`
.toLowerCase()
.localeCompare(`${b.original.cidade}/${b.original.uf}`.toLowerCase()),
},
// Data de cadastro
{
accessorKey: 'data_cadastro',
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
Cadastro <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
</Button>
),
cell: ({ row }) => FormatDateTime(row.getValue('data_cadastro')),
sortingFn: 'datetime',
},
// Ações
{
id: 'actions',
header: 'Ações',
cell: ({ row }) => {
const pessoa = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="cursor-pointer">
<EllipsisIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="left" align="start">
<DropdownMenuGroup>
<DropdownMenuItem className="cursor-pointer" onSelect={() => onEdit(pessoa, true)}>
<PencilIcon className="mr-2 h-4 w-4" />
Editar
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="cursor-pointer text-red-600"
onSelect={() => onDelete(pessoa, true)}
>
<Trash2Icon className="mr-2 h-4 w-4" />
Remover
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
},
enableSorting: false,
enableHiding: false,
},
];
}

View file

@ -25,12 +25,12 @@ import {
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { TPessoaSchema } from '../../../_schemas/TPessoaSchema';
import { TPessoaSchema } from '../../../schemas/TPessoa/TPessoaSchema';
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
import { Textarea } from '@/components/ui/textarea';
import { useTPessoaRepresentanteIndexHook } from '../../../_hooks/t_pessoa_representante/useTPessoaRepresentanteIndexHook';
import { useTPessoaRepresentanteIndexHook } from '../../../hooks/t_pessoa_representante/useTPessoaRepresentanteIndexHook';
import TPessoaRepresentantePage from '../../t_pessoa_representante/TPessoaRepresentantePage';
type FormValues = z.infer<typeof TPessoaSchema>;

View file

@ -0,0 +1,27 @@
'use client';
import { DataTable } from '@/app/_components/dataTable/DataTable';
import TPessoaJuridicaColumns from './TPessoaJuridicaColumns';
import TPessoaJuridicaTableInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaJuridica/TPessoaJuridicaTableInterface';
/**
* Componente principal da tabela
*/
export default function TPessoaJuridicaTable({
data,
onEdit,
onDelete,
}: TPessoaJuridicaTableInterface) {
const columns = TPessoaJuridicaColumns(onEdit, onDelete);
return (
<div>
<DataTable
data={data}
columns={columns}
filterColumn="nome_completo"
filterPlaceholder="Buscar por nome ou email..."
/>
</div>
);
}

View file

@ -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,
},
];
}

View file

@ -0,0 +1,386 @@
'use client';
import React, { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
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 { TImovelFormValues, TImovelSchema } from '../../schemas/TImovelSchema';
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { CheckIcon, ChevronsUpDownIcon, HouseIcon, IdCardIcon } from 'lucide-react';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select';
import TImovelUnidadePage from '../t_imovel_unidade/TImovelUnidadePage';
import { ImovelTipoRegistro } from '@/enums/ImovelTipoRegistro';
import { ImovelTipoClasseEnum } from '@/enums/ImovelTipoClasseEnum';
import { ResetFormIfData } from '@/actions/form/ResetFormIfData';
import { TImovelFormProps } from './TImovelFormProps';
import { useGTBBairroReadHook } from '../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_bairro/useGTBBairroReadHook';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command';
import { cn } from '@/lib/utils';
import GetCapitalize from '@/actions/text/GetCapitalize';
export default function TImovelForm({ isOpen, data, onClose, onSave, buttonIsLoading }: TImovelFormProps) {
const { gTBBairro, fetchGTBBairro } = useGTBBairroReadHook();
// Inicializa o react-hook-form com schema zod
const form = useForm<TImovelFormValues>({
resolver: zodResolver(TImovelSchema),
defaultValues: {},
});
// Atualiza o formulário quando recebe dados para edição
useEffect(() => {
// Se existir dados, reseta o formulário com os mesmos
ResetFormIfData(form, data);
// Função sincrona para carregamento de dados
async function loadData() {
// Busca os bairros
await fetchGTBBairro();
}
// Executa a função
loadData();
}, [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 cursor-pointer" value="dadosDoImovel">
<HouseIcon className="me-1 inline" />
Dados do Imóvel
</TabsTrigger>
<TabsTrigger className="flex-1 text-center cursor-pointer" value="unidades">
<IdCardIcon className="inline" />
Unidades
</TabsTrigger>
</TabsList>
{/* Dados do Imóvel */}
<TabsContent value="dadosDoImovel" className="space-y-4">
<div className="grid w-full grid-cols-12 gap-4">
{/* UF */}
<div className="col-span-12 sm:col-span-6 md:col-span-2">
<FormField
control={form.control}
name="uf"
render={({ field }) => (
<FormItem>
<FormLabel>UF</FormLabel>
<FormControl>
<Input {...field} type='text' placeholder="UF" maxLength={2} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* CEP */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="cep"
render={({ field }) => (
<FormItem>
<FormLabel>CEP</FormLabel>
<FormControl>
<Input {...field} type='text' placeholder="Digite o CEP" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Cidade */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="cidade"
render={({ field }) => (
<FormItem>
<FormLabel>Cidade</FormLabel>
<FormControl>
<Input {...field} type="text" placeholder="Digite a cidade" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Bairro */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tb_bairro_id"
render={({ field }) => {
const [open, setOpen] = React.useState(false);
return (
<FormItem>
<FormLabel>Bairro</FormLabel>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<FormControl className="w-full">
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="justify-between"
>
{field.value
? gTBBairro.find(
(item) =>
String(item.tb_bairro_id) === String(field.value),
)?.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>Nenhum resultado encontrado.</CommandEmpty>
<CommandGroup>
{gTBBairro?.map((item) => (
<CommandItem
key={item.tb_bairro_id}
value={(item.descricao ?? '').toLowerCase()}
onSelect={() => {
field.onChange(Number(item.tb_bairro_id));
setOpen(false);
}}
>
<CheckIcon
className={cn(
'mr-2 h-4 w-4',
String(field.value) === String(item.descricao)
? 'opacity-100'
: 'opacity-0',
)}
/>
{GetCapitalize(item.descricao)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
);
}}
/>
</div>
{/* Cartório */}
<div className="col-span-12 sm:col-span-6 md:col-span-2">
<FormField
control={form.control}
name="cartorio"
render={({ field }) => (
<FormItem>
<FormLabel>Cartório</FormLabel>
<FormControl>
<Input {...field} type='number' placeholder="Digite o cartório" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* CNS */}
<div className="col-span-12 sm:col-span-6 md:col-span-5">
<FormField
control={form.control}
name="cns"
render={({ field }) => (
<FormItem>
<FormLabel>CNS</FormLabel>
<FormControl>
<Input {...field} type="number" placeholder="Digite o CNS" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Livro */}
<div className="col-span-12 sm:col-span-6 md:col-span-5">
<FormField
control={form.control}
name="livro"
render={({ field }) => (
<FormItem>
<FormLabel>Livro</FormLabel>
<FormControl>
<Input {...field} type='text' placeholder="Digite o livro" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Tipo Registro */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tipo_registro"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Tipo Registro</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-full">
{field.value
? ImovelTipoRegistro[field.value as keyof typeof ImovelTipoRegistro]
: "Selecione"}
</SelectTrigger>
<SelectContent>
{Object.entries(ImovelTipoRegistro).map(([key, label]) => (
<SelectItem key={key} value={key} className="cursor-pointer">
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Número */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<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>
)}
/>
</div>
{/* Número Letra */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="numero_letra"
render={({ field }) => (
<FormItem>
<FormLabel>Número Letra</FormLabel>
<FormControl>
<Input {...field} type='text' placeholder="Digite a letra" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Tipo Registro */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tipo_classe"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Tipo Classe</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-full">
{field.value
? ImovelTipoClasseEnum[field.value as keyof typeof ImovelTipoClasseEnum]
: "Selecione"}
</SelectTrigger>
<SelectContent>
{Object.entries(ImovelTipoClasseEnum).map(([key, label]) => (
<SelectItem key={key} value={key} className="cursor-pointer">
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</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>
);
}

View file

@ -0,0 +1,7 @@
export interface TImovelFormProps {
isOpen: boolean;
data: FormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: FormValues) => void;
buttonIsLoading: boolean;
}

View file

@ -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>
);
}

View file

@ -0,0 +1,90 @@
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")),
},
// Número da Unidade
{
accessorKey: "numero_unidade",
header: ({ column }) => SortableHeader("Número da Unidade", column),
cell: ({ row }) => row.getValue("numero_unidade"),
},
// Quadra
{
accessorKey: "quadra",
header: ({ column }) => SortableHeader("Quadra", column),
cell: ({ row }) => row.getValue("quadra"),
},
// Area
{
accessorKey: "area",
header: ({ column }) => SortableHeader("Área", column),
cell: ({ row }) => row.getValue("area"),
},
// Logradouros
{
accessorKey: "logradouro",
header: ({ column }) => SortableHeader("Logradouro", column),
cell: ({ row }) => row.getValue("logradouro"),
},
// 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,
},
];
}

View file

@ -0,0 +1,545 @@
'use client';
import React, { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
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 '@/app/_components/loadingButton/LoadingButton';
import { TImovelUnidadeFormValues, TImovelUnidadeSchema } from '../../schemas/TImovelUnidadeSchema';
import TImovelUnidadeProps from './TImovelUnidadeFormProps';
import { useGTBTipoLogradouroReadHook } from '../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_tipologradouro/useGTBTipoLogradouroReadHook';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command';
import { cn } from '@/lib/utils';
import GetCapitalize from '@/actions/text/GetCapitalize';
import { ResetFormIfData } from '@/actions/form/ResetFormIfData';
import { parseNumberInput } from '@/actions/form/parseNumberInput';
import { ImovelTipoEnum } from '@/enums/ImovelTipoEnum';
import { ImovelConstrucaoEnum } from '@/enums/ImovelConstrucaoEnum';
export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, buttonIsLoading }: TImovelUnidadeProps) {
const { gTBTipoLogradouro, fetchGTBTipoLogradouro } = useGTBTipoLogradouroReadHook();
// Inicializa o react-hook-form com schema zod
const form = useForm<TImovelUnidadeFormValues>({
resolver: zodResolver(TImovelUnidadeSchema),
defaultValues: {
imovel_id: 1,
},
});
// Atualiza o formulário quando recebe dados para edição
useEffect(() => {
// Se existir dados, reseta o formulário com os mesmos
ResetFormIfData(form, data);
// Carregamento de dados iniciais
async function loadData() {
// Carrega o tipo de logradouro
await fetchGTBTipoLogradouro();
}
// Executa a função
loadData();
}, [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-2xl md:max-w-2xl lg:max-w-3xl max-h-[60vh] overflow-auto">
<DialogHeader>
<DialogTitle>
Unidades do Imóvel
</DialogTitle>
<DialogDescription>
Cadastro de unidades do imóvel
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
<div className="grid grid-cols-12 sm:grid-cols-12 lg:grid-cols-12 gap-4">
{/* Quadra */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="quadra"
render={({ field }) => (
<FormItem>
<FormLabel>Quadra</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Lote */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="lote"
render={({ field }) => (
<FormItem>
<FormLabel>Lote</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Area */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="area"
render={({ field }) => (
<FormItem>
<FormLabel>Área(m2)</FormLabel>
<FormControl>
<Input {...field}
type='number'
onChange={e => field.onChange(parseNumberInput(e))}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Inscrição Municipal */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="inscricao_municipal"
render={({ field }) => (
<FormItem>
<FormLabel>Inscrição Municipal</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Tipo Logradouro */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tb_tipologradouro_id"
render={({ field }) => {
const [open, setOpen] = React.useState(false);
return (
<FormItem>
<FormLabel>Tipo logradouro</FormLabel>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<FormControl className="w-full">
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="justify-between"
>
{field.value
? gTBTipoLogradouro.find(
(item) =>
String(item.tb_tipologradouro_id) === String(field.value),
)?.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>Nenhum resultado encontrado.</CommandEmpty>
<CommandGroup>
{gTBTipoLogradouro?.map((item) => (
<CommandItem
key={item.tb_tipologradouro_id}
value={(item.descricao ?? '').toLowerCase()}
onSelect={() => {
field.onChange(Number(item.tb_tipologradouro_id));
setOpen(false);
}}
>
<CheckIcon
className={cn(
'mr-2 h-4 w-4',
String(field.value) === String(item.descricao)
? 'opacity-100'
: 'opacity-0',
)}
/>
{GetCapitalize(item.descricao)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
);
}}
/>
</div>
{/* Logradouro */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="logradouro"
render={({ field }) => (
<FormItem>
<FormLabel>Logradouro</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Tipo Imóvel */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tipo_imovel"
render={({ field }) => {
const [open, setOpen] = React.useState(false);
// transforma o objeto em um array [{value, label}]
const options = Object.entries(ImovelTipoEnum).map(([id, label]) => ({
value: Number(id),
label,
}));
return (
<FormItem>
<FormLabel>Tipo Imóvel</FormLabel>
<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 tipo imóvel..." />
<CommandList>
<CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
<CommandGroup>
{options.map((item) => (
<CommandItem
key={item.value}
value={item.label.toLowerCase()}
onSelect={() => {
field.onChange(item.value); // salva o número (id)
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>
<FormMessage />
</FormItem>
);
}}
/>
</div>
{/* Construção */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="tipo_construcao"
render={({ field }) => {
const [open, setOpen] = React.useState(false);
const options = Object.entries(ImovelConstrucaoEnum).map(([id, label]) => ({
value: Number(id),
label,
}));
return (
<FormItem>
<FormLabel>Construção</FormLabel>
<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 tipo construçã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>
<FormMessage />
</FormItem>
);
}}
/>
</div>
{/* Iptu */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="iptu"
render={({ field }) => (
<FormItem>
<FormLabel>IPTU</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Unidade */}
<div className="col-span-12 sm:col-span-6 md:col-span-2">
<FormField
control={form.control}
name="numero_unidade"
render={({ field }) => (
<FormItem>
<FormLabel>Unidade</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Torre */}
<div className="col-span-12 sm:col-span-6 md:col-span-2">
<FormField
control={form.control}
name="torre"
render={({ field }) => (
<FormItem>
<FormLabel>Torre</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Condominio */}
<div className="col-span-12 sm:col-span-6 md:col-span-2">
<FormField
control={form.control}
name="nomecondominio"
render={({ field }) => (
<FormItem>
<FormLabel>Condominio</FormLabel>
<FormControl>
<Input {...field}
type='text'
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Loteamento */}
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="nomeloteamento"
render={({ field }) => (
<FormItem>
<FormLabel>Loteamento</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* CNM */}
<div className="col-span-12 sm:col-span-6 md:col-span-6">
<FormField
control={form.control}
name="cib"
render={({ field }) => (
<FormItem>
<FormLabel>CNM</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* CIB */}
<div className="col-span-12 sm:col-span-6 md:col-span-6">
<FormField
control={form.control}
name="cnm_numero"
render={({ field }) => (
<FormItem>
<FormLabel>CIB</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Numero da Edificação */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="numero_edificacao"
render={({ field }) => (
<FormItem>
<FormLabel>Número da Edificação</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
{/* Complemento */}
<div className="col-span-12 sm:col-span-6 md:col-span-8">
<FormField
control={form.control}
name="complemento"
render={({ field }) => (
<FormItem>
<FormLabel>Complemento</FormLabel>
<FormControl>
<Input {...field} />
</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>
{/* Campo oculto */}
<input type="hidden" {...form.register("imovel_unidade_id")} />
<input type="hidden" {...form.register("imovel_id")} />
</form>
</Form>
</DialogContent>
</Dialog>
);
}

View file

@ -0,0 +1,9 @@
import { TImovelUnidadeFormValues } from "../../schemas/TImovelUnidadeSchema";
export default interface TImovelUnidadeProps {
isOpen: boolean;
data: TImovelUnidadeFormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: TImovelUnidadeFormValues) => void;
buttonIsLoading: boolean;
}

View file

@ -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>
);
}

View file

@ -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_unidade"
filterPlaceholder="Busque pelo numero da unidade"
/>
</div>
);
}

View file

@ -25,7 +25,7 @@ import {
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { TPessoaSchema } from '../../_schemas/TPessoaSchema';
import { TPessoaSchema } from '../../schemas/TPessoa/TPessoaSchema';
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
@ -47,10 +47,10 @@ import {
UserIcon,
} from 'lucide-react';
import { Sexo } from '@/enums/SexoEnum';
import { useGTBEstadoCivilReadHook } from '../../_hooks/g_tb_estadocivil/useGTBEstadoCivilReadHook';
import { useGTBEstadoCivilReadHook } from '../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_estadocivil/useGTBEstadoCivilReadHook';
import GetCapitalize from '@/actions/text/GetCapitalize';
import { useGTBRegimeComunhaoReadHook } from '../../_hooks/g_tb_regimecomunhao/useGTBRegimeComunhaoReadHook';
import { useGTBProfissaoReadHook } from '../../_hooks/g_tb_profissao/useGTBProfissaoReadHook';
import { useGTBRegimeComunhaoReadHook } from '../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_regimecomunhao/useGTBRegimeComunhaoReadHook';
import { useGTBProfissaoReadHook } from '../../../../app/(protected)/(cadastros)/cadastros/_hooks/g_tb_profissao/useGTBProfissaoReadHook';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import {
Command,
@ -61,9 +61,9 @@ import {
CommandList,
} from '@/components/ui/command';
import { cn } from '@/lib/utils';
import { useTPessoaIndexHook } from '../../_hooks/t_pessoa/useTPessoaIndexHook';
import TPessoaTable from '../t_pessoa/TPessoaTable';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { useTPessoaIndexHook } from '../../hooks/t_pessoa/useTPessoaIndexHook';
import TPessoaTable from '../TPessoa/TPessoaFisica/TPessoaFisicaTable';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { ColumnDef } from '@tanstack/react-table';
import GetNameInitials from '@/actions/text/GetNameInitials';
import empty from '@/actions/validations/empty';

View file

@ -3,18 +3,18 @@
import React, { useEffect, useState, useCallback } from 'react';
import Loading from '@/app/_components/loading/loading';
import TPessoaForm from '../../_components/t_pessoa/TPessoaForm';
import TPessoaForm from '../TPessoa/TPessoaFisica/TPessoaFisicaForm';
import { useTPessoaIndexHook } from '../../_hooks/t_pessoa/useTPessoaIndexHook';
import { useTPessoaSaveHook } from '../../_hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '../../_hooks/t_pessoa/useTPessoaDeleteHook';
import { useTPessoaIndexHook } from '../../hooks/t_pessoa/useTPessoaIndexHook';
import { useTPessoaSaveHook } from '../../hooks/t_pessoa/useTPessoaSaveHook';
import { useTPessoaDeleteHook } from '../../hooks/t_pessoa/useTPessoaDeleteHook';
import ConfirmDialog from '@/app/_components/confirm_dialog/ConfirmDialog';
import { useConfirmDialog } from '@/app/_components/confirm_dialog/useConfirmDialog';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import TPessoaRepresentanteTable from './TPessoaRepresentanteTable';
import { useTPessoaRepresentanteIndexHook } from '../../_hooks/t_pessoa_representante/useTPessoaRepresentanteIndexHook';
import { useTPessoaRepresentanteIndexHook } from '../../hooks/t_pessoa_representante/useTPessoaRepresentanteIndexHook';
import { Button } from '@/components/ui/button';
import Header from '@/app/_components/structure/Header';
import TPessoaRepresentanteForm from './TPessoaRepresentanteForm';

View file

@ -16,7 +16,7 @@ import { ColumnDef } from '@tanstack/react-table';
import GetNameInitials from '@/actions/text/GetNameInitials';
import { DataTable } from '@/app/_components/dataTable/DataTable';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { FormatCPF } from '@/actions/CPF/FormatCPF';
import { FormatPhone } from '@/actions/phone/FormatPhone';
import empty from '@/actions/validations/empty';

View file

@ -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

View file

@ -0,0 +1,18 @@
import { withClientErrorHandler } from "@/actions/withClientErrorHandler/withClientErrorHandler";
import TImovelInterface from "../../interfaces/TImovelInterface";
async function executeTImovelSaveData(data: TImovelInterface) {
console.log({
status: 200,
message: 'Dados salvos',
});
return Promise.resolve({
status: 200,
message: 'Dados salvos',
});
}
export const TImovelSaveData = withClientErrorHandler(executeTImovelSaveData);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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 };
};

View file

@ -0,0 +1,27 @@
'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[]>();
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
};
};

View file

@ -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 };
};

View file

@ -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 };
};

View file

@ -0,0 +1,28 @@
'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[]>();
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
};
};

View file

@ -0,0 +1,34 @@
'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 };
};

View file

@ -0,0 +1,16 @@
// hooks/useTPessoaForm.ts
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { TPessoaFormValues, TPessoaSchema } from "@/packages/administrativo/schemas/TPessoa/TPessoaSchema";
// Hook customizado
export function useTPessoaForm(defaults?: Partial<TPessoaFormValues>) {
return useForm<TPessoaFormValues>({
resolver: zodResolver(TPessoaSchema),
defaultValues: {
nome: "",
pessoa_id: 0,
...defaults, // sobrescreve valores iniciais se forem passados
},
});
}

View file

@ -1,6 +1,6 @@
import { useResponse } from '@/app/_response/ResponseContext';
import TPessoaJuridicaInterface from '../../../_interfaces/TPessoaJuridicaInterface';
import { TCensecDeleteService } from '../../../_services/t_censec/TCensecDeleteService';
import TPessoaJuridicaInterface from '../../../interfaces/TPessoa/TPessoaJuridica/TPessoaJuridicaInterface';
import { TCensecDeleteService } from '../../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService';
export const useTPessoaJuridicaDeleteHook = () => {
const { setResponse } = useResponse();

View file

@ -1,7 +1,7 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { TPessoaJuridicaIndexService } from '../../../_services/t_pessoa/juridica/TPessoaJuridicaIndexService';
import { TPessoaJuridicaIndexService } from '../../../services/t_pessoa/juridica/TPessoaJuridicaIndexService';
import { useState } from 'react';
import TPessoaJuridicaInterface from '../../../_interfaces/TPessoaJuridicaInterface';
import TPessoaJuridicaInterface from '../../../interfaces/TPessoa/TPessoaJuridica/TPessoaJuridicaInterface';
export const useTPessoaJuridicaIndexHook = () => {
const { setResponse } = useResponse();

View file

@ -2,8 +2,8 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { useState } from 'react';
import TPessoaInterface from '../../../_interfaces/TPessoaInterface';
import { TCensecSaveService } from '../../../_services/t_censec/TCensecSaveService';
import TPessoaInterface from '../../../interfaces/TPessoa/TPessoaInterface';
import { TCensecSaveService } from '../../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService';
export const useTPessoaJuridicaSaveHook = () => {
const { setResponse } = useResponse();

View file

@ -1,6 +1,6 @@
import { useResponse } from '@/app/_response/ResponseContext';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { TCensecDeleteService } from '../../_services/t_censec/TCensecDeleteService';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { TCensecDeleteService } from '../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService';
export const useTPessoaDeleteHook = () => {
const { setResponse } = useResponse();

View file

@ -1,7 +1,7 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { TPessoaIndexService } from '../../_services/t_pessoa/TPessoaIndexService';
import { TPessoaIndexService } from '../../services/t_pessoa/TPessoaIndexService';
import { useState } from 'react';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
export const useTPessoaIndexHook = () => {
const { setResponse } = useResponse();

View file

@ -2,8 +2,8 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { useState } from 'react';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { TCensecSaveService } from '../../_services/t_censec/TCensecSaveService';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { TCensecSaveService } from '../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService';
export const useTPessoaSaveHook = () => {
const { setResponse } = useResponse();

View file

@ -1,6 +1,6 @@
import { useResponse } from '@/app/_response/ResponseContext';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { TCensecDeleteService } from '../../_services/t_censec/TCensecDeleteService';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { TCensecDeleteService } from '../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecDeleteService';
export const useTPessoaDeleteHook = () => {
const { setResponse } = useResponse();

View file

@ -1,8 +1,8 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { TPessoaIndexService } from '../../_services/t_pessoa/TPessoaIndexService';
import { TPessoaIndexService } from '../../services/t_pessoa/TPessoaIndexService';
import { useState } from 'react';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { TPessoaRepresentanteIndexData } from '../../_data/TPessoaRepresentante/TPessoaRepresentanteIndexData';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { TPessoaRepresentanteIndexData } from '../../data/TPessoaRepresentante/TPessoaRepresentanteIndexData';
export const useTPessoaRepresentanteIndexHook = () => {
const { setResponse } = useResponse();

View file

@ -2,8 +2,8 @@
import { useResponse } from '@/app/_response/ResponseContext';
import { useState } from 'react';
import TPessoaInterface from '../../_interfaces/TPessoaInterface';
import { TCensecSaveService } from '../../_services/t_censec/TCensecSaveService';
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
import { TCensecSaveService } from '../../../../app/(protected)/(cadastros)/cadastros/_services/t_censec/TCensecSaveService';
export const useTPessoaSaveHook = () => {
const { setResponse } = useResponse();

View file

@ -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,
}

View file

@ -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;
}

View file

@ -0,0 +1,9 @@
import { TPessoaFisicaFormValues } from "../../../schemas/TPessoa/TPessoaFisicaSchema";
export default interface TPessoaFisicaFormInterface {
isOpen: boolean;
data: TPessoaFisicaFormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: TPessoaFisicaFormValues) => void;
buttonIsLoading: boolean;
}

View file

@ -0,0 +1,33 @@
import TPessoaInterface from "../TPessoaInterface";
export default interface TPessoaFisicaInterface extends TPessoaInterface {
nacionalidade?: string;
tb_documentotipo_id?: number;
tb_profissao_id?: number;
tb_estadocivil_id?: number;
nome_pai?: string;
nome_mae?: string;
data_nascimento?: string;
sexo?: string;
tb_regimecomunhao_id?: number;
pessoa_conjuge_id?: number;
documento_expedicao?: string;
documento_validade?: string;
cert_casamento_numero?: string;
cert_casamento_folha?: string;
cert_casamento_livro?: string;
cert_casamento_cartorio?: string;
cert_casamento_data?: string;
cert_casamento_lei?: string;
pessoa_conjuge_nome?: string;
estrangeiro_nat?: string;
estrangeiro_nat_tb_pais_id?: number;
estrangeiro_res_tb_pais_id?: number;
estrangeiro_res?: string;
documento_orgao?: string;
documento_uf?: string;
uf_residencia?: string;
deficiencias?: string;
grau_instrucao?: string;
cidade_nat_id?: number;
}

View file

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

View file

@ -0,0 +1,32 @@
export default interface TPessoaInterface {
pessoa_id?: number;
pessoa_tipo?: string;
nome?: string;
documento?: string;
data_cadastro?: string;
naturalidade?: string;
telefone?: string;
endereco?: string;
cidade?: string;
uf?: string;
email?: string;
documento_numero?: string;
bairro?: string;
cep?: string;
observacao?: string;
cpf_cnpj?: string;
cpf_terceiro?: string;
texto?: string;
ddd?: number;
municipio_id?: number;
enviado_cnncnb?: boolean;
data_auteracao?: string;
data_envioccn?: string;
ccnregistros_id?: number;
observacao_envioccn?: string;
observacao_envio_ccn?: string;
tb_tipologradouro_id?: number;
unidade?: string;
numero_end?: string;
foto?: string;
}

View file

@ -0,0 +1,9 @@
import TPessoaJuridicaInterface from "./TPessoaJuridicaInterface";
export default interface TPessoaJuridicaFormInterface {
isOpen: boolean;
data: TPessoaJuridicaInterface | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: TPessoaJuridicaInterface) => void;
buttonIsLoading: boolean;
}

View file

@ -0,0 +1,12 @@
import TPessoaInterface from "../TPessoaInterface";
export default interface TPessoaJuridicaInterface extends TPessoaInterface {
razao_social?: string;
nome_fantasia?: string;
inscricao_estadual?: string;
inscricao_municipal?: string;
capital_social?: number;
data_abertura?: string;
cnae_principal?: string;
cnae_secundario?: string[];
}

View file

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

View file

@ -0,0 +1,19 @@
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(),
});
export type TImovelFormValues = z.infer<typeof TImovelSchema>;

View file

@ -0,0 +1,42 @@
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().min(1, 'O campo deve ser preenchido').max(90, 'O campo não deve exceder 90 caracteres'),
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(),
});
// Exportar o tipo inferido junto (opcional)
export type TImovelUnidadeFormValues = z.infer<typeof TImovelUnidadeSchema>;

View file

@ -0,0 +1,36 @@
import { TPessoaSchema } from "./TPessoaSchema";
import z from "zod";
export const TPessoaFisicaSchema = TPessoaSchema.extend({
nacionalidade: z.string().optional(),
tb_documentotipo_id: z.number().optional(),
tb_profissao_id: z.number().optional(),
tb_estadocivil_id: z.number().optional(),
nome_pai: z.string().optional(),
nome_mae: z.string().optional(),
data_nascimento: z.string().optional(),
sexo: z.string().optional(),
tb_regimecomunhao_id: z.number().optional(),
pessoa_conjuge_id: z.number().optional(),
documento_expedicao: z.string().optional(),
documento_validade: z.string().optional(),
cert_casamento_numero: z.string().optional(),
cert_casamento_folha: z.string().optional(),
cert_casamento_livro: z.string().optional(),
cert_casamento_cartorio: z.string().optional(),
cert_casamento_data: z.string().optional(),
cert_casamento_lei: z.string().optional(),
pessoa_conjuge_nome: z.string().optional(),
estrangeiro_nat: z.string().optional(),
estrangeiro_nat_tb_pais_id: z.number().optional(),
estrangeiro_res_tb_pais_id: z.number().optional(),
estrangeiro_res: z.string().optional(),
documento_orgao: z.string().optional(),
documento_uf: z.string().optional(),
uf_residencia: z.string().optional(),
deficiencias: z.string().optional(),
grau_instrucao: z.string().optional(),
cidade_nat_id: z.number().optional(),
});
export type TPessoaFisicaFormValues = z.infer<typeof TPessoaFisicaSchema>;

View file

@ -0,0 +1,15 @@
import { TPessoaSchema } from "./TPessoaSchema";
import z from "zod";
export const TPessoaJuridicaSchema = TPessoaSchema.extend({
razao_social: z.string().min(1, "Razão social é obrigatória"),
nome_fantasia: z.string().optional(),
inscricao_estadual: z.string().optional(),
inscricao_municipal: z.string().optional(),
capital_social: z.number().optional(),
data_abertura: z.string().optional(),
cnae_principal: z.string().optional(),
cnae_secundario: z.array(z.string()).optional(),
});
export type TPessoaJuridicaFormValues = z.infer<typeof TPessoaJuridicaSchema>;

View file

@ -0,0 +1,33 @@
import z from 'zod';
export const TPessoaSchema = z.object({
pessoa_id: z.number().optional(),
pessoa_tipo: z.string().optional(),
nome: z.string().min(1, 'O campo deve ser preenchido').max(120, 'O nome excede 120 caracteres'),
documento: z.string().optional(),
data_cadastro: z.string().optional(),
telefone: z.string().optional(),
endereco: z.string().optional(),
cidade: z.string().optional(),
uf: z.string().optional(),
email: z.string().email().optional(),
documento_numero: z.string().optional(),
bairro: z.string().optional(),
cep: z.string().optional(),
observacao: z.string().optional(),
cpf_cnpj: z.string().optional(),
cpf_terceiro: z.string().optional(),
texto: z.string().optional(),
ddd: z.number().optional(),
municipio_id: z.number().optional(),
enviado_cnncnb: z.boolean().optional(),
data_auteracao: z.string().optional(),
data_envioccn: z.string().optional(),
ccnregistros_id: z.number().optional(),
observacao_envioccn: z.string().optional(),
observacao_envio_ccn: z.string().optional(),
tb_tipologradouro_id: z.number().optional(),
unidade: z.string().optional(),
numero_end: z.string().optional(),
foto: z.string().optional(),
});

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -1,5 +1,5 @@
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
import { TPessoaIndexData } from '../../_data/TPessoa/TPessoaIndexData';
import { TPessoaIndexData } from '../../data/TPessoa/TPessoaIndexData';
async function executeTPessoaIndexService() {
const response = TPessoaIndexData();

View file

@ -1,5 +1,5 @@
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
import { TPessoaJuridicaIndexData } from '../../../_data/TPessoa/juridica/TPessoaJuridicaIndexData';
import { TPessoaJuridicaIndexData } from '../../../data/TPessoa/juridica/TPessoaJuridicaIndexData';
async function executeTPessoaJuridicaIndexService() {
const response = TPessoaJuridicaIndexData();

View file

@ -1,5 +1,5 @@
import { withClientErrorHandler } from '@/actions/withClientErrorHandler/withClientErrorHandler';
import { TPessoaRepresentanteIndexData } from '../../_data/TPessoaRepresentante/TPessoaRepresentanteIndexData';
import { TPessoaRepresentanteIndexData } from '../../data/TPessoaRepresentante/TPessoaRepresentanteIndexData';
async function executeTPessoaRepresentanteIndexService() {
const response = TPessoaRepresentanteIndexData();