diff --git a/client/app/axios/axios.ts b/client/app/axios/axios.ts index 1837e4e..ec8c856 100644 --- a/client/app/axios/axios.ts +++ b/client/app/axios/axios.ts @@ -1,4 +1,5 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; +import userStore from '../stores/user-store'; // create our own instance of axios so we can set request headers const ax: AxiosInstance = axios.create(); @@ -9,11 +10,10 @@ ax.interceptors.response.use( return config; }, (error: any) => { - // TODO: log the user out if they get a 401 // if code is unauthorized (401) then logout if already logged in - // if (error.response.status === 401 && store.getState().user.loggedIn) { - // store.dispatch(userActions.logout()); - // } + if (error.response.status === 401 && userStore.user) { + userStore.resetUser(); + } return Promise.reject(error); }, diff --git a/client/app/components/login-button/login-button.tsx b/client/app/components/login-button/login-button.tsx index 47d59a5..ac8b55d 100644 --- a/client/app/components/login-button/login-button.tsx +++ b/client/app/components/login-button/login-button.tsx @@ -1,7 +1,10 @@ import React from 'react'; +import { inject, observer } from 'mobx-react'; +import { UserStore } from '../../stores/user-store'; interface Props { className?: string; + userStore?: UserStore; } interface State {} @@ -12,14 +15,17 @@ const oauthUrl: string = ? '' : 'https://us.battle.net/oauth/authorize?redirect_uri=https://localhost/oauth&scope=wow.profile&client_id=2pfsnmd57svcpr5c93k7zb5zrug29xvp&response_type=code'; +@inject('userStore') +@observer export class LoginButton extends React.Component { + login() { window.open(oauthUrl, '_blank', 'resizeable=yes, height=900, width=1200'); } render() { return ( -
+
diff --git a/client/app/model/user.ts b/client/app/model/user.ts index 7f6132b..db5f342 100644 --- a/client/app/model/user.ts +++ b/client/app/model/user.ts @@ -1,3 +1,8 @@ export interface UserModel { - + access_token: string; + battle_net_id: number; + battletag: string; + id: number; + permissions: string; + token: string; } diff --git a/client/app/pages/user-account/user-account.tsx b/client/app/pages/user-account/user-account.tsx index b36338a..949d5c9 100644 --- a/client/app/pages/user-account/user-account.tsx +++ b/client/app/pages/user-account/user-account.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { ContentContainer } from '../../components'; -import { UserService } from '../../services'; interface Props extends RouteComponentProps {} @@ -9,9 +8,7 @@ interface State {} export class UserAccount extends React.Component { - componentDidMount() { - console.log(UserService.getUser()); - } + componentDidMount() {} render() { return ( diff --git a/client/app/routes.tsx b/client/app/routes.tsx index f070034..b0f15e4 100644 --- a/client/app/routes.tsx +++ b/client/app/routes.tsx @@ -1,7 +1,9 @@ import React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; +import { Provider } from 'mobx-react'; import { Footer, Header } from './components'; import { Forum, Home, NotFound, Oauth, Realms, UserAccount } from './pages'; +import { stores } from './stores/stores'; // styling import './scss/index.scss'; @@ -14,20 +16,22 @@ export class Routes extends React.Component { public render() { return ( - -
-
- - - - - - - - -
-
-
+ + +
+
+ + + + + + + + +
+
+
+
); } } diff --git a/client/app/services/category.service.ts b/client/app/services/category.service.ts index ca3d623..602c2db 100644 --- a/client/app/services/category.service.ts +++ b/client/app/services/category.service.ts @@ -12,7 +12,7 @@ const getCategories = async () => { const res = await axios.get('/api/category'); categoryCache = cloneDeep(res.data.data); return res.data.data; -} +}; export const CategoryService = { getCategories, diff --git a/client/app/services/user.service.ts b/client/app/services/user.service.ts index 1da3c27..c6c3aea 100644 --- a/client/app/services/user.service.ts +++ b/client/app/services/user.service.ts @@ -1,27 +1,16 @@ import axios from '../axios/axios'; -import { UserModel } from '../model'; - -const storeUser = (user: UserModel): void => { - localStorage.setItem('user', JSON.stringify(user)); -} - -const getUser = (): UserModel => { - const u = localStorage.getItem('user'); - return u ? JSON.parse(u) : null; -} +import userStore from '../stores/user-store'; // fetch user and store in local storage const authorize = async (code: string): Promise => { try { const res = await axios.post('/api/battlenet/authorize', { code }); - UserService.storeUser(res.data.data); + userStore.setUser(res.data.data); } catch (e) { console.error(e); } -} +}; export const UserService = { - storeUser, - getUser, authorize, -} +}; diff --git a/client/app/stores/stores.ts b/client/app/stores/stores.ts new file mode 100644 index 0000000..cd89940 --- /dev/null +++ b/client/app/stores/stores.ts @@ -0,0 +1,5 @@ +import userStore from './user-store'; + +export const stores = { + userStore, +}; diff --git a/client/app/stores/user-store.ts b/client/app/stores/user-store.ts new file mode 100644 index 0000000..5dddf13 --- /dev/null +++ b/client/app/stores/user-store.ts @@ -0,0 +1,38 @@ +import { action, observable } from 'mobx'; +import { UserModel } from '../model'; +import { resetAuthorizationHeader, setAuthorizationHeader } from '../axios/axios'; + +export class UserStore { + + @observable user?: UserModel; + + constructor() { + // use timeout or axios won't be defined + setTimeout(() => { + this.getUserFromStorage(); + }); + } + + @action setUser(user: UserModel) { + localStorage.setItem('user', JSON.stringify(user)); + this.getUserFromStorage(); + } + + @action private getUserFromStorage(): void { + const u = localStorage.getItem('user'); + if (u) { + this.user = JSON.parse(u); + setAuthorizationHeader(this.user!.token); + } + } + + // when the user logs out + @action resetUser() { + this.user = undefined; + resetAuthorizationHeader(); + localStorage.removeItem('user'); + } + +} + +export default new UserStore(); diff --git a/client/package.json b/client/package.json index 890462e..e3e7fcb 100644 --- a/client/package.json +++ b/client/package.json @@ -34,6 +34,8 @@ "font-awesome": "^4.7.0", "html-webpack-plugin": "^2.30.1", "lodash": "^4.17.4", + "mobx": "^3.4.1", + "mobx-react": "^4.3.5", "node-sass": "^4.7.2", "normalize.css": "^7.0.0", "postcss-loader": "^2.0.9", diff --git a/client/tsconfig.json b/client/tsconfig.json index 1feeace..8798303 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "experimentalDecorators": true, "target": "es2015", "module": "es2015", "moduleResolution": "node", diff --git a/client/tslint.json b/client/tslint.json index 1f98643..99dc48a 100644 --- a/client/tslint.json +++ b/client/tslint.json @@ -3,6 +3,7 @@ "rules": { "import-name": false, "max-line-length": [true, 140], - "no-unused-variable": [true] + "no-unused-variable": [true], + "variable-name": [false] } } diff --git a/client/yarn.lock b/client/yarn.lock index 7f3df48..a1b71b8 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2830,7 +2830,7 @@ hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" -hoist-non-react-statics@^2.3.0: +hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3833,6 +3833,16 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi dependencies: minimist "0.0.8" +mobx-react@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-4.3.5.tgz#76853f2f2ef4a6f960c374bcd9f01e875929c04c" + dependencies: + hoist-non-react-statics "^2.3.1" + +mobx@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.4.1.tgz#37abe5ee882d401828d9f26c6c1a2f47614bbbef" + ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"