ソースを参照

Added loading indicator for CRUD document lists

Fela Maslen 7 年 前
コミット
d7096c9e94

+ 18 - 0
src/components/LoadingIndicator/index.js

@@ -0,0 +1,18 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+
+import './style.scss';
+
+export default function LoadingIndicator({ loading }) {
+    return (
+        <span className={classNames('loading-indicator', { loading })}>
+            {'Loading...'}
+        </span>
+    );
+}
+
+LoadingIndicator.propTypes = {
+    loading: PropTypes.bool.isRequired
+};
+

+ 8 - 0
src/components/LoadingIndicator/style.scss

@@ -0,0 +1,8 @@
+.loading-indicator {
+    display: none;
+
+    &.loading {
+        display: block;
+    }
+}
+

+ 9 - 1
src/containers/CrudList/index.js

@@ -3,7 +3,10 @@ import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import uniqid from 'uniqid';
 
-import { getDocs } from 'selectors/crud';
+import {
+    getCrudLoading,
+    getDocs
+} from 'selectors/crud';
 
 import {
     docCreated,
@@ -12,10 +15,12 @@ import {
     docDeleted
 } from 'actions/crud';
 
+import LoadingIndicator from 'components/LoadingIndicator';
 import CrudDocument from 'components/CrudDocument';
 import AddCrudItem from 'components/AddCrudItem';
 
 const mapStateToProps = (state, { route }) => ({
+    loading: getCrudLoading(state, route),
     items: getDocs(state, route)
 });
 
@@ -36,6 +41,7 @@ class CrudList extends Component {
     static propTypes = {
         title: PropTypes.string.isRequired,
         route: PropTypes.string.isRequired,
+        loading: PropTypes.bool.isRequired,
         docFields: PropTypes.object.isRequired,
         items: PropTypes.array.isRequired,
         onCreate: PropTypes.func.isRequired,
@@ -68,6 +74,7 @@ class CrudList extends Component {
         const {
             title,
             items,
+            loading,
             docFields
         } = this.props;
 
@@ -91,6 +98,7 @@ class CrudList extends Component {
                             onClick={this.onRefresh}>
                             {'Refresh'}
                         </button>
+                        <LoadingIndicator loading={loading} />
                     </div>
                 </div>
                 <div className="body">

+ 3 - 0
src/selectors/crud.js

@@ -1,5 +1,8 @@
 import { createSelector } from 'reselect';
 
+export const getCrudLoading = (state, route) =>
+    Boolean(state.crud[route] && state.crud[route].loading);
+
 const routeExists = (state, route) => route in state.crud;
 
 function getRouteDocs(state, route) {

+ 37 - 0
test/selectors/crud.spec.js

@@ -1,10 +1,47 @@
 import { expect } from 'chai';
 
 import {
+    getCrudLoading,
     getDocs
 } from 'selectors/crud';
 
 describe('CRUD selectors', () => {
+    describe('getCrudLoading', () => {
+        const route = 'employees';
+
+        it('should return true if the CRUD page is loading', () => {
+            const state = {
+                crud: {
+                    [route]: {
+                        loading: true,
+                        items: []
+                    }
+                }
+            };
+
+            expect(getCrudLoading(state, route)).to.equal(true);
+        });
+
+        it('should return false if the CRUD page is not loading', () => {
+            expect(getCrudLoading({
+                crud: {
+                    [route]: {
+                        loading: false
+                    },
+                    otherRoute: {
+                        loading: true
+                    }
+                }
+            }), route)
+                .to.equal(false);
+
+            expect(getCrudLoading({
+                crud: {}
+            }), route)
+                .to.equal(false);
+        });
+    });
+
     describe('getDocs', () => {
         const route = 'employees';