[MVPTN-86] feat(crud): Conclusão do CRUD Tipos de Serviço - t_servico_tipo

This commit is contained in:
Kenio 2025-10-28 15:40:08 -03:00
parent 77ea800aaa
commit 4b7afd6a8f
33 changed files with 1126 additions and 332 deletions

View file

@ -13,6 +13,7 @@ import TServicoTipoForm from '../../_components/t_servico_tipo/TServicoTipoForm'
import { useTServicoTipoReadHook } from '../../_hooks/t_servico_tipo/useTServicoTipoReadHook';
import { useTServicoTipoSaveHook } from '../../_hooks/t_servico_tipo/useTServicoTipoSaveHook';
import { useTServicoTipoRemoveHook } from '../../_hooks/t_servico_tipo/useTServicoTipoRemoveHook';
import { useTServicoTipoEditHook } from '../../_hooks/t_servico_tipo/useTServicoTipoEditHook';
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
@ -26,6 +27,7 @@ export default function TServicoTipoPage() {
const { tServicoTipo, fetchTServicoTipo } = useTServicoTipoReadHook();
const { saveTServicoTipo } = useTServicoTipoSaveHook();
const { removeTServicoTipo } = useTServicoTipoRemoveHook();
const { editTServicoTipo } = useTServicoTipoEditHook();
// Estados
const [selectedServicoTipo, setSelectedServicoTipo] = useState<TServicoTipoInterface | null>(null);
@ -47,10 +49,31 @@ export default function TServicoTipoPage() {
/**
* Abre o formulário no modo de edição ou criação
*/
const handleOpenForm = useCallback((data: TServicoTipoInterface | null) => {
setSelectedServicoTipo(data);
const handleOpenForm = useCallback(async (data: TServicoTipoInterface | null) => {
// Fecha o formulário antes de reabrir (garante reset limpo)
setIsFormOpen(false);
// Se nenhum dado for passado, abre o formulário em modo de criação
if (!data) {
setSelectedServicoTipo(null);
setIsFormOpen(true);
}, []);
return;
}
// Define o item selecionado para edição
setSelectedServicoTipo(data);
// Aguarda carregar/editar o registro (o hook espera o objeto TServicoTipoInterface)
await editTServicoTipo(data);
// Atualiza a lista de dados
await fetchTServicoTipo();
setIsFormOpen(true);
}, [editTServicoTipo, fetchTServicoTipo]);
/**
* Fecha o formulário e limpa o item selecionado
@ -72,8 +95,13 @@ export default function TServicoTipoPage() {
fetchTServicoTipo();
},
[saveTServicoTipo, fetchTServicoTipo],
);
/**
* Quando o usuário clica em "remover" na tabela
*/
@ -88,6 +116,7 @@ export default function TServicoTipoPage() {
[openConfirmDialog],
);
/**
* Executa a exclusão de fato quando o usuário confirma
*/
@ -108,6 +137,8 @@ export default function TServicoTipoPage() {
handleCancel();
}, [itemToDelete, removeTServicoTipo, fetchTServicoTipo, handleCancel]);
/**
* Busca inicial dos dados
*/
@ -147,7 +178,7 @@ export default function TServicoTipoPage() {
title="Confirmar exclusão"
description="Atenção"
// Adaptação da mensagem para a interface TServicoTipo
message={`Deseja realmente excluir o tipo de serviço "${itemToDelete?.stipo_nome}"?`}
message={`Deseja realmente excluir o tipo de serviço "${itemToDelete?.descricao}"?`}
confirmText="Sim, excluir"
cancelText="Cancelar"
onConfirm={handleDelete}

View file

@ -52,6 +52,14 @@ import { GEmolumentoItemReadInterface } from "@/app/(protected)/(cadastros)/cada
import CategoriaServicoSelect from "@/shared/components/categoriaServicoSelect/CategoriaServicoSelect";
import CCaixaServicoSelect from "@/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect";
import { TServicoTipoSaveData } from "../../_data/TServicoTipo/TServicoTipoSaveData";
import TTBReconhecimentoTipoSelect from "@/packages/administrativo/components/TTBReconhecimentoTipo/TTBReconhecimentoTipoSelect";
import { ConfirmacaoCheckBox } from "@/shared/components/confirmacao/ConfirmacaoCheckBox";
import ConfirmacaoSelect from "@/shared/components/confirmacao/ConfirmacaoSelect";
import { TipoPessoaSelect } from "@/shared/components/tipoPessoa/tipoPessoaSelect";
import { useTServicoEtiquetaReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaReadHook";
import { useTServicoEtiquetaSaveHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaSaveHook";
import { useTServicoEtiquetaRemoveHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaRemoveHook";
// Propriedades esperadas pelo componente
interface Props {
@ -64,32 +72,176 @@ interface Props {
// Componente principal do formulário
export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Props) {
// Inicializa o react-hook-form com validação via Zod
const form = useForm<TServicoTipoFormValues>({
resolver: zodResolver(TServicoTipoSchema),
defaultValues: {
servico_tipo_id: 0,
emolumento_id: 0,
emolumento_obrigatorio: 0,
descricao: "",
maximo_pessoa: 0,
tipo_item: "",
frenteverso: "N",
averbacao: "N",
transferencia_veiculo: "N",
usar_a4: "N",
etiqueta_unica: "N",
situacao: "A",
selar: "N",
valor_emolumento: 0,
valor_taxa_judiciaria: 0,
fundesp_valor: 0,
valor_total: 0,
tipo_pessoa: "F", // ou "J"
} as unknown as TServicoTipoFormValues,
});
// Carrega o ID caso esteja informado no form
const servico_tipo_id = form.getValues('servico_tipo_id') || 0;
// Hook responsável por buscar emolumentos no backend
const { tServicoEtiqueta, fetchTServicoEtiqueta } = useTServicoEtiquetaReadHook();
// Hook responsável em salvar o a etiqueta selecionada
const { tServicoEtiquetaSave, fetchTServicoEtiquetaSave } = useTServicoEtiquetaSaveHook();
// Hook responsável em excluir a etiqueta selecionada
const { fetchTServicoEtiquetaRemove } = useTServicoEtiquetaRemoveHook();
// Estado para gerenciar os itens da tabela de etiquetas/carimbos
const [itensTabela, setItensTabela] = useState<{ marcacao_tipo_id: string; descricao: string }[]>([]);
const [itensTabela, setItensTabela] = useState<{ servico_etiqueta_id: string | number; descricao: string }[]>([]);
// Função para adicionar um novo item à tabela
const handleAddEtiquetaCarimbo = () => {
const valorSelecionado = form.getValues('etiquetas_carimbos');
// Carrega os dados de emolumentos apenas uma vez ao montar o componente
React.useEffect(() => {
// Função para consumir o endpoint da api
const loadData = async () => {
// Verifica se o ID do serviço tipo foi informado
if(servico_tipo_id > 0){
// Consumo o endpoint da api
await fetchTServicoEtiqueta({servico_tipo_id});
}
};
// Chama a função para consumir o endpoint da api
loadData();
}, [servico_tipo_id]);
// Atualiza itensTabela sempre que tServicoEtiqueta for carregado
React.useEffect(() => {
// Verifica se a consulta retornou os dados como objeto
if (Array.isArray(tServicoEtiqueta) && tServicoEtiqueta.length > 0) {
// Lista os itens
const mapped = tServicoEtiqueta.map((item) => ({
servico_etiqueta_id: Number(item.servico_etiqueta_id ?? 0),
descricao: String(item.descricao ?? 'Sem descrição'),
}));
setItensTabela(mapped);
} else {
setItensTabela([]);
}
}, [tServicoEtiqueta]);
// Função para adicionar um novo item à tabela Etiquetas/Carimbos
const handleAddEtiquetaCarimbo = async () => {
// Captura o valor selecionado do formulário
const valorSelecionado = form.getValues("etiquetas_carimbos");
// Se não houver valor selecionado, não faz nada
if (!valorSelecionado) return;
// Aqui você pode buscar o texto/descrição com base no seu componente GMarcacaoTipoSelect
// Exemplo: supondo que o valor seja um objeto { id, descricao }
// Verifica se o item já se encontra na tabela
const alreadyExists = itensTabela.some(
(p) => String(p.descricao).trim() === String(valorSelecionado.value).trim()
);
// Caso o item já esteja na tabela, para o procedimento
if (alreadyExists) {
return;
}
// --- Envio opcional para API ---
try {
// Verifica se o ID do serviço tipo foi informado
if(servico_tipo_id > 0){
// Monta o objeto do item selecionado
const data = {
etiqueta_modelo_id: valorSelecionado.key,
servico_tipo_id: servico_tipo_id,
};
// Consumo o endpoint da api
const response = await fetchTServicoEtiquetaSave(data);
// Verifica se tServicoEtiquetaSave é um objeto válido (não null e não array)
if (response && typeof response === 'object' && !Array.isArray(response)) {
// Monta o objeto com um único item para a tabela
const item = {
marcacao_tipo_id: valorSelecionado.key ?? valorSelecionado, // ou ajusta conforme a estrutura do seu componente
descricao: valorSelecionado.value ?? 'Sem descrição',
servico_etiqueta_id: Number(response.servico_etiqueta_id) ?? 0,
descricao: String(valorSelecionado.value) ?? "Sem descrição",
};
// Evita duplicatas
// Adiciona o item na tabela
setItensTabela((prev) => {
if (prev.some((p) => p.marcacao_tipo_id === item.marcacao_tipo_id)) return prev;
return [...prev, item];
const idAtual = String(response.servico_etiqueta_id ?? '');
const exists = prev.some((p) => String(p.servico_etiqueta_id ?? '') === idAtual);
return exists ? prev : [...prev, item];
});
}
}
// Se ocorrer erros, informo
} catch (error) {
console.log("Erro ao enviar o serviço para a API: " + error)
}
};
const handleRemoveItem = (marcacao_tipo_id: string) => {
setItensTabela((prev) => prev.filter((p) => p.marcacao_tipo_id !== marcacao_tipo_id));
// Função para remover um item da tabela
const handleRemoveItem = async (servico_etiqueta_id: number) => {
try{
// Verifica se o ID da etiqueta tipo foi informado
if(servico_etiqueta_id > 0){
// Monta o objeto do item selecionado
const data = {
servico_etiqueta_id: servico_etiqueta_id,
};
// Consumo o endpoint da api
await fetchTServicoEtiquetaRemove(data);
}
// Atualiza a tabela no form
setItensTabela((prev) => prev.filter((p) => Number(p.servico_etiqueta_id) !== servico_etiqueta_id));
// Se ocorrer erros, informo
} catch (error) {
console.log("Erro ao enviar o serviço para a API: " + error)
}
};
@ -128,13 +280,82 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop
}, [gEmolumentoItemReadParams.emolumento_id]);
// Inicializa o react-hook-form com validação via Zod
const form = useForm<TServicoTipoFormValues>({
resolver: zodResolver(TServicoTipoSchema),
defaultValues: {
// Captura o ID do serviço para uso local
const servicoTipoId = Number(form.watch("servico_tipo_id") || data?.servico_tipo_id || 0);
// Função chamada ao clicar em "Salvar"
const handleSave = async (formData: TServicoTipoFormValues) => {
try {
// Se o form não trouxe o ID, tenta puxar de `data`
const servico_tipo_id = formData.servico_tipo_id || data?.servico_tipo_id || form.getValues('servico_tipo_id') || 0;
// Atualiza o valor dentro do formData
formData.servico_tipo_id = Number(servico_tipo_id);
// Intercepta e trata o valor de emolumento_id
const emolumentoId = Number(formData.emolumento_id ?? 0);
formData.emolumento_id = emolumentoId === 0 ? null : emolumentoId;
// Intercepta e trata o valor de emolumento_obrigatorio
const emolumentoObrigatorio = Number(formData.emolumento_obrigatorio ?? 0);
formData.emolumento_obrigatorio =
emolumentoObrigatorio === 0 ? null : emolumentoObrigatorio;
// Detecta automaticamente se é edição
const isEditing = !!formData.servico_tipo_id && Number(formData.servico_tipo_id) > 0;
// Envia os dados para o módulo com o método correto
const response = await TServicoTipoSaveData({
...formData,
metodo: isEditing ? 'PUT' : 'POST', // 💡 Definição explícita do método
});
// Atualiza o formulário apenas se o retorno for válido
if (response?.data?.servico_tipo_id) {
const novoId = response.data.servico_tipo_id;
form.setValue('servico_tipo_id', novoId); // mantém o ID atualizado
// Merge dos dados para preservar valores locais
form.reset({ ...form.getValues(), ...response.data });
console.log(`Serviço ${isEditing ? 'atualizado' : 'criado'} com sucesso (ID: ${novoId})`);
} else {
console.log('Erro ao salvar o tipo de serviço.');
}
} catch (error) {
console.log('Erro ao salvar:', error);
}
};
// Carrega os dados apenas quando o modal
// abrir e houver um registro para editar
useEffect(() => {
// Remove as etiquetas selecionadas
setItensTabela([]);
if (isOpen && data && Number(data.servico_tipo_id ?? 0) > 0) {
/** Carrega os dados no formulário */
form.reset(data); // edição
} else if (isOpen && !data) {
/** Reseta os campos do formulário */
form.reset({
servico_tipo_id: 0,
emolumento_id: 0,
emolumento_obrigatorio: 0,
descricao: "",
categoria: "",
maximo_pessoa: 0,
tipo_item: "",
frenteverso: "N",
averbacao: "N",
transferencia_veiculo: "N",
@ -146,60 +367,14 @@ const form = useForm<TServicoTipoFormValues>({
valor_taxa_judiciaria: 0,
fundesp_valor: 0,
valor_total: 0,
},
});
// Captura o ID do serviço para uso local
const servicoTipoId = Number(form.watch("servico_tipo_id") || data?.servico_tipo_id || 0);
// Atualiza os valores quando há dados para edição
useEffect(() => {
if (data && Number(data.servico_tipo_id) > 0) {
//Carrega os valores no form
form.reset(data);
} else {
// Se não houver dados, reseta o
// formulário para os valores iniciais
// Modo novo cadastro → zera o ID manualmente
form.reset({
...form.getValues(), // mantém outros valores default
servico_tipo_id: 0,
descricao: '',
tipo_pessoa: "F",
});
}
}, [data, form]);
}, [isOpen, data]);
// Função chamada ao clicar em "Salvar"
const handleSave = async (formData: TServicoTipoFormValues) => {
try {
// Envia os dados para API
const response = await TServicoTipoSaveData(formData);
// Se a resposta contiver um ID válido
if (response?.data?.servico_tipo_id) {
const novoId = response.data.servico_tipo_id;
// Atualiza o hidden input no formulário
form.setValue("servico_tipo_id", novoId);
// Atualiza todos os campos do formulário com o retorno da API
form.reset(response.data);
// Exibe mensagem de sucesso
console.log(`Serviço salvo com sucesso (ID: ${novoId})`);
} else {
console.log("Erro ao salvar o tipo de serviço.");
function onError(errors: any) {
console.log('Erros de validação:', errors);
}
} catch (error) {
console.log("Erro ao salvar:", error);
}
};
return (
<Dialog
@ -216,8 +391,8 @@ const form = useForm<TServicoTipoFormValues>({
</DialogHeader>
{/* Estrutura do formulário */}
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSave)} className="space-y-6">
<Form key={data?.servico_tipo_id ?? 'new'} {...form}>
<form onSubmit={form.handleSubmit(handleSave, onError)} className="space-y-6">
<Tabs defaultValue="dadosTipoServico" className="space-y-4">
@ -271,7 +446,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="categoria"
name="tipo_item"
render={({ field }) => (
<FormItem className="w-full cursor-pointer">
<FormLabel>Categoria</FormLabel>
@ -292,20 +467,9 @@ const form = useForm<TServicoTipoFormValues>({
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Serviço Padrão</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione o tipo padrão" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
<SelectItem value="N" className="cursor-pointer">Não</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
@ -332,81 +496,37 @@ const form = useForm<TServicoTipoFormValues>({
{/* Campo: Averbação (Checkbox) */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
<ConfirmacaoCheckBox
name="averbacao"
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
<FormControl>
<Checkbox
className="cursor-pointer"
checked={field.value === "S"} // marcado se for "S"
onCheckedChange={(checked) => field.onChange(checked ? "S" : "N")} // salva "S" ou "N"
/>
</FormControl>
<FormLabel className="font-normal cursor-pointer">Averbação</FormLabel>
</FormItem>
)}
label="Averbação"
control={form.control}
/>
</div>
{/* Campo: Transferência de Veículo (Checkbox) */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
<ConfirmacaoCheckBox
name="transferencia_veiculo"
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
<FormControl>
<Checkbox
className="cursor-pointer"
checked={field.value === "S"} // marcado se o valor for "S"
onCheckedChange={(checked) => field.onChange(checked ? "S" : "N")} // salva "S" ou "N"
/>
</FormControl>
<FormLabel className="font-normal cursor-pointer">Transferência Veículo</FormLabel>
</FormItem>
)}
label="Transferência de Veículo"
control={form.control}
/>
</div>
{/* Campo: Usar A4 (Checkbox) */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
<ConfirmacaoCheckBox
name="usar_a4"
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
<FormControl>
<Checkbox
className="cursor-pointer"
checked={field.value === "S"} // marcado se o valor for "S"
onCheckedChange={(checked) => field.onChange(checked ? "S" : "N")} // grava "S" ou "N"
/>
</FormControl>
<FormLabel className="font-normal cursor-pointer">Usar A4</FormLabel>
</FormItem>
)}
label="Usar A4"
control={form.control}
/>
</div>
{/* Campo: Etiqueta Única (Texto normal) */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
<ConfirmacaoCheckBox
name="etiqueta_unica"
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
<FormControl>
<Checkbox
className="cursor-pointer"
checked={field.value === "S"} // marcado se o valor for "S"
onCheckedChange={(checked) => field.onChange(checked ? "S" : "N")} // grava "S" ou "N"
/>
</FormControl>
<FormLabel className="font-normal cursor-pointer">Etiqueta Única</FormLabel>
</FormItem>
)}
label="Etiqueta Única"
control={form.control}
/>
</div>
@ -417,7 +537,7 @@ const form = useForm<TServicoTipoFormValues>({
control={form.control}
name="frenteverso"
render={({ field }) => {
const categoriaSelecionada = form.watch("categoria");
const categoriaSelecionada = form.watch("tipo_item");
const isEnabled = categoriaSelecionada === "A";
return (
@ -478,25 +598,13 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="servico_tipo"
name="tb_reconhecimentotipo_id"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Tipo</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="1" className="cursor-pointer">Semelhança</SelectItem>
<SelectItem value="2" className="cursor-pointer">Verdadeiro</SelectItem>
<SelectItem value="3" className="cursor-pointer">Abono</SelectItem>
</SelectContent>
</Select>
<TTBReconhecimentoTipoSelect
field={field}
/>
<FormMessage />
</FormItem>
)}
@ -506,30 +614,7 @@ const form = useForm<TServicoTipoFormValues>({
{/* Campo: Pessoa (Select) */}
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="pessoa_tipo"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Pessoa</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="F" className="cursor-pointer">Física</SelectItem>
<SelectItem value="J" className="cursor-pointer">Juridica</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<TipoPessoaSelect control={form.control} name="tipo_pessoa" />
</div>
@ -537,37 +622,29 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-4">
<FormField
control={form.control}
name="quantidade_pessoas"
name="maximo_pessoa"
render={({ field }) => (
<FormItem>
{/* Rótulo do campo */}
<FormItem className="w-full">
<FormLabel>Quantidade de pessoas</FormLabel>
<FormControl>
<Input
{...field}
// Garante que sempre exista um valor (evita undefined)
value={field.value ?? ''}
// Placeholder explicativo
<input
type="number" // Aceita apenas números
min={1}
max={100}
placeholder="Digite a quantidade de pessoas"
// Mostra teclado numérico em celulares
inputMode="numeric"
// Sugere ao navegador que aceite apenas números
pattern="[0-9]*"
// Intercepta a digitação e remove tudo que não for número
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm
ring-offset-background placeholder:text-muted-foreground
focus-visible:outline-none focus-visible:ring-2
focus-visible:ring-ring focus-visible:ring-offset-2"
{...field}
value={field.value ?? ""} // Garante que nunca seja undefined
onChange={(e) => {
const apenasNumeros = e.target.value.replace(/[^0-9]/g, '');
field.onChange(apenasNumeros);
// Converte para número se houver valor
const value = e.target.value === "" ? "" : Number(e.target.value);
field.onChange(value);
}}
/>
</FormControl>
{/* Exibe mensagens de erro do React Hook Form */}
<FormMessage />
</FormItem>
)}
@ -580,7 +657,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="biometria"
name="requer_biometria"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Biometria</FormLabel>
@ -588,10 +665,8 @@ const form = useForm<TServicoTipoFormValues>({
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
@ -608,7 +683,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="cpf_cnpj"
name="requer_cpf"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>CPF/CNPJ</FormLabel>
@ -616,10 +691,8 @@ const form = useForm<TServicoTipoFormValues>({
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
@ -637,7 +710,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="autorizacao"
name="requer_autorizacao"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Autorização</FormLabel>
@ -645,10 +718,8 @@ const form = useForm<TServicoTipoFormValues>({
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
@ -666,7 +737,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="abonador"
name="requer_abonador"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Abonador</FormLabel>
@ -674,10 +745,8 @@ const form = useForm<TServicoTipoFormValues>({
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
@ -740,7 +809,7 @@ const form = useForm<TServicoTipoFormValues>({
</TableHeader>
<TableBody>
{itensTabela.map((item, index) => (
<TableRow key={item.marcacao_tipo_id}>
<TableRow key={item.servico_etiqueta_id}>
<TableCell className="w-[90px] text-center">
{String(index + 1).padStart(3, '0')}
</TableCell>
@ -750,7 +819,7 @@ const form = useForm<TServicoTipoFormValues>({
variant="outline"
className="w-full cursor-pointer"
type="button"
onClick={() => handleRemoveItem(item.marcacao_tipo_id)}
onClick={() => handleRemoveItem(item.servico_etiqueta_id)}
>
<Trash /> Remover
</Button>
@ -789,10 +858,8 @@ const form = useForm<TServicoTipoFormValues>({
value={field.value}
onValueChange={field.onChange}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder="Selecione uma opção" />
</SelectTrigger>
<FormControl>
<ConfirmacaoSelect field={field} />
</FormControl>
<SelectContent>
<SelectItem value="S" className="cursor-pointer">Sim</SelectItem>
@ -810,7 +877,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-10">
<FormField
control={form.control}
name="emolumento"
name="emolumento_id"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Emolumento</FormLabel>
@ -851,7 +918,7 @@ const form = useForm<TServicoTipoFormValues>({
(item.valor_taxa_judiciaria ?? 0) +
(item.valor_outra_taxa1 ?? 0);
form.setValue("valor_total", total);
form.setValue("valor", total);
}
} catch (error) {
console.error("Erro ao buscar item de emolumento:", error);
@ -873,7 +940,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-12">
<FormField
control={form.control}
name="emolumento_auxiliar"
name="emolumento_obrigatorio"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Emolumento Adicional (Mesma etiqueta)</FormLabel>
@ -953,7 +1020,7 @@ const form = useForm<TServicoTipoFormValues>({
<div className="col-span-12 sm:col-span-6 md:col-span-3">
<FormField
control={form.control}
name="valor_total"
name="valor"
render={({ field }) => (
<FormItem>
<FormLabel>Total R$</FormLabel>

View file

@ -0,0 +1,26 @@
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/shared/services/api/Api'; //
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface';
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
// Função assíncrona que implementa a lógica de localizar um tipo de serviço
async function executeTServicoEtiquetaService(data: TServicoEtiquetaInterface) {
// Instancia o cliente da API para enviar a requisição
const api = new API(); //
// Executa a requisição para a API com o método apropriado e envia o ID no endpoint
return await api.send({
method: Methods.GET, // Verbo GET para consulta
endpoint: `administrativo/t_servico_etiqueta/servico_tipo/${data.servico_tipo_id}`, // Endpoint e ID alterados
});
}
// Exporta a função de Readr tipo de serviço já encapsulada com tratamento de erros
export const TServicoEtiquetaReadData = withClientErrorHandler(executeTServicoEtiquetaService); // Nome da exportação alterado

View file

@ -0,0 +1,27 @@
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/shared/services/api/Api'; //
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface'; // Alterado de GCidadeInterface
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
// Função assíncrona que implementa a lógica de remover um tipo de serviço
async function executeTServicoEtiquetaRemoveData(data: TServicoEtiquetaInterface) { // Nome da função alterado
// Instancia o cliente da API para enviar a requisição
const api = new API(); //
// Executa a requisição para a API com o método apropriado e envia o ID no endpoint
return await api.send({
method: Methods.DELETE, // Verbo DELETE para exclusão
endpoint: `administrativo/t_servico_etiqueta/${data.servico_etiqueta_id}`, // Endpoint e ID alterados
});
}
// Exporta a função de remover tipo de serviço já encapsulada com tratamento de erros
export const TServicoEtiquetaRemoveData = withClientErrorHandler(executeTServicoEtiquetaRemoveData); // Nome da exportação alterado

View file

@ -0,0 +1,39 @@
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/shared/services/api/Api'; //
// Importa o esquema de validação de dados para tipos de serviço
import { TServicoEtiquetaFormValues } from '../../_schemas/TServicoEtiquetaSchema';
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface'; // Interface alterada
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
// Função assíncrona que implementa a lógica de salvar (criar/atualizar) um tipo de serviço
async function executeTServicoEtiquetaSaveData(data: TServicoEtiquetaFormValues) {
try{
// Instancia o cliente da API para enviar a requisição
const api = new API(); //
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
return await api.send({
method: Methods.POST, // PUT se atualizar, POST se criar
endpoint: `administrativo/t_servico_etiqueta`, // Endpoint e ID alterados
body: data, // payload enviado para a API
});
} catch (error) {
console.error('Erro no TServicoEtiquetaSaveData:', error);
throw error; // propaga erro para o form
}
}
// Exporta a função de salvar tipo de serviço já encapsulada com tratamento de erros
export const TServicoEtiquetaSaveData = withClientErrorHandler(executeTServicoEtiquetaSaveData); // Nome da exportação alterado

View file

@ -0,0 +1,26 @@
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/shared/services/api/Api'; //
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface'; // Alterado de GCidadeInterface
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
// Função assíncrona que implementa a lógica de localizar um tipo de serviço
async function executeTServicoTipoEditService(data: TServicoTipoInterface) {
// Instancia o cliente da API para enviar a requisição
const api = new API(); //
// Executa a requisição para a API com o método apropriado e envia o ID no endpoint
return await api.send({
method: Methods.GET, // Verbo GET para consulta
endpoint: `administrativo/t_servico_tipo/${data.servico_tipo_id}`, // Endpoint e ID alterados
});
}
// Exporta a função de Readr tipo de serviço já encapsulada com tratamento de erros
export const TServicoTipoEditData = withClientErrorHandler(executeTServicoTipoEditService); // Nome da exportação alterado

View file

@ -19,7 +19,7 @@ async function executeTServicoTipoRemoveData(data: TServicoTipoInterface) { // N
// Executa a requisição para a API com o método apropriado e envia o ID no endpoint
return await api.send({
method: Methods.DELETE, // Verbo DELETE para exclusão
endpoint: `administrativo/t_servico_tipo/${data.servico_tipo_id}`, // Endpoint e ID alterados de g_cidade/cidade_id
endpoint: `administrativo/t_servico_tipo/${data.servico_tipo_id}`, // Endpoint e ID alterados
});
}

View file

@ -1,6 +1,9 @@
// Importa o serviço de API que será utilizado para realizar requisições HTTP
import API from '@/shared/services/api/Api'; //
// Importa o esquema de validação de dados para tipos de serviço
import { TServicoTipoFormValues } from '../../_schemas/TServicoTipoSchema';
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
@ -11,20 +14,33 @@ import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface'; //
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
// Função assíncrona que implementa a lógica de salvar (criar/atualizar) um tipo de serviço
async function executeTServicoTipoSaveData(data: TServicoTipoInterface) { // Nome da função alterado
async function executeTServicoTipoSaveData(data: TServicoTipoFormValues & { metodo?: 'POST' | 'PUT' }) {
// Verifica se existe ID do tipo de serviço para decidir se é atualização (PUT) ou criação (POST)
const isUpdate = Boolean(data.servico_tipo_id); // Campo de ID alterado de 'cidade_id' para 'servico_tipo_id'
const isEditing = !!data.servico_tipo_id && Number(data.servico_tipo_id) > 0;
// Define método: prioridade para valor passado manualmente (metodo)
const method = data.metodo ?? (isEditing ? 'PUT' : 'POST');
try{
console.log(data)
// Instancia o cliente da API para enviar a requisição
const api = new API(); //
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
return await api.send({
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
method: isEditing ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
endpoint: `administrativo/t_servico_tipo/${data.servico_tipo_id || ''}`, // Endpoint e ID alterados
body: data, // payload enviado para a API
});
} catch (error) {
console.error('Erro no TServicoTipoSaveData:', error);
throw error; // propaga erro para o form
}
}
// Exporta a função de salvar tipo de serviço já encapsulada com tratamento de erros

View file

@ -0,0 +1,27 @@
// Importa o utilitário responsável por tratar erros de forma padronizada no cliente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
// Importa a classe de serviço que gerencia requisições HTTP para a API
import API from '@/shared/services/api/Api';
// Importa o enum que define os métodos HTTP disponíveis (GET, POST, PUT, DELETE, etc.)
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
import { TTBReconhecimentoTipoReadInterface } from '../../_interfaces/TTBReconhecimentoTipoReadInterface';
// Função assíncrona responsável por executar a requisição para listar os tipos de marcação
async function executeTTBReconhecimentoTipoIndexData(data: TTBReconhecimentoTipoReadInterface) {
// Cria uma nova instância da classe API para enviar a requisição
const api = new API();
// Concatena o endpoint com a query string (caso existam parâmetros)
const endpoint = `administrativo/t_tb_reconhecimentotipo/`;
// Envia uma requisição GET para o endpoint 'administrativo/g_marcacao_tipo/'
return await api.send({
method: Methods.GET,
endpoint: endpoint,
});
}
// Exporta a função encapsulada pelo handler de erro, garantindo tratamento uniforme em caso de falhas
export const TTBReconhecimentoTipoIndexData = withClientErrorHandler(executeTTBReconhecimentoTipoIndexData);

View file

@ -6,14 +6,15 @@ import { useMemo, useState } from 'react';
// Importa a interface que define a estrutura dos dados de "GMarcacaoTipo"
import { GMarcacaoTipoReadInterface } from '../../_interfaces/GMarcacaoTipoReadInterface';
import { GMarcacaoTipoInterface } from '../../_interfaces/GMarcacaoTipoInterface';
// Importa o serviço responsável por buscar os dados de "GMarcacaoTipo" na API
import { GMarcacaoTipoIndexService } from '../../_services/g_marcacao_tipo/GMarcacaoTipoIndexService';
import { GMarcacaoTipoInterface } from '../../_interfaces/GMarcacaoTipoInterface';
// Hook personalizado para leitura (consulta) dos tipos de marcação
export const useGMarcacaoTipoReadHook = () => {
// Obtém a função que atualiza a resposta global do sistema
const { setResponse } = useResponse();

View file

@ -0,0 +1,44 @@
// Importa o hook responsável por gerenciar e exibir respostas globais (sucesso, erro, etc.)
import { useResponse } from '@/shared/components/response/ResponseContext';
// Importa hooks do React para gerenciamento de estado e memorização de valores
import { useCallback, useState } from 'react';
// Importa a interface que define a estrutura dos dados de "TServicoEtiqueta"
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface';
// Importa o serviço responsável por buscar os dados de "TServicoEtiqueta" na API
import { TServicoEtiquetaServicoIdService } from '../../_services/t_servico_etiqueta/TServicoEtiquetaServicoIdService';
// Hook personalizado para leitura (consulta) dos tipos de marcação
export const useTServicoEtiquetaReadHook = () => {
// Obtém a função que atualiza a resposta global do sistema
const { setResponse } = useResponse();
// Define o estado local que armazenará a lista de tipos de marcação
const [tServicoEtiqueta, setTServicoEtiqueta] = useState<TServicoEtiquetaInterface[]>([]);
// Função responsável por buscar os dados da API e atualizar o estado
const fetchTServicoEtiqueta = useCallback(async (data: TServicoEtiquetaInterface) => {
try{
// Executa o serviço que faz a requisição à API
const response = await TServicoEtiquetaServicoIdService(data);
// Atualiza o estado local com os dados retornados
setTServicoEtiqueta(response.data);
// Atualiza o contexto global de resposta (ex: para exibir alertas ou mensagens)
setResponse(response);
} catch (error) {
console.error('Erro ao buscar etiquetas:', error);
return { data: [] };
}
}, [setResponse]);
// Retorna os dados e a função de busca, memorizando o valor para evitar recriações desnecessárias
return { tServicoEtiqueta, fetchTServicoEtiqueta };
};

View file

@ -0,0 +1,25 @@
import { useResponse } from "@/shared/components/response/ResponseContext"; // Contexto global para gerenciar respostas da API
// Interface tipada do tipo de serviço
import { TServicoEtiquetaInterface } from "../../_interfaces/TServicoEtiquetaInterface";
// Função que remove o tipo de serviço via API
import { TServicoEtiquetaRemoveData } from "../../_data/TServicoEtiqueta/TServicoEtiquetaRemoveData";
// Hook customizado para remoção de tipos de serviço
export const useTServicoEtiquetaRemoveHook = () => {
// Hook do contexto de resposta para feedback global (alertas, mensagens etc.)
const { setResponse } = useResponse();
// Função assíncrona que remove um tipo de serviço
const fetchTServicoEtiquetaRemove = async (data: TServicoEtiquetaInterface) => {
// Chama a função de remoção passando os dados do tipo de serviço
const response = await TServicoEtiquetaRemoveData(data);
// Atualiza o contexto global com a resposta da API
setResponse(response);
};
// Retorna a função de remoção para ser usada no componente
return { fetchTServicoEtiquetaRemove };
};

View file

@ -0,0 +1,37 @@
import { useState } from 'react';
import { useResponse } from '@/shared/components/response/ResponseContext';
// Interface tipada do serviço etiqueta
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface';
// Serviço que salva os dados do serviço etiqueta
import { TServicoEtiquetaSaveService } from '../../_services/t_servico_etiqueta/TServicoEtiquetaSaveService';
export const useTServicoEtiquetaSaveHook = () => {
const { setResponse } = useResponse();
// Estado local para armazenar os dados do serviço etiqueta salvos
const [tServicoEtiquetaSave, setTServicoEtiquetaSave] = useState<TServicoEtiquetaInterface | null>(null);
/**
* Função que executa o salvamento de um serviço etiqueta.
* @param data Os dados do serviço etiqueta a serem salvos.
*/
const fetchTServicoEtiquetaSave = async (data: TServicoEtiquetaInterface) => {
// Chama o serviço de salvamento
const response = await TServicoEtiquetaSaveService(data);
// Guardar os dados localizados
setTServicoEtiquetaSave(response.data);
// Manda a resposta para o verificador de resposta global
///setResponse(response);
// Manda a resposta para o verificador de resposta global
return response.data;
}
// Retorna o estado e a função de salvamento para uso no componente
return { tServicoEtiquetaSave, fetchTServicoEtiquetaSave };
};

View file

@ -0,0 +1,26 @@
import { useResponse } from "@/shared/components/response/ResponseContext"; // Contexto global para gerenciar respostas da API
// Interface tipada do tipo de serviço
import TServicoTipoInterface from "../../_interfaces/TServicoTipoInterface";
// Função que Edit o tipo de serviço via API
import { TServicoTipoEditData } from "../../_data/TServicoTipo/TServicoTipoEditData";
// Hook customizado para remoção de tipos de serviço
export const useTServicoTipoEditHook = () => {
// Hook do contexto de resposta para feedback global (alertas, mensagens etc.)
const { setResponse } = useResponse();
// Função assíncrona que Edit um tipo de serviço
const editTServicoTipo = async (data: TServicoTipoInterface) => {
// Chama a função de remoção passando os dados do tipo de serviço
const response = await TServicoTipoEditData(data);
// Atualiza o contexto global com a resposta da API
setResponse(response);
};
// Retorna a função de remoção para ser usada no componente
return { editTServicoTipo };
};

View file

@ -0,0 +1,37 @@
// Importa o hook responsável por gerenciar e exibir respostas globais (sucesso, erro, etc.)
import { useResponse } from '@/shared/components/response/ResponseContext';
// Importa hooks do React para gerenciamento de estado e memorização de valores
import { useMemo, useState } from 'react';
// Importa a interface que define a estrutura dos dados de "TTBReconhecimentoTipo"
import { TTBReconhecimentoTipoReadInterface } from '../../_interfaces/TTBReconhecimentoTipoReadInterface';
import { TTBReconhecimentoTipoInterface } from '../../_interfaces/TTBReconhecimentoTipoInterface';
// Importa o serviço responsável por buscar os dados de "TTBReconhecimentoTipo" na API
import { TTBReconhecimentoTipoIndexService } from '../../_services/t_tb_reconhecimentotipo/TTBReconhecimentoTipoIndexService';
// Hook personalizado para leitura (consulta) dos tipos de marcação
export const useTTBReconhecimentoTipoReadHook = () => {
// Obtém a função que atualiza a resposta global do sistema
const { setResponse } = useResponse();
// Define o estado local que armazenará a lista de tipos de marcação
const [tTBReconhecimentoTipo, setTTBReconhecimentoTipo] = useState<TTBReconhecimentoTipoInterface[]>([]);
// Função responsável por buscar os dados da API e atualizar o estado
const fetchTTBReconhecimentoTipo = async (data: TTBReconhecimentoTipoReadInterface) => {
// Executa o serviço que faz a requisição à API
const response = await TTBReconhecimentoTipoIndexService(data);
// Atualiza o estado local com os dados retornados
setTTBReconhecimentoTipo(response.data);
// Atualiza o contexto global de resposta (ex: para exibir alertas ou mensagens)
setResponse(response);
};
// Retorna os dados e a função de busca, memorizando o valor para evitar recriações desnecessárias
return useMemo(() => ({ tTBReconhecimentoTipo, fetchTTBReconhecimentoTipo }), [tTBReconhecimentoTipo, fetchTTBReconhecimentoTipo]);
};

View file

@ -0,0 +1,7 @@
// Interface que representa a tabela T_TB_RECONHECIMENTOTIPO
export interface TServicoEtiquetaInterface {
servico_etiqueta_id?: number; // NUMERIC(10,2) NOT NULL - Chave primária
etiqueta_modelo_id?: number; // NUMERIC(10,2)
servico_tipo_id?: number; // NUMERIC(10,2)
descricao?: string
}

View file

@ -0,0 +1,3 @@
export interface TServicoEtiquetaServicoIdReadInterface {
servico_tipo_id?: number
}

View file

@ -2,34 +2,24 @@ export default interface TServicoTipoInterface {
servico_tipo_id?: number; // SERVICO_TIPO_ID NUMERIC(10,2) NOT NULL (PK)
descricao: string; // DESCRICAO VARCHAR(60)
valor?: number; // VALOR NUMERIC(14,3)
tipo_item?: string; // TIPO_ITEM VARCHAR(1)
requer_autorizacao?: string; // REQUER_AUTORIZACAO VARCHAR(1)
requer_biometria?: string; // REQUER_BIOMETRIA VARCHAR(1)
tipo_pessoa?: string; // TIPO_PESSOA VARCHAR(1)
tb_reconhecimentotipo_id?: number; // TB_RECONHECIMENTOTIPO_ID NUMERIC(10,2) (FK)
tipo_permissao_cpf?: string; // TIPO_PERMISSAO_CPF VARCHAR(1)
requer_abonador?: string; // REQUER_ABONADOR VARCHAR(1)
requer_representante?: string; // REQUER_REPRESENTANTE VARCHAR(1)
situacao?: string; // SITUACAO VARCHAR(1)
requer_cpf?: string; // REQUER_CPF VARCHAR(1)
servico_padrao?: string; // SERVICO_PADRAO VARCHAR(1)
maximo_pessoa?: number; // MAXIMO_PESSOA NUMERIC(10,2)
alterar_valor?: string; // ALTERAR_VALOR VARCHAR(1)
servico_caixa_id?: number; // SERVICO_CAIXA_ID NUMERIC(10,2)
lancar_taxa?: string; // LANCAR_TAXA VARCHAR(1)
lancar_fundesp?: string; // LANCAR_FUNDESP VARCHAR(1)
liberar_desconto?: string; // LIBERAR_DESCONTO VARCHAR(1)
fundesp_automatica?: string; // FUNDESP_AUTOMATICA VARCHAR(1)
lancar_valor_documento?: string; // LANCAR_VALOR_DOCUMENTO VARCHAR(1)
caixa_servico_id?: number; // LIBERAR_DESCONTO VARCHAR(1)
valor_fixo?: string; // VALOR_FIXO VARCHAR(1)
emolumento_id?: number; // EMOLUMENTO_ID NUMERIC(10,2) (FK)
emolumento_obrigatorio?: number; // EMOLUMENTO_OBRIGATORIO NUMERIC(10,2) (FK)
ato_praticado?: string; // ATO_PRATICADO VARCHAR(1)
selar?: string; // SELAR VARCHAR(1)
frenteverso?: string; // FRENTEVERSO VARCHAR(1)
pagina_acrescida?: string; // PAGINA_ACRESCIDA VARCHAR(1)
emolumento_obrigatorio?: number; // EMOLUMENTO_OBRIGATORIO NUMERIC(10,2)
apresentante_selo?: string; // APRESENTANTE_SELO VARCHAR(1)
renovacao_cartao?: string; // RENOVACAO_CARTAO VARCHAR(1)
etiqueta_unica?: string; // ETIQUETA_UNICA VARCHAR(1)
transferencia_veiculo?: string; // TRANSFERENCIA_VEICULO VARCHAR(1)
usar_a4?: string; // USAR_A4 VARCHAR(1)

View file

@ -0,0 +1,6 @@
// Interface que representa a tabela T_TB_RECONHECIMENTOTIPO
export interface TTbReconhecimentoTipoInterface {
tb_reconhecimentotipo_id: number; // NUMERIC(10,2) NOT NULL - Chave primária
descricao?: string; // VARCHAR(30)
situacao?: string; // VARCHAR(1)
}

View file

@ -0,0 +1,4 @@
export interface TTBReconhecimentoTipoReadInterface {
tb_reconhecimentotipo_id?: number,
descricao?: string
}

View file

@ -0,0 +1,15 @@
/**
* Interface principal baseada na DDL
* Tabela: T_SERVICO_ETIQUETA
*/
export interface TServicoEtiquetaFormValues {
/** Identificador principal (PK) */
servico_etiqueta_id?: number;
/** Relacionamento com o modelo de etiqueta (FK) */
etiqueta_modelo_id?: number;
/** Relacionamento com o tipo de serviço (FK) */
servico_tipo_id?: number;
}

View file

@ -29,15 +29,15 @@ export const TServicoTipoSchema = z.object({
etiqueta_unica: SN.optional(),
selar: SN.optional(),
servico_padrao: SN.optional(),
lancar_taxa: SN.optional(),
lancar_fundesp: SN.optional(),
liberar_desconto: SN.optional(),
fundesp_automatica: SN.optional(),
lancar_valor_documento: SN.optional(),
// lancar_taxa: SN.optional(),
// lancar_fundesp: SN.optional(),
// liberar_desconto: SN.optional(),
// fundesp_automatica: SN.optional(),
// lancar_valor_documento: SN.optional(),
valor_fixo: SN.optional(),
ato_praticado: SN.optional(),
apresentante_selo: SN.optional(),
renovacao_cartao: SN.optional(),
// apresentante_selo: SN.optional(),
// renovacao_cartao: SN.optional(),
// Situação
situacao: AI,
@ -46,8 +46,8 @@ export const TServicoTipoSchema = z.object({
valor: OptionalNumber,
maximo_pessoa: OptionalNumber,
servico_caixa_id: OptionalNumber,
emolumento_id: OptionalNumber,
emolumento_obrigatorio: OptionalNumber,
emolumento_id: z.number().nullable(),
emolumento_obrigatorio: z.number().nullable(),
// Relacionamentos e permissões
tipo_item: OneCharString,
@ -55,12 +55,12 @@ export const TServicoTipoSchema = z.object({
requer_biometria: OneCharString,
tipo_pessoa: OneCharString,
tb_reconhecimentotipo_id: OptionalNumber,
tipo_permissao_cpf: OneCharString,
// tipo_permissao_cpf: OneCharString,
requer_abonador: OneCharString,
requer_representante: OneCharString,
// requer_representante: OneCharString,
requer_cpf: OneCharString,
alterar_valor: OneCharString,
pagina_acrescida: OneCharString,
// alterar_valor: OneCharString,
// pagina_acrescida: OneCharString,
// Campos auxiliares usados apenas no formulário (não persistidos)
valor_emolumento: z.number().optional(),

View file

@ -0,0 +1,21 @@
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
// Função que salva os dados do serviço etiqueta via API (ou mock)
import { TServicoEtiquetaSaveData } from '../../_data/TServicoEtiqueta/TServicoEtiquetaSaveData';
// Interface tipada do serviço etiqueta
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface';
// Função assíncrona que executa o salvamento de um serviço etiqueta
async function executeTServicoEtiquetaSaveService(data: TServicoEtiquetaInterface) {
// Chama a função que salva os dados do serviço etiqueta
const response = await TServicoEtiquetaSaveData(data);
// Retorna a resposta do salvamento
return response;
}
// Exporta o serviço de salvamento de serviço etiqueta já encapsulado com tratamento de erros
export const TServicoEtiquetaSaveService = withClientErrorHandler(executeTServicoEtiquetaSaveService);

View file

@ -0,0 +1,20 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
import { TServicoEtiquetaReadData } from '../../_data/TServicoEtiqueta/TServicoEtiquetaReadData';
import { TServicoEtiquetaInterface } from '../../_interfaces/TServicoEtiquetaInterface';
// Interface tipada do tipo de serviço
// Função assíncrona que executa a consulta de um tipo de serviço etiqueta
async function executeTServicoEtiquetaServicoIdService(data: TServicoEtiquetaInterface) {
// Chama a função que consulta os dados do tipo de serviço etiqueta
const response = await TServicoEtiquetaReadData(data);
// Retorna a resposta da remoção
return response;
}
// Exporta o serviço de remoção de tipo de serviço já encapsulado com tratamento de erros
export const TServicoEtiquetaServicoIdService = withClientErrorHandler(executeTServicoEtiquetaServicoIdService);

View file

@ -0,0 +1,20 @@
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
import { TServicoTipoEditData } from '../../_data/TServicoTipo/TServicoTipoEditData';
// Função que remove os dados do tipo de serviço via API
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
// Interface tipada do tipo de serviço
// Função assíncrona que executa a remoção de um tipo de serviço
async function executeTServicoTipoEditService(data: TServicoTipoInterface) {
// Chama a função que remove os dados do tipo de serviço
const response = await TServicoTipoEditData(data);
// Retorna a resposta da remoção
return response;
}
// Exporta o serviço de remoção de tipo de serviço já encapsulado com tratamento de erros
export const TServicoTipoEditService = withClientErrorHandler(executeTServicoTipoEditService);

View file

@ -0,0 +1,20 @@
// Importa o utilitário responsável por lidar com erros de forma padronizada no cliente
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
// Importa a função que realiza a requisição de listagem dos tipos de marcação
import { TTBReconhecimentoTipoIndexData } from '../../_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoIndexData';
import { TTBReconhecimentoTipoReadInterface } from '../../_interfaces/TTBReconhecimentoTipoReadInterface';
// Função assíncrona responsável por executar o serviço de listagem de tipos de marcação
async function executeTTBReconhecimentoTipoIndexService(data: TTBReconhecimentoTipoReadInterface) {
// Chama a função que realiza a requisição à API e aguarda a resposta
const response = await TTBReconhecimentoTipoIndexData(data);
// Retorna a resposta obtida da requisição
return response;
}
// Exporta o serviço encapsulado pelo handler de erro, garantindo tratamento uniforme em caso de falhas
export const TTBReconhecimentoTipoIndexService = withClientErrorHandler(
executeTTBReconhecimentoTipoIndexService,
);

View file

@ -52,10 +52,8 @@ export default function CCaixaServicoSelect({ sistema_id, field }: any) {
>
{isLoading
? "Carregando..."
: field.value && typeof field.value === 'object' && field.value.value
? GetCapitalize(field.value.value) // Exibe a descrição do objeto
: field.value && typeof field.value !== 'object'
? field.value // Se for um ID (valor antigo), exibe ele
: selected
? GetCapitalize(selected.descricao)
: "Selecione o serviço"}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
@ -75,10 +73,7 @@ export default function CCaixaServicoSelect({ sistema_id, field }: any) {
key={item.caixa_servico_id}
value={item.descricao?.toLowerCase() ?? ""}
onSelect={() => {
field.onChange({
key: Number(item.caixa_servico_id),
value: item.descricao,
});
field.onChange(Number(item.caixa_servico_id)); // envia apenas o número
setOpen(false);
}}
>

View file

@ -56,7 +56,7 @@ export default function GEmolumentoSelect({ sistema_id, field, onSelectChange, c
// Obtém o item selecionado com base no valor atual do campo
const selected = gEmolumento?.find(
(item) => String(item.emolumento_id) === String(field.value?.key ?? field.value)
(item) => Number(item.emolumento_id) === Number(field.value ?? 0)
);
@ -112,6 +112,7 @@ export default function GEmolumentoSelect({ sistema_id, field, onSelectChange, c
className="cursor-pointer w-full"
key={item.emolumento_id}
value={item.descricao?.toLowerCase() ?? ""}
// Quando o item é selecionado
onSelect={() => {
// Cria objeto com ID e descrição
@ -120,15 +121,20 @@ export default function GEmolumentoSelect({ sistema_id, field, onSelectChange, c
value: item.descricao,
};
// Atualiza o valor no react-hook-form
field.onChange(selectedValue);
// Atualiza o valor no react-hook-form com o ID numérico
field.onChange(Number(item.emolumento_id ?? 0));
// Dispara callback externo, se existir (ex: fetchGEmolumentoItem)
if (onSelectChange) onSelectChange(selectedValue);
// Dispara callback externo, se existir (mantém o objeto completo)
if (onSelectChange)
onSelectChange({
key: Number(item.emolumento_id),
value: item.descricao,
});
// Fecha o popover
setOpen(false);
}}
>
{/* Ícone de seleção (check) */}
<CheckIcon

View file

@ -0,0 +1,95 @@
'use client';
import React from "react";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import { FormControl } from "@/components/ui/form";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
import GetCapitalize from "@/shared/actions/text/GetCapitalize";
import { useTTBReconhecimentoTipoReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/t_tb_reconhecimentotipo/useTTBReconhecimentoTipoReadHook";
import { TTBREconhecimentoTipoReadInterface } from "@/app/(protected)/(cadastros)/cadastros/_interfaces/TTBREconhecimentoTipoReadInterface";
export default function TTBReconhecimentoTipoSelect({ field }: any) {
const [open, setOpen] = React.useState(false);
const [isLoading, setIsLoading] = React.useState(false);
const { tTBReconhecimentoTipo, fetchTTBReconhecimentoTipo } = useTTBReconhecimentoTipoReadHook();
// Busca os dados uma única vez ao montar
React.useEffect(() => {
const loadData = async () => {
if (!tTBReconhecimentoTipo.length) {
setIsLoading(true);
await fetchTTBReconhecimentoTipo();
setIsLoading(false);
}
};
loadData();
}, []);
const selected = tTBReconhecimentoTipo?.find(
(item) => Number(item.tb_reconhecimentotipo_id) === Number(field.value)
);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<FormControl className="w-full">
<Button
variant="outline"
role="combobox"
aria-expanded={open}
disabled={isLoading}
className="justify-between cursor-pointer"
>
{isLoading
? "Carregando..."
: selected
? GetCapitalize(selected.descricao)
: "Selecione o serviço"}
<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 etiquetas/carimbos..." />
<CommandList>
<CommandEmpty>
{isLoading ? "Carregando..." : "Nenhum resultado encontrado."}
</CommandEmpty>
<CommandGroup>
{tTBReconhecimentoTipo?.map((item) => (
<CommandItem
className="cursor-pointer"
key={item.tb_reconhecimentotipo_id}
value={item.descricao?.toLowerCase() ?? ""}
onSelect={() => {
field.onChange(Number(item.tb_reconhecimentotipo_id)); // envia apenas o número
setOpen(false);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
String(field.value) === String(item.tb_reconhecimentotipo_id)
? "opacity-100"
: "opacity-0"
)}
/>
{GetCapitalize(item.descricao)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

View file

@ -0,0 +1,28 @@
import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form";
import { Checkbox } from "@/components/ui/checkbox";
interface ConfirmacaoCheckBoxProps {
name: string;
label: string;
control: any;
}
export function ConfirmacaoCheckBox({ name, label, control }: ConfirmacaoCheckBoxProps) {
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
<FormControl>
<Checkbox
checked={field.value === "S"}
onCheckedChange={(checked) => field.onChange(checked ? "S" : "N")}
/>
</FormControl>
<FormLabel className="font-normal cursor-pointer">{label}</FormLabel>
</FormItem>
)}
/>
);
}

View file

@ -31,16 +31,16 @@ export default function ConfirmacaoSelect({ field }: any) {
variant="outline"
role="combobox"
aria-expanded={open}
className="justify-between"
className="justify-between cursor-pointer"
>
{field.value
? options.find((item) => item.value === field.value)?.label
: 'Selecione...'}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50 cursor-pointer" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<PopoverContent className="w-full p-0 cursor-pointer">
<Command>
<CommandInput placeholder="Buscar situação..." />
<CommandList>
@ -48,6 +48,7 @@ export default function ConfirmacaoSelect({ field }: any) {
<CommandGroup>
{options.map((item) => (
<CommandItem
className="cursor-pointer"
key={item.value}
value={item.label.toLowerCase()}
onSelect={() => {
@ -57,7 +58,7 @@ export default function ConfirmacaoSelect({ field }: any) {
>
<CheckIcon
className={cn(
'mr-2 h-4 w-4',
'mr-2 h-4 w-4 cursor-pointer',
field.value === item.value ? 'opacity-100' : 'opacity-0',
)}
/>

View file

@ -0,0 +1,68 @@
"use client";
import React from "react";
import { Control, FieldValues, Path } from "react-hook-form";
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
interface NumericInputFieldProps<T extends FieldValues> {
control: Control<T>;
name: Path<T>;
label?: string;
placeholder?: string;
disabled?: boolean;
min?: number;
max?: number;
}
export function NumericInputField<T extends FieldValues>({
control,
name,
label = "Número",
placeholder = "Digite um número",
disabled = false,
min,
max,
}: NumericInputFieldProps<T>) {
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem className="w-full">
{label && <FormLabel>{label}</FormLabel>}
<FormControl>
<Input
{...field}
type="text"
disabled={disabled}
value={field.value ?? ""}
placeholder={placeholder}
inputMode="numeric"
pattern="[0-9]*"
onChange={(e) => {
// Mantém apenas números
let value = e.target.value.replace(/[^0-9]/g, "");
// Limita faixa, se definido
if (min !== undefined && Number(value) < min) value = String(min);
if (max !== undefined && Number(value) > max) value = String(max);
field.onChange(value);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}

View file

@ -0,0 +1,66 @@
"use client";
import React from "react";
import { Control, FieldValues, Path } from "react-hook-form";
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from "@/components/ui/form";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/components/ui/select";
interface PessoaTipoSelectProps<T extends FieldValues> {
control: Control<T>;
name: Path<T>;
label?: string;
disabled?: boolean;
placeholder?: string;
}
export function TipoPessoaSelect<T extends FieldValues>({
control,
name,
label = "Pessoa",
disabled = false,
placeholder = "Selecione uma opção",
}: PessoaTipoSelectProps<T>) {
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem className="w-full">
{label && <FormLabel>{label}</FormLabel>}
<Select
value={field.value}
onValueChange={field.onChange}
disabled={disabled}
>
<FormControl className="w-full">
<SelectTrigger className="w-full cursor-pointer">
<SelectValue placeholder={placeholder} />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="F" className="cursor-pointer">
Física
</SelectItem>
<SelectItem value="J" className="cursor-pointer">
Jurídica
</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
);
}