Skip to content

Commit

Permalink
Merge branch 'feat/paginated-table-components' into alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
mguellsegarra committed Feb 13, 2025
2 parents 6837dd2 + f732cbb commit 6dd5a78
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 51 deletions.
51 changes: 30 additions & 21 deletions src/components/ui/PaginationHeader/PaginationHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useLocale } from "@/context";
import { Col, Pagination, Row } from "antd";
import { Col, Pagination, Row, Spin } from "antd";
import type { PaginationProps } from "antd";
import { useMemo, useState, useCallback, memo } from "react";
import { SelectAllRecordsRow } from "../SelectAllRecordsRow/SelectAllRecordsRow";
import {
SelectAllRecordsRow,
shouldShowSelectionRow,
} from "../SelectAllRecordsRow/SelectAllRecordsRow";
import type { PaginationHeaderProps } from "./PaginationHeader.types";
import type { SelectAllRecordsRowProps } from "../SelectAllRecordsRow/SelectAllRecordsRow.types";

Expand All @@ -14,8 +17,8 @@ const PaginationHeaderComponent = (props: PaginationHeaderProps) => {
currentPageSelectedCount,
totalSelectedCount,
onRequestPageChange,
onPageSizeChange,
onSelectAllGlobalRecords,
totalRowsLoading,
} = props;

const { t } = useLocale();
Expand All @@ -40,16 +43,6 @@ const PaginationHeaderComponent = (props: PaginationHeaderProps) => {
[onRequestPageChange],
);

const handlePageSizeChange = useCallback(
(newPageSize: number, newPage: number) => {
setPageSize(newPageSize);
setPage(newPage);
onPageSizeChange(newPageSize);
onRequestPageChange(newPage, newPageSize);
},
[onPageSizeChange, onRequestPageChange],
);

const summary = useMemo(() => {
if (total === undefined) return null;
if (total === 0) return t("no_results");
Expand All @@ -67,47 +60,63 @@ const PaginationHeaderComponent = (props: PaginationHeaderProps) => {
current: page,
onChange: handlePageChange,
showSizeChanger: true,
onShowSizeChange: handlePageSizeChange,
showLessItems: true,
locale: {
items_per_page: t("items_per_page"),
},
}),
[total, pageSize, page, handlePageChange, handlePageSizeChange, t],
[total, pageSize, page, handlePageChange, t],
);

const shouldShowSelectAllRecordsRow = useMemo(() => {
if (!onSelectAllGlobalRecords) return false;
return shouldShowSelectionRow({
currentPageSelectedCount,
currentPageSize: pageSize,
totalRecordsCount: total,
totalSelectedCount,
currentPage: page,
});
}, [
onSelectAllGlobalRecords,
currentPageSelectedCount,
pageSize,
total,
totalSelectedCount,
page,
]);

const selectAllRecordsProps: SelectAllRecordsRowProps = useMemo(
() => ({
shouldShow: shouldShowSelectAllRecordsRow,
currentPageSelectedCount,
currentPageSize: pageSize,
totalRecordsCount: total,
totalSelectedCount,
onSelectAllRecords: onSelectAllGlobalRecords!,
}),
[
shouldShowSelectAllRecordsRow,
currentPageSelectedCount,
pageSize,
total,
totalSelectedCount,
onSelectAllGlobalRecords,
],
);

const hasSelectionFeature = onSelectAllGlobalRecords !== undefined;
const columnSpan = hasSelectionFeature ? 8 : 12;
const columnSpan = shouldShowSelectAllRecordsRow ? 8 : 12;

