- Adiciona integração com API de produtos em http://10.1.1.212:8805/api/v1/data-consult/products/{id} - Corrige mapeamento de resposta da API para formato Product interface - Atualiza ProductSearchInput para usar description como nome do produto - Corrige API_BASE_URL adicionando protocolo http:// para evitar URLs relativas - Resolve erro 404 causado por URLs malformadas em requisições de API
733 lines
23 KiB
TypeScript
733 lines
23 KiB
TypeScript
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";
|
|
import { clearUrlAndNavigate } from "@/src/utils/url-helpers";
|
|
|
|
/**
|
|
* 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;
|
|
clearAndNavigateToOrders: () => 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",
|
|
productId: "productId"
|
|
};
|
|
|
|
/**
|
|
* 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,
|
|
}));
|
|
}, []);
|
|
|
|
// Limpar todos os campos relacionados ao produto
|
|
const clearProductFields = useCallback(() => {
|
|
setSearchParams(prev => ({
|
|
...prev,
|
|
productId: "",
|
|
selectedProduct: 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 campos que não devem ser enviados para a API
|
|
if (paramsToSend.selectedCustomer) {
|
|
delete paramsToSend.selectedCustomer;
|
|
}
|
|
if (paramsToSend.selectedProduct) {
|
|
delete paramsToSend.selectedProduct;
|
|
}
|
|
|
|
// 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);
|
|
}, []);
|
|
|
|
// Função para limpar parâmetros e navegar para orders/find
|
|
const clearAndNavigateToOrders = useCallback(() => {
|
|
// Limpar parâmetros do localStorage
|
|
setStorage("orderSearchParams", null);
|
|
// Limpar parâmetros do estado
|
|
setSearchParams({});
|
|
// Limpar URL e navegar
|
|
clearUrlAndNavigate("/orders/find");
|
|
}, [setSearchParams]);
|
|
|
|
/**
|
|
* 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,
|
|
clearAndNavigateToOrders,
|
|
handleMultiInputChange
|
|
};
|
|
}
|