[MVPTN-87] feat(CRUD): Ajustes diversos no crud de imovel e unidade
This commit is contained in:
parent
4eabe19ee3
commit
1fcc5e442d
23 changed files with 886 additions and 465 deletions
15
src/actions/form/ResetFormIfData.ts
Normal file
15
src/actions/form/ResetFormIfData.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
6
src/actions/form/parseNumberInput.ts
Normal file
6
src/actions/form/parseNumberInput.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
|
|
@ -25,35 +23,50 @@ import {
|
|||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { TImovelSchema } from '../../_schemas/TImovelSchema';
|
||||
import { TImovelFormValues, TImovelSchema } from '../../_schemas/TImovelSchema';
|
||||
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
|
||||
import { Select } from '@/components/ui/select';
|
||||
import { 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 '../../_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';
|
||||
|
||||
type FormValues = z.infer<typeof TImovelSchema>;
|
||||
export default function TImovelForm({ isOpen, data, onClose, onSave, buttonIsLoading }: TImovelFormProps) {
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
const { gTBBairro, fetchGTBBairro } = useGTBBairroReadHook();
|
||||
|
||||
export default function TCensecForm({ isOpen, data, onClose, onSave, buttonIsLoading }: Props) {
|
||||
// Inicializa o react-hook-form com schema zod
|
||||
const form = useForm<FormValues>({
|
||||
const form = useForm<TImovelFormValues>({
|
||||
resolver: zodResolver(TImovelSchema),
|
||||
defaultValues: {},
|
||||
});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
if (data) form.reset(data);
|
||||
|
||||
// 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 (
|
||||
|
|
@ -77,200 +90,270 @@ export default function TCensecForm({ isOpen, data, onClose, onSave, buttonIsLoa
|
|||
{/* Tabs */}
|
||||
<Tabs defaultValue="dadosDoImovel" className="space-y-4">
|
||||
<TabsList className="flex w-full">
|
||||
<TabsTrigger className="flex-1 text-center" value="dadosDoImovel">
|
||||
<UserIcon className="me-1 inline" />
|
||||
<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" value="unidades">
|
||||
<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 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{/* Tipo Classe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_classe"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Classe</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o tipo de classe" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Tipo Registro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_registro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Tipo Registro</FormLabel>
|
||||
<FormControl>
|
||||
<Select {...field}>
|
||||
<option value="M">Matrícula</option>
|
||||
<option value="T">Transcrição</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o número" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número Letra */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero_letra"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número Letra</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a letra" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cidade */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cidade"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cidade</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a cidade" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
{/* UF */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="uf"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UF</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="UF" maxLength={2} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Bairro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tb_bairro_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bairro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o ID do bairro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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 */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cep"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CEP</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o CEP" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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 */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cartorio"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cartório</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o cartório" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Livro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="livro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Livro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o livro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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 */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cns"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CNS</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o CNS" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* GTB Descrição */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="gtb_descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>GTB Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a descrição" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div 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 */}
|
||||
|
|
@ -286,7 +369,6 @@ export default function TCensecForm({ isOpen, data, onClose, onSave, buttonIsLoa
|
|||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Aguarde..."
|
||||
|
|
@ -301,4 +383,4 @@ export default function TCensecForm({ isOpen, data, onClose, onSave, buttonIsLoa
|
|||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export interface TImovelFormProps {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import TImovelColumns from './TImovelColumns';
|
|||
import TImovelInterface from '../../_interfaces/TImovelInterface';
|
||||
|
||||
interface TImovelTableProps {
|
||||
data: TImovelInterface[];
|
||||
data?: TImovelInterface[];
|
||||
onEdit: (item: TImovelInterface, isEditingFormStatus: boolean) => void;
|
||||
onDelete: (item: TImovelInterface, isEditingFormStatus: boolean) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,30 @@ export default function TImovelUnidadeColumns(
|
|||
accessorKey: "imovel_unidade_id",
|
||||
header: ({ column }) => SortableHeader("#", column),
|
||||
cell: ({ row }) => Number(row.getValue("imovel_unidade_id")),
|
||||
enableSorting: false,
|
||||
},
|
||||
// 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
|
|
@ -25,34 +23,50 @@ import {
|
|||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { TImovelSchema } from '../../_schemas/TImovelSchema';
|
||||
import LoadingButton from '@/app/_components/loadingButton/LoadingButton';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
|
||||
import { Select } from '@/components/ui/select';
|
||||
import { TImovelUnidadeFormValues, TImovelUnidadeSchema } from '../../_schemas/TImovelUnidadeSchema';
|
||||
import TImovelUnidadeProps from './TImovelUnidadeFormProps';
|
||||
import { useGTBTipoLogradouroReadHook } from '../../_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';
|
||||
|
||||
type FormValues = z.infer<typeof TImovelSchema>;
|
||||
export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, buttonIsLoading }: TImovelUnidadeProps) {
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
const { gTBTipoLogradouro, fetchGTBTipoLogradouro } = useGTBTipoLogradouroReadHook();
|
||||
|
||||
export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, buttonIsLoading }: Props) {
|
||||
// Inicializa o react-hook-form com schema zod
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(TImovelSchema),
|
||||
defaultValues: {},
|
||||
const form = useForm<TImovelUnidadeFormValues>({
|
||||
resolver: zodResolver(TImovelUnidadeSchema),
|
||||
defaultValues: {
|
||||
imovel_id: 1,
|
||||
},
|
||||
});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
if (data) form.reset(data);
|
||||
|
||||
// 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 (
|
||||
|
|
@ -62,224 +76,450 @@ export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, butt
|
|||
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">
|
||||
<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>
|
||||
Imóvel Urbano
|
||||
Unidades do Imóvel
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Cadastro de imóvel urbano
|
||||
Cadastro de unidades do imóvel
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
|
||||
{/* Tabs */}
|
||||
<Tabs defaultValue="dadosDoImovel" className="space-y-4">
|
||||
<TabsList className="flex w-full">
|
||||
<TabsTrigger className="flex-1 text-center" value="dadosDoImovel">
|
||||
<UserIcon className="me-1 inline" />
|
||||
Dados do Imóvel
|
||||
</TabsTrigger>
|
||||
<TabsTrigger className="flex-1 text-center" value="unidades">
|
||||
<IdCardIcon className="inline" />
|
||||
Unidades
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* Dados do Imóvel */}
|
||||
<TabsContent value="dadosDoImovel" className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{/* Tipo Classe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_classe"
|
||||
render={({ field }) => (
|
||||
<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 Classe</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o tipo de classe" />
|
||||
</FormControl>
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Tipo Registro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_registro"
|
||||
render={({ field }) => (
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</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 Registro</FormLabel>
|
||||
<FormControl>
|
||||
<Select {...field}>
|
||||
<option value="M">Matrícula</option>
|
||||
<option value="T">Transcrição</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero"
|
||||
render={({ field }) => (
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</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>Número</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o número" />
|
||||
</FormControl>
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Número Letra */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="numero_letra"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Número Letra</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a letra" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cidade */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cidade"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cidade</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a cidade" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* UF */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="uf"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UF</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="UF" maxLength={2} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Bairro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tb_bairro_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bairro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o ID do bairro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CEP */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cep"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CEP</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o CEP" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Cartório */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cartorio"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cartório</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o cartório" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Livro */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="livro"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Livro</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o livro" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* CNS */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cns"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CNS</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="Digite o CNS" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* GTB Descrição */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="gtb_descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>GTB Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite a descrição" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Unidades */}
|
||||
<TabsContent value="unidades" className="space-y-4">
|
||||
{/* Conteúdo das unidades */}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</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>
|
||||
|
|
@ -287,7 +527,6 @@ export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, butt
|
|||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Aguarde..."
|
||||
|
|
@ -295,8 +534,8 @@ export default function TImovelUnidadeForm({ isOpen, data, onClose, onSave, butt
|
|||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
|
||||
{/* Campo oculto */}
|
||||
<input type="hidden" {...form.register("imovel_unidade_id")} />
|
||||
<input type="hidden" {...form.register("imovel_id")} />
|
||||
</form>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -20,8 +20,8 @@ export default function TImovelUnidadeTable({ data, onEdit, onDelete }: TImovelU
|
|||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="numero"
|
||||
filterPlaceholder="Buscar pelo numero de transcrição, matricula etc..."
|
||||
filterColumn="numero_unidade"
|
||||
filterPlaceholder="Busque pelo numero da unidade"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -716,7 +716,6 @@ export default function TCensecForm({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Número */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-5">
|
||||
<FormField
|
||||
|
|
@ -733,7 +732,6 @@ export default function TCensecForm({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* CPF */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
|
|
@ -750,7 +748,6 @@ export default function TCensecForm({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Órgão Emissor */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
|
|
@ -771,7 +768,6 @@ export default function TCensecForm({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* UF */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-2">
|
||||
<FormField
|
||||
|
|
@ -788,7 +784,6 @@ export default function TCensecForm({
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Data de Expedição */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-3">
|
||||
<FormField
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ 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',
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ import { TImovelIndexData } from '../../_data/TImovel/TImovelIndexData';
|
|||
export const useTImovelIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<
|
||||
TImovelInterface[] | null
|
||||
>(null);
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface[]>();
|
||||
|
||||
const indexTImovel = async () => {
|
||||
const response = await TImovelIndexData();
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ export const useTImovelUnidadeIndexHook = () => {
|
|||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovelUnidade, setTImovelUnidade] = useState<
|
||||
TImovelUnidadeInterface[] | null
|
||||
>(null);
|
||||
TImovelUnidadeInterface[]>();
|
||||
|
||||
const indexTImovelUnidade = async () => {
|
||||
const response = await TImovelUnidadeIndexData();
|
||||
|
|
|
|||
|
|
@ -30,4 +30,5 @@ export const useTImovelUnidadeSaveHook = () => {
|
|||
};
|
||||
|
||||
return { tImovelUnidade, saveTImovelUnidade };
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export default interface TImovelUnidadeInterface {
|
|||
caracteristica?: string;
|
||||
reserva_florestal?: string;
|
||||
geo_referenciamento?: string;
|
||||
logradouro?: string;
|
||||
logradouro: string;
|
||||
tb_tipologradouro_id?: number;
|
||||
selecionado?: string;
|
||||
complemento?: string;
|
||||
|
|
|
|||
|
|
@ -1,17 +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,
|
||||
});
|
||||
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>;
|
||||
|
|
@ -13,7 +13,7 @@ export const TImovelUnidadeSchema = z.object({
|
|||
caracteristica: z.string().optional(),
|
||||
reserva_florestal: z.string().optional(),
|
||||
geo_referenciamento: z.string().optional(),
|
||||
logradouro: 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(),
|
||||
|
|
@ -36,4 +36,7 @@ export const TImovelUnidadeSchema = z.object({
|
|||
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>;
|
||||
|
|
@ -216,6 +216,7 @@ export function DataTable<TData>({
|
|||
onClick={() => table.setPageIndex(0)}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
aria-label="Primeira página"
|
||||
className='cursor-pointer'
|
||||
>
|
||||
Primeira
|
||||
</Button>
|
||||
|
|
@ -225,6 +226,7 @@ export function DataTable<TData>({
|
|||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
aria-label="Página anterior"
|
||||
className='cursor-pointer'
|
||||
>
|
||||
<ChevronLeftIcon className="h-4 w-4" />
|
||||
Anterior
|
||||
|
|
@ -235,6 +237,7 @@ export function DataTable<TData>({
|
|||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
aria-label="Próxima página"
|
||||
className='cursor-pointer'
|
||||
>
|
||||
Próxima
|
||||
<ChevronRightIcon className="h-4 w-4" />
|
||||
|
|
@ -245,6 +248,7 @@ export function DataTable<TData>({
|
|||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||
disabled={!table.getCanNextPage()}
|
||||
aria-label="Última página"
|
||||
className='cursor-pointer'
|
||||
>
|
||||
Última
|
||||
</Button>
|
||||
|
|
|
|||
5
src/enums/ImovelConstrucaoEnum.ts
Normal file
5
src/enums/ImovelConstrucaoEnum.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const ImovelConstrucaoEnum: { [key: number]: string } = {
|
||||
0: 'Construção averbada',
|
||||
1: 'Em construção',
|
||||
2: 'Não se aplica',
|
||||
};
|
||||
4
src/enums/ImovelTipoClasseEnum.ts
Normal file
4
src/enums/ImovelTipoClasseEnum.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export const ImovelTipoClasseEnum: { [key: number]: string } = {
|
||||
1: 'Urbano',
|
||||
3: 'Rural',
|
||||
};
|
||||
22
src/enums/ImovelTipoEnum.ts
Normal file
22
src/enums/ImovelTipoEnum.ts
Normal 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'
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
export enum ImovelTipoRegistro {
|
||||
M = 'Matrícula',
|
||||
T = 'Transcrição'
|
||||
T = 'Transcrição',
|
||||
I = 'Inscrição',
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue