2018-09-12 13:15:55 +00:00
|
|
|
import * as React from "react";
|
|
|
|
|
|
|
|
import Card from "@material-ui/core/Card";
|
2018-09-12 17:23:00 +00:00
|
|
|
import CardContent from "@material-ui/core/CardContent";
|
2018-09-12 13:15:55 +00:00
|
|
|
import TextField from "@material-ui/core/TextField";
|
|
|
|
import Grid from "@material-ui/core/Grid";
|
|
|
|
import Button from "@material-ui/core/Button";
|
2018-09-12 17:23:00 +00:00
|
|
|
import Typography from "@material-ui/core/Typography";
|
|
|
|
import Popover from "@material-ui/core/Popover";
|
|
|
|
import Paper from "@material-ui/core/Paper";
|
2018-09-12 13:15:55 +00:00
|
|
|
|
2018-09-12 17:23:00 +00:00
|
|
|
import { Redirect } from "react-router-dom";
|
|
|
|
|
|
|
|
import { IVocab, ReviewMode, VocabType } from "../models/vocab";
|
2018-09-15 12:26:22 +00:00
|
|
|
import { ReviewType } from "../models/review";
|
2018-09-12 13:15:55 +00:00
|
|
|
|
2018-09-14 15:02:50 +00:00
|
|
|
import { levW } from "../algorithms/levenshtein";
|
|
|
|
import { LEVENSHTEIN_MAX_DISTANCE } from "../config";
|
|
|
|
|
2018-09-12 13:15:55 +00:00
|
|
|
interface IProps {
|
2018-09-15 12:26:22 +00:00
|
|
|
levelId?: number;
|
|
|
|
vocabByLevel?: (level: number) => IVocab[];
|
|
|
|
vocabByQueue?: () => IVocab[];
|
|
|
|
|
|
|
|
reviewType: ReviewType;
|
|
|
|
|
|
|
|
drawerButtonState: (state: boolean) => void;
|
2018-09-12 13:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
interface IState {
|
|
|
|
input: string;
|
|
|
|
current: number;
|
2018-09-12 17:23:00 +00:00
|
|
|
|
|
|
|
toSummary: boolean;
|
|
|
|
|
|
|
|
popoverOpen: boolean;
|
|
|
|
popoverText: string;
|
|
|
|
popoverColor: string;
|
2018-09-12 13:15:55 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 17:23:00 +00:00
|
|
|
export default class ReviewPage extends React.Component<IProps, IState> {
|
2018-09-12 13:15:55 +00:00
|
|
|
private vocab: IVocab[] = [];
|
2018-09-12 17:23:00 +00:00
|
|
|
// Used for positioning the popover
|
|
|
|
private buttonRef: HTMLButtonElement;
|
|
|
|
|
2018-09-12 13:15:55 +00:00
|
|
|
constructor(props: any) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
input: "",
|
|
|
|
current: 0,
|
2018-09-12 17:23:00 +00:00
|
|
|
|
|
|
|
toSummary: false,
|
|
|
|
|
|
|
|
popoverOpen: false,
|
|
|
|
popoverText: "",
|
|
|
|
popoverColor: "red",
|
2018-09-12 13:15:55 +00:00
|
|
|
};
|
|
|
|
|
2018-09-15 12:26:22 +00:00
|
|
|
// Hide the drawer button
|
|
|
|
this.props.drawerButtonState(false);
|
|
|
|
|
|
|
|
// Get the correct vocabulary
|
|
|
|
const { reviewType, vocabByLevel, levelId, vocabByQueue } = this.props;
|
|
|
|
switch (reviewType) {
|
|
|
|
case ReviewType.LEVEL:
|
|
|
|
if (!vocabByLevel || !levelId) {
|
|
|
|
alert("[ReviewPage::constructor] vocabByLevel or levelId undefined");
|
|
|
|
} else {
|
|
|
|
this.vocab = vocabByLevel(levelId);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case ReviewType.QUEUE:
|
|
|
|
if (!vocabByQueue) {
|
|
|
|
alert("[ReviewPage::constructor] vocabByQueue undefined");
|
|
|
|
} else {
|
|
|
|
this.vocab = vocabByQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2018-09-12 13:15:55 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 17:23:00 +00:00
|
|
|
currentVocab = () => {
|
2018-09-12 13:15:55 +00:00
|
|
|
return this.vocab[this.state.current];
|
|
|
|
}
|
|
|
|
|
|
|
|
checkInput = () => {
|
|
|
|
const current = this.currentVocab();
|
|
|
|
|
2018-09-14 14:13:42 +00:00
|
|
|
// Check if the given answer is somewhere in the german words
|
2018-09-14 15:02:50 +00:00
|
|
|
const { input } = this.state;
|
|
|
|
const german = current.german.map((str) => str.toLowerCase());
|
|
|
|
const dists = german.map((ger) => levW(input.toLowerCase(), ger));
|
|
|
|
const minDist = Math.min(...dists);
|
2018-09-14 14:13:42 +00:00
|
|
|
|
2018-09-12 13:15:55 +00:00
|
|
|
// Check if the user's answer was correct
|
2018-09-14 15:02:50 +00:00
|
|
|
if (minDist === 0) {
|
|
|
|
// TODO: Show it's correct?
|
2018-09-12 13:15:55 +00:00
|
|
|
// Show the next vocab word
|
|
|
|
if (this.state.current + 1 >= this.vocab.length) {
|
2018-09-12 17:23:00 +00:00
|
|
|
// TODO: Set some data that the summary screen will show
|
|
|
|
this.setState({
|
|
|
|
toSummary: true,
|
|
|
|
});
|
2018-09-12 13:15:55 +00:00
|
|
|
} else {
|
|
|
|
// Increase the vocab
|
|
|
|
this.setState({
|
|
|
|
current: this.state.current + 1,
|
2018-09-12 17:23:00 +00:00
|
|
|
input: "",
|
2018-09-12 13:15:55 +00:00
|
|
|
});
|
|
|
|
}
|
2018-09-14 15:02:50 +00:00
|
|
|
} else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) {
|
|
|
|
// TODO: Show a hint
|
|
|
|
console.log("Partially correct");
|
2018-09-12 13:15:55 +00:00
|
|
|
} else {
|
2018-09-12 17:23:00 +00:00
|
|
|
this.setState({
|
|
|
|
popoverOpen: true,
|
|
|
|
popoverText: "Das war nicht richtig",
|
|
|
|
popoverColor: "red",
|
|
|
|
// TODO: Or maybe don't reset the text
|
|
|
|
input: "",
|
|
|
|
});
|
2018-09-12 13:15:55 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 17:23:00 +00:00
|
|
|
// TODO(?): Show a snackbar for showing the updated score
|
2018-09-12 13:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2018-09-12 17:23:00 +00:00
|
|
|
return <div>
|
|
|
|
{
|
|
|
|
this.state.toSummary ? (
|
|
|
|
<Redirect to="/review/summary" />
|
|
|
|
) : undefined
|
|
|
|
}
|
2018-09-12 13:15:55 +00:00
|
|
|
<Grid container justify="center">
|
2018-09-15 12:26:22 +00:00
|
|
|
<Grid item style={{ width: "100%" }}>
|
2018-09-12 13:15:55 +00:00
|
|
|
<Card>
|
2018-09-12 17:23:00 +00:00
|
|
|
<CardContent>
|
|
|
|
<Grid container direction="column">
|
|
|
|
<Typography variant="display2">
|
2018-09-14 14:13:42 +00:00
|
|
|
{this.currentVocab().latin.grundform}
|
2018-09-12 17:23:00 +00:00
|
|
|
</Typography>
|
|
|
|
<TextField
|
|
|
|
margin="normal"
|
|
|
|
fullWidth={true}
|
|
|
|
value={this.state.input}
|
|
|
|
onChange={(ev) => this.setState({
|
|
|
|
input: ev.target.value,
|
|
|
|
})}
|
|
|
|
onKeyPress={(ev) => {
|
|
|
|
// Allow checking of the answer by pressing Enter
|
|
|
|
if (ev.key === "Enter")
|
|
|
|
this.checkInput();
|
|
|
|
}} />
|
|
|
|
<Popover
|
|
|
|
open={this.state.popoverOpen}
|
|
|
|
anchorOrigin={{
|
|
|
|
vertical: "center",
|
|
|
|
horizontal: "left"
|
|
|
|
}}
|
|
|
|
transformOrigin={{
|
|
|
|
vertical: "bottom",
|
|
|
|
horizontal: "left"
|
|
|
|
}}
|
|
|
|
anchorEl={this.buttonRef}
|
|
|
|
onClose={() => this.setState({
|
|
|
|
popoverOpen: false,
|
|
|
|
})}
|
|
|
|
PaperProps={{
|
|
|
|
style: {
|
|
|
|
backgroundColor: this.state.popoverColor,
|
|
|
|
padding: 10,
|
|
|
|
color: "white"
|
|
|
|
}
|
|
|
|
}}>
|
|
|
|
<Typography variant="button" color="inherit">
|
|
|
|
{this.state.popoverText}
|
|
|
|
</Typography>
|
|
|
|
</Popover>
|
|
|
|
<Button onClick={this.checkInput} buttonRef={node => this.buttonRef = node}>
|
|
|
|
Prüfen
|
2018-09-12 13:15:55 +00:00
|
|
|
</Button>
|
2018-09-12 17:23:00 +00:00
|
|
|
</Grid>
|
|
|
|
</CardContent>
|
2018-09-12 13:15:55 +00:00
|
|
|
</Card>
|
|
|
|
</Grid>
|
|
|
|
</Grid>
|
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
};
|