From bcf03887f1cc4b270ce7345482a2b27237568ff8 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Thu, 2 Jul 2026 10:43:55 +0330 Subject: [PATCH] pagination orders list --- src/pages/orders/List.tsx | 3 +- src/pages/orders/hooks/useOrderFilters.ts | 94 ++++++++++++++++++++--- src/pages/orders/types/Types.ts | 11 ++- 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/pages/orders/List.tsx b/src/pages/orders/List.tsx index ea00dff..d69abf0 100644 --- a/src/pages/orders/List.tsx +++ b/src/pages/orders/List.tsx @@ -21,7 +21,6 @@ const OrdersList: FC = () => { apiParams, handleFiltersChange, handlePageChange, - limit, } = useOrderFilters() const { data: ordersData, isLoading } = useGetOrders(apiParams) @@ -30,7 +29,7 @@ const OrdersList: FC = () => { const columns = getOrderTableColumns({ t }) const filterFields = useOrderFiltersFields() - const totalPages = Math.ceil(orders.length / limit) || 1 + const totalPages = ordersData?.meta?.totalPages || 1 return (
diff --git a/src/pages/orders/hooks/useOrderFilters.ts b/src/pages/orders/hooks/useOrderFilters.ts index c8d5f19..654e8cf 100644 --- a/src/pages/orders/hooks/useOrderFilters.ts +++ b/src/pages/orders/hooks/useOrderFilters.ts @@ -1,14 +1,80 @@ -import { useState, useMemo } from "react"; +import { useState, useMemo, useCallback, useEffect } from "react"; +import { useSearchParams } from "react-router-dom"; import type { FilterValues } from "@/components/Filters"; const DEFAULT_PAGE = 1; const DEFAULT_LIMIT = 10; +const DEFAULT_FILTERS: FilterValues = { + statuses: [], + paymentStatus: "", +}; + +const getFiltersFromParams = (searchParams: URLSearchParams): FilterValues => { + const filters: FilterValues = { ...DEFAULT_FILTERS }; + const search = searchParams.get("search"); + const statuses = searchParams.getAll("statuses"); + const paymentStatus = searchParams.get("paymentStatus"); + + if (search) filters.search = search; + if (statuses.length > 0) filters.statuses = statuses; + if (paymentStatus) filters.paymentStatus = paymentStatus; + + return filters; +}; + +const getPageFromParams = (searchParams: URLSearchParams): number => { + const page = searchParams.get("page"); + const parsed = page ? parseInt(page, 10) : DEFAULT_PAGE; + return Number.isNaN(parsed) || parsed < 1 ? DEFAULT_PAGE : parsed; +}; + +const buildSearchParams = (filters: FilterValues, page: number): URLSearchParams => { + const params = new URLSearchParams(); + + if (page > DEFAULT_PAGE) { + params.set("page", String(page)); + } + + if (filters.search) { + params.set("search", filters.search as string); + } + + if (filters.statuses && Array.isArray(filters.statuses) && filters.statuses.length > 0) { + (filters.statuses as string[]).forEach((status) => { + params.append("statuses", status); + }); + } + + if (filters.paymentStatus) { + params.set("paymentStatus", filters.paymentStatus as string); + } + + return params; +}; export const useOrderFilters = () => { - const [filters, setFilters] = useState({}); - const [currentPage, setCurrentPage] = useState(DEFAULT_PAGE); + const [searchParams, setSearchParams] = useSearchParams(); + + const [filters, setFilters] = useState(() => + getFiltersFromParams(searchParams), + ); + const [currentPage, setCurrentPage] = useState(() => + getPageFromParams(searchParams), + ); const [limit] = useState(DEFAULT_LIMIT); + useEffect(() => { + setFilters(getFiltersFromParams(searchParams)); + setCurrentPage(getPageFromParams(searchParams)); + }, [searchParams]); + + const updateUrlParams = useCallback( + (newFilters: FilterValues, page: number) => { + setSearchParams(buildSearchParams(newFilters, page), { replace: true }); + }, + [setSearchParams], + ); + const apiParams = useMemo(() => { const params: Record = { page: currentPage, @@ -30,14 +96,22 @@ export const useOrderFilters = () => { return params; }, [filters, currentPage, limit]); - const handleFiltersChange = (newFilters: FilterValues) => { - setFilters(newFilters); - setCurrentPage(DEFAULT_PAGE); - }; + const handleFiltersChange = useCallback( + (newFilters: FilterValues) => { + setFilters(newFilters); + setCurrentPage(DEFAULT_PAGE); + updateUrlParams(newFilters, DEFAULT_PAGE); + }, + [updateUrlParams], + ); - const handlePageChange = (page: number) => { - setCurrentPage(page); - }; + const handlePageChange = useCallback( + (page: number) => { + setCurrentPage(page); + updateUrlParams(filters, page); + }, + [filters, updateUrlParams], + ); return { filters, diff --git a/src/pages/orders/types/Types.ts b/src/pages/orders/types/Types.ts index ae21909..6ab7678 100644 --- a/src/pages/orders/types/Types.ts +++ b/src/pages/orders/types/Types.ts @@ -218,7 +218,16 @@ export interface Order extends RowDataType { items: OrderItem[]; } -export type GetOrdersResponse = IResponse; +export type PaginationMeta = { + total: number; + page: number; + limit: number; + totalPages: number; +}; + +export type GetOrdersResponse = IResponse & { + meta: PaginationMeta; +}; export type GetOrderByIdResponse = IResponse; export interface FoodOrderReportFood {