[feature] Better loading indicator

- Use react-topbar-progress-indicator as a global loading indicator.
- Added a global reducer that only holds `isFetching` for now.
- Display loading indicator on any `*_REQUEST` actions.
- Closes #103
This commit is contained in:
Andrey Okonetchnikov 2016-10-20 18:16:46 +02:00
parent f7b74453ab
commit 188fec4529
5 changed files with 46 additions and 4 deletions

View File

@ -122,10 +122,11 @@
"react-router-redux": "^4.0.5", "react-router-redux": "^4.0.5",
"react-simple-dnd": "^0.1.2", "react-simple-dnd": "^0.1.2",
"react-toolbox": "^1.2.1", "react-toolbox": "^1.2.1",
"react-topbar-progress-indicator": "^1.0.0",
"react-waypoint": "^3.1.3", "react-waypoint": "^3.1.3",
"redux": "^3.3.1", "redux": "^3.3.1",
"redux-optimist": "^0.0.2",
"redux-notifications": "^2.1.1", "redux-notifications": "^2.1.1",
"redux-optimist": "^0.0.2",
"redux-thunk": "^1.0.3", "redux-thunk": "^1.0.3",
"selection-position": "^1.0.0", "selection-position": "^1.0.0",
"semaphore": "^1.0.5", "semaphore": "^1.0.5",

View File

@ -6,6 +6,7 @@ import { Layout, Panel, NavDrawer } from 'react-toolbox/lib/layout';
import { Navigation } from 'react-toolbox/lib/navigation'; import { Navigation } from 'react-toolbox/lib/navigation';
import { Link } from 'react-toolbox/lib/link'; import { Link } from 'react-toolbox/lib/link';
import { Notifs } from 'redux-notifications'; import { Notifs } from 'redux-notifications';
import TopBarProgress from 'react-topbar-progress-indicator';
import { loadConfig } from '../actions/config'; import { loadConfig } from '../actions/config';
import { loginUser } from '../actions/auth'; import { loginUser } from '../actions/auth';
import { currentBackend } from '../backends/backend'; import { currentBackend } from '../backends/backend';
@ -21,6 +22,14 @@ import AppHeader from '../components/AppHeader/AppHeader';
import { Loader, Toast } from '../components/UI/index'; import { Loader, Toast } from '../components/UI/index';
import styles from './App.css'; import styles from './App.css';
TopBarProgress.config({
barColors: {
0: '#3ab7a5',
'1.0': '#3ab7a5',
},
shadowBlur: 5,
});
class App extends React.Component { class App extends React.Component {
static propTypes = { static propTypes = {
@ -33,6 +42,7 @@ class App extends React.Component {
navigateToCollection: PropTypes.func.isRequired, navigateToCollection: PropTypes.func.isRequired,
user: ImmutablePropTypes.map, user: ImmutablePropTypes.map,
runCommand: PropTypes.func.isRequired, runCommand: PropTypes.func.isRequired,
isFetching: PropTypes.bool.isRequired,
}; };
static configError(config) { static configError(config) {
@ -126,6 +136,7 @@ class App extends React.Component {
runCommand, runCommand,
navigateToCollection, navigateToCollection,
createNewEntryInCollection, createNewEntryInCollection,
isFetching,
} = this.props; } = this.props;
if (config === null) { if (config === null) {
@ -184,6 +195,7 @@ class App extends React.Component {
toggleNavDrawer={this.toggleNavDrawer} toggleNavDrawer={this.toggleNavDrawer}
/> />
<Panel scrollY> <Panel scrollY>
{ isFetching && <TopBarProgress /> }
<div className={styles.main}> <div className={styles.main}>
{children} {children}
</div> </div>
@ -194,10 +206,10 @@ class App extends React.Component {
} }
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, config, collections } = state; const { auth, config, collections, global } = state;
const user = auth && auth.get('user'); const user = auth && auth.get('user');
const { isFetching } = global;
return { auth, config, collections, user }; return { auth, config, collections, user, isFetching };
} }
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {

17
src/reducers/global.js Normal file
View File

@ -0,0 +1,17 @@
/* Reducer for some global UI state that we want to share between components
* Now being used for isFetching state to display global loading indicator
* */
const globalReducer = (state = { isFetching: false }, action) => {
if ((action.type.indexOf('REQUEST') > -1)) {
return { isFetching: true };
} else if (
(action.type.indexOf('SUCCESS') > -1) ||
(action.type.indexOf('FAILURE') > -1)
) {
return { isFetching: false };
}
return state;
};
export default globalReducer;

View File

@ -7,6 +7,7 @@ import editorialWorkflow, * as fromEditorialWorkflow from './editorialWorkflow';
import entryDraft from './entryDraft'; import entryDraft from './entryDraft';
import collections from './collections'; import collections from './collections';
import medias, * as fromMedias from './medias'; import medias, * as fromMedias from './medias';
import global from './global';
const reducers = { const reducers = {
auth, auth,
@ -18,6 +19,7 @@ const reducers = {
editorialWorkflow, editorialWorkflow,
entryDraft, entryDraft,
medias, medias,
global,
}; };
export default reducers; export default reducers;

View File

@ -6811,6 +6811,12 @@ react-toolbox@^1.2.1:
normalize.css "~5.0.0" normalize.css "~5.0.0"
react-css-themr "~1.4.1" react-css-themr "~1.4.1"
react-topbar-progress-indicator:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-topbar-progress-indicator/-/react-topbar-progress-indicator-1.0.0.tgz#3379ab2cb840c1bc1bc22fb5fc871688b9104dd4"
dependencies:
topbar "^0.1.3"
react-waypoint@^3.1.3: react-waypoint@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/react-waypoint/-/react-waypoint-3.1.3.tgz#1101fb8a27556a199150c7bfd34428606b5fc7e4" resolved "https://registry.yarnpkg.com/react-waypoint/-/react-waypoint-3.1.3.tgz#1101fb8a27556a199150c7bfd34428606b5fc7e4"
@ -8043,6 +8049,10 @@ to-fast-properties@^1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
topbar@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/topbar/-/topbar-0.1.3.tgz#c9ef8776dc4469f7840e6416f4136ddeccf4b7c6"
tough-cookie@^2.3.1, tough-cookie@~2.3.0: tough-cookie@^2.3.1, tough-cookie@~2.3.0:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.1.tgz#99c77dfbb7d804249e8a299d4cb0fd81fef083fd" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.1.tgz#99c77dfbb7d804249e8a299d4cb0fd81fef083fd"