Merge branch 'MVPTN-76' into release(MVP)

This commit is contained in:
Keven Willian Pereira de Souza 2025-09-22 15:40:26 -03:00
commit bc61cb8fde
50 changed files with 1933 additions and 20 deletions

71
package-lock.json generated
View file

@ -22,6 +22,7 @@
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tooltip": "^1.2.8",
"@tinymce/tinymce-react": "^6.3.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cookies-next": "^6.1.0",
@ -37,6 +38,7 @@
"react-hook-form": "^7.62.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tinymce": "^8.1.2",
"zod": "^4.0.17"
},
"devDependencies": {
@ -1952,6 +1954,25 @@
"tailwindcss": "4.1.12"
}
},
"node_modules/@tinymce/tinymce-react": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/@tinymce/tinymce-react/-/tinymce-react-6.3.0.tgz",
"integrity": "sha512-E++xnn0XzDzpKr40jno2Kj7umfAE6XfINZULEBBeNjTMvbACWzA6CjiR6V8eTDc9yVmdVhIPqVzV4PqD5TZ/4g==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0",
"react-dom": "^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0",
"tinymce": "^8.0.0 || ^7.0.0 || ^6.0.0 || ^5.5.1"
},
"peerDependenciesMeta": {
"tinymce": {
"optional": true
}
}
},
"node_modules/@types/js-cookie": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz",
@ -2234,6 +2255,12 @@
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
"node_modules/js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
@ -2576,6 +2603,18 @@
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lucide-react": {
"version": "0.540.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.540.0.tgz",
@ -2748,6 +2787,15 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -2783,6 +2831,17 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/react": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
@ -2820,6 +2879,12 @@
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/react-remove-scroll": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
@ -3067,6 +3132,12 @@
"node": ">=18"
}
},
"node_modules/tinymce": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-8.1.2.tgz",
"integrity": "sha512-KITxHEEHRlxC5xOnxA123eAJ67NgsWxNphtItWt9TRu07DiTZrWIqJeIKRX9euE51/l3kJO4WQiqoBXKTJJGsA==",
"license": "GPL-2.0-or-later"
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",

View file

@ -23,6 +23,7 @@
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tooltip": "^1.2.8",
"@tinymce/tinymce-react": "^6.3.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cookies-next": "^6.1.0",
@ -38,6 +39,7 @@
"react-hook-form": "^7.62.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tinymce": "^8.1.2",
"zod": "^4.0.17"
},
"devDependencies": {

View file

@ -22,6 +22,7 @@ export default function UsuarioDetalhes() {
if (params.id) {
fetchUsuario({ usuario_id: Number(params.id) } as Usuario);
}
console.log("pagina",usuario)
}, []);
if (!usuario) return <Loading type={1} />;

View file

@ -14,6 +14,7 @@ export const useGUsuarioReadHooks = () => {
const fetchUsuario = async (Usuario: Usuario) => {
const response = await GUsuarioRead(Usuario.usuario_id);
console.log("hook",response.data)
setUsuario(response.data);

View file

@ -12,6 +12,14 @@ export default async function GUsuarioRead(usuarioId: number) {
}
}
return await GUsuarioReadData(usuarioId);
try {
const response = await GUsuarioReadData(usuarioId);
console.log("service",response)
return response
} catch (error) {
console.log(error)
return error
}
}

View file

@ -0,0 +1,134 @@
'use client';
import { useEffect, useState, useCallback } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog";
import Header from "@/app/_components/structure/Header";
import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog";
import Loading from "@/app/_components/loading/loading";
import TCensecNaturezaLitigioTable from "../../_components/t_censecnaturezalitigio/TCensecNaturezaLitigioTable";
import TCensecNaturezaLitigioForm from "../../_components/t_censecnaturezalitigio/TCensecNaturezaLitigioForm";
import { useTCensecNaturezaLitigioReadHook } from "../../_hooks/t_censecnaturezalitigio/useTCensecNaturezaLitigioReadHook";
import { useTCensecNaturezaLitigioSaveHook } from "../../_hooks/t_censecnaturezalitigio/useTCensecNaturezaLitigioSaveHook";
import { useTCensecNaturezaLitigioRemoveHook } from "../../_hooks/t_censecnaturezalitigio/useTCensecNaturezaLitigioRemoveHook";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
const initialCensecNaturezaLitigio: TCensecNaturezaLitigioInterface = {
censec_naturezalitigio_id: 0,
descricao: "",
situacao: 'A'
}
export default function TCensecNaturezaLitigioPage() {
// Hooks
const { tCensecNaturezaLitigio, fetchTCensecNaturezaLitigio } = useTCensecNaturezaLitigioReadHook();
const { saveTCensecNaturezaLitigio } = useTCensecNaturezaLitigioSaveHook();
const { removeTCensecNaturezaLitigio } = useTCensecNaturezaLitigioRemoveHook();
// Estados
const [selectedItem, setSelectedItem] = useState<TCensecNaturezaLitigioInterface | null>(null);
const [isFormOpen, setIsFormOpen] = useState(false);
const [itemToDelete, setItemToDelete] = useState<TCensecNaturezaLitigioInterface | null>(null);
// Modal de confirmação
const {
isOpen: isConfirmOpen,
openDialog: openConfirmDialog,
handleConfirm,
handleCancel,
} = useConfirmDialog();
// Abrir formulário (criação ou edição)
const handleOpenForm = useCallback((item: TCensecNaturezaLitigioInterface | null) => {
setSelectedItem(item);
setIsFormOpen(true);
}, []);
// Fechar formulário
const handleCloseForm = useCallback(() => {
setSelectedItem(null);
setIsFormOpen(false);
}, []);
// Salvar item
const handleSave = useCallback(async (formData: TCensecNaturezaLitigioInterface) => {
await saveTCensecNaturezaLitigio(formData);
console.log(formData)
await fetchTCensecNaturezaLitigio();
}, [saveTCensecNaturezaLitigio, fetchTCensecNaturezaLitigio]);
// Confirmar remoção
const handleConfirmDelete = useCallback((item: TCensecNaturezaLitigioInterface) => {
console.log("item", item)
setItemToDelete(item);
openConfirmDialog();
}, [openConfirmDialog]);
// Executar remoção
const handleDelete = useCallback(async () => {
if (!itemToDelete) return;
console.log("item to delete",itemToDelete)
await removeTCensecNaturezaLitigio(itemToDelete);
await fetchTCensecNaturezaLitigio();
setItemToDelete(null);
handleCancel();
}, [itemToDelete, fetchTCensecNaturezaLitigio, handleCancel]);
// Fetch inicial
useEffect(() => {
fetchTCensecNaturezaLitigio();
}, []);
// Loading enquanto carrega
if (!tCensecNaturezaLitigio) {
return <Loading type={2} />;
}
return (
<div>
{/* Cabeçalho */}
<Header
title={"Natureza do Litígio"}
description={"Gerenciamento de Naturezas do Litígio"}
buttonText={"Nova Natureza"}
buttonAction={(data) => handleOpenForm(data = initialCensecNaturezaLitigio)}
/>
{/* Tabela */}
<Card>
<CardContent>
<TCensecNaturezaLitigioTable
data={tCensecNaturezaLitigio}
onEdit={handleOpenForm}
onDelete={handleConfirmDelete}
/>
</CardContent>
</Card>
{/* Modal de confirmação */}
<ConfirmDialog
isOpen={isConfirmOpen}
title="Confirmar exclusão"
description="Atenção"
message={`Deseja realmente excluir a natureza "${itemToDelete?.descricao}"?`}
confirmText="Sim, excluir"
cancelText="Cancelar"
onConfirm={handleDelete}
onCancel={handleCancel}
/>
{/* Formulário */}
<TCensecNaturezaLitigioForm
isOpen={isFormOpen}
data={selectedItem}
onClose={handleCloseForm}
onSave={handleSave}
/>
</div>
);
}

