From 5f7e7ce009d4854bd360bee8b7164cbd5ec84347 Mon Sep 17 00:00:00 2001
From: Todd Dembrey <todd.dembrey@torchbox.com>
Date: Thu, 21 Feb 2019 11:24:36 +0000
Subject: [PATCH] GH-991: correctly handle back/forward behaviour

---
 .../static_src/src/app/src/SwitcherApp.js     | 35 ++++++++++--
 .../src/app/src/redux/actions/submissions.js  | 56 +++++++++++++++----
 .../src/app/src/redux/reducers/index.js       |  2 +-
 .../static_src/src/app/src/redux/store.js     |  8 ++-
 .../src/app/src/submissionsByStatusIndex.js   |  7 ++-
 5 files changed, 87 insertions(+), 21 deletions(-)

diff --git a/opentech/static_src/src/app/src/SwitcherApp.js b/opentech/static_src/src/app/src/SwitcherApp.js
index 19d30aaec..a7fd6bff6 100644
--- a/opentech/static_src/src/app/src/SwitcherApp.js
+++ b/opentech/static_src/src/app/src/SwitcherApp.js
@@ -4,7 +4,11 @@ import { connect } from 'react-redux'
 
 import Switcher from '@components/Switcher';
 import MessagesContainer from '@containers/MessagesContainer'
