PagedLoader.tsx 3.33 KB
Newer Older
1
2
3
4
5
import * as React from 'react';
import {log} from 'utilities/debug';

import { Page } from 'model/common.model';
import * as VisibilitySensor from 'react-visibility-sensor';
Matija Obreza's avatar
Matija Obreza committed
6
import Loading from 'ui/common/Loading';
7
8
9
10

interface IProps<T> extends React.Props<any> {
  paged: Page<T>;
  colSpan?: number; // if in table, set the colSpan to render <tr><td colSpan=...
Matija Obreza's avatar
Matija Obreza committed
11
  roughItemHeight?: number; // px of height of element, defaults to 50px, determines when loadNextPage is called
12
  itemRenderer: (item: T, index?: number) => any;
Matija Obreza's avatar
Matija Obreza committed
13
  loadingIndicator?: any;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  loadPage: (page: number, pageSize: number) => Promise<Page<T>>;
}

export default class PagedLoader<T> extends React.Component<IProps<T>, any> {

  public constructor(props: any) {
      super(props);
      const { paged: { number: pageNumber, content: newContent } } = this.props;
      this.state = {
        list: [ ...newContent ],
        pageNumber,
        loading: false,
      };
  }

  public componentWillMount() {
    // ?
  }

  public componentWillReceiveProps(nextProps) {
Matija Obreza's avatar
Cleanup    
Matija Obreza committed
34
    // log('nextProps', nextProps);
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    const { paged: { number: pageNumber, content: newContent } } = nextProps;

    if (newContent) {
      this.setState({
        ...this.state,
        list: [ ...newContent ],
        pageNumber,
        loading: false,
      });
    }
  }

  private endOfListVisibilityChange = (isVisible: boolean): void => {
    const { paged, loadPage } = this.props;
    const { list, pageNumber, loading } = this.state;
    // log(`Visibility ${isVisible}`);

    if (paged && isVisible) {
      // we should load some stuff
      if (! loading && paged.totalElements > list.length) {
Matija Obreza's avatar
Matija Obreza committed
55
        log('Calling for next page', pageNumber + 1);
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

        this.setState({
          ...this.state,
          loading: true,
        });

        loadPage(pageNumber + 1, paged.size)
          .then((nextPage) => {
            log('Received next page', nextPage);
            this.setState({
              ...this.state,
              list: [ ...this.state.list, ...nextPage.content ],
              pageNumber: nextPage.number,
              loading: false,
            });
            // log('State', this.state, this.state.list);
          });
      }
    }
  }

  public render() {
    const { list, loading } = this.state;
Matija Obreza's avatar
Matija Obreza committed
79
    const { itemRenderer, loadingIndicator, colSpan, roughItemHeight } = this.props;
80
81
82
83

    if (! list || list.length === 0) {
      return null;
    }
Matija Obreza's avatar
Cleanup    
Matija Obreza committed
84
    // log(`Rendering ${list.length} items`);
85
86

    const inTable = colSpan ? true : false;
Matija Obreza's avatar
Matija Obreza committed
87
88
    const visibilityOffset = (roughItemHeight && roughItemHeight || 50) * 10;
    const myLoadingIndicator = loadingIndicator || <Loading />;
Matija Obreza's avatar
Cleanup    
Matija Obreza committed
89
    // log(`Visibility offset bottom: ${-visibilityOffset}`);
90
91
92
93
94
95

    const result = [
      ...list.map((item: T, index) => itemRenderer(item, index)),
      inTable ? (
        <tr key="pagedLoaderLastItem"><td colSpan={ colSpan }>
          <VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
Matija Obreza's avatar
Matija Obreza committed
96
          { loading ? <div>{ myLoadingIndicator }</div> : null }
97
98
99
        </td></tr>
        ) : (
        <div key="pagedLoaderLastItem">
Matija Obreza's avatar
Matija Obreza committed
100
101
          <VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
          { loading ? myLoadingIndicator : null }
102
103
104
        </div>
        ),
    ];
Matija Obreza's avatar
Cleanup    
Matija Obreza committed
105
    // log('Done rendering');
106
107
108
    return result;
  }
}