Commit fd13a428 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov

PagedLoader to state

implemented relevant reducer variant
parent 1fbc627b
......@@ -7,13 +7,18 @@ import Accession from 'model/Accession';
import AccessionFilter from 'model/AccessionFilter';
import {list as listAccessions, getByUuid, getByDoi, listOverview as listAccessionOverview} from 'actions/genesys/accessionService';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW} from 'constants/accessions';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS} from 'constants/accessions';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: RECEIVE_ACCESSIONS,
payload: { paged, error },
});
const appendAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: APPEND_ACCESSIONS,
payload: { paged, error },
});
const receiveAccessionOverview = (overview: any, error = null) => ({
type: RECEIVE_ACCESSION_OVERVIEW,
payload: { overview, error },
......@@ -74,7 +79,11 @@ export const loadAccessionsPage = (page: IPageRequest) => (dispatch, getState) =
const filterCode = getState().accessions.paged.filterCode;
return dispatch(listAccessions(filterCode, page))
.then((paged) => {
dispatch(receiveAccessions(paged));
if (paged.number === 0) {
dispatch(receiveAccessions(paged));
} else {
dispatch(appendAccessions(paged));
}
dispatch(updateRoute(paged));
}).catch((error) => {
console.log(`API error`, error);
......
import { list as listInstitutes, get } from 'actions/genesys/instituteService';
import {RECEIVE_INSTITUTE, RECEIVE_INSTITUTES} from 'constants/institutes';
import {APPEND_INSTITUTES, RECEIVE_INSTITUTE, RECEIVE_INSTITUTES} from 'constants/institutes';
import FaoInstitute from 'model/FaoInstitute';
import FaoInstituteFilter from 'model/FaoInstituteFilter';
......@@ -12,6 +12,11 @@ const receiveInstitutes = (paged: FilteredPage<FaoInstitute>, error = null) => (
payload: { paged, error },
});
const appendInstitutes = (paged: FilteredPage<FaoInstitute>, error = null) => ({
type: APPEND_INSTITUTES,
payload: { paged, error },
});
const receiveInstitute = (institute: FaoInstitute, error = null) => ({
type: RECEIVE_INSTITUTE,
payload: { institute, error },
......@@ -44,7 +49,11 @@ export const loadInstitutesPage = (page: IPageRequest) => (dispatch, getState) =
const filterCode = getState().institutes.paged.filterCode;
return dispatch(listInstitutes(filterCode, page))
.then((paged) => {
dispatch(receiveInstitutes(paged));
if (paged.number === 0) {
dispatch(receiveInstitutes(paged));
} else {
dispatch(appendInstitutes(paged));
}
dispatch(updateRoute(paged));
}).catch((error) => {
console.log(`API error`, error);
......
......@@ -2,7 +2,7 @@ import * as _ from 'lodash';
import {getRequest, listRequests, sendValidationEmail, recheckPid, validateRequest} from 'actions/genesys/requestService';
// constants
import {RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
import {APPEND_MATERIAL_REQUESTS, RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
// models
import MaterialRequest from 'model/MaterialRequest';
......@@ -14,6 +14,11 @@ const receiveRequests = (paged: FilteredPage<MaterialRequest>, error = null) =>
payload: { paged, error },
});
const appendRequests = (paged: FilteredPage<MaterialRequest>, error = null) => ({
type: APPEND_MATERIAL_REQUESTS,
payload: { paged, error },
});
const receiveRequest = (request: MaterialRequest, error = null) => ({
type: RECEIVE_MATERIAL_REQUEST,
payload: { request, error },
......@@ -51,7 +56,11 @@ export { listRequests as listMaterialRequestsPromise };
export const listMaterialRequests = (page: IPageRequest) => (dispatch) => {
return dispatch(listRequests(null, page))
.then((page) => {
dispatch(receiveRequests(page));
if (page.number === 0) {
dispatch(receiveRequests(page));
} else {
dispatch(appendRequests(page));
}
})
.catch((error) => {
dispatch(receiveRequests(null, error.response));
......
......@@ -7,13 +7,18 @@ import Subset from 'model/Subset';
import SubsetFilter from 'model/SubsetFilter';
import { list as listSubsets, get } from 'actions/genesys/subsetService';
import { RECEIVE_SUBSETS, RECEIVE_SUBSET } from 'constants/subsets';
import {RECEIVE_SUBSETS, RECEIVE_SUBSET, APPEND_SUBSETS} from 'constants/subsets';
const receiveSubsets = (paged: FilteredPage<Subset>, error = null) => ({
type: RECEIVE_SUBSETS,
payload: { paged, error },
});
const appendSubsets = (paged: FilteredPage<Subset>, error = null) => ({
type: APPEND_SUBSETS,
payload: { paged, error },
});
const receiveSubset = (subset: Subset, error = null) => ({
type: RECEIVE_SUBSET,
payload: { subset, error },
......@@ -45,7 +50,11 @@ export const loadSubsetsPage = (page: IPageRequest) => (dispatch, getState) => {
const filterCode = getState().subsets.paged.filterCode;
return dispatch(listSubsets(filterCode, page))
.then((paged) => {
dispatch(receiveSubsets(paged));
if (paged.number === 0) {
dispatch(receiveSubsets(paged));
} else {
dispatch(appendSubsets(paged));
}
dispatch(updateRoute(paged));
}).catch((error) => {
console.log(`API error`, error);
......
export const RECEIVE_ACCESSIONS = 'accessions/RECEIVE_ACCESSIONS';
export const APPEND_ACCESSIONS = 'accessions/APPEND_ACCESSIONS';
export const RECEIVE_ACCESSION_OVERVIEW = 'accessions/RECEIVE_ACCESSION_OVERVIEW';
export const RECEIVE_ACCESSION = 'accessions/RECEIVE_ACCESSION';
......
export const RECEIVE_INSTITUTES = 'institutes/RECEIVE_INSTITUTES';
export const APPEND_INSTITUTES = 'institutes/APPEND_INSTITUTES';
export const RECEIVE_INSTITUTE = 'institutes/RECEIVE_INSTITUTE';
export const INSTITUTE_FILTERFORM = 'Form/institutes/INSTITUTE_FILTERFORM';
export const RECEIVE_MATERIAL_REQUESTS = 'requests/RECEIVE_MATERIAL_REQUESTS';
export const APPEND_MATERIAL_REQUESTS = 'requests/APPEND_MATERIAL_REQUESTS';
export const RECEIVE_MATERIAL_REQUEST = 'requests/RECEIVE_MATERIAL_REQUEST';
export const RECEIVE_SUBSETS = 'subsets/RECEIVE_SUBSETS';
export const APPEND_SUBSETS = 'subsets/APPEND_SUBSETS';
export const RECEIVE_SUBSET = 'subsets/RECEIVE_SUBSET';
export const SUBSET_FILTERFORM = 'Form/Subset/SUBSET_FILTERFORM';
......
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW} from 'constants/accessions';
import {RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPEND_ACCESSIONS} from 'constants/accessions';
import FilteredPage from 'model/FilteredPage';
import Accession from 'model/Accession';
......@@ -25,11 +25,26 @@ function accessions(state = INITIAL_STATE, action: IReducerAction) {
switch (action.type) {
case RECEIVE_ACCESSION: {
const { accession, error } = action.payload;
return update(state, {
accession: { $set: accession },
accessionError: { $set: error },
});
const {accession, error} = action.payload;
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.uuid === accession.uuid) : -1;
if (receivedIndex !== -1) {
return update(state, {
accession: { $set: accession },
paged: {
content: {
[receivedIndex]: {$set: accession},
},
},
accessionError: {$set: error},
});
} else {
return update(state, {
accession: { $set: accession},
paged: {$set: null},
accessionError: {$set: error},
});
}
}
case RECEIVE_ACCESSIONS: {
......@@ -47,6 +62,24 @@ function accessions(state = INITIAL_STATE, action: IReducerAction) {
pagedError: { $set: error },
});
}
case APPEND_ACCESSIONS: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
},
pagedError: {$set: error},
});
}
default:
return state;
}
......
......@@ -3,7 +3,7 @@ import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import FilteredPage from 'model/FilteredPage';
import {RECEIVE_INSTITUTE, RECEIVE_INSTITUTES} from 'constants/institutes';
import {APPEND_INSTITUTES, RECEIVE_INSTITUTE, RECEIVE_INSTITUTES} from 'constants/institutes';
import FaoInstitute from 'model/FaoInstitute';
const INITIAL_STATE: {
......@@ -23,11 +23,26 @@ function institutes(state = INITIAL_STATE, action: IReducerAction) {
switch (action.type) {
case RECEIVE_INSTITUTE: {
const { institute, error } = action.payload;
const { institute, error } = action.payload;
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.code === institute.code) : -1;
if (receivedIndex !== -1) {
return update(state, {
institute: { $set: institute },
paged: {
content: {
[receivedIndex]: {$set: institute},
},
},
instituteError: {$set: error},
});
} else {
return update(state, {
institute: { $set: institute },
instituteError: { $set: error },
institute: { $set: institute},
paged: {$set: null},
instituteError: {$set: error},
});
}
}
case RECEIVE_INSTITUTES: {
......@@ -38,6 +53,23 @@ function institutes(state = INITIAL_STATE, action: IReducerAction) {
});
}
case APPEND_INSTITUTES: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
},
pagedError: {$set: error},
});
}
default:
return state;
}
......
......@@ -4,7 +4,7 @@ import { IReducerAction } from 'model/common.model';
import MaterialRequest from 'model/MaterialRequest';
import FilteredPage from 'model/FilteredPage';
import {RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
import {APPEND_MATERIAL_REQUESTS, RECEIVE_MATERIAL_REQUEST, RECEIVE_MATERIAL_REQUESTS} from 'constants/requests';
const INITIAL_STATE: {
request: Request;
......@@ -24,10 +24,25 @@ function requests(state = INITIAL_STATE, action: IReducerAction) {
case RECEIVE_MATERIAL_REQUEST: {
const { request, error } = action.payload;
return update(state, {
request: { $set: request },
requestError: { $set: error },
});
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.uuid === request.uuid) : -1;
if (receivedIndex !== -1) {
return update(state, {
request: { $set: request },
paged: {
content: {
[receivedIndex]: {$set: request},
},
},
requestError: {$set: error},
});
} else {
return update(state, {
request: { $set: request},
paged: {$set: null},
requestError: {$set: error},
});
}
}
case RECEIVE_MATERIAL_REQUESTS: {
......@@ -38,6 +53,22 @@ function requests(state = INITIAL_STATE, action: IReducerAction) {
});
}
case APPEND_MATERIAL_REQUESTS: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
},
pagedError: {$set: error},
});
}
default:
return state;
}
......
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import { RECEIVE_SUBSETS, RECEIVE_SUBSET } from 'constants/subsets';
import {RECEIVE_SUBSETS, RECEIVE_SUBSET, APPEND_SUBSETS} from 'constants/subsets';
import FilteredPage from 'model/FilteredPage';
import Subset from 'model/Subset';
......@@ -24,10 +24,25 @@ function subsets(state = INITIAL_STATE, action: IReducerAction) {
case RECEIVE_SUBSET: {
const { subset, error } = action.payload;
return update(state, {
subset: { $set: subset },
subsetError: { $set: error },
});
const receivedIndex = state.paged ? state.paged.content.findIndex((item) => item.uuid === subset.uuid) : -1;
if (receivedIndex !== -1) {
return update(state, {
subset: { $set: subset },
paged: {
content: {
[receivedIndex]: {$set: subset},
},
},
subsetError: {$set: error},
});
} else {
return update(state, {
subset: { $set: subset},
paged: {$set: null},
subsetError: {$set: error},
});
}
}
case RECEIVE_SUBSETS: {
......@@ -38,6 +53,23 @@ function subsets(state = INITIAL_STATE, action: IReducerAction) {
});
}
case APPEND_SUBSETS: {
const {paged, error} = action.payload;
return !state.paged ? update(state, {
paged: {$set: paged},
pagedError: {$set: error},
}) :
update(state, {
paged: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
},
pagedError: {$set: error},
});
}
default:
return state;
}
......
......@@ -4,6 +4,7 @@ import {log} from 'utilities/debug';
import Page from 'model/Page';
import * as VisibilitySensor from 'react-visibility-sensor';
import Loading from 'ui/common/Loading';
import {ScrollToTopOnMount} from 'ui/common/page/scrollers';
interface IProps<T> extends React.Props<any> {
paged: Page<T>;
......@@ -16,75 +17,31 @@ interface IProps<T> extends React.Props<any> {
export default class PagedLoader<T> extends React.Component<IProps<T>, any> {
public constructor(props: any) {
super(props);
const { paged: { last, number: pageNumber, content: newContent } } = this.props;
this.state = {
list: [ ...newContent ],
last,
pageNumber,
loading: false,
};
}
public componentWillMount() {
// ?
}
public componentWillReceiveProps(nextProps) {
// log('nextProps', nextProps);
const { paged: { last, number: pageNumber, content: newContent } } = nextProps;
if (newContent) {
this.setState({
...this.state,
list: [ ...newContent ],
pageNumber,
last,
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) {
log('Calling for next page', pageNumber + 1);
this.setState({
...this.state,
loading: true,
});
if (paged && paged.content && paged.totalElements > paged.content.length) {
log('Calling for next page', paged.number + 1);
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,
last: nextPage.last,
loading: false,
});
// log('State', this.state, this.state.list);
});
loadPage(paged.number + 1, paged.size);
}
}
}
public render() {
const { list, last } = this.state;
const { paged, itemRenderer, loadingIndicator, colSpan, roughItemHeight } = this.props;
if (! list || list.length === 0) {
if (! paged || ! paged.content || paged.content.length === 0) {
return null;
}
// log(`Rendering ${list.length} items`);
console.log(`Rendering ${paged.content.length} items`);
const inTable = colSpan ? true : false;
const visibilityOffset = (roughItemHeight && roughItemHeight || 50) * (paged.size * .4);
......@@ -92,18 +49,19 @@ export default class PagedLoader<T> extends React.Component<IProps<T>, any> {
// log(`Visibility offset bottom: ${-visibilityOffset}`);
const result = [
...list.map((item: T, index) => itemRenderer(item, index)),
<ScrollToTopOnMount key="PAGED_LOADER_SCROLL" />,
...paged.content.map((item: T, index) => itemRenderer(item, index)),
inTable ? (
<tr key="pagedLoaderLastItem">
<td colSpan={ colSpan }>
<VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
{ ! last ? <div>{ myLoadingIndicator }</div> : null }
{ ! paged.last ? <div>{ myLoadingIndicator }</div> : null }
</td>
</tr>
) : (
<div key="pagedLoaderLastItem">
<VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
{ ! last ? myLoadingIndicator : null }
{ ! paged.last ? myLoadingIndicator : null }
</div>
),
];
......
......@@ -9,7 +9,6 @@ interface IBrowsePageProps<T> extends React.ClassAttributes<any> {
filterCode: string;
applyFilters: any;
loadDataPage: any;
loadDataPromise: any;
updateRoute: any;
currentTab: any;
}
......@@ -36,8 +35,8 @@ class BrowsePage<T> extends React.Component<IBrowsePageProps<T>, any> {
// Wrap loadDataPromise dispatch and add current sort selection
protected loadNextPage = (page: number, pageSize: number) => {
const { paged, loadDataPromise } = this.props;
return loadDataPromise(paged.filterCode, { direction: paged.sort[0].direction, properties: [ paged.sort[0].property ], page, size: pageSize });
const { paged, loadDataPage } = this.props;
return loadDataPage({ direction: paged.sort[0].direction, properties: [ paged.sort[0].property ], page, size: pageSize });
}
/// Wrap applyFilters dispatch and fills the current sort selection
......
......@@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux';
import { parse } from 'query-string';
// Actions
import { applyFilters, loadAccessionsPage, listAccessionsPromise, updateRoute } from 'actions/accessions';
import { applyFilters, loadAccessionsPage, updateRoute } from 'actions/accessions';
// Models
import Accession from 'model/Accession';
......@@ -103,7 +103,6 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
applyFilters,
loadDataPage: loadAccessionsPage,
loadDataPromise: listAccessionsPromise,
updateRoute,
}, dispatch);
......
......@@ -4,7 +4,6 @@ import {bindActionCreators} from 'redux';
// Actions
import {listMaterialRequests} from 'actions/requests';
import {listRequests} from 'actions/genesys/requestService';
// Models
import MaterialRequest from 'model/MaterialRequest';
......@@ -57,7 +56,6 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
loadDataPage: listMaterialRequests,
loadDataPromise: listRequests,
}, dispatch);
......
......@@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux';
import { parse } from 'query-string';
// Actions
import { applyFilters, loadInstitutesPage, listInstitutesPromise, updateRoute } from 'actions/institutes';
import {applyFilters, loadInstitutesPage, updateRoute} from 'actions/institutes';
// Models
import FaoInstitute from 'model/FaoInstitute';
......@@ -86,7 +86,6 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
applyFilters,
loadDataPage: loadInstitutesPage,
loadDataPromise: listInstitutesPromise,
updateRoute,
}, dispatch);
......
......@@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux';
import { parse } from 'query-string';
// Actions
import { applyFilters, loadSubsetsPage, listSubsetsPromise, updateRoute } from 'actions/subsets';
import { applyFilters, loadSubsetsPage, updateRoute } from 'actions/subsets';
// Models
import Subset from 'model/Subset';
......@@ -87,7 +87,6 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
applyFilters,
loadDataPage: loadSubsetsPage,
loadDataPromise: listSubsetsPromise,
updateRoute,
}, dispatch);
......