summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--app/app.js26
-rw-r--r--app/containers/AccountPage.js5
-rw-r--r--app/containers/App.js16
-rw-r--r--app/containers/ConnectPage.js5
-rw-r--r--app/containers/LoginPage.js3
-rw-r--r--app/containers/SelectLocationPage.js5
-rw-r--r--app/containers/SettingsPage.js5
-rw-r--r--app/routes.js95
-rw-r--r--app/store.js4
-rw-r--r--package.json5
10 files changed, 92 insertions, 77 deletions
diff --git a/app/app.js b/app/app.js
index 7ce2e3418d..cab3bcb896 100644
--- a/app/app.js
+++ b/app/app.js
@@ -2,8 +2,8 @@ import path from 'path';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
-import { Router, createMemoryHistory } from 'react-router';
-import { syncHistoryWithStore } from 'react-router-redux';
+import { ConnectedRouter } from 'react-router-redux';
+import { createMemoryHistory } from 'history';
import { webFrame, ipcRenderer } from 'electron';
import log from 'electron-log';
import makeRoutes from './routes';
@@ -18,7 +18,6 @@ import { LoginState, ConnectionState, TrayIconType } from './enums';
const initialState = {};
const memoryHistory = createMemoryHistory();
const store = configureStore(initialState, memoryHistory);
-const routes = makeRoutes(store);
const backend = new Backend();
// reset login state if user quit the app during login
@@ -35,15 +34,6 @@ if(store.getState().connect.status === ConnectionState.connecting) {
}));
}
-// desperately trying to fix https://github.com/reactjs/react-router-redux/issues/534
-memoryHistory.replace('/');
-
-const recentLocation = (store.getState().routing || {}).locationBeforeTransitions;
-const routerHistory = syncHistoryWithStore(memoryHistory, store, { adjustUrlOnReplay: true });
-if(recentLocation && recentLocation.pathname) {
- routerHistory.replace(recentLocation.pathname);
-}
-
// Tray icon
/**
@@ -86,14 +76,6 @@ backend.on(Backend.EventType.disconnect, updateTrayIcon);
// force update tray
updateTrayIcon();
-// helper method for router to pass backend down the component tree
-const createElement = (Component, props) => {
- const newProps = { ...props, backend };
- return (
- <Component {...newProps} />
- );
-};
-
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
// disable smart pinch.
@@ -112,7 +94,9 @@ ipcRenderer.send('on-browser-window-ready');
ReactDOM.render(
<Provider store={ store }>
- <Router history={ routerHistory } routes={ routes } createElement={ createElement } />
+ <ConnectedRouter history={ memoryHistory }>
+ { makeRoutes(store.getState, { backend }) }
+ </ConnectedRouter>
</Provider>,
rootElement
);
diff --git a/app/containers/AccountPage.js b/app/containers/AccountPage.js
index bc5e3d3b73..5e695e1d4a 100644
--- a/app/containers/AccountPage.js
+++ b/app/containers/AccountPage.js
@@ -1,5 +1,6 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { push } from 'react-router-redux';
import Account from '../components/Account';
import userActions from '../actions/user';
import { shell } from 'electron';
@@ -13,8 +14,8 @@ const mapDispatchToProps = (dispatch, props) => {
const { logout } = bindActionCreators(userActions, dispatch);
return {
onLogout: () => logout(props.backend),
- onClose: () => props.router.push('/settings'),
- onViewAccount: () => props.router.push('/settings/account'),
+ onClose: () => dispatch(push('/settings')),
+ onViewAccount: () => dispatch(push('/settings/account')),
onExternalLink: (type) => shell.openExternal(links[type])
};
};
diff --git a/app/containers/App.js b/app/containers/App.js
deleted file mode 100644
index 2b45c8ed12..0000000000
--- a/app/containers/App.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React, { Component, PropTypes } from 'react';
-
-export default class App extends Component {
- static propTypes = {
- children: PropTypes.element.isRequired
- };
-
- render() {
- return (
- <div>
- {this.props.children}
- </div>
- );
- }
-}
-
diff --git a/app/containers/ConnectPage.js b/app/containers/ConnectPage.js
index 5f7067b709..fdcc9463af 100644
--- a/app/containers/ConnectPage.js
+++ b/app/containers/ConnectPage.js
@@ -1,5 +1,6 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { push } from 'react-router-redux';
import { shell } from 'electron';
import { links } from '../config';
import Connect from '../components/Connect';
@@ -14,8 +15,8 @@ const mapDispatchToProps = (dispatch, props) => {
const { backend } = props;
return {
- onSettings: () => props.router.push('/settings'),
- onSelectLocation: () => props.router.push('/select-location'),
+ onSettings: () => dispatch(push('/settings')),
+ onSelectLocation: () => dispatch(push('/select-location')),
onConnect: (addr) => connect(backend, addr),
onCopyIP: () => copyIPAddress(),
onDisconnect: () => disconnect(backend),
diff --git a/app/containers/LoginPage.js b/app/containers/LoginPage.js
index 571156ecb2..f5a75ca989 100644
--- a/app/containers/LoginPage.js
+++ b/app/containers/LoginPage.js
@@ -1,6 +1,7 @@
import { shell } from 'electron';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { push } from 'react-router-redux';
import Login from '../components/Login';
import userActions from '../actions/user';
import { LoginState } from '../enums';
@@ -11,7 +12,7 @@ const mapDispatchToProps = (dispatch, props) => {
const { loginChange, login } = bindActionCreators(userActions, dispatch);
const { backend } = props;
return {
- onSettings: () => props.router.push('/settings'),
+ onSettings: () => dispatch(push('/settings')),
onLogin: (account) => login(backend, account),
onChange: (account) => loginChange({ account }),
onFirstChangeAfterFailure: () => loginChange({ status: LoginState.none, error: null }),
diff --git a/app/containers/SelectLocationPage.js b/app/containers/SelectLocationPage.js
index 81fbcfe203..462ffd7bb4 100644
--- a/app/containers/SelectLocationPage.js
+++ b/app/containers/SelectLocationPage.js
@@ -1,5 +1,6 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { push } from 'react-router-redux';
import SelectLocation from '../components/SelectLocation';
import settingsActions from '../actions/settings';
@@ -8,11 +9,11 @@ const mapDispatchToProps = (dispatch, props) => {
const { backend } = props;
const settings = bindActionCreators(settingsActions, dispatch);
return {
- onClose: () => props.router.push('/connect'),
+ onClose: () => dispatch(push('/connect')),
onSelect: (preferredServer) => {
const server = backend.serverInfo(preferredServer);
- props.router.push('/connect');
+ dispatch(push('/connect'));
// add delay to let the map load
setTimeout(() => {
diff --git a/app/containers/SettingsPage.js b/app/containers/SettingsPage.js
index fa1a98a44b..b0bc7868b0 100644
--- a/app/containers/SettingsPage.js
+++ b/app/containers/SettingsPage.js
@@ -1,5 +1,6 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { push } from 'react-router-redux';
import Settings from '../components/Settings';
import userActions from '../actions/user';
import settingsActions from '../actions/settings';
@@ -16,8 +17,8 @@ const mapDispatchToProps = (dispatch, props) => {
return {
onQuit: () => remote.app.quit(),
onLogout: () => logout(props.backend),
- onClose: () => props.router.push('/connect'),
- onViewAccount: () => props.router.push('/settings/account'),
+ onClose: () => dispatch(push('/connect')),
+ onViewAccount: () => dispatch(push('/settings/account')),
onExternalLink: (type) => shell.openExternal(links[type]),
onUpdateSettings: updateSettings
};
diff --git a/app/routes.js b/app/routes.js
index e4bdd21471..bcee8ca5e1 100644
--- a/app/routes.js
+++ b/app/routes.js
@@ -1,55 +1,96 @@
import React from 'react';
-import { Route, IndexRoute } from 'react-router';
-
-import App from './containers/App';
+import { Switch, Route, Redirect } from 'react-router';
import LoginPage from './containers/LoginPage';
import ConnectPage from './containers/ConnectPage';
import SettingsPage from './containers/SettingsPage';
import AccountPage from './containers/AccountPage';
import SelectLocationPage from './containers/SelectLocationPage';
-
import { LoginState } from './enums';
/**
* Create routes
*
* @export
- * @param {Redux.Store} store
+ * @param {function} getState - function to get redux state
+ * @param {object} componentProps - extra props to propagate across components
* @returns {React.element}
*/
-export default function makeRoutes(store) {
+export default function makeRoutes(getState, componentProps) {
+
+ /**
+ * Merge props and render component
+ * @param {React.Component} component - component class
+ * @param {...} rest - props
+ * @private
+ */
+ const renderMergedProps = (component, ...rest) => {
+ const finalProps = Object.assign({}, componentProps, ...rest);
+ return (
+ React.createElement(component, finalProps)
+ );
+ };
/**
- * Ensures that user is redirected to /connect if logged in
+ * Renders public route
+ * Example: <PublicRoute path="/" component={ MyComponent } />
* @private
*/
- const ensureConnect = (nextState, replace) => {
- let { user } = store.getState();
- if(user.status === LoginState.ok) {
- replace('/connect');
- }
+ const PublicRoute = ({ component, ...rest }) => {
+ return (
+ <Route {...rest} render={ (routeProps) => {
+ return renderMergedProps(component, routeProps, ...rest);
+ }} />
+ );
};
/**
- * Ensures that user is redirected to / login if not logged in
+ * Renders protected route that requires authentication, otherwise redirects to /
+ * Example: <PrivateRoute path="/protected" component={ MyComponent } />
* @private
*/
- const ensureLoggedIn = (nextState, replace) => {
- let { user } = store.getState();
- if(user.status !== LoginState.ok) {
- replace('/');
- }
+ const PrivateRoute = ({ component, ...rest }) => {
+ return (
+ <Route {...rest} render={ (routeProps) => {
+ const { user } = getState();
+ const isLoggedIn = user.status === LoginState.ok;
+
+ if(isLoggedIn) {
+ return renderMergedProps(component, routeProps, ...rest);
+ } else {
+ return (<Redirect to={ '/' } />);
+ }
+ }} />
+ );
+ };
+
+ /**
+ * Renders login route that is only available to non-authenticated
+ * users. Otherwise this route redirects user to /connect.
+ * Example: <LoginRoute path="/login" component={ MyComponent } />
+ * @private
+ */
+ const LoginRoute = ({ component, ...rest }) => {
+ return (
+ <Route {...rest} render={ (routeProps) => {
+ const { user } = getState();
+ const isLoggedIn = user.status === LoginState.ok;
+
+ if(isLoggedIn) {
+ return (<Redirect to={ '/connect' } />);
+ } else {
+ return renderMergedProps(component, routeProps, ...rest);
+ }
+ }} />
+ );
};
return (
- <Route path="/" component={ App }>
- <IndexRoute component={ LoginPage } onEnter={ ensureConnect } />
- <Route path="connect" component={ ConnectPage } onEnter={ ensureLoggedIn } />
- <Route path="settings">
- <IndexRoute component={ SettingsPage } />
- <Route path="account" component={ AccountPage } onEnter={ ensureLoggedIn } />
- </Route>
- <Route path="select-location" component={ SelectLocationPage } onEnter={ ensureLoggedIn } />
- </Route>
+ <Switch>
+ <LoginRoute exact path="/" component={ LoginPage } />
+ <PrivateRoute exact path="/connect" component={ ConnectPage } />
+ <PublicRoute exact path="/settings" component={ SettingsPage } />
+ <PrivateRoute path="/settings/account" component={ AccountPage } />
+ <PrivateRoute path="/select-location" component={ SelectLocationPage } />
+ </Switch>
);
}
diff --git a/app/store.js b/app/store.js
index cbe1e3bb97..6c48cbcde8 100644
--- a/app/store.js
+++ b/app/store.js
@@ -1,5 +1,5 @@
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
-import { routerMiddleware, routerReducer as routing, push, replace } from 'react-router-redux';
+import { routerMiddleware, routerReducer, push, replace } from 'react-router-redux';
import persistState from 'redux-localstorage';
import thunk from 'redux-thunk';
@@ -30,7 +30,7 @@ export default function configureStore(initialState, routerHistory) {
};
const reducers = {
- user, connect, settings, routing
+ user, connect, settings, router: routerReducer
};
const middlewares = [ thunk, router ];
diff --git a/package.json b/package.json
index 8ad7abf859..8f41608b96 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"babel-runtime": "^6.22.0",
"cheap-ruler": "^2.4.1",
"electron-log": "^2.2.0",
+ "history": "^4.6.1",
"jsonrpc-lite": "^1.2.3",
"moment": "^2.17.1",
"react": "^15.4.2",
@@ -21,8 +22,8 @@
"react-if": "^2.1.0",
"react-mapbox-gl": "^1.3.0",
"react-redux": "^5.0.2",
- "react-router": "^3.0.2",
- "react-router-redux": "^4.0.7",
+ "react-router": "^4.1.1",
+ "react-router-redux": "5.0.0-alpha.6",
"redux": "^3.0.0",
"redux-actions": "^2.0.1",
"redux-localstorage": "^0.4.1",