Separated user and auth stores

This commit is contained in:
Jori Lallo
2017-05-29 19:08:03 -07:00
parent 98a5283e27
commit 0d87d6abf5
12 changed files with 191 additions and 143 deletions

View File

@@ -0,0 +1,100 @@
// @flow
import { observable, action, computed, autorunAsync } from 'mobx';
import invariant from 'invariant';
import { client } from 'utils/ApiClient';
import UserStore from 'stores/UserStore';
import type { User, Team } from 'types';
const AUTH_STORE = 'AUTH_STORE';
class AuthStore {
@observable user: ?User;
@observable team: ?Team;
@observable token: ?string;
@observable oauthState: string;
@observable isLoading: boolean = false;
/* Computed */
@computed get authenticated(): boolean {
return !!this.token;
}
@computed get asJson(): string {
return JSON.stringify({
user: this.user,
team: this.team,
token: this.token,
oauthState: this.oauthState,
});
}
/* Actions */
@action logout = (cb: Function) => {
this.user = null;
this.token = null;
cb();
};
@action getOauthState = () => {
const state = Math.random().toString(36).substring(7);
this.oauthState = state;
return this.oauthState;
};
@action authWithSlack = async (code: string, state: string) => {
if (state !== this.oauthState) {
return {
success: false,
};
}
let res;
try {
res = await client.post('/auth.slack', { code });
} catch (e) {
return {
success: false,
};
}
invariant(
res && res.data && res.data.user && res.data.team && res.data.accessToken,
'All values should be available'
);
this.user = res.data.user;
this.team = res.data.team;
this.token = res.data.accessToken;
return {
success: true,
};
};
getUserStore(): UserStore {
invariant(
this.user && this.team,
'Tried to create a user store without data'
);
return new UserStore({
user: this.user,
team: this.team,
});
}
constructor() {
// Rehydrate
const data = JSON.parse(localStorage.getItem(AUTH_STORE) || '{}');
this.user = data.user;
this.team = data.team;
this.token = data.token;
this.oauthState = data.oauthState;
autorunAsync(() => {
localStorage.setItem(AUTH_STORE, this.asJson);
});
}
}
export default AuthStore;

View File

@@ -2,6 +2,7 @@
import { observable, action, runInAction, ObservableArray } from 'mobx';
import ApiClient, { client } from 'utils/ApiClient';
import _ from 'lodash';
import invariant from 'invariant';
import stores from 'stores';
import Collection from 'models/Collection';
@@ -26,6 +27,7 @@ class CollectionsStore {
const res = await this.client.post('/collections.list', {
id: this.teamId,
});
invariant(res && res.data, 'Collection list not available');
const { data } = res;
runInAction('CollectionsStore#fetch', () => {
this.data.replace(

View File

@@ -1,5 +1,5 @@
// @flow
import { observable, action, computed } from 'mobx';
import { observable, action, computed, autorunAsync } from 'mobx';
const UI_STORE = 'UI_STORE';
@@ -24,8 +24,11 @@ class UiStore {
// Rehydrate
const data = JSON.parse(localStorage.getItem(UI_STORE) || '{}');
this.sidebar = data.sidebar;
autorunAsync(() => {
localStorage.setItem(UI_STORE, this.asJson);
});
}
}
export default UiStore;
export { UI_STORE };

View File

@@ -1,87 +1,32 @@
// @flow
import { observable, action, computed } from 'mobx';
import invariant from 'invariant';
import { client } from 'utils/ApiClient';
import { observable, computed } from 'mobx';
import type { User, Team } from 'types';
const USER_STORE = 'USER_STORE';
type Options = {
user: User,
team: Team,
};
class UserStore {
@observable user: ?User;
@observable team: ?Team;
@observable token: ?string;
@observable oauthState: string;
@observable user: User;
@observable team: Team;
@observable isLoading: boolean = false;
/* Computed */
@computed get authenticated(): boolean {
return !!this.token;
}
@computed get asJson(): string {
return JSON.stringify({
user: this.user,
team: this.team,
token: this.token,
oauthState: this.oauthState,
});
}
/* Actions */
@action logout = (cb: Function) => {
this.user = null;
this.token = null;
cb();
};
@action getOauthState = () => {
const state = Math.random().toString(36).substring(7);
this.oauthState = state;
return this.oauthState;
};
@action authWithSlack = async (code: string, state: string) => {
if (state !== this.oauthState) {
return {
success: false,
};
}
let res;
try {
res = await client.post('/auth.slack', { code });
} catch (e) {
return {
success: false,
};
}
invariant(
res && res.data && res.data.user && res.data.team && res.data.accessToken,
'All values should be available'
);
this.user = res.data.user;
this.team = res.data.team;
this.token = res.data.accessToken;
return {
success: true,
};
};
constructor() {
constructor(options: Options) {
// Rehydrate
const data = JSON.parse(localStorage.getItem(USER_STORE) || '{}');
this.user = data.user;
this.team = data.team;
this.token = data.token;
this.oauthState = data.oauthState;
this.user = options.user;
this.team = options.team;
}
}
export default UserStore;
export { USER_STORE };

View File

@@ -1,20 +1,13 @@
// @flow
import { autorunAsync } from 'mobx';
import UserStore, { USER_STORE } from './UserStore';
import UiStore, { UI_STORE } from './UiStore';
import AuthStore from './AuthStore';
import UiStore from './UiStore';
import ErrorsStore from './ErrorsStore';
const stores = {
user: new UserStore(),
user: null, // Including for Layout
auth: new AuthStore(),
ui: new UiStore(),
errors: new ErrorsStore(),
};
// Persist stores to localStorage
// TODO: move to store constructors
autorunAsync(() => {
localStorage.setItem(USER_STORE, stores.user.asJson);
localStorage.setItem(UI_STORE, stores.ui.asJson);
});
export default stores;