From b5852772146c913eafb18e83e78b7b6a0760808f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 24 Sep 2026 18:46:53 +0700 Subject: [PATCH] feat(admin): allow selecting items per page (10, 20, 50, 100, 500) on /products --- apps/admin/src/pages/ProductsPage.tsx | 121 ++++++++++++++++++++------ 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/apps/admin/src/pages/ProductsPage.tsx b/apps/admin/src/pages/ProductsPage.tsx index 70b2853..b70e50b 100644 --- a/apps/admin/src/pages/ProductsPage.tsx +++ b/apps/admin/src/pages/ProductsPage.tsx @@ -42,7 +42,9 @@ export default function ProductsPage() { // Pagination State const page = searchParams.get('page') ? Number(searchParams.get('page')) : 1 - const [limit] = useState(10) // Small limit for testing pagination UI easily + const validLimits = [10, 20, 50, 100, 500] + const limitParam = Number(searchParams.get('limit')) + const limit = validLimits.includes(limitParam) ? limitParam : 10 const [meta, setMeta] = useState(null) const fixUrl = (url: string) => { @@ -265,7 +267,19 @@ export default function ProductsPage() { }) } - // Fetch when page, category, or search changes + const handleLimitChange = (newLimit: number) => { + setSearchParams(prev => { + if (newLimit === 10) { + prev.delete('limit') + } else { + prev.set('limit', newLimit.toString()) + } + prev.delete('page') + return prev + }) + } + + // Fetch when page, category, search, or limit changes useEffect(() => { // Only debounce if we have a search value to avoid rapid fetches while typing const timeout = setTimeout(() => { @@ -273,7 +287,7 @@ export default function ProductsPage() { }, search ? 300 : 0) return () => clearTimeout(timeout) - }, [page, activeCategory, search]) + }, [page, activeCategory, search, limit]) // Reset to page 1 when filter changes const handleCategoryChange = (catId: number | null) => { @@ -493,48 +507,101 @@ export default function ProductsPage() { {/* Pagination Controls */} -
-
-

+

+
+

Showing page {page} of {meta?.lastPage || 1} + {meta?.total !== undefined ? ` (${meta.total} ${t('products.totalItems', 'รายการทั้งหมด')})` : ''}

+ +
+ {t('products.perPage', 'แสดงต่อหน้า:')} + +
- {/* Page numbers (limited) */} + {/* Page numbers with sliding window */}
- {Array.from({ length: Math.min(5, meta?.lastPage || 0) }).map((_, i) => { - const pageNum = i + 1; - // Logic for showing a realistic range could go here, but 5 is enough for now - return ( - - ) - })} - {(meta?.lastPage || 0) > 5 && ...} + {(() => { + const lastPage = meta?.lastPage || 1 + const maxButtons = 5 + let start = Math.max(1, page - 2) + let end = Math.min(lastPage, start + maxButtons - 1) + if (end - start < maxButtons - 1) { + start = Math.max(1, end - maxButtons + 1) + } + const pages = [] + for (let i = start; i <= end; i++) { + pages.push(i) + } + + return ( + <> + {start > 1 && ( + <> + + {start > 2 && ...} + + )} + {pages.map((pageNum) => ( + + ))} + {end < lastPage && ( + <> + {end < lastPage - 1 && ...} + + + )} + + ) + })()}