function normalizePageNumber(value) { const pageNumber = Math.floor(Number(value) || 1); return Math.max(1, pageNumber); } function buildQueryString(query) { const searchParams = new URLSearchParams(); Object.keys(query || {}).forEach(function (key) { const value = query[key]; if (value === undefined || value === null || value === '') { return; } searchParams.set(key, String(value)); }); const queryString = searchParams.toString(); return queryString ? `?${queryString}` : ''; } function buildPagination(totalItems, currentPage, pageParam, queryState, pageSize, itemLabel, ariaLabel) { const normalizedPageParam = String(pageParam || 'page').trim() || 'page'; const normalizedPageSize = Math.max(1, Number(pageSize) || 10); const totalPages = Math.max(1, Math.ceil(Number(totalItems) / normalizedPageSize)); const safeCurrentPage = Math.min(normalizePageNumber(currentPage), totalPages); const startIndex = totalItems <= 0 ? 0 : (safeCurrentPage - 1) * normalizedPageSize; const endIndex = totalItems <= 0 ? 0 : Math.min(totalItems, startIndex + normalizedPageSize); const pages = []; for (let pageNumber = 1; pageNumber <= totalPages; pageNumber += 1) { const nextQuery = Object.assign({}, queryState, { [normalizedPageParam]: pageNumber }); pages.push({ number: pageNumber, active: pageNumber === safeCurrentPage, url: buildQueryString(nextQuery) }); } const previousQuery = Object.assign({}, queryState, { [normalizedPageParam]: safeCurrentPage - 1 }); const nextQuery = Object.assign({}, queryState, { [normalizedPageParam]: safeCurrentPage + 1 }); return { currentPage: safeCurrentPage, totalPages: totalPages, totalItems: Number(totalItems) || 0, hasMultiplePages: totalPages > 1, startItem: startIndex + 1, endItem: endIndex, hasPrevious: safeCurrentPage > 1, hasNext: safeCurrentPage < totalPages, previousUrl: buildQueryString(previousQuery), nextUrl: buildQueryString(nextQuery), pages: pages, pageSize: normalizedPageSize, pageParam: normalizedPageParam, itemLabel: String(itemLabel || 'items'), ariaLabel: String(ariaLabel || 'Pagination') }; } module.exports = { normalizePageNumber, buildQueryString, buildPagination };