return (
<Row align="bottom" className="pb-4" wrap={false}>
<Col span={columnSpan}>
<Pagination {...paginationProps} />
</Col>
{hasSelectionFeature && (
{shouldShowSelectAllRecordsRow && (
<Col span={8} className="text-center">
<SelectAllRecordsRow {...selectAllRecordsProps} />
</Col>
)}
<Col span={columnSpan} className="text-right">
{summary}
{totalRowsLoading ? <Spin /> : summary}
</Col>
</Row>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/PaginationHeader/PaginationHeader.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export type PaginationHeaderProps = {
totalSelectedCount: number;
/** Callback when page or page size changes */
onRequestPageChange: (page: number, pageSize?: number) => void;
/** Callback when page size changes */
onPageSizeChange: (pageSize: number) => void;
/** Optional callback to select all records across all pages */
onSelectAllGlobalRecords?: () => Promise<void>;
/** Whether the total number of rows is loading */
totalRowsLoading: boolean;
};
63 changes: 42 additions & 21 deletions src/components/ui/SelectAllRecordsRow/SelectAllRecordsRow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from "styled-components";
import { useState, useCallback, memo, useMemo } from "react";
import { useState, useCallback, memo } from "react";
import { Spin } from "antd";
import Link from "antd/es/typography/Link";
import { useLocale } from "@/context";
Expand All @@ -11,45 +11,65 @@ export const Container = styled.div`
justify-content: center;
`;

const SelectAllRecordsRowComponent = ({
export const shouldShowSelectionRow = ({
currentPageSelectedCount,
currentPageSize,
totalRecordsCount,
totalSelectedCount,
onSelectAllRecords,
}: SelectAllRecordsRowProps) => {
currentPage,
}: {
currentPageSelectedCount: number;
currentPageSize: number;
totalRecordsCount: number;
totalSelectedCount: number;
currentPage: number;
}) => {
// Don't show if there are no records
if (totalRecordsCount === 0) return false;

// Calculate the actual number of records on the current page
const totalPages = Math.ceil(totalRecordsCount / currentPageSize);
const isLastPage = currentPage === totalPages;
const currentPageRecords = isLastPage
? totalRecordsCount - (totalPages - 1) * currentPageSize
: currentPageSize;

// Don't show if current page is not fully selected
if (currentPageSelectedCount < currentPageRecords) return false;

// Don't show if we don't have more records than current page
if (totalRecordsCount <= currentPageSize) return false;

// Show either the "select all" option or the "all selected" message
return true;
};

const SelectAllRecordsRowComponent = (props: SelectAllRecordsRowProps) => {
const [loading, setLoading] = useState(false);
const { t } = useLocale();

const {
shouldShow,
totalRecordsCount,
currentPageSelectedCount,
totalSelectedCount,
onSelectAllRecords,
} = props;

const handleClick = useCallback(
async (event: React.MouseEvent) => {
event.preventDefault();
event.stopPropagation();
setLoading(true);
try {
await onSelectAllRecords();
await props.onSelectAllRecords();
} finally {
setLoading(false);
}
},
[onSelectAllRecords],
);

// Don't render anything if there are no records
if (totalRecordsCount === 0) {
return null;
}

// Don't render if current page is not fully selected
if (currentPageSelectedCount < currentPageSize) {
return null;
}

// Don't render if we don't have more records than current page
if (totalRecordsCount <= currentPageSize) {
return null;
}

// If all records are selected, show the total count message
if (totalSelectedCount === totalRecordsCount) {
return (
Expand All @@ -64,7 +84,8 @@ const SelectAllRecordsRowComponent = ({
);
}

// Show the select all option
if (!shouldShow) return null;

return (
<Container>
<span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
export type SelectAllRecordsRowProps = {
/** Number of records selected in the current page */
shouldShow: boolean;
onSelectAllRecords: () => Promise<void>;
currentPageSelectedCount: number;
/** Size of the current page */
currentPageSize: number;
/** Total number of records across all pages */
totalRecordsCount: number;
/** Total number of selected records across all pages */
totalSelectedCount: number;
/** Callback to select all records across all pages */
onSelectAllRecords: () => Promise<void>;
};

0 comments on commit 6dd5a78

Please sign in to comment.