Skip to content

Commit

Permalink
GKN-230: Refactor loading indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
levenkov committed Jul 23, 2020
1 parent 0f05c0d commit 6159ada
Show file tree
Hide file tree
Showing 20 changed files with 1,875 additions and 143 deletions.
2 changes: 0 additions & 2 deletions src/v1/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as R from 'ramda';
import * as acts from './Constants/Actions';
import routeMarkColorsStoreReducer from './stores/route_mark_colors/reducers';
import usersStoreReducer from './stores/users/reducers';
import routesStoreReducer from './stores/routes/reducers';
import sectorsStoreReducer from './stores/sectors/reducers';
import spotsStoreReducer from './stores/spots/reducers';
import newsStoreReducer from './stores/news/reducers';
Expand Down Expand Up @@ -73,7 +72,6 @@ export default combineReducers({
usersStore: usersStoreReducer,
spotsStore: spotsStoreReducer,
sectorsStore: sectorsStoreReducer,
routesStore: routesStoreReducer,
newsStore: newsStoreReducer,
usersStoreV2: usersReducerV2,
userSessionV2: userSessionReducerV2,
Expand Down
10 changes: 3 additions & 7 deletions src/v1/store.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createStore, applyMiddleware } from 'redux';
import * as R from 'ramda';
import thunk from 'redux-thunk';
import localForage from 'localforage';
import rootReducer from './reducers';
Expand Down Expand Up @@ -52,9 +51,9 @@ const getDataFromLocalForagePromise = () => (
state.routeMarkColorsStore = ROUTE_MARK_COLORS_DEFAULT_STORE_FORMAT;
state.routeMarkColorsStore.routeMarkColors = data.routeMarkColors;

state.routesStore = ROUTES_DEFAULT_STORE_FORMAT;
state.routesStore.routes = data.routes;
state.routesStore.filtrationResults = data.filtrationResults;
state.routesStoreV2 = ROUTES_DEFAULT_STORE_FORMAT;
state.routesStoreV2.routes = data.routes;
state.routesStoreV2.filtrationResults = data.filtrationResults;

state.spotsStore = SPOTS_DEFAULT_STORE_FORMAT;
state.spotsStore.spots = data.spots;
Expand Down Expand Up @@ -92,6 +91,3 @@ export const configureStoreAsync = () => (
}
})
);


export default configureStoreAsync;
4 changes: 3 additions & 1 deletion src/v1/utils/reloadSector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApiUrl } from '../Environ';
import { loadSector } from '../stores/sectors/utils';
import { NUM_OF_DAYS } from '../Constants/Route';

