fix: Multiple API calls when bypassing /login

This commit is contained in:
Alexander Polynomdivision 2018-09-23 16:30:14 +02:00
parent 08cd51c2a3
commit be7a616fb5
7 changed files with 41 additions and 13 deletions

View File

@ -2,6 +2,7 @@ import { IVocab, IReviewCard } from "../models/vocab";
import { IUser } from "../models/user"; import { IUser } from "../models/user";
import { ILevel } from "../models/level"; import { ILevel } from "../models/level";
import { IReviewMetadata } from "../models/review"; import { IReviewMetadata } from "../models/review";
import { TopTen } from "../models/learner";
export const SET_DRAWER = "SET_DRAWER"; export const SET_DRAWER = "SET_DRAWER";
export function setDrawer(state: boolean) { export function setDrawer(state: boolean) {
@ -161,7 +162,7 @@ export function setDashboardNLLoading(state: boolean) {
}; };
export const SET_TOP_TEN = "SET_TOP_TEN"; export const SET_TOP_TEN = "SET_TOP_TEN";
export function setTopTen(topTen: ILearner[]) { export function setTopTen(topTen: TopTen[]) {
return { return {
type: SET_TOP_TEN, type: SET_TOP_TEN,
topTen, topTen,
@ -175,3 +176,11 @@ export function setDashboardTTLoading(state: boolean) {
state, state,
}; };
}; };
export const SET_DID_LOGIN = "SET_DID_LOGIN";
export function setDidLogin(state: boolean) {
return {
type: SET_DID_LOGIN,
state,
};
};

View File

@ -3,7 +3,7 @@ import * as React from "react";
import { BrowserRouter, Route, Redirect } from "react-router-dom"; import { BrowserRouter, Route, Redirect } from "react-router-dom";
import AuthRoute from "../security/AuthRoute"; import AuthRoute from "../security/AuthRoute";
import { setSessionToken, removeSessionToken } from "../security/Token"; import { setSessionToken, removeSessionToken, getSessionToken } from "../security/Token";
import Dashboard from "../containers/Dashboard"; import Dashboard from "../containers/Dashboard";
import LoginPage from "../containers/LoginPage"; import LoginPage from "../containers/LoginPage";
@ -29,13 +29,21 @@ interface IProps {
user: IUser; user: IUser;
setAuthenticated: (status: boolean) => void; setAuthenticated: (status: boolean) => void;
setDidLogin: (status: boolean) => void;
setUser: (user: IUser) => void; setUser: (user: IUser) => void;
}; };
// TODO: Replace the sessionStorage with localStorage? // TODO: Replace the sessionStorage with localStorage?
// TODO: Cache API-Calls
// TODO: When mounting without a login, check if the sessionToken is still valid
export default class Application extends React.Component<IProps> { export default class Application extends React.Component<IProps> {
componentDidMount() {
// TODO: Ask the server if our session is still valid
// TODO: When asking the server if our session is still valid, a spinner
// should be shown
if (getSessionToken(window) !== null) {
this.props.setAuthenticated(true);
}
}
getLevels(): Promise<ILevel[]> { getLevels(): Promise<ILevel[]> {
console.log("STUB: Application::getLevels"); console.log("STUB: Application::getLevels");
@ -143,8 +151,6 @@ export default class Application extends React.Component<IProps> {
}).then(resp => resp.json(), }).then(resp => resp.json(),
err => rej(err)) err => rej(err))
.then(data => { .then(data => {
console.log(data);
if (data.error === "0") { if (data.error === "0") {
res(data.data.topTen); res(data.data.topTen);
} else { } else {
@ -164,8 +170,6 @@ export default class Application extends React.Component<IProps> {
}).then(resp => resp.json(), }).then(resp => resp.json(),
err => rej(err)) err => rej(err))
.then(data => { .then(data => {
console.log(data);
if (data.error === "0") { if (data.error === "0") {
res(data.data); res(data.data);
} else { } else {
@ -215,6 +219,7 @@ export default class Application extends React.Component<IProps> {
if (resp.error === "0") { if (resp.error === "0") {
// Successful login // Successful login
this.props.setUser(resp.data); this.props.setUser(resp.data);
this.props.setDidLogin(true);
setSessionToken(window, resp.data.sessionToken); setSessionToken(window, resp.data.sessionToken);
this.props.setAuthenticated(true); this.props.setAuthenticated(true);
@ -234,8 +239,6 @@ export default class Application extends React.Component<IProps> {
// Checks whether the user is logged in // Checks whether the user is logged in
isAuthenticated = () => { isAuthenticated = () => {
// TODO: Security?
// TODO: Implement
return this.props.authenticated; return this.props.authenticated;
} }

View File

@ -4,7 +4,7 @@ import { IUser } from "../models/user";
import Application from "../components/app"; import Application from "../components/app";
import { setAuthenticated, setUser } from "../actions"; import { setAuthenticated, setUser, setDidLogin } from "../actions";
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
@ -15,6 +15,7 @@ const mapStateToProps = state => {
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
setAuthenticated: (status: boolean) => dispatch(setAuthenticated(status)), setAuthenticated: (status: boolean) => dispatch(setAuthenticated(status)),
setDidLogin: (state: boolean) => dispatch(setDidLogin(state)),
setUser: (user: IUser) => dispatch(setUser(user)), setUser: (user: IUser) => dispatch(setUser(user)),
}; };
}; };

View File

@ -10,6 +10,7 @@ const mapStateToProps = state => {
snackOpen: state.login.snackOpen, snackOpen: state.login.snackOpen,
snackMsg: state.login.snackMsg, snackMsg: state.login.snackMsg,
authenticated: state.authenticated, authenticated: state.authenticated,
didLogin: state.didLogin,
}; };
}; };
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {

View File

@ -18,6 +18,7 @@ interface IProps {
authenticated: boolean; authenticated: boolean;
history: any; history: any;
didLogin: boolean;
setLoading: (state: boolean) => void; setLoading: (state: boolean) => void;
setSnackbar: (state: boolean, msg: string) => void; setSnackbar: (state: boolean, msg: string) => void;
loading: boolean; loading: boolean;
@ -54,7 +55,11 @@ const LoginPageWithRouter = withRouter(
componentDidMount() { componentDidMount() {
// If we're already authenticated, we can skip the login page // If we're already authenticated, we can skip the login page
if (this.props.authenticated) { // NOTE: The '!this.props.didLogin' is here, as the Component gets
// remounted, when the auth status changes. Thus we would
// redirect to /dashboard, redirect back to /welcome
// (or /dashboard again) and cause mulitple API calls!
if (this.props.authenticated && !this.props.didLogin) {
this.props.history.push("/dashboard"); this.props.history.push("/dashboard");
} }
} }

View File

@ -11,6 +11,7 @@ interface IState {
scorePopoverOpen: boolean; scorePopoverOpen: boolean;
drawerButton: boolean; drawerButton: boolean;
authenticated: boolean; authenticated: boolean;
didLogin: boolean;
// TODO: Rework this // TODO: Rework this
user: IUser | {}, user: IUser | {},
@ -64,6 +65,7 @@ const initialState: IState = {
// Should we show the button to open the drawer? // Should we show the button to open the drawer?
drawerButton: true, drawerButton: true,
scorePopoverOpen: false, scorePopoverOpen: false,
didLogin: false,
// Is the user authenticated? // Is the user authenticated?
// TODO: Set this to false // TODO: Set this to false
@ -228,7 +230,6 @@ export function LateinicusApp(state: IState = initialState, action: any) {
}), }),
}); });
case Actions.SET_TOP_TEN: case Actions.SET_TOP_TEN:
console.log(action.topTen);
return Object.assign({}, state, { return Object.assign({}, state, {
topTen: action.topTen, topTen: action.topTen,
}); });
@ -238,6 +239,10 @@ export function LateinicusApp(state: IState = initialState, action: any) {
loadingTT: action.state, loadingTT: action.state,
}), }),
}); });
case Actions.SET_DID_LOGIN:
return Object.assign({}, state, {
didLogin: state,
});
default: default:
// Ignore the initialization call to the reducer. By that we can // Ignore the initialization call to the reducer. By that we can
// catch all actions that are not implemented // catch all actions that are not implemented

View File

@ -2,6 +2,10 @@ export function setSessionToken(window: Window, token: string) {
window.sessionStorage.setItem("sessionToken", token); window.sessionStorage.setItem("sessionToken", token);
}; };
export function getSessionToken(window: Window) {
return window.sessionStorage.getItem("sessionToken");
}
export function removeSessionToken(window: Window) { export function removeSessionToken(window: Window) {
window.sessionStorage.removeItem("sessionToken"); window.sessionStorage.removeItem("sessionToken");
} }