View file

@ -0,0 +1,83 @@
'use client'
import { useEffect, useState } from "react";
import { useParams } from "next/navigation";
import {
Card,
CardContent
} from "@/components/ui/card";
import MainEditor from "@/components/MainEditor";
import Loading from "@/app/_components/loading/loading";
import { useTMinutaReadHook } from '../../../../_hooks/t_minuta/useTMinutaReadHook';
import { TMinutaInterface } from '../../../../_interfaces/TMinutaInterface';
export default function TMinutaDetalhes() {
const params = useParams();
const { tMinuta, fetchTMinuta } = useTMinutaReadHook();
const [editorContent, setEditorContent] = useState<string | null>(null); // Inicialmente nulo até o texto ser carregado
useEffect(() => {
if (params.id) {
fetchTMinuta({ t_minuta_id: Number(params.id) } as TMinutaInterface);
}
}, []);
useEffect(() => {
if (tMinuta?.texto) {
setEditorContent(tMinuta.texto); // Atualiza o conteúdo assim que estiver disponível
}
}, [tMinuta]); // Dependência de `tMinuta` para que a atualização aconteça quando os dados chegarem
const handleEditorChange = (content: string) => {
setEditorContent(content); // Atualiza o estado com o conteúdo do editor
};
if (!tMinuta) return <Loading type={1} />;
// Renderiza o editor apenas se o texto foi carregado
if (editorContent === null) {
return <Loading type={1} />; // Pode mostrar um carregando ou qualquer outra coisa enquanto o conteúdo não está disponível
}
return (
<div>
<Card>
<CardContent>
<div className="mb-4 grid gap-4 grid-cols-2">
<div>
<div className="text-2xl font-semibold">
Descrição
</div>
<div className="text-xl">
{tMinuta.descricao}
</div>
</div>
<div>
<div className="text-2xl font-semibold">
Situação
</div>
<div className="text-xl">
{tMinuta.situacao === "A" ? "Ativo" : "Inativo"}
</div>
</div>
<div className="col-span-2">
<div className="text-2xl font-semibold">
Texto
</div>
<MainEditor
initialValue={editorContent} // Passa o conteúdo do editor
onEditorChange={handleEditorChange} // Função que atualiza o estado
margins={{
top: "2", bottom: "2", left: "2", right: "2"
}}
size={{ width: 794, height: 1123 }} // Você pode ajustar o tamanho aqui
/>
</div>
</div>
</CardContent>
</Card>
</div>
);
}

View file

