diff --git a/package.json b/package.json
index d43dfba2a..f20e7b377 100644
--- a/package.json
+++ b/package.json
@@ -25,96 +25,96 @@
},
"homepage": "https://github.com/jorilallo/atlas#readme",
"dependencies": {
- "babel-core": "^6.4.5",
- "babel-eslint": "^4.1.8",
- "babel-loader": "^6.2.1",
- "babel-plugin-transform-decorators-legacy": "^1.3.4",
- "babel-polyfill": "^6.7.4",
- "babel-preset-es2015": "^6.3.13",
- "babel-preset-react": "^6.3.13",
- "babel-preset-react-hmre": "^1.0.1",
- "babel-preset-stage-0": "^6.5.0",
- "classnames": "^2.2.3",
- "codemirror": "^5.11.0",
- "cross-env": "^1.0.7",
+ "babel-core": "6.10.4",
+ "babel-eslint": "6.1.0",
+ "babel-loader": "6.2.1",
+ "babel-plugin-transform-decorators-legacy": "1.3.4",
+ "babel-polyfill": "6.7.4",
+ "babel-preset-es2015": "6.3.13",
+ "babel-preset-react": "6.3.13",
+ "babel-preset-react-hmre": "1.0.1",
+ "babel-preset-stage-0": "6.5.0",
+ "classnames": "2.2.3",
+ "codemirror": "5.16.0",
+ "cross-env": "1.0.7",
"crypto": "0.0.3",
- "css-loader": "^0.23.1",
- "debug": "^2.2.0",
- "dotenv": "^2.0.0",
- "emoji-name-map": "^1.1.1",
- "eslint": "^1.10.3",
- "eslint-config-airbnb": "^5.0.0",
- "eslint-plugin-react": "^3.16.1",
- "exports-loader": "^0.6.3",
- "extract-text-webpack-plugin": "^1.0.1",
- "file-loader": "^0.8.5",
- "highlight.js": "^9.4.0",
- "history": "^1.17.0",
- "html-webpack-plugin": "^2.17.0",
- "http-errors": "^1.4.0",
- "imports-loader": "^0.6.5",
- "isomorphic-fetch": "^2.2.1",
- "js-tree": "^1.1.0",
- "json-loader": "^0.5.4",
- "jsonwebtoken": "^5.7.0",
- "koa": "^2.0.0",
- "koa-bodyparser": "^2.0.1",
- "koa-compress": "^2.0.0",
- "koa-connect": "^1.0.0",
- "koa-convert": "^1.2.0",
- "koa-helmet": "^1.0.0",
- "koa-jwt": "^1.2.0",
- "koa-logger": "^2.0.0",
- "koa-mount": "^2.0.0",
- "koa-router": "^7.0.1",
- "koa-sendfile": "^2.0.0",
- "koa-webpack-dev-middleware": "^1.2.0",
- "koa-webpack-hot-middleware": "^1.0.3",
- "localenv": "^0.2.2",
- "localforage": "^1.4.2",
- "lodash": "^4.13.1",
- "lodash.orderby": "^4.4.0",
- "marked": "^0.3.5",
- "mobx": "^2.2.2",
- "mobx-react": "^3.3.0",
- "mobx-react-devtools": "^4.2.0",
- "moment": "^2.13.0",
- "node-dev": "^3.1.0",
- "node-sass": "^3.4.2",
- "nodemon": "^1.9.1",
- "normalize.css": "^3.0.3",
- "normalizr": "^2.0.1",
- "pg": "^4.5.3",
- "pg-hstore": "^2.3.2",
- "querystring": "^0.2.0",
- "randomstring": "^1.1.5",
- "react": "^0.14.7",
- "react-codemirror": "^0.2.5",
- "react-dom": "^0.14.7",
- "react-dropzone": "^3.3.2",
- "react-helmet": "^3.1.0",
- "react-router": "^2.0.0",
- "rebass": "^0.2.6",
- "safestart": "^0.8.0",
- "sass-loader": "^3.2.0",
- "sequelize": "^3.21.0",
- "sequelize-cli": "^2.4.0",
- "sequelize-encrypted": "^0.1.0",
- "slug": "^0.9.1",
- "style-loader": "^0.13.0",
+ "css-loader": "0.23.1",
+ "debug": "2.2.0",
+ "dotenv": "2.0.0",
+ "emoji-name-map": "1.1.2",
+ "eslint": "2.13.1",
+ "eslint-config-airbnb": "9.0.1",
+ "eslint-plugin-react": "5.2.2",
+ "exports-loader": "0.6.3",
+ "extract-text-webpack-plugin": "1.0.1",
+ "file-loader": "0.9.0",
+ "highlight.js": "9.4.0",
+ "history": "3.0.0",
+ "html-webpack-plugin": "2.17.0",
+ "http-errors": "1.4.0",
+ "imports-loader": "0.6.5",
+ "isomorphic-fetch": "2.2.1",
+ "js-tree": "1.1.0",
+ "json-loader": "0.5.4",
+ "jsonwebtoken": "7.0.1",
+ "koa": "2.0.0",
+ "koa-bodyparser": "2.0.1",
+ "koa-compress": "2.0.0",
+ "koa-connect": "1.0.0",
+ "koa-convert": "1.2.0",
+ "koa-helmet": "1.0.0",
+ "koa-jwt": "1.2.0",
+ "koa-logger": "2.0.0",
+ "koa-mount": "2.0.0",
+ "koa-router": "7.0.1",
+ "koa-sendfile": "2.0.0",
+ "koa-webpack-dev-middleware": "1.2.0",
+ "koa-webpack-hot-middleware": "1.0.3",
+ "localenv": "0.2.2",
+ "localforage": "1.4.2",
+ "lodash": "4.13.1",
+ "lodash.orderby": "4.4.0",
+ "marked": "0.3.5",
+ "mobx": "2.3.3",
+ "mobx-react": "3.4.0",
+ "mobx-react-devtools": "4.2.0",
+ "moment": "2.13.0",
+ "node-dev": "3.1.0",
+ "node-sass": "3.4.2",
+ "nodemon": "1.9.1",
+ "normalize.css": "4.1.1",
+ "normalizr": "2.0.1",
+ "pg": "6.0.1",
+ "pg-hstore": "2.3.2",
+ "querystring": "0.2.0",
+ "randomstring": "1.1.5",
+ "react": "15.1.0",
+ "react-codemirror": "0.2.5",
+ "react-dom": "15.1.0",
+ "react-dropzone": "3.3.2",
+ "react-helmet": "3.1.0",
+ "react-router": "2.5.1",
+ "rebass": "0.2.6",
+ "safestart": "0.8.0",
+ "sass-loader": "3.2.1",
+ "sequelize": "3.23.4",
+ "sequelize-cli": "2.4.0",
+ "sequelize-encrypted": "0.1.0",
+ "slug": "0.9.1",
+ "style-loader": "0.13.0",
"truncate-html": "0.0.6",
- "url-loader": "^0.5.7",
- "uuid": "^2.0.2",
- "validator": "^5.2.0",
- "webpack": "^1.12.12"
+ "url-loader": "0.5.7",
+ "uuid": "2.0.2",
+ "validator": "5.2.0",
+ "webpack": "1.12.12"
},
"devDependencies": {
- "babel-regenerator-runtime": "^6.5.0",
- "fsevents": "^1.0.11",
- "ignore-loader": "^0.1.1",
- "koa-webpack-dev-middleware": "^1.2.0",
- "koa-webpack-hot-middleware": "^1.0.3",
- "node-dev": "^3.1.0",
- "nodemon": "^1.9.1"
+ "babel-regenerator-runtime": "6.5.0",
+ "fsevents": "1.0.11",
+ "ignore-loader": "0.1.1",
+ "koa-webpack-dev-middleware": "1.2.0",
+ "koa-webpack-hot-middleware": "1.0.3",
+ "node-dev": "3.1.0",
+ "nodemon": "1.9.1"
}
}
diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js
index e1a6c9fff..c4793295f 100644
--- a/src/components/Layout/Layout.js
+++ b/src/components/Layout/Layout.js
@@ -1,9 +1,7 @@
import React from 'react';
import Link from 'react-router/lib/Link';
import Helmet from 'react-helmet';
-import { observe } from 'mobx';
-
-import store from 'stores/UserStore';
+import { observer } from 'mobx-react';
import DropdownMenu, { MenuItem } from 'components/DropdownMenu';
import Flex from 'components/Flex';
@@ -14,6 +12,7 @@ import styles from './Layout.scss';
import classNames from 'classnames/bind';
const cx = classNames.bind(styles);
+@observer(['user'])
class Layout extends React.Component {
static propTypes = {
actions: React.PropTypes.node,
@@ -21,9 +20,12 @@ class Layout extends React.Component {
titleText: React.PropTypes.node,
fixed: React.PropTypes.bool,
loading: React.PropTypes.bool,
+ user: React.PropTypes.object.isRequired,
}
render() {
+ const user = this.props.user;
+
return (
-
{ store.team.name }
+
{ user.team.name }
{ this.props.title && ( / ) }{ this.props.title }
@@ -53,10 +55,10 @@ class Layout extends React.Component {
}>
-
+
diff --git a/src/components/SlackAuthLink/SlackAuthLink.js b/src/components/SlackAuthLink/SlackAuthLink.js
index 14d36b1d0..0fa6aebab 100644
--- a/src/components/SlackAuthLink/SlackAuthLink.js
+++ b/src/components/SlackAuthLink/SlackAuthLink.js
@@ -1,12 +1,13 @@
import React from 'react';
-import { observe } from 'mobx'
-import store from 'stores/UserStore';
+import { observer } from 'mobx-react';
import styles from './SlackAuthLink.scss';
+@observer(['user'])
class SlackAuthLink extends React.Component {
static propTypes = {
scopes: React.PropTypes.arrayOf(React.PropTypes.string),
+ user: React.PropTypes.object.isRequired,
}
static defaultProps = {
@@ -26,7 +27,7 @@ class SlackAuthLink extends React.Component {
redirect_uri: __DEV__ ?
'http://localhost:3000/auth/slack/' :
'https://www.beautifulatlas.com/auth/slack/',
- state: store.getOauthState(),
+ state: this.props.user.getOauthState(),
};
const urlParams = Object.keys(params).map(function(key) {
diff --git a/src/index.js b/src/index.js
index c9195be42..9b5c5ef9d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,11 +1,13 @@
import React from 'react';
import { render } from 'react-dom';
+import { Provider } from 'mobx-react';
import Router from 'react-router/lib/Router';
import Route from 'react-router/lib/Route';
import IndexRoute from 'react-router/lib/IndexRoute';
import History from 'utils/History';
-import userStore from 'stores/UserStore';
+import stores from 'stores';
+window.stores = stores;
import 'normalize.css/normalize.css';
import 'utils/base-styles.scss';
@@ -28,7 +30,7 @@ if (__DEV__) {
}
function requireAuth(nextState, replace) {
- if (!userStore.authenticated) {
+ if (!stores.user.authenticated) {
replace({
pathname: '/',
state: { nextPathname: nextState.location.pathname },
@@ -38,20 +40,22 @@ function requireAuth(nextState, replace) {
render((
-
-
-
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
+
{ __DEV__ ?
: null }
), document.getElementById('root'));
diff --git a/src/scenes/Application.js b/src/scenes/Application.js
index dd6c14e11..346848474 100644
--- a/src/scenes/Application.js
+++ b/src/scenes/Application.js
@@ -1,7 +1,8 @@
import React from "react";
+import { observer } from 'mobx-react';
import Helmet from "react-helmet";
-const Application = (props) => {
+const Application = observer((props) => {
return (
{
{ props.children }
);
-};
+});
Application.propTypes = {
children: React.PropTypes.node.isRequired,
diff --git a/src/scenes/Dashboard/Dashboard.js b/src/scenes/Dashboard/Dashboard.js
index 447ae2c70..9cb5b473e 100644
--- a/src/scenes/Dashboard/Dashboard.js
+++ b/src/scenes/Dashboard/Dashboard.js
@@ -1,7 +1,6 @@
import React from 'react';
import { observer } from 'mobx-react';
-import userStore from 'stores/UserStore';
import store from './DashboardStore';
import Flex from 'components/Flex';
@@ -14,10 +13,14 @@ import FullscreenField from 'components/FullscreenField';
import styles from './Dashboard.scss';
-@observer
+@observer(['user'])
class Dashboard extends React.Component {
+ static propTypes = {
+ user: React.PropTypes.object.isRequired,
+ }
+
componentDidMount = () => {
- store.fetchAtlases(userStore.team.id);
+ store.fetchAtlases(this.props.user.team.id);
}
state = {
diff --git a/src/scenes/Home/Home.js b/src/scenes/Home/Home.js
index 82c908531..270503da6 100644
--- a/src/scenes/Home/Home.js
+++ b/src/scenes/Home/Home.js
@@ -1,14 +1,19 @@
import React from 'react';
-import store from 'stores/UserStore';
+import { observer } from 'mobx-react';
import { browserHistory } from 'react-router'
import SlackAuthLink from 'components/SlackAuthLink';
import styles from './Home.scss';
+@observer(['user'])
export default class Home extends React.Component {
+ static propTypes = {
+ user: React.PropTypes.object.isRequired,
+ }
+
componentDidMount = () => {
- if (store.authenticated) {
+ if (this.props.user.authenticated) {
browserHistory.replace('/dashboard');
}
}
diff --git a/src/scenes/SlackAuth/SlackAuth.js b/src/scenes/SlackAuth/SlackAuth.js
index ffb6dbf4f..4362e304c 100644
--- a/src/scenes/SlackAuth/SlackAuth.js
+++ b/src/scenes/SlackAuth/SlackAuth.js
@@ -1,10 +1,15 @@
import React from 'react';
-import store from 'stores/UserStore';
+import { observer } from 'mobx-react';
+
+@observer(['user'])
+class SlackAuth extends React.Component {
+ static propTypes = {
+ user: React.PropTypes.object.isRequired,
+ }
-export default class SlackAuth extends React.Component {
componentDidMount = () => {
const { code, state } = this.props.location.query;
- store.authWithSlack(code, state);
+ this.props.user.authWithSlack(code, state);
}
render() {
@@ -13,3 +18,5 @@ export default class SlackAuth extends React.Component {
);
}
}
+
+export default SlackAuth;
\ No newline at end of file
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js
index fd73bdb52..ac156095c 100644
--- a/src/stores/UserStore.js
+++ b/src/stores/UserStore.js
@@ -1,11 +1,10 @@
-import { observable, action, computed, autorun } from 'mobx';
+import { observable, action, computed } from 'mobx';
import { browserHistory } from 'react-router';
import { client } from 'utils/ApiClient';
-import localforage from 'localforage';
const USER_STORE = 'USER_STORE';
-const store = new class UserStore {
+class UserStore {
@observable user;
@observable team;
@@ -71,12 +70,9 @@ const store = new class UserStore {
this.token = data.token;
this.oauthState = data.oauthState;
}
-}();
+};
-// Persist store to localStorage
-autorun(() => {
- localStorage.setItem(USER_STORE, store.asJson);
-});
-
-
-export default store;
+export default UserStore;
+export {
+ USER_STORE,
+};
diff --git a/src/stores/index.js b/src/stores/index.js
new file mode 100644
index 000000000..88effef75
--- /dev/null
+++ b/src/stores/index.js
@@ -0,0 +1,13 @@
+import UserStore, { USER_STORE } from './UserStore';
+import { autorun } from 'mobx';
+
+const stores = {
+ user: new UserStore(),
+};
+
+// Persist store to localStorage
+autorun(() => {
+ localStorage.setItem(USER_STORE, stores.user.asJson);
+});
+
+export default stores;
\ No newline at end of file
diff --git a/src/utils/ApiClient.js b/src/utils/ApiClient.js
index dcfcaec8d..79a3ada09 100644
--- a/src/utils/ApiClient.js
+++ b/src/utils/ApiClient.js
@@ -1,5 +1,5 @@
import _map from 'lodash/map';
-import store from 'stores/UserStore';
+import stores from 'stores';
import constants from '../constants';
@@ -25,8 +25,8 @@ class ApiClient {
'Content-Type': 'application/json',
'User-Agent': this.userAgent,
});
- if (store.authenticated) {
- headers.set('Authorization', `Bearer ${store.token}`);
+ if (stores.user.authenticated) {
+ headers.set('Authorization', `Bearer ${stores.user.token}`);
}
// Construct request
@@ -48,7 +48,7 @@ class ApiClient {
// Handle 401, log out user
if (response.status === 401) {
- store.logout();
+ stores.user.logout();
}
// Handle failed responses