pagination
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-06-29 09:45:56 +03:30
parent 2a5905b35f
commit 7601368bd3
6 changed files with 87 additions and 23 deletions
+48
View File
@@ -0,0 +1,48 @@
import { useCallback, useMemo } from "react";
import { useSearchParams } from "react-router-dom";
const PAGE_PARAM = "page";
export const useUrlPagination = (defaultPage = 1) => {
const [searchParams, setSearchParams] = useSearchParams();
const currentPage = useMemo(() => {
const page = Number.parseInt(searchParams.get(PAGE_PARAM) ?? "", 10);
return Number.isFinite(page) && page > 0 ? page : defaultPage;
}, [searchParams, defaultPage]);
const handlePageChange = useCallback(
(page: number) => {
setSearchParams(
(prev) => {
const next = new URLSearchParams(prev);
if (page <= defaultPage) {
next.delete(PAGE_PARAM);
} else {
next.set(PAGE_PARAM, page.toString());
}
return next;
},
{ replace: false },
);
},
[setSearchParams, defaultPage],
);
const resetPage = useCallback(() => {
setSearchParams(
(prev) => {
const next = new URLSearchParams(prev);
next.delete(PAGE_PARAM);
return next;
},
{ replace: true },
);
}, [setSearchParams]);
return {
currentPage,
handlePageChange,
resetPage,
};
};
+15 -11
View File
@@ -1,7 +1,8 @@
import Table from '@/components/Table' import Table from '@/components/Table'
import Filters, { type FilterValues, type FieldType } from '@/components/Filters' import Filters, { type FilterValues, type FieldType } from '@/components/Filters'
import { type FC, useState, useMemo, useCallback } from 'react' import { type FC, useState, useMemo, useCallback, useEffect } from 'react'
import { useGetUsers } from './hooks/useUsersData' import { useGetUsers } from './hooks/useUsersData'
import { useUrlPagination } from '@/hooks/useUrlPagination'
import type { Customer, CustomerListRow } from '@/pages/customers/types/Types' import type { Customer, CustomerListRow } from '@/pages/customers/types/Types'
import { formatOptionalDate, formatFaNumber } from '@/helpers/func' import { formatOptionalDate, formatFaNumber } from '@/helpers/func'
@@ -22,7 +23,7 @@ const mapCustomerToRow = (customer: Customer): CustomerListRow => {
const CustomersList: FC = () => { const CustomersList: FC = () => {
const { data: usersData, isLoading } = useGetUsers() const { data: usersData, isLoading } = useGetUsers()
const [filters, setFilters] = useState<FilterValues>({ search: '', status: 'all' }) const [filters, setFilters] = useState<FilterValues>({ search: '', status: 'all' })
const [currentPage, setCurrentPage] = useState(1) const { currentPage, handlePageChange, resetPage } = useUrlPagination()
const limit = 10 const limit = 10
const filterFields = useMemo<FieldType[]>(() => [ const filterFields = useMemo<FieldType[]>(() => [
@@ -67,11 +68,18 @@ const CustomersList: FC = () => {
}, [customers, filters]) }, [customers, filters])
const totalPages = Math.max(1, Math.ceil(filteredCustomers.length / limit) || 1) const totalPages = Math.max(1, Math.ceil(filteredCustomers.length / limit) || 1)
const effectivePage = Math.min(currentPage, totalPages)
useEffect(() => {
if (currentPage > totalPages) {
handlePageChange(totalPages)
}
}, [currentPage, totalPages, handlePageChange])
const paginatedCustomers = useMemo(() => { const paginatedCustomers = useMemo(() => {
const startIndex = (currentPage - 1) * limit const startIndex = (effectivePage - 1) * limit
return filteredCustomers.slice(startIndex, startIndex + limit) return filteredCustomers.slice(startIndex, startIndex + limit)
}, [filteredCustomers, currentPage, limit]) }, [filteredCustomers, effectivePage, limit])
const tableData = useMemo<CustomerListRow[]>(() => paginatedCustomers.map(mapCustomerToRow), [paginatedCustomers]) const tableData = useMemo<CustomerListRow[]>(() => paginatedCustomers.map(mapCustomerToRow), [paginatedCustomers])
@@ -117,14 +125,10 @@ const CustomersList: FC = () => {
}, },
], []) ], [])
const handlePageChange = (page: number) => {
setCurrentPage(page)
}
const handleFiltersChange = useCallback((newFilters: FilterValues) => { const handleFiltersChange = useCallback((newFilters: FilterValues) => {
setFilters(newFilters) setFilters(newFilters)
setCurrentPage(1) resetPage()
}, []) }, [resetPage])
return ( return (
<div className='mt-5'> <div className='mt-5'>
@@ -155,7 +159,7 @@ const CustomersList: FC = () => {
isloading={isLoading} isloading={isLoading}
selectable selectable
pagination={{ pagination={{
currentPage, currentPage: effectivePage,
totalPages, totalPages,
onPageChange: handlePageChange, onPageChange: handlePageChange,
}} }}
+10 -4
View File
@@ -1,4 +1,4 @@
import { type FC } from 'react' import { type FC, useEffect } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Table from '@/components/Table' import Table from '@/components/Table'
import Filters from '@/components/Filters' import Filters from '@/components/Filters'
@@ -17,7 +17,6 @@ const OrdersList: FC = () => {
apiParams, apiParams,
handleFiltersChange, handleFiltersChange,
handlePageChange, handlePageChange,
limit,
} = useOrderFilters() } = useOrderFilters()
const { data: ordersData, isLoading } = useGetOrders(apiParams) const { data: ordersData, isLoading } = useGetOrders(apiParams)
@@ -26,7 +25,14 @@ const OrdersList: FC = () => {
const columns = getOrderTableColumns({ t }) const columns = getOrderTableColumns({ t })
const filterFields = useOrderFiltersFields() const filterFields = useOrderFiltersFields()
const totalPages = Math.ceil(orders.length / limit) || 1 const totalPages = ordersData?.meta?.totalPages || 1
const effectivePage = Math.min(currentPage, totalPages)
useEffect(() => {
if (currentPage > totalPages) {
handlePageChange(totalPages)
}
}, [currentPage, totalPages, handlePageChange])
return ( return (
<div className='mt-5'> <div className='mt-5'>
@@ -48,7 +54,7 @@ const OrdersList: FC = () => {
data={orders as (Order & RowDataType)[]} data={orders as (Order & RowDataType)[]}
isloading={isLoading} isloading={isLoading}
pagination={{ pagination={{
currentPage, currentPage: effectivePage,
totalPages, totalPages,
onPageChange: handlePageChange, onPageChange: handlePageChange,
}} }}
+3 -6
View File
@@ -1,12 +1,13 @@
import { useState, useMemo } from "react"; import { useState, useMemo } from "react";
import type { FilterValues } from "@/components/Filters"; import type { FilterValues } from "@/components/Filters";
import { useUrlPagination } from "@/hooks/useUrlPagination";
const DEFAULT_PAGE = 1; const DEFAULT_PAGE = 1;
const DEFAULT_LIMIT = 10; const DEFAULT_LIMIT = 10;
export const useOrderFilters = () => { export const useOrderFilters = () => {
const [filters, setFilters] = useState<FilterValues>({}); const [filters, setFilters] = useState<FilterValues>({});
const [currentPage, setCurrentPage] = useState(DEFAULT_PAGE); const { currentPage, handlePageChange, resetPage } = useUrlPagination(DEFAULT_PAGE);
const [limit] = useState(DEFAULT_LIMIT); const [limit] = useState(DEFAULT_LIMIT);
const apiParams = useMemo(() => { const apiParams = useMemo(() => {
@@ -32,11 +33,7 @@ export const useOrderFilters = () => {
const handleFiltersChange = (newFilters: FilterValues) => { const handleFiltersChange = (newFilters: FilterValues) => {
setFilters(newFilters); setFilters(newFilters);
setCurrentPage(DEFAULT_PAGE); resetPage();
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
}; };
return { return {
+4 -2
View File
@@ -1,4 +1,4 @@
import type { IResponse } from "@/types/response.types"; import type { IResponse, PaginationMeta } from "@/types/response.types";
import type { RowDataType } from "@/components/types/TableTypes"; import type { RowDataType } from "@/components/types/TableTypes";
export interface OrderUser { export interface OrderUser {
@@ -220,5 +220,7 @@ export interface Order extends RowDataType {
items: OrderItem[]; items: OrderItem[];
} }
export type GetOrdersResponse = IResponse<Order[]>; export type GetOrdersResponse = IResponse<Order[]> & {
meta?: PaginationMeta;
};
export type GetOrderByIdResponse = IResponse<Order>; export type GetOrderByIdResponse = IResponse<Order>;
+7
View File
@@ -6,3 +6,10 @@ export interface IBaseResponse {
export interface IResponse<T> extends IBaseResponse { export interface IResponse<T> extends IBaseResponse {
data: T; data: T;
} }
export interface PaginationMeta {
total: number;
page: string;
limit: string;
totalPages: number;
}