-import { loadSubmissionFromURL } from '@actions/submissions';
+import {
+    clearCurrentSubmissionParam,
+    loadSubmissionFromURL,
+    setCurrentSubmissionParam,
+} from '@actions/submissions';
 
 
 class SwitcherApp extends React.Component {
@@ -14,6 +18,9 @@ class SwitcherApp extends React.Component {
         switcherSelector: PropTypes.string.isRequired,
         startOpen: PropTypes.bool,
         processParams: PropTypes.func.isRequired,
+        searchParam: PropTypes.string,
+        setParams: PropTypes.func.isRequired,
+        clearParams: PropTypes.func.isRequired,
     };
 
     state = {
@@ -26,15 +33,28 @@ class SwitcherApp extends React.Component {
             mounting: false
         })
 
-        const success = this.props.processParams()
+        console.log(this.props.searchParam)
+        const success = this.props.processParams(this.props.searchParam)
         if (success) {
             this.openDetail()
         }
+    }
+
+    componentDidUpdate(prevProps) {
+        if (prevProps.searchParam !== this.props.searchParam) {
+            const success = this.props.processParams(this.props.searchParam)
 
+            if (!success) {
+                this.closeDetail()
+            } else {
+                this.openDetail()
+            }
+        }
     }
 
     openDetail = () => {
         document.body.classList.add('app-open');
+        this.props.setParams();
         this.setState(state => ({
             style: { ...state.style, display: 'none' } ,
             detailOpened: true,
@@ -43,6 +63,7 @@ class SwitcherApp extends React.Component {
 
     closeDetail = () => {
         document.body.classList.remove('app-open');
+        this.props.clearParams();
         this.setState(state => {
             const newStyle = { ...state.style };
             delete newStyle.display;
@@ -70,8 +91,14 @@ class SwitcherApp extends React.Component {
     }
 }
 
+const mapStateToProps = (state) => ({
+    searchParam: state.router.location.search
+})
+
 const mapDispatchToProps = dispatch => ({
-    processParams: id => dispatch(loadSubmissionFromURL()),
+    processParams: params => dispatch(loadSubmissionFromURL(params)),
+    clearParams: () => dispatch(clearCurrentSubmissionParam()),
+    setParams: () => dispatch(setCurrentSubmissionParam()),
 });
 
-export default connect(null, mapDispatchToProps)(SwitcherApp);
+export default connect(mapStateToProps, mapDispatchToProps)(SwitcherApp);
diff --git a/opentech/static_src/src/app/src/redux/actions/submissions.js b/opentech/static_src/src/app/src/redux/actions/submissions.js
index f55cd9a36..005860211 100644
--- a/opentech/static_src/src/app/src/redux/actions/submissions.js
+++ b/opentech/static_src/src/app/src/redux/actions/submissions.js
@@ -69,25 +69,59 @@ export const setCurrentSubmissionRound = id => ({
 });
 
 
-export const loadSubmissionFromURL = () => (dispatch, getState) => {
-    const urlParams = new URLSearchParams(window.location.search);
+export const loadSubmissionFromURL = (params) => (dispatch, getState) => {
+    const urlParams = new URLSearchParams(params);
     if (urlParams.has('submission')) {
         const activeId = Number(urlParams.get('submission'));
-        return dispatch(setCurrentSubmission(activeId));
+        const submissionID = getCurrentSubmissionID(getState());
+
+        if (activeId !== null  && submissionID !== activeId) {
+            dispatch(setCurrentSubmission(activeId));
+        }
+        return true;
     }
-    return null;
-}
+    return false;
+};
 
 
-export const setCurrentSubmission = id => (dispatch, getState) => {
-    const submissionID = getCurrentSubmissionID(getState())
 
-    if (id !== null  && submissionID !== id) {
-        dispatch(push(`?submission=${id}`));
-    } else if (!id) {
-        dispatch(push('?'));
+export const clearCurrentSubmissionParam = () => (dispatch, getState) => {
+    const state = getState();
+    if (state.router.location.search !== '') {
+        return dispatch(push({search: ''}));
+    }
+};
+
+
+const setSubmissionParam = (id) => (dispatch, getState) => {
+    const state = getState();
+    const submissionID = getCurrentSubmissionID(state);
+
+    const urlParams = new URLSearchParams(state.router.location.search);
+    const urlID = Number(urlParams.get('submission'));
+
+    const shouldSet = !urlID && !!id;
+    const shouldUpdate = id !== null  && submissionID !== id && urlID !== id;
+
+    if (shouldSet || shouldUpdate) {
+        dispatch(push({search: `?submission=${id}`}));
+    } else if (id === null) {
+        dispatch(clearCurrentSubmissionParam());
     }
 
+};
+
+
+export const setCurrentSubmissionParam = () => (dispatch, getState) => {
+    const submissionID = getCurrentSubmissionID(getState());
+    return dispatch(setSubmissionParam(submissionID));
+};
+
+
+
+export const setCurrentSubmission = id => (dispatch, getState) => {
+    dispatch(setSubmissionParam(id));
+
     return dispatch({
         type: SET_CURRENT_SUBMISSION,
         id,
diff --git a/opentech/static_src/src/app/src/redux/reducers/index.js b/opentech/static_src/src/app/src/redux/reducers/index.js
index c2af517e8..e29835e85 100644
--- a/opentech/static_src/src/app/src/redux/reducers/index.js
+++ b/opentech/static_src/src/app/src/redux/reducers/index.js
@@ -7,7 +7,7 @@ import notes from '@reducers/notes';
 import messages from '@reducers/messages';
 import statuses from '@reducers/statuses';
 
-export default combineReducers({
+export default (history) => combineReducers({
     router: connectRouter(history),
     notes,
     messages,
diff --git a/opentech/static_src/src/app/src/redux/store.js b/opentech/static_src/src/app/src/redux/store.js
index c0a523012..17b69824b 100644
--- a/opentech/static_src/src/app/src/redux/store.js
+++ b/opentech/static_src/src/app/src/redux/store.js
@@ -5,10 +5,11 @@ import logger from 'redux-logger'
 import { routerMiddleware } from 'connected-react-router';
 import { createBrowserHistory } from 'history';
 
-import rootReducer from '@reducers';
+import createRootReducer from '@reducers';
 import api from '@middleware/api'
 
-export const history = createBrowserHistory()
+
+export const history = createBrowserHistory();
 
 const MIDDLEWARE = [
     routerMiddleware(history),
@@ -23,7 +24,8 @@ if (process.env.NODE_ENV === 'development') {
 
 export default initialState => {
     const store = createStore(
-        rootReducer,
+        createRootReducer(history),
+        initialState,
         composeWithDevTools(
             applyMiddleware(...MIDDLEWARE)
         )
diff --git a/opentech/static_src/src/app/src/submissionsByStatusIndex.js b/opentech/static_src/src/app/src/submissionsByStatusIndex.js
index 830d011a3..a62ef16ea 100644
--- a/opentech/static_src/src/app/src/submissionsByStatusIndex.js
+++ b/opentech/static_src/src/app/src/submissionsByStatusIndex.js
@@ -2,9 +2,10 @@ import React from 'react';
 import ReactDOM from 'react-dom';
 import Modal from 'react-modal';
 import { Provider } from 'react-redux';
+import { ConnectedRouter } from 'connected-react-router';
 
 import SubmissionsByStatusApp from './SubmissionsByStatusApp';
-import createStore from '@redux/store';
+import createStore, { history } from '@redux/store';
 
 
 const container = document.getElementById('submissions-by-status-react-app');
@@ -15,7 +16,9 @@ Modal.setAppElement(container)
 
 ReactDOM.render(
     <Provider store={store}>
-        <SubmissionsByStatusApp pageContent={container.innerHTML} statuses={container.dataset.statuses.split(',')} />
+        <ConnectedRouter history={history}>
+            <SubmissionsByStatusApp pageContent={container.innerHTML} statuses={container.dataset.statuses.split(',')} />
+        </ConnectedRouter>
     </Provider>,
     container
 );
-- 
GitLab