This repository has been archived on 2022-03-12. You can view files and clone it, but cannot push or open issues or pull requests.
Lateinicus/src/components/app.tsx

320 lines
11 KiB
TypeScript
Raw Normal View History

2018-08-24 17:03:08 +00:00
import * as React from "react";
2018-09-18 16:06:08 +00:00
import { BrowserRouter, Route, Redirect } from "react-router-dom";
2018-08-26 14:23:48 +00:00
import AuthRoute from "../security/AuthRoute";
import { setSessionToken, removeSessionToken } from "../security/Token";
2018-08-26 14:23:48 +00:00
import Dashboard from "../pages/dashboard";
2018-09-18 16:59:15 +00:00
import LoginPage from "../containers/LoginPage";
import LevelListPage from "../containers/LevelList";
2018-09-18 18:20:26 +00:00
import LevelPage from "../containers/LevelPage";
import ReviewPage from "../containers/Review";
2018-09-12 17:23:00 +00:00
import SummaryPage from "../pages/summary";
2018-09-15 13:28:27 +00:00
import WelcomePage from "../pages/intro";
2018-08-26 14:23:48 +00:00
2018-09-18 16:06:08 +00:00
import Drawer from "../containers/Drawer";
2018-09-16 15:16:24 +00:00
import { BACKEND_URL } from "../config";
2018-09-06 18:13:29 +00:00
import { ILevel } from "../models/level";
2018-09-14 16:53:01 +00:00
import { ILearner } from "../models/learner";
2018-09-12 17:23:00 +00:00
import { IVocab, VocabType } from "../models/vocab";
import { IReviewMetadata, ReviewType } from "../models/review";
2018-09-16 15:16:24 +00:00
import { IUser } from "../models/user";
2018-08-24 17:03:08 +00:00
2018-09-18 16:59:15 +00:00
interface IProps {
authenticated: boolean;
2018-09-18 16:59:15 +00:00
setAuthenticated: (status: boolean) => void;
setUser: (user: IUser) => void;
};
2018-09-14 16:53:01 +00:00
// TODO: Replace the sessionStorage with localStorage?
// TODO: Cache API-Calls
2018-09-16 15:16:24 +00:00
// TODO: When mounting without a login, check if the sessionToken is still valid
2018-09-18 16:59:15 +00:00
export default class Application extends React.Component<IProps> {
2018-09-19 16:00:38 +00:00
getLevels(): Promise<ILevel[]> {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getLevels");
2018-08-26 14:23:48 +00:00
2018-09-19 16:00:38 +00:00
return new Promise((res, rej) => {
// TODO: Actually fetch them from somewhere
setTimeout(() => {
const levels = [{
name: "Der Bauer auf dem Feld",
desc: "So fängt alles an: Du bist ein einfacher Bauer und musst dich die Karriereleiter mit deinen freshen Latein-Skills hinaufarbeiten",
level: 1,
done: true,
}, {
name: "???",
desc: "Warum schreibe ich überhaupt was?dsd dddddddddddddddddddddd",
level: 2,
done: false,
}];
res(levels);
}, 2000);
});
2018-08-24 17:03:08 +00:00
}
getLastReview = (): IReviewMetadata => {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getLastReview");
2018-09-12 17:23:00 +00:00
// TODO: Actually fetch this
2018-09-18 16:06:08 +00:00
// TODO: Stub
return {} as IReviewMetadata;
}
setLastReview = (meta: IReviewMetadata) => {
2018-09-16 15:16:24 +00:00
console.log("STUB: Application::setLastReview");
// TODO: Send this to the server
this.setState({
lastReview: meta,
});
2018-09-12 17:23:00 +00:00
}
2018-09-19 16:06:59 +00:00
getReviewQueue = (): Promise<IVocab[]> => {
console.log("STUB: Application::getReviewQueue");
// TODO: Implement
2018-09-19 16:06:59 +00:00
return new Promise((res, rej) => {
setTimeout(() => {
res([
{
german: ["Wein"],
hint: "Worte auf '-um' sind meistens NeutrUM",
type: VocabType.NOMEN,
latin: {
grundform: "Vinum",
genitiv: "Vini",
genus: "Neutrum"
},
id: 0
}/* , {
* latin: "Vici",
* german: "<Wortbedeutung>",
* hint: "Wird \"Viki\" und nicht \"Vichi\" ausgesprochen",
* mnemonic: "Merk dir das Wort mit Caesars berühmten Worten: \"Veni Vidi Vici\"; Er kam, sah und siegte",
* type: VocabType.NOMEN,
* id: 2
}, {
* latin: "fuga",
* german: "Flucht",
* hint: "Worte auf \"-a\" sind FeminA",
* type: VocabType.NOMEN,
* id: 3
} */
]);
}, 2000);
});
}
2018-09-06 18:05:21 +00:00
getLearners(): ILearner[] {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getLearners");
// TODO: Implement
return [{
username: "Polynomdivision",
level: 5,
score: 400,
}, {
username: "Polynomdivision2",
level: 3,
score: 500,
}, {
username: "Der eine Typ",
level: 7,
score: 100,
}];
}
getTopTenLearners(): ILearner[] {
console.log("STUB: Application::getTopTenLearners");
// TODO: Implement
2018-08-26 15:12:07 +00:00
return [{
username: "Polynomdivision",
level: 5,
score: 400,
}, {
username: "Polynomdivision2",
level: 3,
score: 500,
}, {
username: "Der eine Typ",
level: 7,
score: 100,
}];
}
2018-09-06 18:13:29 +00:00
getNextLevel(): ILevel {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getNextLevel");
2018-09-06 18:05:21 +00:00
// TODO: Actually fetch data
return {
name: "???",
desc: "Warum schreibe ich überhaupt was?dsd dddddddddddddddddddddd",
level: 2,
done: false,
};
}
2018-09-18 18:20:26 +00:00
getLevelVocab(id: number): Promise<IVocab[]> {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getLevelVocab");
2018-09-06 18:05:21 +00:00
// TODO: Actually implement this
2018-09-18 18:20:26 +00:00
return new Promise((res, rej) => {
setTimeout(() => {
res([{
german: ["Wein"],
hint: "Worte auf '-um' sind meistens NeutrUM",
type: VocabType.NOMEN,
latin: {
grundform: "Vinum",
genitiv: "Vini",
genus: "Neutrum"
},
id: 0
}/* , {
* latin: "Vici",
* german: "<Wortbedeutung>",
* hint: "Wird \"Viki\" und nicht \"Vichi\" ausgesprochen",
* mnemonic: "Merk dir das Wort mit Caesars berühmten Worten: \"Veni Vidi Vici\"; Er kam, sah und siegte",
* type: VocabType.NOMEN,
* id: 2
}, {
* latin: "fuga",
* german: "Flucht",
* hint: "Worte auf \"-a\" sind FeminA",
* type: VocabType.NOMEN,
* id: 3
} */]);
}, 2000);
});
2018-09-06 18:05:21 +00:00
}
2018-09-18 16:59:15 +00:00
login = (username: string, password: string): Promise<IUser | {}> => {
2018-08-24 17:03:08 +00:00
return new Promise((res, rej) => {
2018-09-16 15:16:24 +00:00
fetch(`${BACKEND_URL}/login`, {
method: "POST",
headers: new Headers({
2018-09-18 16:59:15 +00:00
"Content-Type": "application/json",
2018-09-16 15:16:24 +00:00
}),
body: JSON.stringify({
2018-09-18 16:59:15 +00:00
// NOTE: We will force HTTPS, so this should not be a
// problem
username,
password,
2018-09-16 15:16:24 +00:00
}),
}).then(data => data.json())
2018-09-18 16:59:15 +00:00
.then(resp => {
2018-09-16 15:16:24 +00:00
if (resp.error === "0") {
2018-09-18 16:59:15 +00:00
// Successful login
this.props.setUser(resp.data);
setSessionToken(window, resp.data.sessionToken);
2018-09-16 15:16:24 +00:00
res(resp.data);
} else {
rej({});
}
});
2018-08-24 17:03:08 +00:00
});
}
logout = () => {
// TODO: Tell the server that we're logging ourselves out
removeSessionToken(window);
this.props.setAuthenticated(false);
}
2018-08-26 14:23:48 +00:00
// Checks whether the user is logged in
2018-09-18 16:59:15 +00:00
isAuthenticated = () => {
2018-08-26 14:23:48 +00:00
// TODO: Security?
2018-09-18 16:06:08 +00:00
// TODO: Implement
return this.props.authenticated;
2018-08-26 14:23:48 +00:00
}
2018-08-24 17:03:08 +00:00
render() {
// TODO: Show a spinner before mounting the routes, so that we can
// check if were authenticated before doing any requests
2018-08-26 14:23:48 +00:00
return <BrowserRouter
2018-08-26 17:27:21 +00:00
basename="/app/">
<div className="flex" >
<Drawer logout={this.logout} />
2018-08-26 14:23:48 +00:00
<div className="content">
<Route exact path="/" component={() => <Redirect to="/login" />} />
<Route exact path="/login" component={() => {
2018-09-18 16:59:15 +00:00
return <LoginPage login={this.login} />
2018-08-26 14:23:48 +00:00
}} />
2018-08-26 15:12:07 +00:00
<AuthRoute
isAuth={this.isAuthenticated}
path="/dashboard"
2018-09-12 17:23:00 +00:00
component={() => {
return <Dashboard
nextLevel={this.getNextLevel}
getLastReview={this.getLastReview}
2018-09-14 16:53:01 +00:00
getTopTen={this.getTopTenLearners} />
2018-09-12 17:23:00 +00:00
}} />
2018-09-15 13:28:27 +00:00
<AuthRoute
isAuth={this.isAuthenticated}
path="/welcome"
component={() => {
return <WelcomePage />
}} />
2018-08-26 15:12:07 +00:00
<AuthRoute
isAuth={this.isAuthenticated}
2018-09-06 18:05:21 +00:00
path="/levelList"
2018-09-19 16:00:38 +00:00
component={() => <LevelListPage
getLevels={this.getLevels} />} />
2018-09-06 18:05:21 +00:00
{/*We cannot use AuthRoute here, because match is undefined otherwise*/}
<Route
path="/level/:id"
component={({ match }) => {
if (this.isAuthenticated()) {
return <LevelPage
id={match.params.id}
levelVocab={this.getLevelVocab}
drawerButtonState={this.drawerButtonState}
setLastReview={this.setLastReview} />;
2018-09-06 18:05:21 +00:00
} else {
return <Redirect to="/login" />;
}
}} />
<Route
path="/review/level/:id"
component={({ match }) => {
if (this.isAuthenticated()) {
return <ReviewPage
reviewType={ReviewType.LEVEL}
levelId={match.params.id}
vocabByLevel={this.getLevelVocab}
setLastReview={this.setLastReview} />;
} else {
return <Redirect to="/login" />;
}
}} />
<AuthRoute
isAuth={this.isAuthenticated}
path="/review/queue"
component={() => {
return <ReviewPage
reviewType={ReviewType.QUEUE}
vocabByQueue={this.getReviewQueue}
drawerButtonState={this.drawerButtonState}
setLastReview={this.setLastReview} />;
}} />
2018-09-12 17:23:00 +00:00
<AuthRoute
isAuth={this.isAuthenticated}
path="/review/summary"
component={() => {
return <SummaryPage
reviewMeta={this.getLastReview} />
2018-09-12 17:23:00 +00:00
}} />
2018-08-26 14:23:48 +00:00
</div>
2018-09-18 16:59:15 +00:00
</div >
</BrowserRouter >;
2018-08-24 17:03:08 +00:00
}
};