first
This commit is contained in:
706
src/hooks/useOrderSearch.ts
Normal file
706
src/hooks/useOrderSearch.ts
Normal file
@@ -0,0 +1,706 @@
|
||||
import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { ordersApi, dataConsultApi } from "@/src/lib/api";
|
||||
import { OrderSearchParams, OrderItem, Customer, Order, Cliente, cutitens } from "@/src/components/types";
|
||||
import { validateDateRange } from "@/src/utils/date-helpers";
|
||||
import { extractApiData } from "@/src/utils/api-helpers";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { clientesApi } from "@/src/lib/api"
|
||||
import { setStorage, getStorage } from "@/src/utils/storage";
|
||||
|
||||
/**
|
||||
* Função de utilidade para aplicar debounce em funções
|
||||
* Evita execuções repetidas em curtos intervalos de tempo
|
||||
*
|
||||
* @template T - Tipo da função a ser debounced
|
||||
* @param {T} callback - Função a aplicar debounce
|
||||
* @param {number} delay - Tempo de espera em ms
|
||||
* @returns {Function} Função com debounce aplicado
|
||||
*/
|
||||
function useDebounce<T extends (...args: any[]) => any>(
|
||||
callback: T,
|
||||
delay: number
|
||||
): (...args: Parameters<T>) => void {
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
return useCallback(
|
||||
(...args: Parameters<T>) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
callback(...args);
|
||||
}, delay);
|
||||
},
|
||||
[callback, delay]
|
||||
);
|
||||
}
|
||||
|
||||
interface UseOrderSearchReturn {
|
||||
orders: Order[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
dateError: string | null;
|
||||
hasSearched: boolean;
|
||||
selectedOrderId: string | null;
|
||||
orderItems: OrderItem[];
|
||||
cutitens: cutitens[];
|
||||
loadingItems: boolean;
|
||||
itemsError: string | null;
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
currentOrders: Order[];
|
||||
indexOfFirstOrder: number;
|
||||
indexOfLastOrder: number;
|
||||
searchParams: OrderSearchParams;
|
||||
setSearchParams: React.Dispatch<React.SetStateAction<OrderSearchParams>>;
|
||||
handleSearch: () => Promise<void>;
|
||||
handleRowClick: (orderId: string) => Promise<void>;
|
||||
goToNextPage: () => void;
|
||||
goToPreviousPage: () => void;
|
||||
goToPage: (page: number) => void;
|
||||
loadMoreOrders: () => void;
|
||||
visibleOrdersCount: number;
|
||||
handleInputChange: (field: keyof OrderSearchParams, value: any) => void;
|
||||
handleCustomerSelect: (customer: Cliente | null) => void;
|
||||
handleCustomerId: (value: string) => Promise<void>;
|
||||
handleCustomerFilter: (value: string) => Promise<void>;
|
||||
setInitialOrders: (savedOrders: Order[], savedPage: number, savedHasSearched: boolean) => void;
|
||||
clearStoredParams: () => void;
|
||||
handleMultiInputChange: (field: keyof OrderSearchParams, values: string[]) => void;
|
||||
}
|
||||
|
||||
// Mapeamento para converter nomes de parâmetros da URL para o estado
|
||||
const paramMapping: Record<string, keyof OrderSearchParams> = {
|
||||
Id: "id",
|
||||
orderId: "orderId",
|
||||
Document: "Document",
|
||||
name: "name",
|
||||
sellerName: "sellerName",
|
||||
codfilial: "codfilial",
|
||||
status: "status",
|
||||
createDateIni: "createDateIni",
|
||||
createDateEnd: "createDateEnd",
|
||||
customerId: "customerId",
|
||||
document: "document",
|
||||
invoiceNumber: "invoiceNumber"
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook personalizado para gerenciar a consulta e exibição de pedidos
|
||||
* Gerencia busca, paginação, armazenamento de parâmetros e detalhes de pedidos
|
||||
*
|
||||
* @param {number} ordersPerPage - Número de pedidos a serem exibidos por página
|
||||
* @returns {UseOrderSearchReturn} Objeto contendo estado e funções para lidar com pedidos
|
||||
*/
|
||||
export function useOrderSearch(ordersPerPage: number = 8): UseOrderSearchReturn {
|
||||
const router = useRouter();
|
||||
const urlSearchParams = useSearchParams();
|
||||
|
||||
// Inicializar searchParams com valores da URL ou do localStorage ou um objeto vazio
|
||||
const [searchParams, setSearchParams] = useState<OrderSearchParams>(() => {
|
||||
const params: OrderSearchParams = {};
|
||||
|
||||
// Tentar recuperar do localStorage primeiro
|
||||
const savedParams = getStorage("orderSearchParams");
|
||||
|
||||
if (savedParams) {
|
||||
return savedParams;
|
||||
}
|
||||
|
||||
// Se não houver no localStorage, extrair valores da URL para o estado
|
||||
Object.entries(paramMapping).forEach(([urlParam, stateParam]) => {
|
||||
const value = urlSearchParams.get(urlParam);
|
||||
if (value) {
|
||||
// Tratando corretamente o tipo do parâmetro
|
||||
(params as any)[stateParam] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Tratamento especial para parâmetros que podem ser arrays
|
||||
const typeParam = urlSearchParams.get('type');
|
||||
if (typeParam) {
|
||||
// Se o parâmetro type contém vírgulas, é um array
|
||||
if (typeParam.includes(',')) {
|
||||
params.type = typeParam.split(',').join(',');
|
||||
} else {
|
||||
params.type = typeParam;
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
});
|
||||
|
||||
const [orders, setOrders] = useState<Order[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [hasSearched, setHasSearched] = useState(false);
|
||||
const [selectedOrderId, setSelectedOrderId] = useState<string | null>(null);
|
||||
const [orderItems, setOrderItems] = useState<OrderItem[]>([]);
|
||||
const [cutItems, setCutItems] = useState<cutitens[]>([]);
|
||||
const [loadingItems, setLoadingItems] = useState(false);
|
||||
const [itemsError, setItemsError] = useState<string | null>(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [visibleOrdersCount, setVisibleOrdersCount] = useState(ordersPerPage);
|
||||
const [dateError, setDateError] = useState<string | null>(null);
|
||||
|
||||
// Detectar parâmetro origem=detalhe para realizar pesquisa automática ao retornar
|
||||
const origin = urlSearchParams.get("origem");
|
||||
|
||||
// Limpar todos os campos relacionados ao cliente
|
||||
const clearCustomerFields = useCallback(() => {
|
||||
setSearchParams(prev => ({
|
||||
...prev,
|
||||
customerId: "",
|
||||
document: "",
|
||||
name: "",
|
||||
selectedCustomer: null,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
// Efeito para realizar pesquisa automática quando a página é carregada
|
||||
// e há parâmetros de pesquisa na URL ou se estamos voltando da página de detalhes
|
||||
useEffect(() => {
|
||||
const hasSearchParams = Object.keys(searchParams).length > 0;
|
||||
|
||||
// Se temos parâmetros de busca e vamos retornando da página de detalhes,
|
||||
// ou se temos parâmetros e ainda não realizamos a pesquisa
|
||||
if ((hasSearchParams && origin === "detalhe") || (hasSearchParams && !hasSearched)) {
|
||||
handleSearch();
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Atualiza a URL com os parâmetros de pesquisa atuais
|
||||
* Salva os parâmetros no localStorage para persistência entre sessões
|
||||
*/
|
||||
const updateUrlWithSearchParams = useCallback(() => {
|
||||
const urlParams = new URLSearchParams();
|
||||
|
||||
// Adicionar apenas parâmetros com valores
|
||||
Object.entries(searchParams).forEach(([key, value]) => {
|
||||
if (value) {
|
||||
if ((key === 'type' || key === 'status' || key === 'deliveryType') && Array.isArray(value)) {
|
||||
// Para arrays, juntar com vírgula
|
||||
urlParams.append(key, value.join(','));
|
||||
} else {
|
||||
urlParams.append(key, value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Preservar parâmetro origem se existir
|
||||
if (origin) {
|
||||
urlParams.append("origem", origin);
|
||||
}
|
||||
|
||||
// Salvar no localStorage
|
||||
setStorage("orderSearchParams", searchParams);
|
||||
|
||||
// Atualizar URL sem causar recarregamento da página
|
||||
const url = window.location.pathname + (urlParams.toString() ? `?${urlParams.toString()}` : "");
|
||||
window.history.replaceState({ path: url }, "", url);
|
||||
}, [searchParams, origin]);
|
||||
|
||||
/**
|
||||
* Executa a busca de pedidos com base nos parâmetros definidos
|
||||
* Valida datas, formata parâmetros e faz a chamada à API
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
// Verificar se pelo menos uma data está preenchida
|
||||
if (!searchParams.createDateIni && !searchParams.createDateEnd) {
|
||||
setDateError("Por favor, informe pelo menos uma data para realizar a pesquisa");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate date range
|
||||
const dateValidation = validateDateRange(
|
||||
searchParams.createDateIni,
|
||||
searchParams.createDateEnd
|
||||
);
|
||||
|
||||
if (!dateValidation.isValid) {
|
||||
setDateError(dateValidation.errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear date error
|
||||
setDateError(null);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setHasSearched(true);
|
||||
|
||||
// Transform the ALL value to empty string for the API call
|
||||
const paramsToSend: OrderSearchParams = { ...searchParams };
|
||||
|
||||
// Remover o campo selectedCustomer antes de enviar para a API
|
||||
if (paramsToSend.selectedCustomer) {
|
||||
delete paramsToSend.selectedCustomer;
|
||||
}
|
||||
|
||||
// Se tiver customerId definido, remover name e document para evitar conflito
|
||||
if (paramsToSend.customerId) {
|
||||
delete paramsToSend.name;
|
||||
delete paramsToSend.document;
|
||||
}
|
||||
|
||||
// Se temos o nome do vendedor mas não temos o ID, tentar buscar o ID primeiro
|
||||
if (paramsToSend.sellerName && !paramsToSend.sellerId) {
|
||||
try {
|
||||
const sellers = await dataConsultApi.getSellers();
|
||||
if (Array.isArray(sellers)) {
|
||||
const matchingSeller = sellers.find((seller: any) =>
|
||||
seller.name.toLowerCase().includes(paramsToSend.sellerName?.toLowerCase() || '')
|
||||
);
|
||||
|
||||
if (matchingSeller) {
|
||||
// Extrair código numérico (887 de "887 - SAL-SIMONI")
|
||||
if (matchingSeller.name && matchingSeller.name.includes("-")) {
|
||||
const parts = matchingSeller.name.split("-");
|
||||
if (parts.length > 0 && parts[0].trim()) {
|
||||
const match = parts[0].trim().match(/\d+/);
|
||||
if (match) {
|
||||
paramsToSend.sellerId = match[0];
|
||||
// Após obter o ID, remover o nome para evitar conflitos
|
||||
delete paramsToSend.sellerName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
console.error("Erro ao buscar vendedores:", err);
|
||||
}
|
||||
}
|
||||
|
||||
// Mapear invoiceNumber para invoiceId que é o que a API espera
|
||||
if (paramsToSend.invoiceNumber) {
|
||||
paramsToSend.invoiceId = paramsToSend.invoiceNumber;
|
||||
delete paramsToSend.invoiceNumber;
|
||||
}
|
||||
|
||||
// Remover campos que a API não espera
|
||||
if ('nfe' in paramsToSend) {
|
||||
delete paramsToSend.nfe;
|
||||
}
|
||||
|
||||
if (paramsToSend.codfilial === "ALL") {
|
||||
paramsToSend.codfilial = "";
|
||||
}
|
||||
if (paramsToSend.status === "ALL") {
|
||||
paramsToSend.status = "";
|
||||
}
|
||||
|
||||
// Remover propriedades vazias para evitar parâmetros desnecessários na URL
|
||||
Object.keys(paramsToSend).forEach(key => {
|
||||
const paramKey = key as keyof OrderSearchParams;
|
||||
if (paramsToSend[paramKey] === "" || paramsToSend[paramKey] === null || paramsToSend[paramKey] === undefined) {
|
||||
delete paramsToSend[paramKey];
|
||||
}
|
||||
});
|
||||
|
||||
// Construir manualmente o queryParams para lidar com arrays
|
||||
const queryParams = new URLSearchParams();
|
||||
|
||||
Object.entries(paramsToSend).forEach(([key, value]) => {
|
||||
if ((key === 'type' || key === 'status' || key === 'deliveryType') && Array.isArray(value)) {
|
||||
// Unir os valores do array em uma única string separada por vírgula
|
||||
queryParams.append(key, value.join(','));
|
||||
} else if (value !== undefined && value !== null && value !== "") {
|
||||
queryParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const response = await ordersApi.findOrders(paramsToSend, queryString);
|
||||
setOrders(extractApiData<Order>(response));
|
||||
setError(null);
|
||||
|
||||
// Reset selected order and items when new search is performed
|
||||
setSelectedOrderId(null);
|
||||
setOrderItems([]);
|
||||
setCutItems([]);
|
||||
|
||||
// Reset pagination state
|
||||
setCurrentPage(1);
|
||||
setVisibleOrdersCount(ordersPerPage);
|
||||
|
||||
// Atualizar a URL com os parâmetros de pesquisa
|
||||
updateUrlWithSearchParams();
|
||||
} catch (err) {
|
||||
setError("Erro ao buscar pedidos. Por favor, tente novamente.");
|
||||
console.error(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manipula alterações em campos de entrada do formulário
|
||||
* Atualiza o estado searchParams com o novo valor
|
||||
*
|
||||
* @param {keyof OrderSearchParams} field - Nome do campo a atualizar
|
||||
* @param {any} value - Novo valor para o campo
|
||||
*/
|
||||
const handleInputChange = (field: keyof OrderSearchParams, value: any) => {
|
||||
// Garantir que valores apropriados sejam tratados como arrays
|
||||
if ((field === 'type' || field === 'status' || field === 'deliveryType') &&
|
||||
typeof value === 'string' && value !== '') {
|
||||
// Converter string para array com um único item
|
||||
setSearchParams((prev) => ({
|
||||
...prev,
|
||||
[field]: [value],
|
||||
}));
|
||||
} else {
|
||||
setSearchParams((prev) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
}
|
||||
|
||||
// Clear date error when user changes dates
|
||||
if (field === "createDateIni" || field === "createDateEnd") {
|
||||
setDateError(null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Seleciona um cliente após busca, preenchendo campos relacionados
|
||||
*
|
||||
* @param {Cliente | null} customer - Cliente selecionado ou null para limpar
|
||||
*/
|
||||
const handleCustomerSelect = (customer: Cliente | null) => {
|
||||
if (!customer) {
|
||||
clearCustomerFields();
|
||||
return;
|
||||
}
|
||||
|
||||
setSearchParams((prev) => ({
|
||||
...prev,
|
||||
selectedCustomer: customer,
|
||||
customerId: customer.id ?? '',
|
||||
document: '',
|
||||
name: '',
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Manipula clique em linha da tabela de pedidos
|
||||
* Carrega detalhes do pedido selecionado
|
||||
*
|
||||
* @param {string} orderId - ID do pedido selecionado
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleRowClick = async (orderId: string) => {
|
||||
if (selectedOrderId === orderId) {
|
||||
// Toggle off if already selected
|
||||
setSelectedOrderId(null);
|
||||
setOrderItems([]);
|
||||
setCutItems([]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoadingItems(true);
|
||||
setSelectedOrderId(orderId);
|
||||
setItemsError(null);
|
||||
|
||||
// Load order items
|
||||
const itemsResponse = await ordersApi.getOrderItems(orderId);
|
||||
setOrderItems(extractApiData<OrderItem>(itemsResponse));
|
||||
|
||||
// Load cut items
|
||||
const cutItemsResponse = await ordersApi.getCutItems(orderId);
|
||||
let cutItems: cutitens[] = [];
|
||||
if (cutItemsResponse && typeof cutItemsResponse === "object") {
|
||||
if ("data" in cutItemsResponse && Array.isArray(cutItemsResponse.data)) {
|
||||
cutItems = cutItemsResponse.data;
|
||||
} else if (Array.isArray(cutItemsResponse)) {
|
||||
cutItems = cutItemsResponse;
|
||||
}
|
||||
}
|
||||
setCutItems(cutItems);
|
||||
|
||||
} catch (err) {
|
||||
setItemsError("Erro ao carregar itens do pedido.");
|
||||
console.error(err);
|
||||
} finally {
|
||||
setLoadingItems(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Pagination calculations - corrigir para garantir 8 itens por página
|
||||
const totalPages = Math.ceil(orders.length / ordersPerPage);
|
||||
|
||||
// Calcular o índice inicial baseado na página atual
|
||||
const indexOfFirstOrder = (currentPage - 1) * ordersPerPage;
|
||||
// Calcular o índice final
|
||||
const indexOfLastOrder = Math.min(indexOfFirstOrder + ordersPerPage, orders.length);
|
||||
// Selecionar apenas os itens da página atual
|
||||
const currentOrders = orders.slice(indexOfFirstOrder, indexOfLastOrder);
|
||||
|
||||
// Navigate to next page
|
||||
const goToNextPage = useCallback(() => {
|
||||
if (currentPage < totalPages) {
|
||||
setCurrentPage(currentPage + 1);
|
||||
// Reset selected order when changing pages
|
||||
setSelectedOrderId(null);
|
||||
setOrderItems([]);
|
||||
setCutItems([]);
|
||||
}
|
||||
}, [currentPage, totalPages]);
|
||||
|
||||
// Navigate to previous page
|
||||
const goToPreviousPage = useCallback(() => {
|
||||
if (currentPage > 1) {
|
||||
setCurrentPage(currentPage - 1);
|
||||
// Reset selected order when changing pages
|
||||
setSelectedOrderId(null);
|
||||
setOrderItems([]);
|
||||
setCutItems([]);
|
||||
}
|
||||
}, [currentPage]);
|
||||
|
||||
// Load more orders function to expand the current view - não é mais necessária
|
||||
// Mantida por retrocompatibilidade
|
||||
const loadMoreOrders = useCallback(() => {
|
||||
// Não faz nada, pois estamos usando paginação tradicional agora
|
||||
}, []);
|
||||
|
||||
// New function to go to a specific page
|
||||
const goToPage = useCallback((page: number) => {
|
||||
if (page >= 1 && page <= totalPages) {
|
||||
setCurrentPage(page);
|
||||
// Reset selected order when changing pages
|
||||
setSelectedOrderId(null);
|
||||
setOrderItems([]);
|
||||
setCutItems([]);
|
||||
}
|
||||
}, [totalPages]);
|
||||
|
||||
// Atualizar visibleOrdersCount para compatibilidade com a interface
|
||||
useEffect(() => {
|
||||
setVisibleOrdersCount(indexOfLastOrder);
|
||||
}, [indexOfLastOrder]);
|
||||
|
||||
/**
|
||||
* Identifica o tipo de entrada para busca de cliente
|
||||
* Diferencia entre ID, documento ou nome baseado no formato
|
||||
*
|
||||
* @param {string} value - Valor de entrada a ser analisado
|
||||
* @returns {'id' | 'document' | 'name'} Tipo identificado da entrada
|
||||
*/
|
||||
const identifyInputType = (value: string): 'id' | 'document' | 'name' => {
|
||||
if (/^\d+$/.test(value)) {
|
||||
return value.length <= 6 ? 'id' : 'document';
|
||||
}
|
||||
return 'name';
|
||||
};
|
||||
|
||||
/**
|
||||
* Busca cliente por ID
|
||||
*
|
||||
* @param {string} value - ID do cliente a ser buscado
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleCustomerId = async (value: string) => {
|
||||
try {
|
||||
// Se value for vazio, limpar todos os campos relacionados ao cliente
|
||||
if (!value) {
|
||||
clearCustomerFields();
|
||||
return;
|
||||
}
|
||||
|
||||
let customerData: any = null;
|
||||
const inputType = identifyInputType(value);
|
||||
|
||||
// Atualizar o campo apropriado com base no tipo de entrada
|
||||
setSearchParams(prev => ({
|
||||
...prev,
|
||||
customerId: inputType === 'id' ? value : "",
|
||||
document: inputType === 'document' ? value : "",
|
||||
name: inputType === 'name' ? value : "",
|
||||
}));
|
||||
|
||||
// Buscar cliente pelo tipo correto
|
||||
if (inputType === 'id') {
|
||||
const response = await dataConsultApi.getCustomer(value);
|
||||
if (response.success && response.data && response.data.length > 0) {
|
||||
customerData = response.data[0];
|
||||
}
|
||||
} else if (inputType === 'document' || inputType === 'name') {
|
||||
const response = await dataConsultApi.getCustomers(value);
|
||||
if (response && response.length > 0) {
|
||||
customerData = response[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (customerData) {
|
||||
// Create customer object from response
|
||||
const customer: Customer = {
|
||||
id: customerData.id.toString(),
|
||||
name: customerData.name,
|
||||
document: customerData.document || ""
|
||||
};
|
||||
|
||||
// Update selected customer in form state
|
||||
setSearchParams(prev => ({
|
||||
...prev,
|
||||
selectedCustomer: customer,
|
||||
customerId: customer.id,
|
||||
name: "",
|
||||
document: "",
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Erro ao buscar dados do cliente:", error);
|
||||
setError("Erro ao buscar dados do cliente. Por favor, tente novamente.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Busca cliente por nome
|
||||
*
|
||||
* @param {string} value - Nome parcial ou completo para busca
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const searchCustomerByName = async (value: string) => {
|
||||
if (!value || value.length < 2) return;
|
||||
|
||||
try {
|
||||
const matches = await clientesApi.search(value);
|
||||
if (matches.length > 0) {
|
||||
const c = matches[0];
|
||||
|
||||
const clientId = c.id || "";
|
||||
const clientName = c.name || "";
|
||||
|
||||
setSearchParams(prev => ({
|
||||
...prev,
|
||||
customerId: clientId,
|
||||
document: "",
|
||||
name: "",
|
||||
selectedCustomer: {
|
||||
id: clientId,
|
||||
name: clientName,
|
||||
document: "",
|
||||
},
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Erro ao buscar cliente:", err);
|
||||
setError("Erro ao buscar cliente. Por favor, tente novamente.");
|
||||
}
|
||||
};
|
||||
|
||||
// Criar versão com debounce da função de busca
|
||||
const debouncedSearchCustomer = useDebounce(searchCustomerByName, 500);
|
||||
|
||||
/**
|
||||
* Manipula entrada de filtro de cliente
|
||||
* Identifica o tipo de filtro e direciona para a busca apropriada
|
||||
*
|
||||
* @param {string} value - Termo de busca (ID, documento ou nome)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleCustomerFilter = async (value: string) => {
|
||||
// Se o campo estiver vazio, limpa todos os campos relacionados ao cliente
|
||||
if (!value) {
|
||||
clearCustomerFields();
|
||||
return;
|
||||
}
|
||||
|
||||
// Atualiza o campo de nome no estado
|
||||
setSearchParams(prev => ({
|
||||
...prev,
|
||||
name: value,
|
||||
customerId: "",
|
||||
document: "",
|
||||
}));
|
||||
|
||||
// Se ainda está digitando poucas letras, apenas atualiza o estado
|
||||
if (value.length < 2) return;
|
||||
|
||||
// Aciona a busca com debounce para evitar chamadas excessivas à API
|
||||
debouncedSearchCustomer(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Restaura o estado da pesquisa com dados previamente salvos
|
||||
* Útil para preservar o estado ao voltar da página de detalhes
|
||||
*/
|
||||
const setInitialOrders = useCallback((savedOrders: Order[], savedPage: number, savedHasSearched: boolean) => {
|
||||
setOrders(savedOrders);
|
||||
setCurrentPage(savedPage);
|
||||
setHasSearched(savedHasSearched);
|
||||
setVisibleOrdersCount(ordersPerPage * savedPage);
|
||||
|
||||
// Calcular total de páginas
|
||||
const calculatedTotalPages = Math.ceil(savedOrders.length / ordersPerPage);
|
||||
// Como não temos acesso direto à função setTotalPages, calcular localmente
|
||||
const totalPages = calculatedTotalPages;
|
||||
|
||||
// Atualizar pedidos da página atual
|
||||
const indexOfLastOrder = savedPage * ordersPerPage;
|
||||
const indexOfFirstOrder = indexOfLastOrder - ordersPerPage;
|
||||
const currentOrdersSlice = savedOrders.slice(indexOfFirstOrder, indexOfLastOrder);
|
||||
// Como não temos acesso direto à função setCurrentOrders, atualizar manualmente
|
||||
// Vamos fazer isso através do atualizador do estado orders, que vai disparar o useEffect
|
||||
// que atualiza currentOrders
|
||||
setOrders(savedOrders);
|
||||
}, [ordersPerPage]);
|
||||
|
||||
// Função para limpar os parâmetros do localStorage
|
||||
const clearStoredParams = useCallback(() => {
|
||||
setStorage("orderSearchParams", null);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Manipula a seleção de múltiplos valores em filtros de seleção
|
||||
*
|
||||
* @param {string} field - Nome do campo no objeto searchParams
|
||||
* @param {string[]} values - Array de valores selecionados
|
||||
*/
|
||||
const handleMultiInputChange = useCallback((field: keyof OrderSearchParams, values: string[]) => {
|
||||
setSearchParams((prev) => ({
|
||||
...prev,
|
||||
[field]: values,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
return {
|
||||
orders,
|
||||
loading,
|
||||
error,
|
||||
dateError,
|
||||
hasSearched,
|
||||
selectedOrderId,
|
||||
orderItems,
|
||||
cutitens: cutItems,
|
||||
loadingItems,
|
||||
itemsError,
|
||||
currentPage,
|
||||
totalPages,
|
||||
currentOrders,
|
||||
indexOfFirstOrder,
|
||||
indexOfLastOrder,
|
||||
searchParams,
|
||||
setSearchParams,
|
||||
handleSearch,
|
||||
handleRowClick,
|
||||
goToNextPage,
|
||||
goToPreviousPage,
|
||||
goToPage,
|
||||
loadMoreOrders,
|
||||
visibleOrdersCount,
|
||||
handleInputChange,
|
||||
handleCustomerSelect,
|
||||
handleCustomerId,
|
||||
handleCustomerFilter,
|
||||
setInitialOrders,
|
||||
clearStoredParams,
|
||||
handleMultiInputChange
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user