Paginate tax rates in the tax class view (#2997)
This commit is contained in:
parent
05b2da8082
commit
221adf25d6
8 changed files with 240 additions and 14 deletions
|
@ -1,10 +1,11 @@
|
|||
import { commonMessages } from "@dashboard/intl";
|
||||
import { TableCell } from "@material-ui/core";
|
||||
import {
|
||||
Pagination,
|
||||
PaginationProps as MacawPaginationProps,
|
||||
} from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
import { defineMessages, useIntl } from "react-intl";
|
||||
import { useIntl } from "react-intl";
|
||||
import { Link, LinkProps } from "react-router-dom";
|
||||
|
||||
import { ListSettings } from "../../types";
|
||||
|
@ -14,14 +15,6 @@ export type ListSettingsUpdate = <T extends keyof ListSettings>(
|
|||
value: ListSettings[T],
|
||||
) => void;
|
||||
|
||||
const messages = defineMessages({
|
||||
noOfRows: {
|
||||
id: "2HfSiT",
|
||||
defaultMessage: "No. of rows",
|
||||
description: "pagination",
|
||||
},
|
||||
});
|
||||
|
||||
export interface PaginationProps
|
||||
extends Omit<
|
||||
MacawPaginationProps,
|
||||
|
@ -57,7 +50,7 @@ export const TablePagination: React.FC<PaginationProps> = ({
|
|||
hasNextPage={hasNextPage && !disabled}
|
||||
hasPreviousPage={hasPreviousPage && !disabled}
|
||||
labels={{
|
||||
noOfRows: intl.formatMessage(messages.noOfRows),
|
||||
noOfRows: intl.formatMessage(commonMessages.noOfRows),
|
||||
}}
|
||||
rowNumber={settings?.rowNumber}
|
||||
onRowNumberUpdate={
|
||||
|
|
1
src/hooks/useClientPagination/index.ts
Normal file
1
src/hooks/useClientPagination/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from "./useClientPagination";
|
94
src/hooks/useClientPagination/useClientPagination.test.tsx
Normal file
94
src/hooks/useClientPagination/useClientPagination.test.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { act } from "@testing-library/react";
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
|
||||
import { useClientPagination } from "./useClientPagination";
|
||||
|
||||
describe("useClientPagination", () => {
|
||||
test("should reset current page when row number change", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeCurrentPage(2));
|
||||
act(() => result.current.changeRowNumber(20));
|
||||
|
||||
// Assert
|
||||
expect(result.current.currentPage).toEqual(1);
|
||||
expect(result.current.rowNumber).toEqual(20);
|
||||
});
|
||||
|
||||
test("should reset current page and row number when call restartPagination", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeCurrentPage(2));
|
||||
act(() => result.current.changeRowNumber(20));
|
||||
act(() => result.current.restartPagination());
|
||||
|
||||
// Assert
|
||||
expect(result.current.currentPage).toEqual(1);
|
||||
expect(result.current.rowNumber).toEqual(10);
|
||||
});
|
||||
|
||||
test("should change current page when call changeCurrentPage", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeCurrentPage(2));
|
||||
|
||||
// Assert
|
||||
expect(result.current.currentPage).toEqual(2);
|
||||
});
|
||||
|
||||
test("should change row number when call changeRowNumber", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeRowNumber(20));
|
||||
|
||||
// Assert
|
||||
expect(result.current.rowNumber).toEqual(20);
|
||||
});
|
||||
|
||||
test("should return paginated data slice to first 10", () => {
|
||||
// Arrange & Act
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
const paginatedData = result.current.paginate(Array.from(Array(20).keys()));
|
||||
|
||||
// Assert
|
||||
expect(paginatedData.hasNextPage).toEqual(true);
|
||||
expect(paginatedData.hasPreviousPage).toEqual(false);
|
||||
expect(paginatedData.data.length).toEqual(10);
|
||||
});
|
||||
|
||||
test("should return paginated data with false hasNextPage", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeCurrentPage(2));
|
||||
|
||||
// Assert
|
||||
const paginatedData = result.current.paginate(Array.from(Array(20).keys()));
|
||||
expect(paginatedData.hasNextPage).toEqual(false);
|
||||
expect(paginatedData.hasPreviousPage).toEqual(true);
|
||||
expect(paginatedData.data.length).toEqual(10);
|
||||
});
|
||||
|
||||
test("should return paginated data with false hasNextPage and hasPreviousPage", () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useClientPagination());
|
||||
|
||||
// Act
|
||||
act(() => result.current.changeRowNumber(25));
|
||||
|
||||
// Assert
|
||||
const paginatedData = result.current.paginate(Array.from(Array(20).keys()));
|
||||
expect(paginatedData.hasNextPage).toEqual(false);
|
||||
expect(paginatedData.hasPreviousPage).toEqual(false);
|
||||
expect(paginatedData.data.length).toEqual(20);
|
||||
});
|
||||
});
|
47
src/hooks/useClientPagination/useClientPagination.ts
Normal file
47
src/hooks/useClientPagination/useClientPagination.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
const DEFAULT_ROWS_COUNT = 10;
|
||||
const FIRST_PAGINATED_PAGE = 1;
|
||||
|
||||
export const useClientPagination = () => {
|
||||
const [rowNumber, setRowNumber] = useState(DEFAULT_ROWS_COUNT);
|
||||
const [currentPage, setCurrentPage] = useState(FIRST_PAGINATED_PAGE);
|
||||
|
||||
const indexOfLastElement = currentPage * rowNumber;
|
||||
const indexOfFirstElement = indexOfLastElement - rowNumber;
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentPage(FIRST_PAGINATED_PAGE);
|
||||
}, [rowNumber]);
|
||||
|
||||
const restartPagination = useCallback(() => {
|
||||
setCurrentPage(FIRST_PAGINATED_PAGE);
|
||||
setRowNumber(DEFAULT_ROWS_COUNT);
|
||||
}, []);
|
||||
|
||||
const changeRowNumber = useCallback((rowNumber: number) => {
|
||||
setRowNumber(rowNumber);
|
||||
}, []);
|
||||
|
||||
const changeCurrentPage = useCallback((page: number) => {
|
||||
setCurrentPage(page);
|
||||
}, []);
|
||||
|
||||
const paginate = useCallback(
|
||||
<T>(data: T[]) => ({
|
||||
data: data.slice(indexOfFirstElement, indexOfLastElement),
|
||||
hasNextPage: data.length / (rowNumber * currentPage) > 1,
|
||||
hasPreviousPage: currentPage > 1,
|
||||
}),
|
||||
[currentPage, indexOfFirstElement, indexOfLastElement, rowNumber],
|
||||
);
|
||||
|
||||
return {
|
||||
rowNumber,
|
||||
changeRowNumber,
|
||||
changeCurrentPage,
|
||||
currentPage,
|
||||
restartPagination,
|
||||
paginate,
|
||||
};
|
||||
};
|
|
@ -190,6 +190,11 @@ export const commonMessages = defineMessages({
|
|||
id: "D3idYv",
|
||||
defaultMessage: "Settings",
|
||||
},
|
||||
noOfRows: {
|
||||
id: "2HfSiT",
|
||||
defaultMessage: "No. of rows",
|
||||
description: "pagination",
|
||||
},
|
||||
});
|
||||
|
||||
export const errorMessages = defineMessages({
|
||||
|
|
58
src/taxes/components/TaxPagination/TaxPagination.tsx
Normal file
58
src/taxes/components/TaxPagination/TaxPagination.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { commonMessages } from "@dashboard/intl";
|
||||
import { makeStyles, Pagination } from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
interface TaxPaginationProps {
|
||||
rowNumber: number;
|
||||
currentPage: number;
|
||||
setRowNumber: (rowNumber: number) => void;
|
||||
hasNextPage: boolean;
|
||||
hasPrevPage: boolean;
|
||||
setCurrentPage: (currentPage: number) => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
container: {
|
||||
padding: theme.spacing(0, 4),
|
||||
},
|
||||
}),
|
||||
{ name: "TaxPagination" },
|
||||
);
|
||||
|
||||
export const TaxPagination = ({
|
||||
rowNumber,
|
||||
setRowNumber,
|
||||
setCurrentPage,
|
||||
hasNextPage,
|
||||
hasPrevPage,
|
||||
currentPage,
|
||||
}: TaxPaginationProps) => {
|
||||
const classes = useStyles();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleNextPage = () => {
|
||||
setCurrentPage(currentPage + 1);
|
||||
};
|
||||
|
||||
const handlePrevPage = () => {
|
||||
setCurrentPage(currentPage - 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<Pagination
|
||||
hasNextPage={hasNextPage}
|
||||
hasPreviousPage={hasPrevPage}
|
||||
labels={{
|
||||
noOfRows: intl.formatMessage(commonMessages.noOfRows),
|
||||
}}
|
||||
rowNumber={rowNumber}
|
||||
onRowNumberUpdate={setRowNumber}
|
||||
onNextPage={handleNextPage}
|
||||
onPreviousPage={handlePrevPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
1
src/taxes/components/TaxPagination/index.ts
Normal file
1
src/taxes/components/TaxPagination/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from "./TaxPagination";
|
|
@ -8,6 +8,7 @@ import Savebar from "@dashboard/components/Savebar";
|
|||
import Skeleton from "@dashboard/components/Skeleton";
|
||||
import { configurationMenuUrl } from "@dashboard/configuration";
|
||||
import { TaxClassFragment } from "@dashboard/graphql";
|
||||
import { useClientPagination } from "@dashboard/hooks/useClientPagination/useClientPagination";
|
||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||
import { getById } from "@dashboard/misc";
|
||||
|
@ -36,10 +37,11 @@ import {
|
|||
PageTabs,
|
||||
SearchIcon,
|
||||
} from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import TaxInput from "../../components/TaxInput";
|
||||
import { TaxPagination } from "../../components/TaxPagination";
|
||||
import TaxClassesForm from "./form";
|
||||
import { useStyles } from "./styles";
|
||||
import TaxClassesMenu from "./TaxClassesMenu";
|
||||
|
@ -72,9 +74,17 @@ export const TaxClassesPage: React.FC<TaxClassesPageProps> = props => {
|
|||
const navigate = useNavigator();
|
||||
const classes = useStyles();
|
||||
|
||||
const [query, setQuery] = React.useState("");
|
||||
const [query, setQuery] = useState("");
|
||||
const {
|
||||
rowNumber,
|
||||
currentPage,
|
||||
paginate,
|
||||
restartPagination,
|
||||
changeCurrentPage,
|
||||
changeRowNumber,
|
||||
} = useClientPagination();
|
||||
|
||||
const currentTaxClass = React.useMemo(
|
||||
const currentTaxClass = useMemo(
|
||||
() => taxClasses?.find(getById(selectedTaxClassId)),
|
||||
[selectedTaxClassId, taxClasses],
|
||||
);
|
||||
|
@ -83,6 +93,10 @@ export const TaxClassesPage: React.FC<TaxClassesPageProps> = props => {
|
|||
currentTaxClass?.id,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
restartPagination();
|
||||
}, [query, restartPagination]);
|
||||
|
||||
return (
|
||||
<TaxClassesForm
|
||||
taxClass={currentTaxClass}
|
||||
|
@ -95,6 +109,10 @@ export const TaxClassesPage: React.FC<TaxClassesPageProps> = props => {
|
|||
rate => rate.label.search(new RegExp(parseQuery(query), "i")) >= 0,
|
||||
);
|
||||
|
||||
const { data: paginatedRates, hasNextPage, hasPreviousPage } = paginate(
|
||||
filteredRates,
|
||||
);
|
||||
|
||||
const formErrors = getFormErrors(["name"], validationErrors);
|
||||
|
||||
return (
|
||||
|
@ -204,7 +222,7 @@ export const TaxClassesPage: React.FC<TaxClassesPageProps> = props => {
|
|||
</ListItem>
|
||||
</ListHeader>
|
||||
<Divider />
|
||||
{filteredRates?.map(
|
||||
{paginatedRates?.map(
|
||||
(countryRate, countryRateIndex) => (
|
||||
<React.Fragment key={countryRate.id}>
|
||||
<ListItem
|
||||
|
@ -238,6 +256,15 @@ export const TaxClassesPage: React.FC<TaxClassesPageProps> = props => {
|
|||
<VerticalSpacer />
|
||||
</>
|
||||
)}
|
||||
|
||||
<TaxPagination
|
||||
rowNumber={rowNumber}
|
||||
setRowNumber={changeRowNumber}
|
||||
hasNextPage={hasNextPage}
|
||||
hasPrevPage={hasPreviousPage}
|
||||
currentPage={currentPage}
|
||||
setCurrentPage={changeCurrentPage}
|
||||
/>
|
||||
</List>
|
||||
</>
|
||||
)}
|
||||
|
|
Loading…
Reference in a new issue