Skip to content

Commit

Permalink
Create UniversalTable and PaginatedQueryUniversalTable components
Browse files Browse the repository at this point in the history
Also update few `angle-*` icons
  • Loading branch information
magicznyleszek committed Sep 13, 2024
1 parent 56df467 commit 2c945a0
Show file tree
Hide file tree
Showing 11 changed files with 687 additions and 4 deletions.
78 changes: 78 additions & 0 deletions jsapp/js/universalTable/paginatedQueryUniversalTable.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Libraries
import React, {useState, useMemo} from 'react';

// Partial components
import UniversalTable from './universalTable.component';

// Types
import type {UseQueryResult} from '@tanstack/react-query';
import type {PaginatedResponse} from 'js/dataInterface';
import type {UniversalTableColumn} from './universalTable.component';

interface PaginatedQueryHook<DataItem> extends Function {
(limit: number, offset: number): UseQueryResult<PaginatedResponse<DataItem>>;
}

interface PaginatedQueryUniversalTableProps<DataItem> {
queryHook: PaginatedQueryHook<DataItem>;
// Below are props from `UniversalTable` that should come from the parent
// component (these are kind of "configuration" props). The other
// `UniversalTable` props are being handled here internally.
columns: UniversalTableColumn[];
}

const PAGE_SIZES = [10, 30, 50, 100];
const DEFAULT_PAGE_SIZE = PAGE_SIZES[0];

/**
* This is a wrapper component for `UniversalTable`. It should be used in
* situations when you use `react-query` to fetch data, and the data is
* paginated. This component handles pagination in a neat, DRY way.
*
* All the rest of the functionalities are the same as `UniversalTable`.
*/
export default function PaginatedQueryUniversalTable<DataItem>(
props: PaginatedQueryUniversalTableProps<DataItem>
) {
const [pagination, setPagination] = useState({
limit: DEFAULT_PAGE_SIZE,
offset: 0,
});

const paginatedQuery = props.queryHook(pagination.limit, pagination.offset);

const availablePages = useMemo(
() => Math.ceil((paginatedQuery.data?.count ?? 0) / pagination.limit),
[paginatedQuery.data, pagination]
);

const currentPageIndex = useMemo(
() => Math.ceil(pagination.offset / pagination.limit),
[pagination]
);

const data = paginatedQuery.data?.results || [];

return (
<UniversalTable<DataItem>
columns={props.columns}
data={data}
pageIndex={currentPageIndex}
pageCount={availablePages}
pageSize={pagination.limit}
pageSizes={PAGE_SIZES}
onRequestPaginationChange={(newPageInfo, oldPageInfo) => {
// Calculate new offset and limit from what we've got
let newOffset = newPageInfo.pageIndex * newPageInfo.pageSize;
const newLimit = newPageInfo.pageSize;

// If we change page size, we switch back to first page
if (newPageInfo.pageSize !== oldPageInfo.pageSize) {
newOffset = 0;
}

setPagination({limit: newLimit, offset: newOffset});
}}
/>
);
}
Loading

0 comments on commit 2c945a0

Please sign in to comment.