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

319 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 Dashboard from "../pages/dashboard";
2018-08-24 17:03:08 +00:00
import LoginPage from "../pages/login";
2018-09-06 18:13:29 +00:00
import LevelListPage from "../pages/levelList";
2018-09-06 18:05:21 +00:00
import LevelPage from "../pages/level";
import ReviewPage from "../pages/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-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:06:08 +00:00
export default class Application extends React.Component<{}> {
2018-08-24 17:03:08 +00:00
constructor(props: any) {
super(props);
// Load a key from the SessionStorage
2018-09-16 15:16:24 +00:00
const authKey = window.sessionStorage.getItem("sessionToken") || null;
// TODO
const loggedIn = authKey !== null;
2018-08-24 17:03:08 +00:00
this.login = this.login.bind(this);
2018-08-26 14:23:48 +00:00
this.isAuthenticated = this.isAuthenticated.bind(this);
}
2018-09-06 18:13:29 +00:00
getLevels(): ILevel[] {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::getLevels");
2018-08-26 15:12:07 +00:00
// TODO: Actually fetch them from somewhere
2018-09-06 18:13:29 +00:00
const levels = [{
2018-08-26 14:23:48 +00:00
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,
}];
2018-09-06 18:13:29 +00:00
return levels;
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
}
getReviewQueue = (): IVocab[] => {
console.log("STUB: Application::getReviewQueue");
// TODO: Implement
return [{
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
} */] as IVocab[];
}
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,
};
}
getLevelVocab(id: number): 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
// TODO: Don't fetch this when it was already fetched once.
return [{
2018-09-14 14:13:42 +00:00
german: ["Wein"],
hint: "Worte auf '-um' sind meistens NeutrUM",
2018-09-12 17:23:00 +00:00
type: VocabType.NOMEN,
2018-09-14 14:13:42 +00:00
latin: {
grundform: "Vinum",
genitiv: "Vini",
genus: "Neutrum"
},
2018-09-06 18:05:21 +00:00
id: 0
2018-09-12 17:23:00 +00:00
}/* , {
* 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
} */] as IVocab[];
2018-09-06 18:05:21 +00:00
}
2018-09-16 15:16:24 +00:00
login(username: string, password: string): Promise<IUser | {}> {
2018-08-24 17:03:08 +00:00
return new Promise((res, rej) => {
2018-09-15 13:28:27 +00:00
// TODO: First login? Redirect to /welcome
2018-09-16 15:16:24 +00:00
fetch(`${BACKEND_URL}/login`, {
method: "POST",
headers: new Headers({
'Content-Type': "application/json",
}),
body: JSON.stringify({
// NOTE: We will force HTTPS and hash using pbkdf2 on the
// server
username: username,
hash: password,
}),
}).then(data => data.json())
.then((resp) => {
if (resp.error === "0") {
this.setState({
loggedIn: true,
user: resp.data,
});
res(resp.data);
} else {
rej({});
}
});
2018-08-24 17:03:08 +00:00
});
}
2018-08-26 14:23:48 +00:00
// Checks whether the user is logged in
isAuthenticated() {
// TODO: Security?
2018-09-18 16:06:08 +00:00
// TODO: Implement
return true;
2018-08-26 14:23:48 +00:00
}
closeDrawer = () => {
this.setState({
drawerOpen: false,
});
}
drawerButtonState = (show: boolean) => {
// This is required as we would otherwise try to continously update
// the state, resulting in an infinte loop
if (show !== this.state.showDrawerButton) {
this.setState({
showDrawerButton: show,
});
}
}
2018-08-24 17:03:08 +00:00
render() {
2018-08-26 14:23:48 +00:00
return <BrowserRouter
2018-08-26 17:27:21 +00:00
basename="/app/">
2018-08-26 14:23:48 +00:00
<div className="flex">
2018-09-18 16:06:08 +00:00
<Drawer />
2018-08-26 14:23:48 +00:00
<div className="content">
<Route exact path="/" component={() => <Redirect to="/login" />} />
<Route exact path="/login" component={() => {
return <LoginPage loggedIn={this.state.loggedIn} login={this.login} />
}} />
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"
component={() => <LevelListPage
levels={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}
drawerButtonState={this.drawerButtonState}
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>
</div>
</BrowserRouter>;
2018-08-24 17:03:08 +00:00
}
};