export const reloadSector = sectorId => (
const reloadSector = sectorId => (
(dispatch, getState) => {
const state = getState();
const user = state.usersStore.users[state.usersStore.currentUserId];
Expand All @@ -15,3 +15,5 @@ export const reloadSector = sectorId => (
dispatch(loadSector(`${ApiUrl}/v1/sectors/${sectorId}`, params));
}
);

export default reloadSector;
225 changes: 225 additions & 0 deletions src/v2/components/Content/Content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import * as R from 'ramda';
import Dropzone from 'react-dropzone';
import Axios from 'axios';
import RouteCardView from '@/v2/components/RouteCardView/RouteCardView';
import FilterBlock from '@/v1/components/FilterBlock/FilterBlock';
import Pagination from '@/v1/components/Pagination/Pagination';
import SectorContext from '@/v1/contexts/SectorContext';
import getNumOfPages from '@/v2/utils/getNumOfPages';
import { StyleSheet, css } from '../../aphrodite';
import {
setSelectedPage,
} from '@/v1/actions';
import getViewMode from '@/v1/utils/getViewMode';
import getPage from '@/v1/utils/getPage';
import { ApiUrl } from '@/v1/Environ';
import { default as reloadRoutesAction } from '@/v2/utils/reloadRoutes';

const NUM_OF_DISPLAYED_PAGES = 5;

class Content extends Component {
componentDidMount() {
this.props.reloadRoutes(this.getSpotId(), this.getSectorId());
}

componentDidUpdate(prevProps) {
if (this.needReload(prevProps)) {
this.props.reloadRoutes(this.getSpotId(), this.getSectorId());
}
}

needReload = (prevProps) => {
for (const k of ['selectedFilters', 'selectedViewModes', 'selectedPages']) {
if (!R.equals(this.props[k], prevProps[k])) {
return true;
}
}

if (!R.equals(this.props.match.url, prevProps.match.url)) {
return true;
}

return false;
};

getSpotId = () => {
const { match } = this.props;
return parseInt(match.params.id, 10);
};

getSectorId = () => {
const { match } = this.props;
return match.params.sector_id ? parseInt(match.params.sector_id, 10) : 0;
};

onRouteClick = (id) => {
const { history, match } = this.props;
history.push(`${match.url}/routes/${id}`);
};

changePage = (page) => {
const {
setSelectedPage: setSelectedPageProp,
} = this.props;
const spotId = this.getSpotId();
const sectorId = this.getSectorId();
setSelectedPageProp(spotId, sectorId, page);
};

pagesList = () => {
const { numOfPages, page } = this.props;
if (NUM_OF_DISPLAYED_PAGES >= numOfPages) {
return R.range(1, numOfPages + 1);
}
const firstPage = page - Math.floor(NUM_OF_DISPLAYED_PAGES / 2);
const lastPage = firstPage + NUM_OF_DISPLAYED_PAGES;
if (firstPage >= 1 && lastPage <= numOfPages) {
return R.range(firstPage, lastPage);
}
if (firstPage >= 1) {
return R.range(numOfPages - NUM_OF_DISPLAYED_PAGES + 1, numOfPages + 1);
}
return R.range(1, NUM_OF_DISPLAYED_PAGES + 1);
};

addRoute = () => { this.props.history.push(`${this.props.match.url}/routes/new`); };

onDropFiles = (acceptedFiles) => {
const data = new FormData();
data.append('route_photo[photo]', acceptedFiles[0]);
data.append('route_photo[sector_id]', this.getSectorId());

Axios({
url: `${ApiUrl}/v1/route_photos`,
method: 'post',
data,
config: { headers: { 'Content-Type': 'multipart/form-data' }, withCredentials: true },
})
.then(() => {
if (acceptedFiles.length > 1) {
this.onDropFiles(R.slice(1, Infinity, acceptedFiles));
}
}).catch((error) => {
console.log(error);
});
};

render() {
const {
numOfPages,
sectors,
selectedViewModes,
selectedPages,
} = this.props;
const page = getPage(selectedPages, this.getSpotId(), this.getSectorId());
const viewMode = getViewMode(
sectors,
selectedViewModes,
this.getSpotId(),
this.getSectorId(),
);
return (
<SectorContext.Consumer>
{
({ sector }) => {
const diagram = sector && sector.diagram && sector.diagram.url;
return (
<div className={css(styles.content)}>
<Dropzone onDrop={this.onDropFiles}>
{
({ getRootProps, getInputProps }) => (
<div
className={css(styles.contentContainer)}
{...getRootProps()}
onClick={event => event.stopPropagation()}
>
<input {...getInputProps()} />
<FilterBlock
viewMode={viewMode}
viewModeData={
sector
? {
scheme: {
title: diagram ? undefined : 'Схема зала ещё не загружена',
disabled: diagram === null,
},
table: {},
list: {},
}
: {
table: {},
list: {},
}
}
/>
<RouteCardView
viewMode={viewMode}
addRoute={this.addRoute}
diagram={diagram}
onRouteClick={this.onRouteClick}
/>
{
viewMode !== 'scheme' && (
<Pagination
onPageChange={this.changePage}
page={page}
pagesList={this.pagesList()}
firstPage={1}
lastPage={numOfPages}
/>
)
}
</div>
)
}
</Dropzone>
</div>
);
}
}
</SectorContext.Consumer>
);
}
}

const styles = StyleSheet.create({
content: {
paddingTop: '105px',
paddingBottom: '105px',
'@media screen and (max-width: 1440px)': {
paddingTop: '65px',
paddingBottom: '65px',
},
},
contentContainer: {
outline: '0',
maxWidth: '1600px',
paddingLeft: '30px',
paddingRight: '30px',
marginRight: 'auto',
marginLeft: 'auto',
},
});

Content.propTypes = {
diagram: PropTypes.string,
numOfPages: PropTypes.number.isRequired,
};

const mapStateToProps = state => ({
numOfPages: getNumOfPages(state),
selectedViewModes: state.selectedViewModes,
selectedPages: state.selectedPages,
selectedFilters: state.selectedFilters,
});

const mapDispatchToProps = dispatch => ({
reloadRoutes: (spotId, sectorId) => dispatch(reloadRoutesAction(spotId, sectorId)),
setSelectedPage: (spotId, sectorId, page) => dispatch(setSelectedPage(spotId, sectorId, page)),
});

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Content));
19 changes: 14 additions & 5 deletions src/v2/components/LoadingIndicator/LoadingIndicator.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import * as R from 'ramda';
import { StyleSheet, css } from '../../aphrodite';


Expand All @@ -8,21 +9,29 @@ class LoadingIndicator extends React.PureComponent {
super(props);

this.state = {
counter: 0,
lastHandler: 0,
handlers: [],
};
}

startLoading = () => {
this.setState({ counter: this.state.counter + 1 });
const newHandler = this.state.lastHandler + 1;

this.setState({
lastHandler: newHandler,
handlers: [...this.state.handlers, newHandler],
});

return newHandler;
};

stopLoading = () => {
this.setState({ counter: this.state.counter - 1 });
stopLoading = (handler) => {
this.setState({ handlers: R.filter(e => e !== handler)(this.state.handlers) });
};

render() {
const { children, showAlways, isSticky } = this.props;
const isLoading = this.state.counter > 0;
const isLoading = this.state.handlers.length > 0;

return (
<div className={css(style.container)} ref={() => { window.loadingIndicator = this; }}>
Expand Down
9 changes: 1 addition & 8 deletions src/v2/components/MainNav/MainNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class MainNav extends Component {
const {
changeTab: changeTabProp,
tab,
signUp,
openProfile,
history,
} = this.props;

Expand Down Expand Up @@ -130,10 +128,7 @@ class MainNav extends Component {
</nav>
</div>
</div>
<UserIcon
signUp={signUp}
openProfile={openProfile}
/>
<UserIcon />
</div>
</div>
);
Expand All @@ -143,8 +138,6 @@ class MainNav extends Component {
MainNav.propTypes = {
changeTab: PropTypes.func,
tab: PropTypes.number,
signUp: PropTypes.func.isRequired,
openProfile: PropTypes.func.isRequired,
};

MainNav.defaultProps = {
Expand Down
Loading

0 comments on commit 6159ada

Please sign in to comment.