Skip to content

Commit

Permalink
SHARED(Frontend): Use native select for pagination rowsPerPage contro…
Browse files Browse the repository at this point in the history
…l on mobile phone. Extract pagination controls to a reusable component.
  • Loading branch information
pkoivisto committed Oct 31, 2023
1 parent 75a8e2b commit b1f6651
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 62 deletions.
4 changes: 3 additions & 1 deletion frontend/packages/shared/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

- New `NativeSelect` and `NativeSelectWithLabel` components for mobile phone use
- Extracted `Pagination` component to ensure that pagination controls are consistent across usages

### Changed

- `LanguageSelect` to use `NativeSelect` when rendered on mobile phone
- `LanguageSelect` now requires `onLanguageChange` prop
- `ComboBox` to use fall back to `NativeSelect` when render on mobile phone
- `ComboBox` to fall back to `NativeSelect` when render on mobile phone
- `ComboBox` onChange prop signature has changed to: `onChange: (value?: string) => void`
- `Pagination` rowsPerPage select to fall back to `NativeSelect` on mobile phone

## [1.9.30] - 2023-10-24

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Table, TableBody, TablePagination } from '@mui/material';
import { ChangeEvent, Fragment, useRef } from 'react';
import { Table, TableBody } from '@mui/material';
import { Fragment, useRef } from 'react';

import {
defaultDisplayedRowsLabel,
PaginatedTableProps,
} from './PaginatedTable';
import { PaginatedTableProps } from './PaginatedTable';
import { Pagination } from './Pagination';
import { WithId } from '../../interfaces/with';
import './Table.scss';

