saas_app/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormControllerHook.ts

363 lines
No EOL
13 KiB
TypeScript

'use client';
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useRef, useState } from 'react';
import TPessoaInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaInterface';
import { useTServicoItemPedidoCalculoHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoCalculoHook';
import { useTServicoItemPedidoIndexHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook';
import { useTServicoItemPedidoLocalHandleHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoLocalHandleHook';
import { useTServicoPedidoFormHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook';
import { useTServicoPedidoLoadParamsHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoLoadParamsHook';
import { useTServicoPedidoSaveHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook';
import { useTServicoPedidoShowHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoShowHook';
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
import { TServicoPedidoFormValues } from '@/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema';
import { useResponse } from '@/shared/components/response/ResponseContext';
import { StepNavigatorRef } from '@/shared/components/step/stepNavigator';
import { SituacoesEnum } from '@/shared/enums/SituacoesEnum';
import { TipoPessoaEnum } from '@/shared/enums/TipoPessoaEnum';
export default function useTServicoPedidoFormControllerHook(servico_pedido_id?: number) {
const router = useRouter();
const form = useTServicoPedidoFormHook({});
const { setValue, reset, watch } = form;
const [isSaving, setIsSaving] = useState(false);
const [isAdding, setIsAdding] = useState(false);
const [isPessoaFormOpen, setIsPessoaFormOpen] = useState(false);
const [isSaveConfirmOpen, setIsSaveConfirmOpen] = useState(false);
const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false);
const [selectedPessoaTipo, setSelectedPessoaTipo] = useState('');
const [shouldKeepFormOpen, setShouldKeepFormOpen] = useState(false);
const ref = useRef<StepNavigatorRef>(null);
// Controles de formulário
const handleClosePessoaForm = useCallback(() => setIsPessoaFormOpen(false), []);
const handleOpenSaveConfirm = useCallback(() => setIsSaveConfirmOpen(true), []);
const handleCloseSaveConfirm = useCallback(() => setIsSaveConfirmOpen(false), []);
// Hooks
// const playSuccess = useSoundHook("/sounds/success.mp3");
const { setResponse } = useResponse();
const { saveTServicoPedido } = useTServicoPedidoSaveHook();
const { showTServicoPedido } = useTServicoPedidoShowHook();
const { TServicoItemPedidoLocal, localAddTServicoItemPedido, localRemoveTServicoItemPedido, setLocalTServicoItemPedido } = useTServicoItemPedidoLocalHandleHook(setValue);
const { calculoTServicoItemPedido } = useTServicoItemPedidoCalculoHook(setValue);
const { indexTServicoItemPedido } = useTServicoItemPedidoIndexHook();
const { TServicoPedidoParams, loadParamsTServicoPedido } = useTServicoPedidoLoadParamsHook();
// Acompanha as alterações, nos campos definidos
const selectedServicoTipo = watch('servico_tipo');
const selectedEmolumento = watch('emolumento');
const handleFormError = useCallback((errors: any) => {
console.group('Erros de validação do formulário');
console.log('Campos com erro:', errors);
console.groupEnd();
}, []);
// Envia a requisição para a API
const handleSavePedido = useCallback(
async (data: TServicoPedidoFormValues) => {
// Ativa o botão de loading
setIsSaving(true);
// Converte o tipo do formulário (Zod) para o tipo da API (Interface)
const payload: TServicoPedidoInterface = {
...data,
situacao: data.situacao as unknown as SituacoesEnum,
};
const response = await saveTServicoPedido(payload);
// Desativa o botão de loading
setIsSaving(false);
// Verifica se devo redirecionar a pagina
if (response?.servico_pedido_id > 0) {
// Toca o som do sistema
// playSuccess()
}
// Verifica se devo redirecionar a pagina
if (response?.servico_pedido_id > 0 && !shouldKeepFormOpen) {
router.replace(`/servicos/balcao/detalhes/${response.servico_pedido_id}`);
}
},
[saveTServicoPedido, shouldKeepFormOpen],
);
// Modal de confirmação de serviço
const handleSubmitWithConfirmation = useCallback(() => {
// Envia o formulário
form.handleSubmit(handleSavePedido, handleFormError)();
}, [form, handleSavePedido, handleFormError]);
// Busca os itens do Pedido
const fetchPedidoItens = useCallback(
async (id: number) => {
const pedidoItens = {
servico_pedido_id: id,
};
// Busca os itens do pedido
const response = await indexTServicoItemPedido(pedidoItens);
// Verifica se os dados foram localizados
if (response?.data?.length) {
// Atualiza os dados dos itens locais
setLocalTServicoItemPedido(response.data);
// Atualiza os itens do formulário
setValue('itens', response.data);
}
},
[indexTServicoItemPedido, setValue, setLocalTServicoItemPedido],
);
// Busca o pedido Principal
const fetchPedido = useCallback(async () => {
// Busca o pedido principal
const response = await showTServicoPedido({ servico_pedido_id });
// Verifica se o pedido foi localizado
if (response?.servico_pedido_id) {
// Atualiza os dados do formulário
reset(response);
// Carrega os itens do pedido
fetchPedidoItens(response.servico_pedido_id);
}
}, [servico_pedido_id, showTServicoPedido, reset, fetchPedidoItens]);
const handleAddItemWithPessoa = useCallback(
async (selectedTPessoa: TPessoaInterface) => {
handleAddItem(selectedTPessoa)
}, [selectedEmolumento, selectedServicoTipo]);
// Controla o formulário de cancelamento de pedido
const handleOpenCancelDialog = useCallback(async () => {
// Fecha a confirmação
setIsCancelDialogOpen(true);
}, []);
// Controle de redirecionamento
const handleConfirmCancel = useCallback(async () => {
// Redireciona o usuário
router.replace(`/servicos/balcao/`);
}, []);
// Controle do formulário de cancelamento do Pedido
const handleCloseCancelDialog = useCallback(async () => {
// Fecha o formulário
setIsCancelDialogOpen(false);
}, []);
const handleRemoveLocalItem = useCallback(async (index: number) => {
localRemoveTServicoItemPedido(index)
}, []);
// Controle de itens
const handleAddItem = useCallback(async (selectedTPessoa?: TPessoaInterface) => {
setIsAdding(true);
// Prepara e valida os dados de item do pedido
const payload = {
servico_tipo: selectedServicoTipo,
emolumento: selectedEmolumento,
};
// Se existir pessoa, adiciona ao payload
if (selectedTPessoa) {
payload.pessoa = selectedTPessoa;
}
// Obtem o resultado da adição do item
const item = await calculoTServicoItemPedido(payload);
// Verifica se foi realizado o calculo
if (!item) {
setResponse({
status: 422,
detail: 'Não foi localizado item para o serviço',
})
setIsAdding(false);
return;
}
// Define índice e adiciona localmente
const index = TServicoItemPedidoLocal.length;
// Guarda o indice
item.index = index
// Adiciona o item calculo localmente
localAddTServicoItemPedido(item)
// Define os itens
form.setValue(`itens.${index}`, item);
setIsAdding(false);
}, [calculoTServicoItemPedido, selectedServicoTipo, selectedEmolumento, localAddTServicoItemPedido]);
// Habilita o formulário de pessoas
const handleOpenPessoaForm = useCallback((tipoPessoa: string) => {
setSelectedPessoaTipo(tipoPessoa);
setIsPessoaFormOpen(true);
}, []);
// Adiciona o item a tabela e verifica se deve ou não montar a subview da linha da tabela
const handleSelectServicoTipo = useCallback(() => {
const tipoPessoa = [TipoPessoaEnum.FISICA, TipoPessoaEnum.JURIDICA]
// Verifica se o emolumento e o tipo de serviço foram selecionados
if (!selectedServicoTipo || !selectedEmolumento) {
setResponse({
status: 422,
detail: 'Serviço e emolumento devem ser selecionados',
})
return;
}
// Verifica se deve selecionar pessoas
switch (tipoPessoa.includes(selectedServicoTipo.tipo_pessoa)) {
// Habilita o formulário
case true:
handleOpenPessoaForm(selectedServicoTipo.tipo_pessoa);
break;
// Adiciona direto
default:
handleAddItem();
break;
}
}, [selectedServicoTipo, selectedEmolumento, handleOpenPessoaForm, handleAddItem]);
const calcularTotais = useCallback(() => {
const itens = form.getValues('itens') || [];
if (!itens.length) {
setValue('valor_pedido', 0, { shouldDirty: true });
setValue('valor_pago', 0, { shouldDirty: true });
return;
}
const total = itens.reduce((acc, item) => acc + Number(item.valor ?? 0), 0);
// Atualiza sempre o valor do pedido
setValue('valor_pedido', total, { shouldDirty: true });
// Atualiza o valor pago apenas se estiver vazio, null, undefined ou 0
const valorPagoAtual = Number(form.getValues('valor_pago')) || 0;
if (!valorPagoAtual) {
setValue('valor_pago', total, { shouldDirty: true });
}
}, [form, setValue]);
// Incremente ou decrementa a quantidade
const handleChangeQtd = useCallback(
(index: number, delta: number) => {
const currentItens = form.getValues('itens') || [];
const currentItem = currentItens[index];
if (!currentItem) return;
const currentQtd = Number(currentItem.qtd ?? 1);
const newQtd = currentQtd + delta;
// Se quantidade for 0 ou menor, remove o item
if (newQtd <= 0) {
const filteredItens = currentItens.filter((_, i) => i !== index);
form.setValue('itens', filteredItens, { shouldDirty: true });
localRemoveTServicoItemPedido(index);
calcularTotais();
return;
}
const multiplier = newQtd / currentQtd;
const updatedItem = {
...currentItem,
qtd: newQtd,
emolumento: (Number(currentItem.emolumento) * multiplier).toFixed(2),
taxa_judiciaria: (Number(currentItem.taxa_judiciaria) * multiplier).toFixed(2),
fundesp: (Number(currentItem.fundesp) * multiplier).toFixed(2),
valor_iss: (Number(currentItem.valor_iss) * multiplier).toFixed(2),
valor: (Number(currentItem.valor) * multiplier).toFixed(2),
};
const updatedItens = [...currentItens];
updatedItens[index] = updatedItem;
form.setValue('itens', updatedItens, { shouldDirty: true });
calcularTotais();
},
[form, localRemoveTServicoItemPedido, calcularTotais],
);
// Dispara a busca do pedido
useEffect(() => {
// Se existir pedido_id, busca o pedido
if (servico_pedido_id) fetchPedido();
}, [servico_pedido_id, fetchPedido]);
// Dispara a busca de itens
useEffect(() => {
// Dispara a busca dos itens
setValue('itens', TServicoItemPedidoLocal, { shouldDirty: true });
}, [TServicoItemPedidoLocal, setValue]);
// Dispara a busca de parâmetros
useEffect(() => {
loadParamsTServicoPedido();
}, []);
// Monitora mudanças na lista de itens
useEffect(() => {
calcularTotais();
}, [TServicoItemPedidoLocal, calcularTotais]);
return {
form,
ref,
isSaving,
isAdding,
isPessoaFormOpen,
isSaveConfirmOpen,
isCancelDialogOpen,
shouldKeepFormOpen,
selectedPessoaTipo,
TServicoItemPedidoLocal,
TServicoPedidoParams,
// setters diretos
setIsSaveConfirmOpen,
setIsCancelDialogOpen,
setShouldKeepFormOpen,
// handlers principais
handleSavePedido,
handleSelectServicoTipo,
handleSubmitWithConfirmation,
handleCloseSaveConfirm,
handleOpenCancelDialog,
handleConfirmCancel,
handleCloseCancelDialog,
handleClosePessoaForm,
handleAddItemWithPessoa,
handleOpenSaveConfirm,
handleChangeQtd
};
}