feat(products-list): add pagination to products list and update filter handling

This commit is contained in:
hossein taromi 2025-08-11 13:55:41 +03:30
parent e601a2cc5a
commit 9bf5d63d1b
1 changed files with 24 additions and 7 deletions

View File

@ -8,6 +8,7 @@ import { Button } from "@/components/ui/Button";
import { Trash2, Edit3, Plus, Package, Eye, Image } from "lucide-react"; import { Trash2, Edit3, Plus, Package, Eye, Image } from "lucide-react";
import { Modal } from "@/components/ui/Modal"; import { Modal } from "@/components/ui/Modal";
import { persianToEnglish } from '../../../utils/numberUtils'; import { persianToEnglish } from '../../../utils/numberUtils';
import { Pagination } from "@/components/ui/Pagination";
const ProductsTableSkeleton = () => ( const ProductsTableSkeleton = () => (
<div className="bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden"> <div className="bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
@ -71,14 +72,16 @@ const ProductsListPage = () => {
category_id: '', category_id: '',
status: '', status: '',
min_price: '', min_price: '',
max_price: '' max_price: '',
page: 1,
limit: 100,
}); });
const { data: productsData, isLoading, error } = useProducts({ const { data: productsData, isLoading, error } = useProducts({
...filters, ...filters,
category_id: filters.category_id ? Number(filters.category_id) : undefined, category_id: filters.category_id ? Number(filters.category_id) : undefined,
min_price: filters.min_price ? Number(filters.min_price) : undefined, min_price: filters.min_price ? Number(filters.min_price) : undefined,
max_price: filters.max_price ? Number(filters.max_price) : undefined max_price: filters.max_price ? Number(filters.max_price) : undefined,
}); });
const { data: categories } = useCategories(); const { data: categories } = useCategories();
const { mutate: deleteProduct, isPending: isDeleting } = useDeleteProduct(); const { mutate: deleteProduct, isPending: isDeleting } = useDeleteProduct();
@ -108,15 +111,15 @@ const ProductsListPage = () => {
}; };
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFilters(prev => ({ ...prev, search: e.target.value })); setFilters(prev => ({ ...prev, search: e.target.value, page: 1 }));
}; };
const handleCategoryChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const handleCategoryChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setFilters(prev => ({ ...prev, category_id: e.target.value })); setFilters(prev => ({ ...prev, category_id: e.target.value, page: 1 }));
}; };
const handleStatusChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const handleStatusChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setFilters(prev => ({ ...prev, status: e.target.value })); setFilters(prev => ({ ...prev, status: e.target.value, page: 1 }));
}; };
const formatPrice = (price: number) => { const formatPrice = (price: number) => {
@ -142,6 +145,11 @@ const ProductsListPage = () => {
} }
}; };
const total = productsData?.total || 0;
const currentPage = productsData?.page || filters.page;
const perPage = productsData?.per_page || filters.limit;
const totalPages = Math.max(1, Math.ceil((total || 0) / (perPage || 20)));
if (error) { if (error) {
return ( return (
<div className="p-6"> <div className="p-6">
@ -233,7 +241,7 @@ const ProductsListPage = () => {
value={filters.min_price} value={filters.min_price}
onChange={(e) => { onChange={(e) => {
const converted = persianToEnglish(e.target.value); const converted = persianToEnglish(e.target.value);
setFilters(prev => ({ ...prev, min_price: converted })); setFilters(prev => ({ ...prev, min_price: converted, page: 1 }));
}} }}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:bg-gray-700 dark:text-gray-100" className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:bg-gray-700 dark:text-gray-100"
/> />
@ -244,7 +252,7 @@ const ProductsListPage = () => {
value={filters.max_price} value={filters.max_price}
onChange={(e) => { onChange={(e) => {
const converted = persianToEnglish(e.target.value); const converted = persianToEnglish(e.target.value);
setFilters(prev => ({ ...prev, max_price: converted })); setFilters(prev => ({ ...prev, max_price: converted, page: 1 }));
}} }}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:bg-gray-700 dark:text-gray-100" className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:bg-gray-700 dark:text-gray-100"
/> />
@ -435,6 +443,15 @@ const ProductsListPage = () => {
</div> </div>
)} )}
{/* Pagination */}
<Pagination
currentPage={currentPage}
totalPages={totalPages}
itemsPerPage={perPage}
totalItems={total}
onPageChange={(page) => setFilters(prev => ({ ...prev, page }))}
/>
{/* Delete Confirmation Modal */} {/* Delete Confirmation Modal */}
<Modal <Modal
isOpen={!!deleteProductId} isOpen={!!deleteProductId}