This commit is contained in:
@@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user