From 36763d5e2e9aead33deceb25eacadb3ec4db6a63 Mon Sep 17 00:00:00 2001
From: Mary Bucknell <mbucknell@usgs.gov>
Date: Tue, 8 May 2018 13:16:04 -0500
Subject: [PATCH] Have working loading indicators for loading initial graph
 data and for extended range.

---
 .../scripts/components/hydrograph/index.js    | 33 ++++++++++++-------
 .../scripts/selectors/timeSeriesSelector.js   |  5 +--
 assets/src/scripts/store/index.js             | 30 +++++++++++++----
 .../scripts/store/timeSeriesStateReducer.js   |  4 +--
 .../styles/components/hydrograph/_app.scss    | 21 +++++++++---
 .../templates/macros/components.html          |  1 +
 6 files changed, 69 insertions(+), 25 deletions(-)

diff --git a/assets/src/scripts/components/hydrograph/index.js b/assets/src/scripts/components/hydrograph/index.js
index 190b64906..3c3cf715c 100644
--- a/assets/src/scripts/components/hydrograph/index.js
+++ b/assets/src/scripts/components/hydrograph/index.js
@@ -355,6 +355,13 @@ const controlDisplay = function (elem, showElem) {
     elem.attr('hidden', showElem ? null : true);
 };
 