@ -0,0 +1,113 @@
'use client';
import z from 'zod';
import { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import MainEditor from '@/components/MainEditor';
import { TMinutaSchema } from '../../../_schemas/TMinutaSchema';
import { useTMinutaSaveHook } from '../../../_hooks/t_minuta/useTMinutaSaveHook';
import { Card, CardContent } from '@/components/ui/card';
type FormValues = z.infer<typeof TMinutaSchema>;
export default function TMinutaForm() {
const { tMinuta, saveTMinuta } = useTMinutaSaveHook();
const form = useForm<FormValues>({
resolver: zodResolver(TMinutaSchema),
defaultValues: {
natureza_id: undefined,
descricao: '',
situacao: 'A',
texto: '',
}
});
async function onSubmit(values: FormValues) {
saveTMinuta(values);
}
return (
<div>
<Card>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
{/* Descrição */}
<FormField
control={form.control}
name="descricao"
render={({ field }) => (
<FormItem>
<FormLabel>Descrição</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a descrição da minuta" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Situação */}
<Controller
name="situacao"
control={form.control}
render={({ field }) => (
<div className="flex items-center space-x-2">
<Checkbox
checked={field.value === "A"}
onCheckedChange={(checked) => field.onChange(checked ? "A" : "I")}
/>
<Label>{field.value === "A" ? "Ativo" : "Inativo"}</Label>
</div>
)}
/>
{/* Editor de Texto */}
<Controller
name="texto"
control={form.control}
render={({ field }) => (
<div>
<MainEditor
initialValue={field.value || ""}
onEditorChange={field.onChange}
margins={{ top: '0', bottom: '0', left: '0', right: '0' }}
size={{ width: 794, height: 1123 }}
/>
{form.formState.errors.texto && (
<p className="text-sm text-red-500 mt-2">
{form.formState.errors.texto.message}
</p>
)}
</div>
)}
/>
<Button type="submit">
Salvar
</Button>
</form>
</Form>
</CardContent>
</Card>
</div>
);
}

View file

@ -0,0 +1,107 @@
'use client';
import { useEffect, useState, useCallback } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { useConfirmDialog } from "@/app/_components/confirm_dialog/useConfirmDialog";
import Header from "@/app/_components/structure/Header";
import ConfirmDialog from "@/app/_components/confirm_dialog/ConfirmDialog";
import Loading from "@/app/_components/loading/loading";
import TMinutaTable from "../../_components/t_minuta/TMinutaTable";
import TMinutaForm from "../../_components/t_minuta/TMinutaForm";
import { useTMinutaReadHook } from "../../_hooks/t_minuta/useTMinutaReadHook";
import { useTMinutaSaveHook } from "../../_hooks/t_minuta/useTMinutaSaveHook";
import { useTMinutaRemoveHook } from "../../_hooks/t_minuta/useTMinutaRemoveHook";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import { useTMinutaIndexHook } from "../../_hooks/t_minuta/useTMinutaIndexHook";
export default function TMinutaPage() {
// Hooks de leitura e escrita
const { tMinuta, fetchTMinuta } = useTMinutaIndexHook();
const { saveTMinuta } = useTMinutaSaveHook();
const { removeTMinuta } = useTMinutaRemoveHook();
// Estados
const [selectedMinuta, setSelectedMinuta] = useState<TMinutaInterface | null>(null);
const [isFormOpen, setIsFormOpen] = useState(false);
const [itemToDelete, setItemToDelete] = useState<TMinutaInterface | null>(null);
// Hook de confirmação
const {
isOpen: isConfirmOpen,
openDialog: openConfirmDialog,
handleConfirm,
handleCancel
} = useConfirmDialog();
// Abertura do formulário
const handleOpenForm = useCallback((data: TMinutaInterface | null) => {
setSelectedMinuta(data);
setIsFormOpen(true);
}, []);
// Ação de clique em remover
const handleConfirmDelete = useCallback((item: TMinutaInterface) => {
setItemToDelete(item);
openConfirmDialog();
}, [openConfirmDialog]);
// Remoção da minuta após confirmação
const handleDelete = useCallback(async () => {
if (!itemToDelete) return;
await removeTMinuta(itemToDelete);
await fetchTMinuta();
setItemToDelete(null);
handleCancel();
}, [itemToDelete, removeTMinuta, fetchTMinuta, handleCancel]);
// Fetch inicial
useEffect(() => {
fetchTMinuta();
}, []);
// Loading enquanto carrega
if (tMinuta === undefined) {
return <Loading type={2} />;
}
return (
<div>
{/* Cabeçalho */}
<Header
title="Minutas"
description="Gerenciamento de minutas de atos notariais"
buttonText="Nova Minuta"
buttonAction={() => handleOpenForm(null)}
/>
{/* Tabela */}
<Card>
<CardContent>
<TMinutaTable
data={tMinuta}
onEdit={handleOpenForm}
onDelete={handleConfirmDelete}
/>
</CardContent>
</Card>
{/* Diálogo de confirmação */}
<ConfirmDialog
isOpen={isConfirmOpen}
title="Confirmar exclusão"
description="Atenção"
message={`Deseja realmente excluir a minuta "${itemToDelete?.descricao}"?`}
confirmText="Sim, excluir"
cancelText="Cancelar"
onConfirm={handleDelete}
onCancel={handleCancel}
/>
</div>
);
}

View file

@ -63,7 +63,7 @@ export default function TTBAndamentoServico() {
// Aguarda salvar o registro
await saveTTBAndamentoServico(formData);
// Atualiza a lista de dados
fetchTTBAndamentoServico();
@ -73,13 +73,8 @@ export default function TTBAndamentoServico() {
* Quando o usuário clica em "remover" na tabela
*/
const handleConfirmDelete = useCallback((item: TTBAndamentoServicoInterface) => {
// Define o item atual para remoção
setItemToDelete(item);
// Abre o modal de confirmação
openConfirmDialog();
}, [openConfirmDialog]);
/**
@ -90,6 +85,7 @@ export default function TTBAndamentoServico() {
// Protege contra null
if (!itemToDelete) return;
// Executa o Hook de remoção
await deleteTTBAndamentoServico(itemToDelete);

View file

@ -0,0 +1,128 @@
'use client';
import z from 'zod';
import { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { TCensecNaturezaLitigioSchema } from '../../_schemas/TCensecNaturezaLitigioSchema';
type FormValues = z.infer<typeof TCensecNaturezaLitigioSchema>;
interface TCensecNaturezaLitigioFormProps {
isOpen: boolean;
data: FormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: FormValues) => void;
}
export default function TCensecNaturezaLitigioForm({
isOpen,
data,
onClose,
onSave
}: TCensecNaturezaLitigioFormProps) {
const form = useForm<FormValues>({
resolver: zodResolver(TCensecNaturezaLitigioSchema),
defaultValues: {
censec_naturezalitigio_id: 0,
descricao: "",
situacao: "A"
}
});
useEffect(() => {
if (data) form.reset(data);
}, [data, form]);
return (
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) onClose(null, false);
}}
>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Natureza do Litígio</DialogTitle>
<DialogDescription>
Crie ou edite uma natureza do litígio
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Descrição */}
<FormField
control={form.control}
name="descricao"
render={({ field }) => (
<FormItem>
<FormLabel>Descrição</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a descrição" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Situação */}
<Controller
name="situacao"
control={form.control}
render={({ field }) => (
<div className="flex items-center space-x-2">
<Checkbox
checked={field.value === "A"}
onCheckedChange={(checked) => field.onChange(checked ? "A" : "I")}
/>
<Label>Ativo</Label>
</div>
)}
/>
{/* Rodapé */}
<DialogFooter className="mt-4">
<DialogClose asChild>
<Button variant="outline" type="button" onClick={() => onClose(null, false)}>
Cancelar
</Button>
</DialogClose>
<Button type="submit">
Salvar
</Button>
</DialogFooter>
{/* Campo oculto */}
<input type="hidden" {...form.register('censec_naturezalitigio_id')} />
</form>
</Form>
</DialogContent>
</Dialog>
);
}

View file

@ -0,0 +1,123 @@
'use client';
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from "@/components/ui/dropdown-menu";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from "@/components/ui/table";
import { EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
interface TCensecNaturezaLitigioTableProps {
data: TCensecNaturezaLitigioInterface[];
onEdit: (item: TCensecNaturezaLitigioInterface, isEditingFormStatus: boolean) => void;
onDelete: (item: TCensecNaturezaLitigioInterface, isEditingFormStatus: boolean) => void;
}
/**
* Renderiza o badge de situação
*/
function StatusBadge({ situacao }: { situacao: 'A' | 'I' }) {
const isActive = situacao === 'A';
const baseClasses =
"text-xs font-medium px-2.5 py-0.5 rounded-sm me-2";
const activeClasses =
"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300";
const inactiveClasses =
"bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300";
return (
<span className={`${baseClasses} ${isActive ? activeClasses : inactiveClasses}`}>
{isActive ? "Ativo" : "Inativo"}
</span>
);
}
export default function TCensecNaturezaLitigioTable({
data,
onEdit,
onDelete
}: TCensecNaturezaLitigioTableProps) {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>#</TableHead>
<TableHead>Situação</TableHead>
<TableHead>Descrição</TableHead>
<TableHead className="text-right">Ações</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((item) => (
<TableRow
key={item.censec_naturezalitigio_id}
className="cursor-pointer"
>
<TableCell className="font-medium">
{item.censec_naturezalitigio_id}
</TableCell>
<TableCell>
<StatusBadge situacao={item.situacao} />
</TableCell>
<TableCell>{item.descricao}</TableCell>
<TableCell className="text-right">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="icon"
className="cursor-pointer"
>
<EllipsisIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="left" align="start">
<DropdownMenuGroup>
<DropdownMenuItem
className="cursor-pointer"
onSelect={() => onEdit(item, true)}
>
<PencilIcon className="mr-2 h-4 w-4" />
Editar
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="cursor-pointer"
onSelect={() => onDelete(item, true)}
>
<Trash2Icon className="mr-2 h-4 w-4" />
Remover
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}

View file

@ -0,0 +1,155 @@
'use client';
import z from 'zod';
import { useEffect } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import MainEditor from '@/components/MainEditor';
import { TMinutaInterface } from '../../_interfaces/TMinutaInterface';
import { TMinutaSchema } from '../../_schemas/TMinutaSchema';
type FormValues = z.infer<typeof TMinutaSchema>;
interface TMinutaFormProps {
isOpen: boolean;
data: FormValues | null;
onClose: (item: null, isFormStatus: boolean) => void;
onSave: (data: FormValues) => void;
}
export default function TMinutaForm({
isOpen,
data,
onClose,
onSave
}: TMinutaFormProps) {
const form = useForm<FormValues>({
resolver: zodResolver(TMinutaSchema),
defaultValues: {
t_minuta_id: 0,
natureza_id: undefined,
descricao: '',
situacao: 'A',
texto: '',
}
});
useEffect(() => {
if (data) form.reset(data);
}, [data, form]);
return (
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) onClose(null, false);
}}
>
<DialogContent className="mx-auto"> {/* tamanho maior para comportar o editor */}
<DialogHeader>
<DialogTitle>Minuta</DialogTitle>
<DialogDescription>
Crie ou edite uma minuta de ato notarial.
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="space-y-6">
{/* Descrição */}
<FormField
control={form.control}
name="descricao"
render={({ field }) => (
<FormItem>
<FormLabel>Descrição</FormLabel>
<FormControl>
<Input {...field} placeholder="Digite a descrição da minuta" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Situação */}
<Controller
name="situacao"
control={form.control}
render={({ field }) => (
<div className="flex items-center space-x-2">
<Checkbox
checked={field.value === "A"}
onCheckedChange={(checked) => field.onChange(checked ? "A" : "I")}
/>
<Label>{field.value === "A" ? "Ativo" : "Inativo"}</Label>
</div>
)}
/>
{/* Editor de Texto */}
<Controller
name="texto"
control={form.control}
render={({ field }) => (
<div>
<MainEditor
initialValue={field.value || ""}
onEditorChange={field.onChange}
margins={{ top: '2', bottom: '2', left: '3', right: '3' }}
size={{ width: 800, height: 500 }}
/>
{form.formState.errors.texto && (
<p className="text-sm text-red-500 mt-2">
{form.formState.errors.texto.message}
</p>
)}
</div>
)}
/>
{/* Rodapé do Dialog */}
<DialogFooter className="mt-4">
<DialogClose asChild>
<Button variant="outline" type="button" onClick={() => onClose(null, false)}>
Cancelar
</Button>
</DialogClose>
<Button type="submit" disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? "Salvando..." : "Salvar"}
</Button>
</DialogFooter>
{/* Campos ocultos */}
<input type="hidden" {...form.register("t_minuta_id")} />
<input type="hidden" {...form.register("natureza_id")} />
</form>
</Form>
</DialogContent>
</Dialog>
);
}

View file

@ -0,0 +1,97 @@
'use client';
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
interface TMinutaTableProps {
data: TMinutaInterface[];
onEdit: (item: TMinutaInterface, isEditing: boolean) => void;
onDelete: (item: TMinutaInterface, isEditing: boolean) => void;
}
/**
* Renderiza o badge de situação
*/
function StatusBadge({ situacao }: { situacao: 'A' | 'I' }) {
const isActive = situacao === "A";
const baseClasses = "text-xs font-medium px-2.5 py-0.5 rounded-sm mr-2";
const activeClasses =
"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300";
const inactiveClasses =
"bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300";
return (
<span className={`${baseClasses} ${isActive ? activeClasses : inactiveClasses}`}>
{isActive ? "Ativo" : "Inativo"}
</span>
);
}
export default function TMinutaTable({
data,
}: TMinutaTableProps) {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>#</TableHead>
<TableHead>Situação</TableHead>
<TableHead>Descrição</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.length === 0 ? (
<TableRow>
<TableCell colSpan={4} className="text-center text-muted-foreground">
Nenhuma minuta encontrada.
</TableCell>
</TableRow>
) : (
data.map((item) => (
<TableRow key={item.t_minuta_id} className="cursor-pointer">
<TableCell className="font-medium">
{item.t_minuta_id}
</TableCell>
<TableCell>
<StatusBadge situacao={item.situacao} />
</TableCell>
<TableCell>{item.descricao}</TableCell>
<TableCell className="text-right">
<Button asChild>
<Link href={`/cadastros/minuta/${item.t_minuta_id}/detalhes`}>
Detalhes
</Link>
</Button>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
);
}

View file

@ -2,7 +2,7 @@ import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
import BairroMockDeDados from "./mockBairro";
const useMock = true
const useMock = false
export default async function GTBBairroIndexData() {
if (useMock) {

View file

@ -2,7 +2,7 @@ import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
import TipoLogradouroMockDeDados from "./mockTipoLogradouro";
const useMock = true
const useMock = false
export default async function GTBTipoLogradouroIndexData() {
if (useMock) {

View file

@ -0,0 +1,25 @@
import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
import CensecNaturezaLitigioMockDeDados from "./mockCensecNaturezaLitigio";
const useMock = false
export default async function TCensecNaturezaLitigioIndexData() {
if (useMock) {
return await CensecNaturezaLitigioMockDeDados();
}
const api = new API();
try {
const dados = await api.send({
method: Methods.GET,
endpoint: `administrativo/t_censec_naturezalitigio/`
});
return dados
} catch (error) {
console.log(error)
return error
}
}

View file

@ -0,0 +1,16 @@
import API from "@/services/api/Api";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
export default async function TCensecNaturezaLitigioRemoveData(data: TCensecNaturezaLitigioInterface) {
const api = new API();
console.log(typeof(data.censec_naturezalitigio_id))
return await api.send({
method: Methods.DELETE,
endpoint: `administrativo/t_censec_naturezalitigio/${data.censec_naturezalitigio_id}`
});
}

View file

@ -0,0 +1,15 @@
import API from "@/services/api/Api";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
export default async function TCensecNaturezaLitigioTipoSaveData(data: TCensecNaturezaLitigioInterface) {
const api = new API();
return await api.send({
method: data.censec_naturezalitigio_id ? Methods.PUT : Methods.POST,
endpoint: `administrativo/t_censec_naturezalitigio/${data.censec_naturezalitigio_id ? data.censec_naturezalitigio_id : ''}`,
body: data
});
}

View file

@ -0,0 +1,113 @@
export default async function CensecNaturezaLitigioMockDeDados() {
return Promise.resolve({
status: 200,
message: 'Dados localizados',
data: [
{
censec_naturezaltigio_id: 1,
descricao: "Bancário",
situacao: "A"
},
{
censec_naturezaltigio_id: 2,
descricao: "Concessionária de Água",
situacao: "A"
},
{
censec_naturezaltigio_id: 3,
descricao: "Concessionária de Gás",
situacao: "A"
},
{
censec_naturezaltigio_id: 4,
descricao: "Concessionária de Luz",
situacao: "A"
},
{
censec_naturezaltigio_id: 5,
descricao: "Consumidor",
situacao: "A"
},
{
censec_naturezaltigio_id: 6,
descricao: "Contrato",
situacao: "A"
},
{
censec_naturezaltigio_id: 7,
descricao: "Empresarial",
situacao: "A"
},
{
censec_naturezaltigio_id: 8,
descricao: "Família",
situacao: "A"
},
{
censec_naturezaltigio_id: 9,
descricao: "Locação",
situacao: "A"
},
{
censec_naturezaltigio_id: 10,
descricao: "Mobiliário",
situacao: "A"
},
{
censec_naturezaltigio_id: 11,
descricao: "Previdência",
situacao: "A"
},
{
censec_naturezaltigio_id: 12,
descricao: "Saúde",
situacao: "A"
},
{
censec_naturezaltigio_id: 13,
descricao: "Seguro",
situacao: "A"
},
{
censec_naturezaltigio_id: 14,
descricao: "Serviço Público",
situacao: "A"
},
{
censec_naturezaltigio_id: 15,
descricao: "Sucessões",
situacao: "A"
},
{
censec_naturezaltigio_id: 16,
descricao: "Telefonia",
situacao: "A"
},
{
censec_naturezaltigio_id: 17,
descricao: "Transporte",
situacao: "A"
},
{
censec_naturezaltigio_id: 18,
descricao: "Transporte - Avião",
situacao: "A"
},
{
censec_naturezaltigio_id: 19,
descricao: "Transporte - Barco",
situacao: "A"
},
{
censec_naturezaltigio_id: 20,
descricao: "Transporte Metrô",
situacao: "A"
},
{
censec_naturezaltigio_id: 21,
descricao: "Transporte - Ônibus",
situacao: "A"
}
]
});
}

View file

@ -0,0 +1,81 @@
export const textoEscrituraCompraEVenda = `
<p><strong>ESCRITURA PÚBLICA DE COMPRA E VENDA</strong></p>
<p>Saibam quantos este público instrumento virem que, aos [[dia]] dias do mês de [[mes]] do ano de [[ano]], nesta cidade de [[cidade]], Estado de [[estado]], neste Tabelionato de Notas, perante mim, [[tabeliao]], Tabelião de Notas, compareceram como partes entre si, de um lado como <strong>VENDEDOR(ES)</strong>:</p>
<p>[[nome_completo_vendedor]], [[nacionalidade_vendedor]], [[estado_civil_vendedor]], [[profissao_vendedor]], portador da cédula de identidade RG [[rg_vendedor]] e inscrito no CPF/MF sob o [[cpf_vendedor]], residente e domiciliado à [[endereco_vendedor]];</p>
<p>E de outro lado como <strong>COMPRADOR(ES)</strong>:</p>
<p>[[nome_completo_comprador]], [[nacionalidade_comprador]], [[estado_civil_comprador]], [[profissao_comprador]], portador da cédula de identidade RG [[rg_comprador]] e inscrito no CPF/MF sob o [[cpf_comprador]], residente e domiciliado à [[endereco_comprador]];</p>
<p>Entre as partes acima identificadas e qualificadas, justas e contratadas, foi ajustada, e por este público instrumento, lavrado na forma da lei, têm como certo e contratado a presente <strong>ESCRITURA PÚBLICA DE COMPRA E VENDA</strong> do imóvel situado à [[endereco_imovel]], com área de [[area_imovel]]m², registrado sob matrícula [[matricula_imovel]], no [[cartorio_registro]] Registro de Imóveis desta cidade.</p>
<p>O preço certo e ajustado para a presente transação é de R$ [[valor_venda]] ([[valor_extenso]]), que o(s) comprador(es) declara(m) ter pago ao(s) vendedor(es), neste ato, em moeda corrente nacional, dando-lhe(s) plena, geral e irrevogável quitação.</p>
<p>Assim, justos e contratados, requerem seja lavrada a presente escritura, que lida e achada conforme, vai assinada pelas partes e por mim, [[tabeliao]], que a subscrevo.</p>
<p>Dou .</p>
`;
export const textoEscrituraPartilhaAmigavel = `
<p><strong>ESCRITURA PÚBLICA DE PARTILHA AMIGÁVEL</strong></p>
<p>Saibam quantos este público instrumento virem que, aos [[dia]] dias do mês de [[mes]] do ano de [[ano]], nesta cidade de [[cidade]], Estado de [[estado]], neste Tabelionato de Notas, perante mim, [[tabeliao]], Tabelião de Notas, compareceram como partes entre si, de um lado como <strong>HERDEIROS(AS)</strong>:</p>
<p>[[nome_herdeiro_1]], [[nacionalidade_herdeiro_1]], [[estado_civil_herdeiro_1]], [[profissao_herdeiro_1]], portador(a) do RG [[rg_herdeiro_1]] e CPF [[cpf_herdeiro_1]], residente e domiciliado(a) à [[endereco_herdeiro_1]];</p>
<p>[[nome_herdeiro_2]], [[nacionalidade_herdeiro_2]], [[estado_civil_herdeiro_2]], [[profissao_herdeiro_2]], portador(a) do RG [[rg_herdeiro_2]] e CPF [[cpf_herdeiro_2]], residente e domiciliado(a) à [[endereco_herdeiro_2]];</p>
<p>e assim por diante, se houver outros herdeiros.</p>
<p>Declararam os presentes que são únicos e legítimos herdeiros do(a) falecido(a) [[nome_falecido]], falecido(a) em [[data_obito]], na cidade de [[cidade_obito]], conforme certidão de óbito lavrada sob o [[numero_certidao_obito]], e que, por meio desta escritura, realizam entre si a <strong>PARTILHA AMIGÁVEL</strong> dos bens deixados pelo(a) de cujus, na forma seguinte:</p>
<p><strong>Relação dos bens:</strong></p>
<ul>
<li>[[descricao_bem_1]] - avaliado em R$ [[valor_bem_1]];</li>
<li>[[descricao_bem_2]] - avaliado em R$ [[valor_bem_2]];</li>
<li>... (outros bens, se houver)</li>
</ul>
<p><strong>Partilha:</strong></p>
<ul>
<li>Ao(à) herdeiro(a) [[nome_herdeiro_1]] caberá o(s) bem(ns): [[bens_herdeiro_1]];</li>
<li>Ao(à) herdeiro(a) [[nome_herdeiro_2]] caberá o(s) bem(ns): [[bens_herdeiro_2]];</li>
<li>... (demais partilhas, se houver)</li>
</ul>
<p>As partes declaram que a partilha foi realizada de comum acordo, de forma livre e consciente, não havendo vícios de consentimento, nem litígios entre os herdeiros.</p>
<p>Requerem que esta escritura seja registrada onde necessário, e produza todos os efeitos legais.</p>
<p>E por estarem assim justos e contratados, firmam o presente instrumento, que lido e achado conforme, vai por todos assinado e por mim, [[tabeliao]], que o lavrei e subscrevo.</p>
<p>Dou .</p>
`;
export const textoProcuracaoAdJudicia = `
<p><strong>PROCURAÇÃO AD JUDICIA</strong></p>
<p>Outorgante: [[nome_outorgante]], [[nacionalidade_outorgante]], [[estado_civil_outorgante]], [[profissao_outorgante]], portador(a) do RG [[rg_outorgante]] e CPF [[cpf_outorgante]], residente e domiciliado(a) à [[endereco_outorgante]].</p>
<p>Outorgado: [[nome_outorgado]], advogado inscrito na OAB/[[uf_oab]] sob o [[numero_oab]], com escritório profissional situado à [[endereco_escritorio]].</p>
<p>Por este instrumento particular, o outorgante nomeia e constitui seu bastante procurador o(a) outorgado(a), para o foro em geral, com poderes para o ajuizamento, defesa, acompanhamento, transação, conciliação, desistência, interposição e recebimento de recursos, substabelecer no todo ou em parte, e praticar todos os demais atos necessários ao fiel cumprimento deste mandato, especialmente para atuar em processos judiciais e administrativos, em todas as instâncias e tribunais, federais ou estaduais, inclusive para firmar compromisso, receber citações, intimações e notificações, assinar petições, requerimentos e demais documentos, e praticar todos os atos necessários para a defesa dos direitos do outorgante.</p>
<p>Esta procuração é válida por [[validade]] meses a contar da data de sua assinatura.</p>
<p>E, por assim estar justo e acordado, firma o presente instrumento em [[cidade]], aos [[dia]] dias do mês de [[mes]] do ano de [[ano]].</p>
<p>_______________________________</p>
<p>[[nome_outorgante]]</p>
<p>Testemunhas:</p>
<p>1. ___________________________</p>
<p>Nome: [[nome_testemunha_1]] - CPF: [[cpf_testemunha_1]]</p>
<p>2. ___________________________</p>
<p>Nome: [[nome_testemunha_2]] - CPF: [[cpf_testemunha_2]]</p>
`;

View file

@ -0,0 +1,24 @@
import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
import { MinutaMockDeDadosPorId } from "./mockMinuta";
const useMock = true;
export default async function TMinutaIndex(t_minuta_id: number) {
if (useMock) {
console.log(await MinutaMockDeDadosPorId(t_minuta_id)); // Retorna o dado específico do mock
return await MinutaMockDeDadosPorId(t_minuta_id); // Retorna o dado específico do mock
}
const api = new API();
try {
const dados = await api.send({
method: Methods.GET,
endpoint: `administrativo/t_minuta/${t_minuta_id}`
});
return dados;
} catch (error) {
console.log(error);
return error;
}
}

View file

@ -0,0 +1,23 @@
import API from "@/services/api/Api";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
import MinutaMockDeDados from "./mockMinuta";
const useMock = true;
export default async function TMinutaIndexData() {
if (useMock) {
return await MinutaMockDeDados(); // Retorna todos os dados mockados
}
const api = new API();
try {
const dados = await api.send({
method: Methods.GET,
endpoint: `administrativo/t_minuta/`
});
return dados;
} catch (error) {
console.log(error);
return error;
}
}

View file

@ -0,0 +1,14 @@
import API from "@/services/api/Api";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
export default async function TMinutaRemoveData(data: TMinutaInterface) {
const api = new API();
return await api.send({
method: Methods.DELETE,
endpoint: `administrativo/t_minuta/${data.t_minuta_id}`
});
}

View file

@ -0,0 +1,17 @@
import API from "@/services/api/Api";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import { Methods } from "@/services/api/enums/ApiMethodEnum";
export default async function TMinutaSaveData(data: TMinutaInterface) {
const isUpdate = Boolean(data.t_minuta_id);
const api = new API();
return await api.send({
method: isUpdate ? Methods.PUT : Methods.POST,
endpoint: `administrativo/t_minuta/${data.t_minuta_id || ''}`,
body: data
});
}

View file

@ -0,0 +1,41 @@
// Função para pegar todos os dados (usada em TMinutaIndexData)
import { textoEscrituraCompraEVenda, textoEscrituraPartilhaAmigavel, textoProcuracaoAdJudicia } from "./MinutaTexto";
export default async function MinutaMockDeDados() {
return Promise.resolve({
status: 200,
message: 'Dados localizados',
data: [
{
t_minuta_id: 1,
natureza_id: 1,
descricao: 'Escritura de Compra e Venda',
situacao: 'A',
texto: textoEscrituraCompraEVenda,
},
{
t_minuta_id: 2,
natureza_id: 1,
descricao: 'Escritura de Partilha Amigável',
situacao: 'A',
texto: textoEscrituraPartilhaAmigavel,
},
{
t_minuta_id: 3,
natureza_id: 2,
descricao: 'Procuração Ad Judicia',
situacao: 'A',
texto: textoProcuracaoAdJudicia,
},
]
});
}
export async function MinutaMockDeDadosPorId(t_minuta_id: number) {
const allData = await MinutaMockDeDados();
return Promise.resolve({
status: 200,
message: 'Dados localizados',
data: allData.data.find((item) => item.t_minuta_id === t_minuta_id) || null
});
}

View file

@ -0,0 +1,29 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { useState } from "react";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
import TCensecNaturezaLitigioIndexService from "../../_services/t_censecnaturezalitigio/TCensecNaturezaLitigioIndexService";
export const useTCensecNaturezaLitigioReadHook = () => {
const { setResponse } = useResponse();
const [tCensecNaturezaLitigio, setTCensecNaturezaLitigio] = useState<TCensecNaturezaLitigioInterface[]>([]);
const fetchTCensecNaturezaLitigio = async () => {
try {
const response = await TCensecNaturezaLitigioIndexService();
setTCensecNaturezaLitigio(response.data);
console.log(response)
setResponse(response);
} catch (error) {
console.log(error)
}
}
return { tCensecNaturezaLitigio, fetchTCensecNaturezaLitigio }
}

View file

@ -0,0 +1,26 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
import { useState } from "react";
import TCensecNaturezaLitigioRemoveData from "../../_data/TCensecNaturezaLitigio/TCensecNaturezaLitigioRemoveData";
export const useTCensecNaturezaLitigioRemoveHook = () => {
const { setResponse } = useResponse();
const [ tCensecNaturezaLitigio, setTCensecNaturezaLitigio ] = useState<TCensecNaturezaLitigioInterface>()
const removeTCensecNaturezaLitigio = async (data: TCensecNaturezaLitigioInterface) => {
console.log(data.censec_naturezaltigio_id)
const response = await TCensecNaturezaLitigioRemoveData(data);
setTCensecNaturezaLitigio(data)
setResponse(response);
}
return { tCensecNaturezaLitigio, removeTCensecNaturezaLitigio }
}

View file

@ -0,0 +1,31 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { useState } from "react";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
import TCensecNaturezaLitigioSaveService from "../../_services/t_censecnaturezalitigio/TCensecNaturezaLitigioSaveService";
export const useTCensecNaturezaLitigioSaveHook = () => {
const { setResponse } = useResponse();
const [TCensecNaturezaLitigio, setTCensecNaturezaLitigio] = useState<TCensecNaturezaLitigioInterface | null>(null);
// controla se o formulário está aberto ou fechado
const [isOpen, setIsOpen] = useState(false);
const saveTCensecNaturezaLitigio = async (data: TCensecNaturezaLitigioInterface) => {
const response = await TCensecNaturezaLitigioSaveService(data);
setTCensecNaturezaLitigio(response.data);
setResponse(response);
// Fecha o formulário automaticamente após salvar
setIsOpen(false);
// Retorna os dados imediatamente
return response;
}
return { TCensecNaturezaLitigio, saveTCensecNaturezaLitigio }
}

View file

@ -0,0 +1,27 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { useState } from "react";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import TMinutaIndex from "../../_services/t_minuta/TMinutaIndex";
export const useTMinutaIndexHook = () => {
const { setResponse } = useResponse();
const [tMinuta, setTMinuta] = useState<TMinutaInterface[]>([]);
const fetchTMinuta = async () => {
try {
const response = await TMinutaIndex();
setTMinuta(response.data);
setResponse(response);
} catch (error) {
console.log(error)
}
}
return { tMinuta, fetchTMinuta }
}

View file

@ -0,0 +1,28 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { useState } from "react";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import TMinutaIndexService from "../../_services/t_minuta/TMinutaIndexService";
export const useTMinutaReadHook = () => {
const { setResponse } = useResponse();
const [tMinuta, setTMinuta] = useState<TMinutaInterface>();
const fetchTMinuta = async (tMinuta: TMinutaInterface) => {
try {
const response = await TMinutaIndexService(tMinuta.t_minuta_id);
console.log("read hook",response.data)
setTMinuta(response.data);
setResponse(response);
} catch (error) {
console.log(error)
}
}
return { tMinuta, fetchTMinuta }
}

View file

@ -0,0 +1,19 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import TMinutaRemoveService from "../../_services/t_minuta/TMinutaRemoveService";
export const useTMinutaRemoveHook = () => {
const { setResponse } = useResponse();
const removeTMinuta = async (data: TMinutaInterface) => {
const response = await TMinutaRemoveService(data);
setResponse(response);
}
return { removeTMinuta }
}

View file

@ -0,0 +1,31 @@
import { useResponse } from "@/app/_response/ResponseContext"
import { useState } from "react";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
import TMinutaSaveService from "../../_services/t_minuta/TMinutaSaveService";
export const useTMinutaSaveHook = () => {
const { setResponse } = useResponse();
const [tMinuta, setTMinuta] = useState<TMinutaInterface>();
// controla se o formulário está aberto ou fechado
const [isOpen, setIsOpen] = useState(false);
const saveTMinuta = async (data: any) => {
const response = await TMinutaSaveService(data);
setTMinuta(response.data);
setResponse(response);
// Fecha o formulário automaticamente após salvar
setIsOpen(false);
// Retorna os dados imediatamente
return response;
}
return { tMinuta, saveTMinuta }
}

View file

@ -15,6 +15,8 @@ export const useTTBAndamentoServicoReadHook = () => {
const response = await TTBAndamentoServicoIndexData();
console.log(response)
// Armazena os dados consultados
setTTBAndamentosServicos(response.data);

View file

@ -0,0 +1,5 @@
export interface TCensecNaturezaLitigioInterface {
censec_naturezalitigio_id?: number;
descricao: string;
situacao: 'A' | 'I';
}

View file

@ -0,0 +1,7 @@
export interface TMinutaInterface {
t_minuta_id: number;
natureza_id: number;
descricao: string;
situacao: 'A' | 'I';
texto: string;
}

View file

@ -0,0 +1,7 @@
import { z } from 'zod';
export const TCensecNaturezaLitigioSchema = z.object({
censec_naturezalitigio_id: z.number().optional(),
descricao: z.string(),
situacao: z.enum(['A', 'I']),
});

View file

@ -0,0 +1,8 @@
import { z } from "zod";
export const TMinutaSchema = z.object({
natureza_id: z.number().int(),
descricao: z.string().min(1, "Descrição é obrigatória"),
situacao: z.enum(["A", "I"]),
texto: z.string().min(1, "Texto é obrigatório"),
});

View file

@ -0,0 +1,12 @@
import TCensecNaturezaLitigioIndexData from "../../_data/TCensecNaturezaLitigio/TCensecNaturezaLitigioIndexData";
export default async function TCensecNaturezaLitigioIndexService() {
try {
const response = await TCensecNaturezaLitigioIndexData();
return response;
} catch (error) {
console.log(error)
return error
}
}

View file

@ -0,0 +1,10 @@
import TCensecNaturezaLitigioRemoveData from "../../_data/TCensecNaturezaLitigio/TCensecNaturezaLitigioRemoveData";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
export default async function TCensecNaturezaLitigioRemoveService(data: TCensecNaturezaLitigioInterface) {
const response = await TCensecNaturezaLitigioRemoveData(data);
return response;
}

View file

@ -0,0 +1,10 @@
import TCensecNaturezaLitigioSaveData from "../../_data/TCensecNaturezaLitigio/TCensecNaturezaLitigioSaveData";
import { TCensecNaturezaLitigioInterface } from "../../_interfaces/TCensecNaturezaLitigioInterface";
export default async function TCensecNaturezaLitigioSaveService(data: TCensecNaturezaLitigioInterface) {
const response = await TCensecNaturezaLitigioSaveData(data);
return response;
}

View file

@ -0,0 +1,13 @@
import TMinutaIndexData from "../../_data/TMinuta/TMinutaIndexData";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
export default async function TMinutaIndex() {
try {
const response = await TMinutaIndexData();
return response;
} catch (error) {
console.log(error)
return error
}
}

View file

@ -0,0 +1,21 @@
import TMinutaIndex from "../../_data/TMinuta/TMinutaIndex";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
export default async function TMinutaIndexService(t_minuta_id: number) {
if (t_minuta_id <= 0) {
return {
'code': 400,
'message': 'Usuário informado inválido',
}
}
try {
const response = await TMinutaIndex(t_minuta_id);
console.log("service",response)
return response;
} catch (error) {
console.log(error)
return error
}
}

View file

@ -0,0 +1,10 @@
import TMinutaRemoveData from "../../_data/TMinuta/TMinutaRemoveData";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
export default async function TMinutaRemoveService(data: TMinutaInterface) {
const response = await TMinutaRemoveData(data);
return response;
}

View file

@ -0,0 +1,10 @@
import TMinutaSaveData from "../../_data/TMinuta/TMinutaSaveData";
import { TMinutaInterface } from "../../_interfaces/TMinutaInterface";
export default async function TMinutaSaveService(data: TMinutaInterface) {
const response = await TMinutaSaveData(data);
return response;
}

View file

@ -0,0 +1,73 @@
import { FileText, Heart, Briefcase, Scale, Link as LinkIcon, MapPin } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import Link from "next/link";
export default function CadastrosPage() {
const items = [
{
title: 'Documentos',
description: 'Gerencie os tipos de documentos aceitos e suas configurações no sistema.',
icon: FileText,
},
{
title: 'Estado Civil',
description: 'Cadastre e mantenha os diferentes estados civis utilizados nos registros.',
icon: Heart,
},
{
title: 'Profissão',
description: 'Gerencie a lista de profissões para utilização em cadastros e registros.',
icon: Briefcase,
},
{
title: 'Regime de Comunhão',
description: 'Defina os regimes de comunhão aplicáveis em matrimônios e registros civis.',
icon: Scale,
},
{
title: 'Vínculo de Sinal Público',
description: 'Controle e cadastre vínculos relacionados a sinais públicos para autenticações.',
icon: LinkIcon,
},
{
title: 'Municípios',
description: 'Gerencie a base de municípios para utilização em endereços e cadastros.',
icon: MapPin,
},
];
return (
<div>
<div className="flex items-center justify-between mb-4">
<div>
<h1 className="text-4xl font-semibold mb-1">
Complementos de Cadastro pessoal
</h1>
<p className="text-base text-muted-foreground">
Gerencie os cadastros relacionados a regimes, como estado civil, regime de comunhão e outras informações complementares necessárias para o registro de pessoas.
</p>
</div>
</div>
<div className="grid grid-cols-5 gap-3">
{items.map((item, key) => (
<Card key={key} className="cursor-pointer hover:bg-muted transition-colors" asChild>
<Link href={"/"}>
<CardContent>
<span className="inline-flex shrink-0 rounded-md border border-blue-300 bg-blue-100 p-2 dark:border-blue-300/10 dark:bg-blue-400/10 mb-2">
<item.icon className="size-6 stroke-blue-700 dark:stroke-blue-500" />
</span>
<h3 className="text-gray-900 dark:text-white mt-3 text-2xl font-medium tracking-tight">
{item.title}
</h3>
<p className="text-gray-500 dark:text-gray-400 mt-1 text-sm ">
{item.description}
</p>
</CardContent>
</Link>
</Card>
))}
</div>
</div>
);
}

View file

@ -1,4 +1,5 @@
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { PlusIcon } from "lucide-react";
interface HeaderProps {
@ -22,9 +23,10 @@ export default function Header({ title, description, buttonText, buttonAction }:
{description}
</p>
</div>
<Button onClick={() => buttonAction()} className="cursor-pointer">
<PlusIcon className="mr-2" />
{buttonText}
<Button asChild>
<Link href="/cadastros/minuta/formulario">
Nova Minuta
</Link>
</Button>
</div>
</div>

View file

@ -0,0 +1,132 @@
import React from 'react';
import { Editor } from '@tinymce/tinymce-react';
// 1. Define as propriedades que nosso componente vai receber
interface MainEditorProps {
initialValue: string;
onEditorChange: (content: string) => void;
margins: {
top: string;
bottom: string;
left: string;
right: string;
};
size: {
width: number;
height: number;
}
}
const MainEditor: React.FC<MainEditorProps> = ({ initialValue, onEditorChange, margins, size }) => {
return (
<div className='flex justify-center'>
<Editor
apiKey='sny4ncto4hf42akdz2eqss2tqd0loo439vfttpuydjc2kqpi'
value={initialValue}
onEditorChange={onEditorChange}
init={{
width: size.width,
height: size.height,
menubar: false,
browser_spellcheck: true,
contextmenu: false,
plugins: [
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
'anchor', 'searchreplace', 'visualblocks', 'fullscreen', 'insertdatetime',
'media', 'table', 'code', 'codesample', 'help', 'wordcount', 'autosave', 'quickbars',
'quickbars link', 'quickbars image editimage', 'pagebreak', 'nonbreaking', 'advlist', 'autolink'
],
autosave_ask_before_unload: true,
toolbar: 'undo redo styles removeformat formatselect fontfamily fontsize forecolor link quickimage bold italic underline align bullist numlist outdent indent removeformat preview fullscreen searchreplace help code codesample quicktable pagebreak nonbreaking charmap customTemplates',
formats: {
linhatopo: {
selector: 'div',
classes: 'borda-superior',
},
linhainferior: {
selector: 'div',
classes: 'borda-inferior',
}
},
style_formats: [
{
title: 'Estilos de Borda', items: [
{ title: 'Linha Superior', format: 'linhatopo' },
{ title: 'Linha Inferior', format: 'linhainferior' }
]
}
],
setup: (editor: any) => {
const customTemplates = [
{
title: 'Qualificação das Partes (Casamento)',
description: 'Insere o bloco de qualificação para contraentes.',
content: `<p><strong>QUALIFICAÇÃO DOS CONTRAENTES:</strong> Ele, brasileiro, solteiro, maior, [Profissão], portador da CI nº [RG], inscrito no CPF sob o nº [CPF], residente e domiciliado em [Endereço]. Ela, brasileira, solteira, maior, [Profissão], portadora da CI nº [RG], inscrita no CPF sob o nº [CPF], residente e domiciliada em [Endereço].</p><br>`
},
{
title: 'Cláusula de Regime de Bens',
description: 'Cláusula padrão de Comunhão Parcial de Bens.',
content: '<p>O regime de bens adotado é o da <strong>Comunhão Parcial de Bens</strong>, nos termos dos artigos 1.658 e seguintes do Código Civil brasileiro.</p><br>'
},
{
title: 'Cláusula de Encerramento (Selo)',
description: 'Texto final com espaço para o selo digital.',
content: '<p>O referido é verdade e dou fé. Emitida nesta data. Selo Digital de Fiscalização: [Número do Selo]</p>'
}
];
editor.ui.registry.addMenuButton('customTemplates', {
text: 'Modelos', // O texto que aparecerá no botão
fetch: (callback: any) => {
const items = customTemplates.map(template => ({
type: 'menuitem',
text: template.title,
onAction: () => {
// 3. Ação que acontece ao clicar no item do menu: insere o conteúdo
editor.insertContent(template.content);
}
}));
callback(items);
}
});
},
quickbars_selection_toolbar: 'bold italic underline | fontfamily | fontsize | quicklink blockquote | quicklink',
quickbars_insert_toolbar: 'bold italic underline fontfamily fontsize quicklink blockquote quicklink quickimage quicktable hr',
quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions',
fontsize_formats: '4pt 5pt 6pt 7pt 8pt 9pt 10pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 28pt 30pt 32pt 34pt 36pt',
font_family_formats: ` Times New Roman=Times New Roman, Times, serif; Arial=Arial, Helvetica, sans-serif; Calibri=Calibri, sans-serif; Courier New=Courier New, Courier, monospace; Georgia=Georgia, serif; Verdana=Verdana, Geneva, sans-serif;`,
fullscreen_native: true,
content_style: `
body {
font-family: 'Times New Roman', Times, serif;
font-size: 12pt;
background: #fff;
margin: ${margins.top}cm ${margins.right}cm ${margins.bottom}cm ${margins.left}cm;
}
.mce-pagebreak { /* Estiliza a linha da quebra de página no editor */
border-top: 1px dashed #bbb;
width: 100%;
margin-top: 15px;
cursor: default;
}
.borda-superior {
border-top: 1px solid #000;
padding-top: 5px;
margin-top: 5px;
}
.borda-inferior {
border-bottom: 1px solid #000;
padding-bottom: 5px;
margin-bottom: 5px;
}
`
}}
/>
</div>
);
};
export default MainEditor;

View file

@ -112,6 +112,26 @@ const data = {
title: "Tipo de Medida",
url: "/cadastros/medida-tipo"
},
{
title: "Natureza Litígio (Censec)",
url: "/cadastros/censec-natureza-litigio"
},
{
title: "Pessoas",
url: "/cadastros/pessoas/complementos/",
},
{
title: "Regimes/Bens",
url: "/cadastros/regime-bens/",
},
{
title: "Regimes/Comunhão",
url: "/cadastros/regime-comunhao/",
},
{
title: "Minuta",
url: "/cadastros/minuta/",
},
{
title: "Regimes/Comunhão",
url: "/cadastros/regime-comunhao/",

View file

@ -1,8 +0,0 @@
{
"state": "go",
"api": {
"url": "http://localhost:8000/",
"prefix": "api/v1/",
"content_type": "application/json"
}
}