Expand All @@ -24,55 +22,45 @@ export function ManagedPaginatedTable<T extends WithId>({
header,
data,
getRowDetails,
rowsPerPageOptions,
className,
stickyHeader,
showBottomPagination = true,
rowsPerPageLabel,
headerContent,
page,
size = 'medium',
onPageChange,
rowsPerPage,
onRowsPerPageChange,
labelDisplayedRows,
backIconButtonProps,
nextIconButtonProps,
...paginationOnlyProps
}: ManagedPaginatedTableProps<T>): JSX.Element {
const headerRef = useRef<HTMLDivElement>(null);
const handlePageChange = (page: number) => {
onPageChange(page);
headerRef.current?.scrollIntoView();
};
const handleRowsPerPageChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleRowsPerPageChange = (rowsPerPage: number) => {
handlePageChange(0);
onRowsPerPageChange(+event.target.value);
onRowsPerPageChange(rowsPerPage);
};

const count = data.length;

const Pagination = () => (
<TablePagination
className="table__head-box__pagination"
count={count}
component="div"
onPageChange={(_event, newPage) => handlePageChange(newPage)}
const paginationControls = (
<Pagination
handlePageChange={handlePageChange}
handleRowsPerPageChange={handleRowsPerPageChange}
page={page}
onRowsPerPageChange={handleRowsPerPageChange}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={rowsPerPageOptions}
labelRowsPerPage={rowsPerPageLabel}
labelDisplayedRows={labelDisplayedRows ?? defaultDisplayedRowsLabel}
backIconButtonProps={backIconButtonProps}
nextIconButtonProps={nextIconButtonProps}
count={count}
{...paginationOnlyProps}
/>
);

return (
<>
<div ref={headerRef} className="table__head-box">
{headerContent}
<Pagination />
{paginationControls}
</div>
<Table
className={`${className} table`}
Expand All @@ -89,9 +77,7 @@ export function ManagedPaginatedTable<T extends WithId>({
</TableBody>
</Table>
{showBottomPagination && (
<div className="table__head-box">
<Pagination />
</div>
<div className="table__head-box">{paginationControls}</div>
)}
</>
);
Expand Down
44 changes: 13 additions & 31 deletions frontend/packages/shared/src/components/Table/PaginatedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,14 @@ import {
LabelDisplayedRowsArgs,
Table,
TableBody,
TablePagination,
} from '@mui/material';
import { ChangeEvent, Fragment, useRef, useState } from 'react';
import { Fragment, useRef, useState } from 'react';

import { CustomTableProps } from './CustomTable';
import { Pagination } from './Pagination';
import { WithId } from '../../interfaces/with';
import './Table.scss';

export const defaultDisplayedRowsLabel = ({
from,
to,
count,
}: LabelDisplayedRowsArgs) => {
return `${from} - ${to} / ${count}`;
};

export interface PaginatedTableProps<T extends WithId>
extends CustomTableProps<T> {
initialRowsPerPage: number;
Expand Down Expand Up @@ -48,17 +40,13 @@ export function PaginatedTable<T extends WithId>({
data,
getRowDetails,
initialRowsPerPage,
rowsPerPageOptions,
className,
stickyHeader,
showBottomPagination = true,
rowsPerPageLabel,
headerContent,
size = 'medium',
labelDisplayedRows,
backIconButtonProps,
nextIconButtonProps,
controlledPaging,
...paginationOnlyProps
}: PaginatedTableProps<T>): JSX.Element {
const headerRef = useRef<HTMLDivElement>(null);
const [internalPage, setInternalPage] = useState(0);
Expand All @@ -67,37 +55,31 @@ export function PaginatedTable<T extends WithId>({
setPage(page);
headerRef.current?.scrollIntoView();
};
const handleRowsPerPageChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleRowsPerPageChange = (rowsPerPage: number) => {
handlePageChange(0);
setRowsPerPage(+event.target.value);
setRowsPerPage(rowsPerPage);
};

const page = controlledPaging?.page ?? internalPage;
const setPage = controlledPaging?.setPage ?? setInternalPage;
const count = data.length;

const Pagination = ({ page }: { page: number }) => (
<TablePagination
className="table__head-box__pagination"
count={count}
component="div"
onPageChange={(_event, newPage) => handlePageChange(newPage)}
const paginationControls = (
<Pagination
page={page}
onRowsPerPageChange={handleRowsPerPageChange}
count={count}
handlePageChange={handlePageChange}
handleRowsPerPageChange={handleRowsPerPageChange}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={rowsPerPageOptions}
labelRowsPerPage={rowsPerPageLabel}
labelDisplayedRows={labelDisplayedRows ?? defaultDisplayedRowsLabel}
backIconButtonProps={backIconButtonProps}
nextIconButtonProps={nextIconButtonProps}
{...paginationOnlyProps}
/>
);

return (
<>
<div ref={headerRef} className="table__head-box">
{headerContent}
<Pagination page={page} />
{paginationControls}
</div>

<Table
Expand All @@ -114,7 +96,7 @@ export function PaginatedTable<T extends WithId>({
})}
</TableBody>
</Table>
{showBottomPagination && <Pagination page={page} />}
{showBottomPagination && { paginationControls }}
</>
);
}
55 changes: 55 additions & 0 deletions frontend/packages/shared/src/components/Table/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { LabelDisplayedRowsArgs, TablePagination } from '@mui/material';

import { PaginatedTableProps } from './PaginatedTable';
import { useWindowProperties } from '../../hooks';
import { WithId } from '../../interfaces';
import './Table.scss';

interface PaginationProps {
count: number;
handlePageChange: (page: number) => void;
handleRowsPerPageChange: (rowsPerPage: number) => void;
page: number;
rowsPerPage: number;
}

const defaultDisplayedRowsLabel = ({
from,
to,
count,
}: LabelDisplayedRowsArgs) => {
return `${from} - ${to} / ${count}`;
};

export function Pagination<T extends WithId>({
count,
handlePageChange,
handleRowsPerPageChange,
labelDisplayedRows,
page,
rowsPerPage,
rowsPerPageOptions,
rowsPerPageLabel,
backIconButtonProps,
nextIconButtonProps,
}: Partial<PaginatedTableProps<T>> & PaginationProps): JSX.Element {
const { isPhone } = useWindowProperties();

return (
<TablePagination
className="table__head-box__pagination"
count={count}
component="div"
onPageChange={(_event, newPage) => handlePageChange(newPage)}
page={page}
onRowsPerPageChange={(e) => handleRowsPerPageChange(+e.target.value)}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={rowsPerPageOptions}
labelRowsPerPage={rowsPerPageLabel}
labelDisplayedRows={labelDisplayedRows ?? defaultDisplayedRowsLabel}
backIconButtonProps={backIconButtonProps}
nextIconButtonProps={nextIconButtonProps}
SelectProps={{ native: isPhone }}
/>
);
}
3 changes: 2 additions & 1 deletion frontend/packages/shared/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ export { DropDownMenuButton } from './DropDownMenuButton/DropDownMenuButton';
export { SkipLink } from './SkipLink/SkipLink';
export { Svg } from './Svg/Svg';
export { CustomTable } from './Table/CustomTable';
export { PaginatedTable } from './Table/PaginatedTable';
export { ManagedPaginatedTable } from './Table/ManagedPaginatedTable';
export { PaginatedTable } from './Table/PaginatedTable';
export { Pagination } from './Table/Pagination';
export { ToggleFilterGroup } from './ToggleFilterGroup/ToggleFilterGroup';
export { LangSelector } from './LangSelector/LangSelector';
export { InfoText } from './InfoText/InfoText';
Expand Down

0 comments on commit b1f6651

Please sign in to comment.