PaginationTable.tsx 4.58 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import * as React from 'react';
import { DetailsList, Dropdown, Icon, IDetailsListProps, IDropdownOption, IStackTokens, Stack } from '@fluentui/react';
import ReactPaginate from 'react-paginate';

interface PaginationTableState {
    itemsPerPage: number;
    currentPage: number;
    itemsOnPage: any[]; // this needs to be stored in state to prevent re-rendering
}

const horizontalGapStackTokens: IStackTokens = {
    childrenGap: 20,
    padding: 10
};

function _currentTableOffset(perPage: number, currentPage: number, source: any[]): number {
    return perPage === -1 ? 0 : Math.min(currentPage, Math.floor((source.length - 1) / perPage)) * perPage;
}

function _obtainPaginationSlice(perPage: number, currentPage: number, source: any[]): any[] {
    if (perPage === -1) {
        return source;
    } else {
        const offset = _currentTableOffset(perPage, currentPage, source);
        return source.slice(offset, offset + perPage);
    }
}

class PaginationTable extends React.PureComponent<IDetailsListProps, PaginationTableState> {
    constructor(props: IDetailsListProps) {
        super(props);
        this.state = {
            itemsPerPage: 20,
            currentPage: 0,
            itemsOnPage: []
        };
    }

    private _onItemsPerPageSelect(event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void {
        if (item !== undefined) {
            const { items } = this.props;
            // use current offset to calculate the next `current_page`
            const currentOffset = _currentTableOffset(this.state.itemsPerPage, this.state.currentPage, items);
            const itemsPerPage = item.key as number;
            const currentPage = Math.floor(currentOffset / itemsPerPage);
            this.setState({
                itemsPerPage: itemsPerPage,
                currentPage: currentPage,
                itemsOnPage: _obtainPaginationSlice(itemsPerPage, currentPage, this.props.items)
            });
        }
    }

    private _onPageSelect(event: any): void {
        const currentPage = event.selected;
        this.setState({
            currentPage: currentPage,
            itemsOnPage: _obtainPaginationSlice(this.state.itemsPerPage, currentPage, this.props.items)
        });
    }

    componentDidUpdate(prevProps: IDetailsListProps): void {
        if (prevProps.items !== this.props.items) {
            this.setState({
                itemsOnPage: _obtainPaginationSlice(this.state.itemsPerPage, this.state.currentPage, this.props.items)
            });
        }
    }

    render(): React.ReactNode {
        const { itemsPerPage, itemsOnPage } = this.state;
        const detailListProps = {
            ...this.props,
            items: itemsOnPage
        };
        const itemsCount = this.props.items.length;
        const pageCount = itemsPerPage === -1 ? 1 : Math.ceil(itemsCount / itemsPerPage);
        const perPageOptions = [
            { key: 10, text: '10 items per page' },
            { key: 20, text: '20 items per page' },
            { key: 50, text: '50 items per page' },
            { key: -1, text: 'All items' }
        ];
        return (
            <div>
                <DetailsList {...detailListProps} />
                <Stack
                    horizontal
                    horizontalAlign='end'
                    verticalAlign='baseline'
                    styles={{ root: { padding: 10 } }}
                    tokens={horizontalGapStackTokens}
                >
                    <Dropdown
                        selectedKey={itemsPerPage}
                        options={perPageOptions}
                        onChange={this._onItemsPerPageSelect.bind(this)}
                        styles={{ dropdown: { width: 150 } }}
                    />
                    <ReactPaginate
                        previousLabel={<Icon aria-hidden={true} iconName='ChevronLeft' />}
                        nextLabel={<Icon aria-hidden={true} iconName='ChevronRight' />}
                        breakLabel={'...'}
                        breakClassName={'break'}
                        pageCount={pageCount}
                        marginPagesDisplayed={2}
                        pageRangeDisplayed={2}
                        onPageChange={this._onPageSelect.bind(this)}
                        containerClassName={itemsCount === 0 ? 'pagination hidden' : 'pagination'}
                        subContainerClassName={'pages pagination'}
                        disableInitialCallback={false}
                        activeClassName={'active'}
                    />
                </Stack>
            </div>
        );
    }
}

export default PaginationTable;