1 |
|
2 |
|
3 |
|
4 | type Settings = {
|
5 | key: string;
|
6 | rowsPerLoad: number;
|
7 | manipulateItems: (items: any) => void;
|
8 | resetView: (data : any) => void;
|
9 | changeView: (data: any) => void;
|
10 | requestPage: (page: string, token : string) => any;
|
11 | }
|
12 |
|
13 | type OwnProps = {
|
14 | token: string;
|
15 | settings: Settings;
|
16 | };
|
17 |
|
18 | type LoadPaginatorPropTypes = {
|
19 | token: string;
|
20 | children: any;
|
21 | settings: Settings;
|
22 | paginator: any;
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | changeView: (info : { token: string, view: number }) => void;
|
34 | resetView: (token : string) => void;
|
35 |
|
36 | loadData: (page : number) => void;
|
37 | changeFilter: (filter : string) => (event : { target : { value : string } }) => void;
|
38 | };
|
39 |
|
40 | import React, { Component } from "react";
|
41 | import * as Immutable from "immutable";
|
42 | import { connect } from "react-redux";
|
43 | import { bindActionCreators } from "redux";
|
44 |
|
45 | import selectors from "./selectors";
|
46 |
|
47 | import LoadingButton from "./LoadingButton";
|
48 |
|
49 | import { LargeErrorMessage, LoadingMessage } from "x25/Messages";
|
50 |
|
51 | const mapStateToProps = (state, { token, settings } : OwnProps) => {
|
52 |
|
53 | const { list, entities } = selectors.getPaginators(state, settings.key);
|
54 |
|
55 | const
|
56 | currentPage = selectors.getCurrentView(list, token),
|
57 | isFetching = selectors.isPageFetching(list, token, currentPage),
|
58 | isFetched = selectors.isPageFetched(list, token, currentPage),
|
59 | isNextFetching = selectors.isPageFetching(list, token, currentPage + 1),
|
60 | isNextFetched = selectors.isPageFetched(list, token, currentPage + 1),
|
61 | resultsUpTo = (
|
62 | selectors.getResultsUpToPage(list, token, entities, currentPage, settings.rowsPerLoad)
|
63 | ),
|
64 | items = settings.manipulateItems(resultsUpTo),
|
65 | total = selectors.getCurrentTotalResultsCount(list, token),
|
66 | hasProblems = selectors.hasPageProblems(list, token, currentPage);
|
67 |
|
68 | const shouldLoadNext = !isNextFetched && !isNextFetching;
|
69 |
|
70 | return {
|
71 | paginator: Immutable.Map({
|
72 | currentPage,
|
73 | hasProblems,
|
74 | isFetched,
|
75 | isFetching,
|
76 | items,
|
77 | shouldLoadNext,
|
78 | total,
|
79 | }),
|
80 | };
|
81 | },
|
82 | mapDispatchToProps = (dispatch, { token, settings } : OwnProps) => ({
|
83 | ...bindActionCreators({
|
84 | resetView : settings.resetView,
|
85 | changeView : settings.changeView,
|
86 | }, dispatch),
|
87 | loadData (page) {
|
88 | dispatch(settings.requestPage(page, token));
|
89 | },
|
90 | });
|
91 |
|
92 | class LoadPaginator extends Component<LoadPaginatorPropTypes> {
|
93 |
|
94 | handleLoadMoreClick: () => void;
|
95 |
|
96 | constructor (props : LoadPaginatorPropTypes) {
|
97 | super(props);
|
98 |
|
99 | this.handleLoadMoreClick = () => {
|
100 | const { paginator, token, changeView, loadData } = this.props;
|
101 |
|
102 | const
|
103 | currentPage = paginator.get("currentPage"),
|
104 | hasProblems = paginator.get("hasProblems"),
|
105 | shouldLoadNext = paginator.get("shouldLoadNext");
|
106 |
|
107 | if (hasProblems) {
|
108 | loadData(currentPage);
|
109 | } else {
|
110 | changeView({
|
111 | token,
|
112 | view: currentPage + 1,
|
113 | });
|
114 |
|
115 | if (shouldLoadNext) {
|
116 | loadData(currentPage + 1);
|
117 | }
|
118 | }
|
119 | };
|
120 | }
|
121 |
|
122 | UNSAFE_componentWillMount () {
|
123 | const { paginator, loadData } = this.props;
|
124 |
|
125 | const
|
126 | isFetched = paginator.get("isFetched"),
|
127 | isFetching = paginator.get("isFetching"),
|
128 | currentPage = paginator.get("currentPage");
|
129 |
|
130 | const shouldFetch = !isFetched && !isFetching;
|
131 |
|
132 | if (shouldFetch) {
|
133 | loadData(currentPage);
|
134 | }
|
135 | }
|
136 |
|
137 | UNSAFE_componentWillReceiveProps (nextProps) {
|
138 | const { loadData, paginator } = nextProps;
|
139 |
|
140 | const
|
141 | isFetched = paginator.get("isFetched"),
|
142 | isFetching = paginator.get("isFetching"),
|
143 | currentPage = paginator.get("currentPage");
|
144 |
|
145 | const shouldFetch = !isFetched && !isFetching;
|
146 |
|
147 | if (shouldFetch) {
|
148 | loadData(currentPage);
|
149 | }
|
150 | }
|
151 |
|
152 | shouldComponentUpdate (nextProps : LoadPaginatorPropTypes) {
|
153 | return (
|
154 | this.props.paginator !== nextProps.paginator
|
155 | );
|
156 | }
|
157 |
|
158 | componentWillUnmount () {
|
159 | this.props.resetView(this.props.token);
|
160 | }
|
161 |
|
162 | render () {
|
163 | const { paginator } = this.props;
|
164 |
|
165 | const
|
166 | items = paginator.get("items"),
|
167 | hasProblems = paginator.get("hasProblems"),
|
168 | currentPage = paginator.get("currentPage"),
|
169 | isFetching = paginator.get("isFetching"),
|
170 | total = paginator.get("total");
|
171 |
|
172 | const
|
173 | isEmpty = items.size === 0,
|
174 | showLoading = total !== items.size;
|
175 |
|
176 | if (isEmpty && isFetching) {
|
177 | return (
|
178 | <LoadingMessage message="Preiau datele..." />
|
179 | );
|
180 | }
|
181 |
|
182 | if (hasProblems && currentPage === 1) {
|
183 | return (
|
184 | <LargeErrorMessage
|
185 | message="Nu pot prelua datele"
|
186 | onRetry={this.handleLoadMoreClick}
|
187 | />
|
188 | );
|
189 | }
|
190 |
|
191 | return (
|
192 | <React.Fragment>
|
193 | {React.cloneElement(this.props.children, this.props)}
|
194 | {
|
195 | showLoading ? (
|
196 | <LoadingButton
|
197 | hasProblems={hasProblems}
|
198 | isFetching={isFetching}
|
199 | onLoadMoreClick={this.handleLoadMoreClick}
|
200 | />
|
201 | ) : null
|
202 | }
|
203 | </React.Fragment>
|
204 | );
|
205 | }
|
206 | }
|
207 |
|
208 | export default connect(mapStateToProps, mapDispatchToProps)(LoadPaginator);
|