From 56bca3ba41d989034fec48651791b8bec93aa5f3 Mon Sep 17 00:00:00 2001 From: Kenio de Souza Date: Fri, 17 Oct 2025 18:21:30 -0300 Subject: [PATCH] =?UTF-8?q?[MVPTN-86]=20feat(CRUD):=20Adicionado=20recurso?= =?UTF-8?q?s=20din=C3=A2micos=20de=20select?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../t_servico_tipo/TServicoTipoForm.tsx | 572 +++++++++++++++--- .../CCaixaServico/CCaixaServicoIndexData.ts | 27 + .../_data/GEmolumento/GEmolumentoIndexData.ts | 27 + .../GEmolumentoItemValorData.ts | 27 + .../useCCaixaServicoReadHook.ts | 37 ++ .../g_emolumento/useGEmolumentoReadHook.ts | 37 ++ .../useGEmolumentoItemReadHook.ts | 46 ++ .../_interfaces/CCaixaServicoInterface.ts | 17 + .../_interfaces/CCaixaServicoReadInterface.ts | 3 + .../_interfaces/GEmolumentoInterface.ts | 20 + .../_interfaces/GEmolumentoItemInterface.ts | 32 + .../GEmolumentoItemReadInterface.ts | 4 + .../_interfaces/GEmolumentoReadInterface.ts | 3 + .../cadastros/_schemas/TServicoTipoSchema.ts | 182 +++--- .../CCaixaServicoIndexService.ts | 20 + .../g_emolumento/GEmolumentoIndexService.ts | 20 + .../GEmolumentoItemValorService.ts | 20 + src/components/ui/table.tsx | 86 ++- .../CCaixaServico/CCaixaServicoSelect.tsx | 102 ++++ .../GEmolumento/GEmolumentoSelect.tsx | 152 +++++ .../GMarcacaoTipo/GMarcacaoTipoSelect.tsx | 13 +- .../CategoriaServicoSelect.tsx | 87 +++ src/shared/enums/CategoriaServicoEnum.ts | 7 + 23 files changed, 1306 insertions(+), 235 deletions(-) create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/CCaixaServico/CCaixaServicoIndexData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GEmolumento/GEmolumentoIndexData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_data/GEmolumentoItem/GEmolumentoItemValorData.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/c_caixa_servico/useCCaixaServicoReadHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoReadInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/c_caixa_servico/CCaixaServicoIndexService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento/GEmolumentoIndexService.ts create mode 100644 src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento_item/GEmolumentoItemValorService.ts create mode 100644 src/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect.tsx create mode 100644 src/packages/administrativo/components/GEmolumento/GEmolumentoSelect.tsx create mode 100644 src/shared/components/categoriaServicoSelect/CategoriaServicoSelect.tsx create mode 100644 src/shared/enums/CategoriaServicoEnum.ts diff --git a/src/app/(protected)/(cadastros)/cadastros/_components/t_servico_tipo/TServicoTipoForm.tsx b/src/app/(protected)/(cadastros)/cadastros/_components/t_servico_tipo/TServicoTipoForm.tsx index 9c03c25..30b4e1a 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_components/t_servico_tipo/TServicoTipoForm.tsx +++ b/src/app/(protected)/(cadastros)/cadastros/_components/t_servico_tipo/TServicoTipoForm.tsx @@ -1,9 +1,10 @@ 'use client'; +import React from "react"; import z from 'zod'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; - +import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -15,7 +16,7 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { DollarSign, Settings, SquarePen } from 'lucide-react'; +import { CirclePlus, DollarSign, Settings, SquarePen, Trash } from 'lucide-react'; import { Form, FormControl, @@ -33,49 +34,143 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" -import { TServicoTipoSchema } from '../../_schemas/TServicoTipoSchema'; +import { TServicoTipoSchema, TServicoTipoFormValues } from '../../_schemas/TServicoTipoSchema'; import { useEffect } from 'react'; import GMarcacaoTipoSelect from '@/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect'; - -// Tipo inferido a partir do schema Zod -type FormValues = z.infer; +import GEmolumentoSelect from '@/packages/administrativo/components/GEmolumento/GEmolumentoSelect'; +import { useGEmolumentoItemReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook"; +import { GEmolumentoItemReadInterface } from "@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface"; +import CategoriaServicoSelect from "@/shared/components/categoriaServicoSelect/CategoriaServicoSelect"; +import CCaixaServicoSelect from "@/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect"; // Propriedades esperadas pelo componente interface Props { isOpen: boolean; - data: FormValues | null; + data: TServicoTipoFormValues | null; onClose: (item: null, isFormStatus: boolean) => void; - onSave: (data: FormValues) => void; + onSave: (data: TServicoTipoFormValues) => void; } // Componente principal do formulário export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Props) { + // Estado para gerenciar os itens da tabela de etiquetas/carimbos + const [itensTabela, setItensTabela] = useState<{ marcacao_tipo_id: string; descricao: string }[]>([]); + + // Função para adicionar um novo item à tabela + const handleAddEtiquetaCarimbo = () => { + const valorSelecionado = form.getValues('etiquetas_carimbos'); + + 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 } + const item = { + + marcacao_tipo_id: valorSelecionado.key ?? valorSelecionado, // ou ajusta conforme a estrutura do seu componente + descricao: valorSelecionado.value ?? 'Sem descrição', + }; + + // Evita duplicatas + setItensTabela((prev) => { + if (prev.some((p) => p.marcacao_tipo_id === item.marcacao_tipo_id)) return prev; + return [...prev, item]; + }); + }; + + const handleRemoveItem = (marcacao_tipo_id: string) => { + setItensTabela((prev) => prev.filter((p) => p.marcacao_tipo_id !== marcacao_tipo_id)); + }; + + + // Parâmetros para o hook de leitura de emolumento_item + // Inicializa com valores padrão (0) para evitar uso de propriedades não declaradas. + const gEmolumentoItemReadParams: GEmolumentoItemReadInterface = { emolumento_id: 0, valor: 0 }; + + // Estados locais + const [open, setOpen] = React.useState(false); + const [isLoading, setIsLoading] = React.useState(false); + + // Hook que realiza a leitura do emolumento_item + const { gGEmolumentoItem, fetchGEmolumentoItem } = useGEmolumentoItemReadHook(); + + // Busca os dados ao montar o componente (somente se houver ID válido) + React.useEffect(() => { + const loadData = async () => { + // Validação: só executa se houver emolumento_id informado e válido + if ( + !gEmolumentoItemReadParams?.emolumento_id || // se não existir o campo + isNaN(Number(gEmolumentoItemReadParams.emolumento_id)) || // se não for número + Number(gEmolumentoItemReadParams.emolumento_id) <= 0 // se for zero ou negativo + ) { + return; // encerra sem executar a busca + } + + // Executa a busca apenas se ainda não houver dados carregados + if (!gGEmolumentoItem.length) { + setIsLoading(true); + await fetchGEmolumentoItem(gEmolumentoItemReadParams); + setIsLoading(false); + } + }; + + loadData(); + }, [gEmolumentoItemReadParams.emolumento_id]); + + // Inicializa o react-hook-form com validação via Zod - const form = useForm({ - resolver: zodResolver(TServicoTipoSchema), - defaultValues: { - servico_tipo_id: 0, - descricao: '', - categoria: '', - servico_padrao: '', - servico_caixa: '', - averbacao: false, - transferencia_veiculo: false, - usar_a4: false, - etiqueta_unica: '', - }, - }); +const form = useForm({ + resolver: zodResolver(TServicoTipoSchema), + defaultValues: { + servico_tipo_id: 0, + descricao: "", + categoria: "", + 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, + }, +}); + + // 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) { + + if (data && Number(data.servico_tipo_id) > 0) { + + //Carrega os valores no form form.reset(data); } else { - form.reset(); + + // 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: '', + }); } - }, [data, form]); + }, [data, form]); return ( Dados do Tipo de Serviço - + Configurações - + Valores @@ -141,25 +244,11 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop control={form.control} name="categoria" render={({ field }) => ( - + Categoria - + )} @@ -198,27 +287,14 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop
( Serviço Caixa - + )} @@ -233,9 +309,10 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop render={({ field }) => ( - field.onChange(checked ? "S" : "N")} // salva "S" ou "N" /> Averbação @@ -252,9 +329,10 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop render={({ field }) => ( - field.onChange(checked ? "S" : "N")} // salva "S" ou "N" /> Transferência Veículo @@ -271,9 +349,10 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop render={({ field }) => ( - field.onChange(checked ? "S" : "N")} // grava "S" ou "N" /> Usar A4 @@ -290,9 +369,10 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop render={({ field }) => ( - field.onChange(checked ? "S" : "N")} // grava "S" ou "N" /> Etiqueta Única @@ -300,6 +380,63 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop )} />
+ + + {/* Campo: Frente/Verso (Texto normal) */} +
+ { + const categoriaSelecionada = form.watch("categoria"); + const isEnabled = categoriaSelecionada === "A"; + + return ( + + + field.onChange(checked ? "S" : "N")} // grava "S" ou "N" + disabled={!isEnabled} + /> + + Frente/Verso + + ); + }} + /> +
+ + + {/* Campo: Etiqueta Única (Texto normal) */} +
+ { + // Considera "A" ou vazio como marcado + const isChecked = field.value === "A" || !field.value; + + return ( + + + { + field.onChange(checked ? "A" : "I"); // grava "A" ou "I" no form + }} + /> + + Ativo + + ); + }} + /> +
+ + @@ -408,7 +545,7 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop /> -
Requerer
+
Requerer:
{/* Campo: Biometria (Select) */}
@@ -526,30 +663,283 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop {/* Campo: etiquetas/carimbos (Select) */} -
+
( Etiquetas/Carimbos - + )} /> -
+
+ + + {/* Campo: etiquetas/carimbos botão adicionar */} +
+ +   + + +
+ + + {/* Campo: etiquetas/carimbos (Select) */} +
+ + + + # + Descrição + + + + + {itensTabela.map((item, index) => ( + + + {String(index + 1).padStart(3, '0')} + + {item.descricao} + + + + + ))} + + {itensTabela.length === 0 && ( + + + Nenhum item adicionado + + + )} + +
+
+
- 003 + +
+ + {/* Campo: Biometria (Select) */} +
+ ( + + Selar + + + + )} + /> +
+ + + {/* Campo: emolumentos (Select) */} +
+ ( + + Emolumento + { + // Extrai o ID do emolumento selecionado + const emolumentoId = Number(selected?.key); + + // Se o ID for inválido, encerra sem fazer a requisição + if (!emolumentoId || isNaN(emolumentoId) || emolumentoId <= 0) return; + + setIsLoading(true); + + try { + // Faz a requisição para buscar o item do emolumento + const response = await fetchGEmolumentoItem({ + emolumento_id: emolumentoId, + valor: 0, + }); + + // Extrai o primeiro item do array "data" + const item = response?.data?.[0]; + + // Se existir item, atualiza os campos do formulário + if (item) { + form.setValue("valor_emolumento", item.valor_emolumento ?? 0); + form.setValue("valor_taxa_judiciaria", item.valor_taxa_judiciaria ?? 0); + // form.setValue("fundesp_valor", item.valor_outra_taxa1 ?? 0); + // form.setValue("valor_pagina_extra", item.valor_pagina_extra ?? 0); + // form.setValue("emolumento_item_id", item.emolumento_item_id ?? 0); + + // (💡 opcional) Atualiza o total automaticamente + const total = + (item.valor_emolumento ?? 0) + + (item.valor_taxa_judiciaria ?? 0) + + (item.valor_outra_taxa1 ?? 0); + + form.setValue("valor_total", total); + } + } catch (error) { + console.error("Erro ao buscar item de emolumento:", error); + } finally { + setIsLoading(false); + } + }} + /> + + + + )} + /> + +
+ + + {/* Campo: emolumentos adicional (Select) */} +
+ ( + + Emolumento Adicional (Mesma etiqueta) + + + + )} + /> +
+ + + {/* Campo: Quantidade de pessoas */} +
+ ( + + Emolumento R$ + + + + + + )} + /> +
+ + {/* Campo: Quantidade de pessoas */} +
+ ( + + Taxa Judiciária R$ + + + + + + )} + /> +
+ + {/* Campo: Quantidade de pessoas */} +
+ ( + + Fundesp R$ + + + + + + )} + /> +
+ + {/* Campo: Quantidade de pessoas */} +
+ ( + + Total R$ + + + + + + )} + /> +
+ + +
+
{/* Campo oculto: ID */} @@ -559,11 +949,19 @@ export default function TServicoTipoForm({ isOpen, data, onClose, onSave }: Prop {/* Rodapé do diálogo */} - - + diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/CCaixaServico/CCaixaServicoIndexData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/CCaixaServico/CCaixaServicoIndexData.ts new file mode 100644 index 0000000..09372dc --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/CCaixaServico/CCaixaServicoIndexData.ts @@ -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 { CCaixaServicoReadInterface } from '../../_interfaces/CCaixaServicoReadInterface'; + +// Função assíncrona responsável por executar a requisição para listar os tipos de marcação +async function executeCCaixaServicoIndexData(data: CCaixaServicoReadInterface) { + // 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/c_caixa_servico/sistema/${data.sistema_id}`; + + // 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 CCaixaServicoIndexData = withClientErrorHandler(executeCCaixaServicoIndexData); diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumento/GEmolumentoIndexData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumento/GEmolumentoIndexData.ts new file mode 100644 index 0000000..422fb54 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumento/GEmolumentoIndexData.ts @@ -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 { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInterface'; + +// Função assíncrona responsável por executar a requisição para listar os tipos de marcação +async function executeGEmolumentoIndexData(data: GEmolumentoReadInterface) { + // 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/g_emolumento/${data.sistema_id}`; + + // 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 GEmolumentoIndexData = withClientErrorHandler(executeGEmolumentoIndexData); diff --git a/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumentoItem/GEmolumentoItemValorData.ts b/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumentoItem/GEmolumentoItemValorData.ts new file mode 100644 index 0000000..96da087 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_data/GEmolumentoItem/GEmolumentoItemValorData.ts @@ -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 { GEmolumentoItemReadInterface } from '../../_interfaces/GEmolumentoItemReadInterface'; + +// Função assíncrona responsável por executar a requisição para listar os tipos de marcação +async function executeGEmolumentoItemValorData(data: GEmolumentoItemReadInterface) { + // 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/g_emolumento_item/faixa/${data.emolumento_id}/${data.valor}`; + + // 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 GEmolumentoItemValorData = withClientErrorHandler(executeGEmolumentoItemValorData); diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/c_caixa_servico/useCCaixaServicoReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/c_caixa_servico/useCCaixaServicoReadHook.ts new file mode 100644 index 0000000..1a4b34d --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/c_caixa_servico/useCCaixaServicoReadHook.ts @@ -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 "CCaixaServico" +import { CCaixaServicoReadInterface } from '../../_interfaces/CCaixaServicoReadInterface'; + +// Importa o serviço responsável por buscar os dados de "CCaixaServico" na API +import { CCaixaServicoIndexService } from '../../_services/c_caixa_servico/CCaixaServicoIndexService'; +import { CCaixaServicoInterface } from '../../_interfaces/CCaixaServicoInterface'; + + +// Hook personalizado para leitura (consulta) dos tipos de marcação +export const useCCaixaServicoReadHook = () => { + // 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 [cCaixaServico, setCCaixaServico] = useState([]); + + // Função responsável por buscar os dados da API e atualizar o estado + const fetchCCaixaServico = async (data: CCaixaServicoReadInterface) => { + // Executa o serviço que faz a requisição à API + const response = await CCaixaServicoIndexService(data); + + // Atualiza o estado local com os dados retornados + setCCaixaServico(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(() => ({ cCaixaServico, fetchCCaixaServico }), [cCaixaServico, fetchCCaixaServico]); +}; diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook.ts new file mode 100644 index 0000000..d4bd9df --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook.ts @@ -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 "GEmolumento" +import { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInterface'; + +// Importa o serviço responsável por buscar os dados de "GEmolumento" na API +import { GEmolumentoIndexService } from '../../_services/g_emolumento/GEmolumentoIndexService'; +import { GEmolumentoInterface } from '../../_interfaces/GEmolumentoInterface'; + + +// Hook personalizado para leitura (consulta) dos emolumentos +export const useGEmolumentoReadHook = () => { + // Obtém a função que atualiza a resposta global do sistema + const { setResponse } = useResponse(); + + // Define o estado local que armazenará a lista de emolumentos + const [gEmolumento, setGEmolumento] = useState([]); + + // Função responsável por buscar os dados da API e atualizar o estado + const fetchGEmolumento = async (data: GEmolumentoReadInterface) => { + // Executa o serviço que faz a requisição à API + const response = await GEmolumentoIndexService(data); + + // Atualiza o estado local com os dados retornados + setGEmolumento(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(() => ({ gEmolumento, fetchGEmolumento }), [gEmolumento, fetchGEmolumento]); +}; diff --git a/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook.ts b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook.ts new file mode 100644 index 0000000..a6ef557 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook.ts @@ -0,0 +1,46 @@ +// 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 "gEmolumentoItem" +import { GEmolumentoItemReadInterface } from '../../_interfaces/GEmolumentoItemReadInterface'; + +// Importa o serviço responsável por buscar os dados de "GEmolumentoItem" na API +import { GEmolumentoItemValorService } from '../../_services/g_emolumento_item/GEmolumentoItemValorService'; +import { GEmolumentoItemInterface } from '../../_interfaces/GEmolumentoItemInterface'; + + +// Hook personalizado para leitura (consulta) dos emolumentos +export const useGEmolumentoItemReadHook = () => { + const { setResponse } = useResponse(); + const [gGEmolumentoItem, setGEmolumentoItem] = useState([]); + + const fetchGEmolumentoItem = async (data: GEmolumentoItemReadInterface) => { + try { + const response = await GEmolumentoItemValorService(data); + + // Atualiza estado e contexto + setGEmolumentoItem(response.data); + setResponse(response); + + // Retorna a resposta completa (para uso externo) + return response; + + } catch (error) { + console.error("Erro ao buscar item de emolumento:", error); + setResponse({ + message: "Erro ao buscar item de emolumento", + error: error instanceof Error ? error.message : String(error), + }); + return null; // Retorna nulo para segurança + } + }; + + // Retorna função e dados memorizados + return useMemo( + () => ({ gGEmolumentoItem, fetchGEmolumentoItem }), + [gGEmolumentoItem] + ); +}; diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoInterface.ts new file mode 100644 index 0000000..13fd319 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoInterface.ts @@ -0,0 +1,17 @@ +// Interface que representa a tabela C_CAIXA_SERVICO +export interface CCaixaServicoInterface { + interno_sistema?: string; // VARCHAR(1) + caixa_servico_id: number; // NUMERIC(10,2) NOT NULL - Chave primária + descricao?: string; // VARCHAR(60) + situacao?: string; // VARCHAR(1) + tipo_transacao?: string; // VARCHAR(1) + sistema_id?: number; // NUMERIC(14,3) + selo_grupo_id?: number; // NUMERIC(10,2) + emitir_relatorio?: string; // VARCHAR(1) + repasse?: string; // VARCHAR(1) + repetir_descricao?: string; // VARCHAR(1) + codigo_conta?: number; // NUMERIC(10,2) + tipo_conta_carneleao?: string; // VARCHAR(60) + centro_de_custa_id?: number; // NUMERIC(10,2) - Chave estrangeira + devolucao_juizo?: string; // VARCHAR(1) +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoReadInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoReadInterface.ts new file mode 100644 index 0000000..b528407 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoReadInterface.ts @@ -0,0 +1,3 @@ +export interface CCaixaServicoReadInterface { + sistema_id?: number; +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoInterface.ts new file mode 100644 index 0000000..9998089 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoInterface.ts @@ -0,0 +1,20 @@ +// Interface que representa a tabela G_EMOLUMENTO +export interface GEmolumentoInterface { + emolumento_id?: number; // NUMERIC(10,2) - Chave primária + descricao?: string; // VARCHAR(260) + tipo?: string; // VARCHAR(1) + sistema_id?: number; // NUMERIC(10,2) + selo_grupo_id?: number; // NUMERIC(10,2) + reg_averb?: string; // VARCHAR(1) + pre_definido?: string; // VARCHAR(1) + situacao?: string; // VARCHAR(1) + situacao_ri?: string; // VARCHAR(1) + com_reducao?: string; // VARCHAR(1) + motivo_reducao?: string; // VARCHAR(120) + valor_maximo_certidao?: number; // NUMERIC(14,3) + tipo_objetivo?: string; // VARCHAR(3) + modelo_tag?: string; // VARCHAR(3) + codigo_nota_id?: number; // NUMERIC(10,2) + convenio_codhab?: string; // VARCHAR(1) + item_df?: string; // VARCHAR(10) +} diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemInterface.ts new file mode 100644 index 0000000..609426d --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemInterface.ts @@ -0,0 +1,32 @@ +// Interface que representa a tabela G_EMOLUMENTO_ITEM (inferido) +export interface GEmolumentoItemInterface { + valor_emolumento?: number; // NUMERIC(14,3) + emolumento_item_id: number; // NUMERIC(10,2) NOT NULL - Chave primária (assumida) + emolumento_id?: number; // NUMERIC(10,2) + valor_inicio?: number; // NUMERIC(14,3) + valor_fim?: number; // NUMERIC(14,3) + valor_taxa_judiciaria?: number; // NUMERIC(14,3) + emolumento_periodo_id?: number; // NUMERIC(10,2) + codigo?: number; // NUMERIC(10,2) + pagina_extra?: number; // NUMERIC(10,2) + valor_pagina_extra?: number; // NUMERIC(14,3) + valor_outra_taxa1?: number; // NUMERIC(14,3) + codigo_selo?: string; // VARCHAR(30) + valor_fundo_ri?: number; // NUMERIC(14,3) + codigo_tabela?: string; // VARCHAR(30) + selo_grupo_id?: number; // NUMERIC(10,2) + codigo_km?: string; // VARCHAR(30) + emolumento_acresce?: number; // NUMERIC(14,3) + taxa_acresce?: number; // NUMERIC(14,3) + funcivil_acresce?: number; // NUMERIC(14,3) + valor_fracao?: number; // NUMERIC(14,3) + valor_por_excedente_emol?: number; // NUMERIC(14,3) + valor_por_excedente_tj?: number; // NUMERIC(14,3) + valor_por_excedente_fundo?: number; // NUMERIC(14,3) + valor_limite_excedente_emol?: number; // NUMERIC(14,3) + valor_limite_excedente_tj?: number; // NUMERIC(14,3) + valor_limite_excedente_fundo?: number; // NUMERIC(14,3) + fundo_selo?: number; // NUMERIC(14,3) + distribuicao?: number; // NUMERIC(14,3) + vrc_ext?: number; // NUMERIC(10,2) - Renomeado de VRCEXT para vrc_ext (convenção) +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface.ts new file mode 100644 index 0000000..1ba73db --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface.ts @@ -0,0 +1,4 @@ +export interface GEmolumentoItemReadInterface { + emolumento_id?: number, + valor?: number +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface.ts b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface.ts new file mode 100644 index 0000000..3e2f596 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface.ts @@ -0,0 +1,3 @@ +export interface GEmolumentoReadInterface { + sistema_id?: number +} \ No newline at end of file diff --git a/src/app/(protected)/(cadastros)/cadastros/_schemas/TServicoTipoSchema.ts b/src/app/(protected)/(cadastros)/cadastros/_schemas/TServicoTipoSchema.ts index 8276189..84a6ed1 100644 --- a/src/app/(protected)/(cadastros)/cadastros/_schemas/TServicoTipoSchema.ts +++ b/src/app/(protected)/(cadastros)/cadastros/_schemas/TServicoTipoSchema.ts @@ -1,122 +1,78 @@ -import z from 'zod'; +import z from "zod"; -// Define um esquema para campos de 1 caractere (sim/não ou tipo) -// Poderia ser um z.enum(['S', 'N']) mais restritivo dependendo da regra de negócio, -// mas seguindo o padrão da DDL (VARCHAR(1)), o string.max(1) é mais flexível. -const OneCharString = z.string().max(1, 'Deve ter no máximo 1 caractere').optional(); - -// Define um esquema para campos string obrigatórios -const RequiredString = z.string().min(1, 'O campo é obrigatório'); - -// Define um esquema para campos numéricos opcionais, baseados em NUMERIC(10,2) ou similar +/** + * Tipos utilitários para campos simples + */ +const SN = z.enum(["S", "N"]).default("N"); // Campos do tipo Sim/Não +const AI = z.enum(["A", "I"]).default("A"); // Situação Ativo/Inativo +const OneCharString = z.string().max(1, "Deve ter no máximo 1 caractere").optional(); +const RequiredString = z.string().min(1, "O campo é obrigatório"); const OptionalNumber = z.number().optional(); - -// Define um esquema para campos numéricos obrigatórios const RequiredNumber = z.number(); +/** + * Schema principal baseado na DDL e adaptado ao formulário React + */ export const TServicoTipoSchema = z.object({ - // Chave primária: NOT NULL na DDL - servico_tipo_id: RequiredNumber.describe('ID do Tipo de Serviço').optional(), // Mantido optional seguindo o padrão de GCidadeSchema para chaves ID - - // VARCHAR(60) - descricao: z.string().max(60, 'A descrição deve ter no máximo 60 caracteres').optional(), - - // NUMERIC(14,3) - valor: z.number().optional(), - - // VARCHAR(1) - tipo_item: OneCharString, - - // VARCHAR(1) - requer_autorizacao: OneCharString, - - // VARCHAR(1) - requer_biometria: OneCharString, - - // VARCHAR(1) - tipo_pessoa: OneCharString, - - // NUMERIC(10,2) - Chave estrangeira - tb_reconhecimentotipo_id: OptionalNumber, - - // VARCHAR(1) - tipo_permissao_cpf: OneCharString, - - // VARCHAR(1) - requer_abonador: OneCharString, - - // VARCHAR(1) - requer_representante: OneCharString, - - // VARCHAR(1) - situacao: OneCharString, - - // VARCHAR(1) - requer_cpf: OneCharString, - - // VARCHAR(1) - servico_padrao: OneCharString, - - // NUMERIC(10,2) + // Identificador + servico_tipo_id: RequiredNumber.describe("ID do Tipo de Serviço").optional(), + + // Campos principais + descricao: z.string().max(60, "A descrição deve ter no máximo 60 caracteres").optional(), + categoria: z.string().optional(), + + // Controle de flags (S/N) + frenteverso: SN.optional(), + averbacao: SN.optional(), + transferencia_veiculo: SN.optional(), + usar_a4: SN.optional(), + 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(), + valor_fixo: SN.optional(), + ato_praticado: SN.optional(), + apresentante_selo: SN.optional(), + renovacao_cartao: SN.optional(), + + // Situação + situacao: AI, + + // Campos numéricos + valor: OptionalNumber, maximo_pessoa: OptionalNumber, - - // VARCHAR(1) - alterar_valor: OneCharString, - - // NUMERIC(10,2) servico_caixa_id: OptionalNumber, - - // VARCHAR(1) - lancar_taxa: OneCharString, - - // VARCHAR(1) - lancar_fundesp: OneCharString, - - // VARCHAR(1) - liberar_desconto: OneCharString, - - // VARCHAR(1) - fundesp_automatica: OneCharString, - - // VARCHAR(1) - lancar_valor_documento: OneCharString, - - // VARCHAR(1) - valor_fixo: OneCharString, - - // NUMERIC(10,2) - Chave estrangeira emolumento_id: OptionalNumber, - - // VARCHAR(1) - ato_praticado: OneCharString, - - // VARCHAR(1) - selar: OneCharString, - - // VARCHAR(1) - frenteverso: OneCharString, - - // VARCHAR(1) - pagina_acrescida: OneCharString, - - // NUMERIC(10,2) emolumento_obrigatorio: OptionalNumber, - - // VARCHAR(1) - apresentante_selo: OneCharString, - - // VARCHAR(1) - renovacao_cartao: OneCharString, - - // VARCHAR(1) - etiqueta_unica: OneCharString, - - // VARCHAR(1) - transferencia_veiculo: OneCharString, - - // VARCHAR(1) - usar_a4: OneCharString, - - // VARCHAR(1) - averbacao: OneCharString, -}); \ No newline at end of file + + // Relacionamentos e permissões + tipo_item: OneCharString, + requer_autorizacao: OneCharString, + requer_biometria: OneCharString, + tipo_pessoa: OneCharString, + tb_reconhecimentotipo_id: OptionalNumber, + tipo_permissao_cpf: OneCharString, + requer_abonador: OneCharString, + requer_representante: OneCharString, + requer_cpf: OneCharString, + alterar_valor: OneCharString, + pagina_acrescida: OneCharString, + + // Campos auxiliares usados apenas no formulário (não persistidos) + valor_emolumento: z.number().optional(), + valor_taxa_judiciaria: z.number().optional(), + fundesp_valor: z.number().optional(), + valor_total: z.number().optional(), + etiquetas_carimbos: z.any().optional(), + emolumento: z.any().optional(), + emolumento_auxiliar: z.any().optional(), +}); + +/** + * Tipo inferido do schema — usado diretamente no useForm + */ +export type TServicoTipoFormValues = z.infer; diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/c_caixa_servico/CCaixaServicoIndexService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/c_caixa_servico/CCaixaServicoIndexService.ts new file mode 100644 index 0000000..1b7f368 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/c_caixa_servico/CCaixaServicoIndexService.ts @@ -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 { CCaixaServicoIndexData } from '../../_data/CCaixaServico/CCaixaServicoIndexData'; +import { CCaixaServicoReadInterface } from '../../_interfaces/CCaixaServicoReadInterface'; + +// Função assíncrona responsável por executar o serviço de listagem de tipos de marcação +async function executeCCaixaServicoIndexService(data: CCaixaServicoReadInterface) { + // Chama a função que realiza a requisição à API e aguarda a resposta + const response = await CCaixaServicoIndexData(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 CCaixaServicoIndexService = withClientErrorHandler( + executeCCaixaServicoIndexService, +); diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento/GEmolumentoIndexService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento/GEmolumentoIndexService.ts new file mode 100644 index 0000000..beef86e --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento/GEmolumentoIndexService.ts @@ -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 { GEmolumentoIndexData } from '../../_data/GEmolumento/GEmolumentoIndexData'; +import { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInterface'; + +// Função assíncrona responsável por executar o serviço de listagem de tipos de marcação +async function executeGEmolumentoIndexService(data: GEmolumentoReadInterface) { + // Chama a função que realiza a requisição à API e aguarda a resposta + const response = await GEmolumentoIndexData(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 GEmolumentoIndexService = withClientErrorHandler( + executeGEmolumentoIndexService, +); diff --git a/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento_item/GEmolumentoItemValorService.ts b/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento_item/GEmolumentoItemValorService.ts new file mode 100644 index 0000000..6bb2963 --- /dev/null +++ b/src/app/(protected)/(cadastros)/cadastros/_services/g_emolumento_item/GEmolumentoItemValorService.ts @@ -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 { GEmolumentoItemValorData } from '../../_data/GEmolumentoItem/GEmolumentoItemValorData'; +import { GEmolumentoItemReadInterface } from '../../_interfaces/GEmolumentoItemReadInterface'; + +// Função assíncrona responsável por executar o serviço de listagem de tipos de marcação +async function executeGEmolumentoItemValorService(data: GEmolumentoItemReadInterface) { + // Chama a função que realiza a requisição à API e aguarda a resposta + const response = await GEmolumentoItemValorData(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 GEmolumentoItemValorService = withClientErrorHandler( + executeGEmolumentoItemValorService, +); diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx index 418ebdd..51b74dd 100644 --- a/src/components/ui/table.tsx +++ b/src/components/ui/table.tsx @@ -1,92 +1,116 @@ -'use client'; +"use client" -import * as React from 'react'; +import * as React from "react" -import { cn } from '@/lib/utils'; +import { cn } from "@/lib/utils" -function Table({ className, ...props }: React.ComponentProps<'table'>) { +function Table({ className, ...props }: React.ComponentProps<"table">) { return ( -
+
- ); + ) } -function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) { - return ; +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + + ) } -function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) { +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { return ( - ); + ) } -function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) { +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { return ( tr]:last:border-b-0', className)} + className={cn( + "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", + className + )} {...props} /> - ); + ) } -function TableRow({ className, ...props }: React.ComponentProps<'tr'>) { +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { return ( - ); + ) } -function TableHead({ className, ...props }: React.ComponentProps<'th'>) { +function TableHead({ className, ...props }: React.ComponentProps<"th">) { return (
[role=checkbox]]:translate-y-[2px]', - className, + "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", + className )} {...props} /> - ); + ) } -function TableCell({ className, ...props }: React.ComponentProps<'td'>) { +function TableCell({ className, ...props }: React.ComponentProps<"td">) { return ( [role=checkbox]]:translate-y-[2px]', - className, + "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", + className )} {...props} /> - ); + ) } -function TableCaption({ className, ...props }: React.ComponentProps<'caption'>) { +function TableCaption({ + className, + ...props +}: React.ComponentProps<"caption">) { return (
- ); + ) } -export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }; +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/src/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect.tsx b/src/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect.tsx new file mode 100644 index 0000000..83761bf --- /dev/null +++ b/src/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect.tsx @@ -0,0 +1,102 @@ +'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 { useCCaixaServicoReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/c_caixa_servico/useCCaixaServicoReadHook"; +import { CCaixaServicoReadInterface } from "@/app/(protected)/(cadastros)/cadastros/_interfaces/CCaixaServicoReadInterface"; + +export default function CCaixaServicoSelect({ sistema_id, field }: any) { + + const cCaixaServicoReadParams: CCaixaServicoReadInterface = { sistema_id }; + + const [open, setOpen] = React.useState(false); + const [isLoading, setIsLoading] = React.useState(false); + const { cCaixaServico, fetchCCaixaServico } = useCCaixaServicoReadHook(); + // Busca os dados uma única vez ao montar + React.useEffect(() => { + const loadData = async () => { + if (!cCaixaServico.length) { + setIsLoading(true); + await fetchCCaixaServico(cCaixaServicoReadParams); + setIsLoading(false); + } + }; + loadData(); + }, []); + const selected = cCaixaServico?.find( + (item) => String(item.caixa_servico_id) === String(field.value) + ); + return ( + + + + + + + + + + + + {isLoading ? "Carregando..." : "Nenhum resultado encontrado."} + + + {cCaixaServico?.map((item) => ( + { + field.onChange({ + key: Number(item.caixa_servico_id), + value: item.descricao, + }); + setOpen(false); + }} + > + + {GetCapitalize(item.descricao)} + + ))} + + + + + + ); +} diff --git a/src/packages/administrativo/components/GEmolumento/GEmolumentoSelect.tsx b/src/packages/administrativo/components/GEmolumento/GEmolumentoSelect.tsx new file mode 100644 index 0000000..c22efd6 --- /dev/null +++ b/src/packages/administrativo/components/GEmolumento/GEmolumentoSelect.tsx @@ -0,0 +1,152 @@ +'use client'; // Garante execução no cliente (Next.js App Router) + +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 { useGEmolumentoReadHook } from "@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook"; +import { GEmolumentoReadInterface } from "@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface"; + + +// Tipagem das props do componente +interface GEmolumentoSelectProps { + sistema_id: number; // ID do sistema usado para buscar os emolumentos + field: any; // Objeto de controle do react-hook-form + onSelectChange?: (emolumento: { key: number; value: string }) => void; // Função callback opcional para disparar eventos externos + className?: string; // Classe CSS opcional para customização +} + + +// Componente principal do select de emolumentos +export default function GEmolumentoSelect({ sistema_id, field, onSelectChange, className }: GEmolumentoSelectProps) { + + // Define parâmetros de leitura para o hook que busca os emolumentos + const gEmolumentoReadParams: GEmolumentoReadInterface = { sistema_id }; + + // Estados locais do componente + const [open, setOpen] = React.useState(false); // Controla abertura do popover + const [isLoading, setIsLoading] = React.useState(false); // Exibe “Carregando...” enquanto busca dados + + // Hook responsável por buscar emolumentos no backend + const { gEmolumento, fetchGEmolumento } = useGEmolumentoReadHook(); + + // Carrega os dados de emolumentos apenas uma vez ao montar o componente + React.useEffect(() => { + const loadData = async () => { + if (!gEmolumento.length) { + setIsLoading(true); + await fetchGEmolumento(gEmolumentoReadParams); + setIsLoading(false); + } + }; + loadData(); + }, []); // ← executa apenas uma vez + + + // 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) + ); + + + // Estrutura visual do componente + return ( + + {/* === Botão principal (exibe valor selecionado) === */} + + + + + + + {/* === Conteúdo do Popover (lista de opções) === */} + + + {/* Campo de busca dentro do popover */} + + + + {/* Estado vazio ou carregando */} + + {isLoading ? "Carregando..." : "Nenhum resultado encontrado."} + + + {/* Grupo de opções */} + + {gEmolumento?.map((item) => ( + { + // Cria objeto com ID e descrição + const selectedValue = { + key: Number(item.emolumento_id), + value: item.descricao, + }; + + // Atualiza o valor no react-hook-form + field.onChange(selectedValue); + + // Dispara callback externo, se existir (ex: fetchGEmolumentoItem) + if (onSelectChange) onSelectChange(selectedValue); + + // Fecha o popover + setOpen(false); + }} + > + {/* Ícone de seleção (check) */} + + {/* Nome formatado do emolumento */} + {GetCapitalize(item.descricao)} + + ))} + + + + + + ); +} diff --git a/src/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect.tsx b/src/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect.tsx index 3946b66..e6c6058 100644 --- a/src/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect.tsx +++ b/src/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect.tsx @@ -52,9 +52,11 @@ export default function GMarcacaoTipoSelect({ grupo, sistema_id, situacao, field > {isLoading ? "Carregando..." - : selected - ? GetCapitalize(selected.descricao) - : "Selecione..."} + : 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 + : "Selecione a etiqueta/carimbo"} @@ -73,7 +75,10 @@ export default function GMarcacaoTipoSelect({ grupo, sistema_id, situacao, field key={item.marcacao_tipo_id} value={item.descricao?.toLowerCase() ?? ""} onSelect={() => { - field.onChange(Number(item.marcacao_tipo_id)); + field.onChange({ + key: Number(item.marcacao_tipo_id), + value: item.descricao, + }); setOpen(false); }} > diff --git a/src/shared/components/categoriaServicoSelect/CategoriaServicoSelect.tsx b/src/shared/components/categoriaServicoSelect/CategoriaServicoSelect.tsx new file mode 100644 index 0000000..47c3a0d --- /dev/null +++ b/src/shared/components/categoriaServicoSelect/CategoriaServicoSelect.tsx @@ -0,0 +1,87 @@ +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 { CategoriaServicoEnum } from "@/shared/enums/CategoriaServicoEnum"; +import { CheckIcon, ChevronsUpDownIcon } from "lucide-react"; +import React from "react"; + +type CategoriaServicoSelectProps = { + field: { + value?: string | null; + onChange: (value: string) => void; + }; +}; + +export default function CategoriaServicoSelect({ field }: CategoriaServicoSelectProps) { + const [open, setOpen] = React.useState(false); + + // Cria as opções a partir do enum + const options = Object.entries(CategoriaServicoEnum).map(([key, label]) => ({ + value: String(key), + label, + })); + + const selectedLabel = + field.value != null + ? options.find((o) => o.value === String(field.value))?.label ?? "Selecione..." + : "Selecione..."; + + return ( + + + + + + + + + + + Nenhum resultado encontrado. + + {options.map((item) => ( + { + field.onChange(item.value); // envia número + setOpen(false); + }} + > + + {item.label} + + ))} + + + + + + ); +} diff --git a/src/shared/enums/CategoriaServicoEnum.ts b/src/shared/enums/CategoriaServicoEnum.ts new file mode 100644 index 0000000..224a0bf --- /dev/null +++ b/src/shared/enums/CategoriaServicoEnum.ts @@ -0,0 +1,7 @@ +export const CategoriaServicoEnum = { + A: 'Autenticação', + C: 'Certidão', + G: 'Serviços Gerais', + R: 'Reconhecimento', + B: 'Geral', +} as const; \ No newline at end of file