+const loadingIndicator = function(elem, {showLoadingIndicator, sizeClass}) {
+    elem.select('.loading-indicator').remove();
+    if (showLoadingIndicator) {
+        elem.append('i')
+            .attr('class', `loading-indicator fas ${sizeClass} fa-spin fa-spinner`);
+    }
+};
 
 const createDaterangeControls = function(elem, {siteno, showControls}) {
     const DATE_RANGE = [{
@@ -372,10 +379,17 @@ const createDaterangeControls = function(elem, {siteno, showControls}) {
     }];
     elem.select('#ts-daterange-select-container').remove();
     if (showControls) {
-        const container = elem.insert('ul', ':first-child')
-            .attr('id', 'ts-daterange-select-container')
+        const container = elem.insert('div', ':nth-child(2)')
+            .attr('id', 'ts-daterange-select-container');
+        const listContainer = container.append('ul')
             .attr('class', 'usa-fieldset-inputs usa-unstyled-list');
-        const li = container.selectAll('li')
+        container.append('div')
+            .attr('class', 'loading-indicator-container')
+            .call(link(loadingIndicator, createStructuredSelector({
+                showLoadingIndicator: isLoadingTS('current'),
+                sizeClass:() => 'fa-lg'
+            })));
+        const li = listContainer.selectAll('li')
             .data(DATE_RANGE)
             .enter().append('li');
         li.append('input')
@@ -408,14 +422,11 @@ const attachToNode = function (store, node, {siteno} = {}) {
     store.dispatch(Actions.resizeUI(window.innerWidth, node.offsetWidth));
     select(node)
         .call(provide(store));
-    select(node)
-        .call(link(function(elem, isLoadingCurrentTS) {
-            elem.select('.loading-indicator').remove();
-            if (isLoadingCurrentTS) {
-                select(elem).append('i')
-                    .attr('class', 'fas fa-spinner fa-spin');
-            }
-        }, isLoadingTS('current:P7D')));
+    select(node).select('.loading-indicator-container')
+        .call(link(loadingIndicator, createStructuredSelector({
+            showLoadingIndicator: isLoadingTS('current', 'P7D'),
+            sizeClass: () =>'fa-3x'
+        })));
     select(node)
         .call(link(createDaterangeControls, createStructuredSelector({
             siteno: () => siteno,
diff --git a/assets/src/scripts/selectors/timeSeriesSelector.js b/assets/src/scripts/selectors/timeSeriesSelector.js
index f5ded6053..30e642027 100644
--- a/assets/src/scripts/selectors/timeSeriesSelector.js
+++ b/assets/src/scripts/selectors/timeSeriesSelector.js
@@ -115,7 +115,8 @@ export const getRequestTimeRange = memoize((tsKey, period, parmCd) => createSele
     }
 ));
 
-export const isLoadingTS = memoize(tsKey => createSelector(
+export const isLoadingTS = memoize((tsKey, period, parmCd) => createSelector(
     getLoadingTsKeys,
-    (loadingTSKeys) => loadingTSKeys.includes(tsKey)
+    getTsRequestKey(tsKey, period, parmCd),
+    (loadingTSKeys, tsRequestKey) => loadingTSKeys.includes(tsRequestKey)
 ));
diff --git a/assets/src/scripts/store/index.js b/assets/src/scripts/store/index.js
index defa7856f..f36eb3c62 100644
--- a/assets/src/scripts/store/index.js
+++ b/assets/src/scripts/store/index.js
@@ -55,7 +55,6 @@ export const Actions = {
 
             const timeSeries = getTimeSeries({sites: [siteno], params}).then(
                 series => {
-                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
                     const collection = normalize(series, requestKey);
 
                     // Get the start/end times of this request's range.
@@ -69,6 +68,8 @@ export const Actions = {
 
                     // Update the series data for the 'current' series
                     dispatch(Actions.addSeriesCollection('current', collection));
+                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
+
 
                     // Update the application state
                     dispatch(Actions.toggleTimeSeries('current', true));
@@ -80,8 +81,9 @@ export const Actions = {
                     return {collection, startTime, endTime};
                 },
                 () => {
-                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
                     dispatch(Actions.resetTimeSeries(getTsRequestKey('current', 'P7D')(currentState)));
+                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
+
                     dispatch(Actions.toggleTimeSeries('current', false));
                     return {
                         collection: null,
@@ -90,7 +92,14 @@ export const Actions = {
                     };
                 }
             );
+
+            const medianRequestKey = getTsRequestKey('median')(currentState);
+            dispatch(Actions.addTimeSeriesLoading([medianRequestKey]));
             const medianStatistics = getMedianStatistics({sites: [siteno]});
+            medianStatistics.finally(() => {
+                dispatch(Actions.removeTimeSeriesLoading([medianRequestKey]));
+            });
+
             return Promise.all([timeSeries, medianStatistics]).then(([{collection, endTime}, stats]) => {
                 if (endTime) {
                     let medianCollection = parseMedianData(stats, endTime, collection && collection.variables ? collection.variables : {});
@@ -102,13 +111,18 @@ export const Actions = {
     },
     retrieveCompareTimeSeries(site, period, startTime, endTime) {
         return function (dispatch, getState) {
+            const requestKey = getTsRequestKey('compare', period)(getState());
+            dispatch(Actions.addTimeSeriesLoading([requestKey]));
             return getPreviousYearTimeSeries({site, startTime, endTime}).then(
                 series => {
-                    const requestKey = getTsRequestKey('compare', period)(getState());
                     const collection = normalize(series, requestKey);
                     dispatch(Actions.addSeriesCollection(requestKey, collection));
+                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
                 },
-                () => dispatch(Actions.resetTimeSeries(getTsRequestKey('compare', period)(getState())))
+                () => {
+                    dispatch(Actions.resetTimeSeries(getTsRequestKey('compare', period)(getState())));
+                    dispatch(Actions.removeTimeSeriesLoading([requestKey]));
+                }
             );
         };
     },
@@ -122,7 +136,8 @@ export const Actions = {
                 const endTime = new Date(getRequestTimeRange('current', 'P7D')(state).end);
                 let startTime = calcStartTime(period, endTime);
 
-                return getTimeSeries({
+                dispatch(Actions.addTimeSeriesLoading([requestKey]));
+                const currentTimeSeries = getTimeSeries({
                     sites: [site],
                     params: [parmCd],
                     startDate: startTime,
@@ -131,13 +146,16 @@ export const Actions = {
                     series => {
                         const collection = normalize(series, requestKey);
                         dispatch(Actions.addSeriesCollection(requestKey, collection));
-                        dispatch(Actions.retrieveCompareTimeSeries(site, period, startTime, endTime));
+                        dispatch(Actions.removeTimeSeriesLoading([requestKey]));
                     },
                     () => {
                         console.log(`Unable to fetch data for period ${period} and parameter code ${parmCd}`);
                         dispatch(Actions.addSeriesCollection(requestKey, {}));
+                        dispatch(Actions.removeTimeSeriesLoading([requestKey]));
                     }
                 );
+                dispatch(Actions.retrieveCompareTimeSeries(site, period, startTime, endTime));
+                return currentTimeSeries;
             }
         };
     },
diff --git a/assets/src/scripts/store/timeSeriesStateReducer.js b/assets/src/scripts/store/timeSeriesStateReducer.js
index 46529150e..ab76dd176 100644
--- a/assets/src/scripts/store/timeSeriesStateReducer.js
+++ b/assets/src/scripts/store/timeSeriesStateReducer.js
@@ -51,14 +51,14 @@ const timeSeriesPlayStop = function(timeSeriesState) {
 const addLoadingTimeSeries = function(timeSeriesState, action) {
     return {
         ...timeSeriesState,
-        loadingTSKeys: timeSeriesState.loadingTSKeys.concat([action.tsKeys])
+        loadingTSKeys: timeSeriesState.loadingTSKeys.concat(action.tsKeys)
     };
 };
 
 const removeLoadingTimeSeries = function(timeSeriesState, action) {
     return {
         ...timeSeriesState,
-        loadingTSKeys: timeSeriesState.loadingTSKeys.filter((tsKey) => action.tsKeys.includes(tsKey))
+        loadingTSKeys: timeSeriesState.loadingTSKeys.filter((tsKey) => !action.tsKeys.includes(tsKey))
     };
 };
 
diff --git a/assets/src/styles/components/hydrograph/_app.scss b/assets/src/styles/components/hydrograph/_app.scss
index 835bd9eda..d0d5fbcaa 100644
--- a/assets/src/styles/components/hydrograph/_app.scss
+++ b/assets/src/styles/components/hydrograph/_app.scss
@@ -4,10 +4,16 @@
 @import './variables';
 
 #ts-daterange-select-container {
-    li {
+    .loading-indicator-container {
         display: inline-block;
-        label {
-            width: 110px;
+    }
+    ul {
+        display: inline-block;
+        li {
+            display: inline-block;
+            label {
+                width: 110px;
+            }
         }
     }
 }
@@ -136,6 +142,14 @@
     }
 }
 
+.loading-indicator-container {
+    i {
+        text-align: center;
+        vertical: middle;
+        width: 100%;
+    }
+}
+
 .watermark {
     position: absolute;
     opacity: .08;
@@ -167,7 +181,6 @@
     button {
         font-size: 1em;
     }
-
     .graph-controls-container {
         display: inline-block;
         @include media($medium-screen) {
diff --git a/wdfn-server/waterdata/templates/macros/components.html b/wdfn-server/waterdata/templates/macros/components.html
index a4d33be14..a1cb75336 100644
--- a/wdfn-server/waterdata/templates/macros/components.html
+++ b/wdfn-server/waterdata/templates/macros/components.html
@@ -1,5 +1,6 @@
 {% macro TimeSeriesComponent(site_no) -%}
     <div class="wdfn-component" data-component="hydrograph" data-siteno="{{ site_no }}">
+        <div class="loading-indicator-container"></div>
         <div class="graph-container"></div>
         <div class="select-time-series-container"></div>
         <div class="usa-alert usa-alert-info provisional-data-alert" role="alert" hidden>
-- 
GitLab