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

441 lines
16 KiB
TypeScript
Raw Normal View History

2018-08-24 17:03:08 +00:00
import * as React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
2018-08-26 17:27:21 +00:00
import SwipeableDrawer from "@material-ui/core/SwipeableDrawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Divider from "@material-ui/core/Divider";
import Avatar from "@material-ui/core/Avatar";
import MenuIcon from "@material-ui/icons/Menu";
2018-08-26 17:27:21 +00:00
import SettingsIcon from "@material-ui/icons/Settings";
import PersonIcon from "@material-ui/icons/Person";
import InfoIcon from "@material-ui/icons/Info";
2018-09-14 15:24:26 +00:00
import HomeIcon from "@material-ui/icons/Home";
import BookIcon from "@material-ui/icons/Book";
import ViewWeekIcon from "@material-ui/icons/ViewWeek";
2018-08-24 17:03:08 +00:00
import { BrowserRouter, Route, Redirect, Link } 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-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-08-24 17:03:08 +00:00
interface IState {
loggedIn: boolean;
2018-08-26 17:27:21 +00:00
lastReview: IReviewMetadata;
2018-08-26 17:27:21 +00:00
drawerOpen: boolean;
showDrawerButton: boolean;
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-08-24 17:03:08 +00:00
export default class Application extends React.Component<{}, IState> {
constructor(props: any) {
super(props);
// Load a key from the SessionStorage
const authKey = window.sessionStorage.getItem("authKey") || null;
// TODO
const loggedIn = authKey !== null;
// TODO: Fetch the last review
2018-08-24 17:03:08 +00:00
this.state = {
loggedIn,
lastReview: {
correct: 0,
wrong: 0,
},
2018-09-06 18:05:21 +00:00
drawerOpen: false,
showDrawerButton: true,
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
return this.state.lastReview;
}
setLastReview = (meta: IReviewMetadata) => {
// 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-08-24 17:03:08 +00:00
login(username: string, password: string): Promise<boolean> {
2018-09-14 16:53:01 +00:00
console.log("STUB: Application::login");
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-08-24 17:03:08 +00:00
// TODO
2018-08-26 14:23:48 +00:00
this.setState({
loggedIn: true
});
2018-08-24 17:03:08 +00:00
res();
});
}
2018-08-26 14:23:48 +00:00
// Checks whether the user is logged in
isAuthenticated() {
// TODO: Security?
return this.state.loggedIn === true;
}
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">
<AppBar position="static">
<Toolbar>
{
(this.isAuthenticated() && this.state.showDrawerButton) ? (
2018-08-26 17:27:21 +00:00
<IconButton
color="inherit"
onClick={() => this.setState({ drawerOpen: true })}>
<MenuIcon />
</IconButton>
) : undefined
}
2018-08-26 14:23:48 +00:00
<Typography className="flex" variant="title" color="inherit">
Lateinicus
2018-09-14 16:53:01 +00:00
</Typography>
2018-08-26 14:23:48 +00:00
</Toolbar>
</AppBar>
2018-08-26 17:27:21 +00:00
<SwipeableDrawer
anchor="left"
open={this.state.drawerOpen}
onClose={() => this.setState({ drawerOpen: false, })}
onOpen={() => this.setState({ drawerOpen: true })}>
<List component="nav">
<ListItem>
{/* TODO: Replace with the actual username */}
<Avatar alt="{Username}" style={{ width: 80, height: 80 }} src="https://avatarfiles.alphacoders.com/105/105250.jpg" />
<ListItemText primary="{Username}" />
</ListItem>
<Divider />
<ListItem button>
<ListItemIcon>
<PersonIcon />
</ListItemIcon>
<ListItemText primary="Profil" />
</ListItem>
<ListItem button>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary="Einstellungen" />
</ListItem>
<Divider />
<ListItem
component={Link}
to="/dashboard"
onClick={this.closeDrawer}
button>
2018-09-14 15:24:26 +00:00
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem
component={Link}
to="/review/queue"
onClick={this.closeDrawer}
button>
2018-09-14 15:24:26 +00:00
<ListItemIcon>
<BookIcon />
</ListItemIcon>
2018-09-15 15:37:08 +00:00
<ListItemText>
Vokabeln üben
</ListItemText>
2018-08-26 17:27:21 +00:00
</ListItem>
<ListItem
component={Link}
to="/levelList"
onClick={this.closeDrawer}
button>
2018-09-14 15:24:26 +00:00
<ListItemIcon>
<ViewWeekIcon />
</ListItemIcon>
2018-09-06 18:05:21 +00:00
<ListItemText>
Levelübersicht
</ListItemText>
2018-08-26 17:27:21 +00:00
</ListItem>
<Divider />
<ListItem button onClick={() => {
// Remove the auth token from the SessionStorage
window.sessionStorage.removeItem("authKey");
// Set the loggedIn State to false
this.setState({
loggedIn: false,
// In case the drawer was open
drawerOpen: false,
});
}}>
<ListItemText>
Abmelden
</ListItemText>
</ListItem>
<Divider />
2018-08-26 17:27:21 +00:00
<ListItem button onClick={() => window.location = "https://gitlab.com/Polynomdivision/Lateinicus/tree/master"}>
<ListItemIcon>
<InfoIcon />
</ListItemIcon>
<ListItemText primary="Über" />
</ListItem>
</List>
</SwipeableDrawer>
2018-08-24 17:03:08 +00:00
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
}
};