import * as React from "react"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import TextField from "@material-ui/core/TextField"; import Grid from "@material-ui/core/Grid"; import Button from "@material-ui/core/Button"; import Typography from "@material-ui/core/Typography"; import Popover from "@material-ui/core/Popover"; import { Redirect } from "react-router-dom"; import { IVocab, IReviewCard, vocabToReviewCard, reviewQTypeToStr } from "../models/vocab"; import { ReviewType } from "../models/review"; import { levW } from "../algorithms/levenshtein"; import { LEVENSHTEIN_MAX_DISTANCE } from "../config"; import { Queue } from "../utils/queue"; interface IProps { levelId?: number; vocabByLevel?: (level: number) => IVocab[]; vocabByQueue?: () => IVocab[]; reviewType: ReviewType; drawerButtonState: (state: boolean) => void; } interface IState { input: string; current: IReviewCard; toSummary: boolean; popoverOpen: boolean; popoverText: string; popoverColor: string; } export default class ReviewPage extends React.Component { private vocab: IVocab[] = []; private reviewQueue: Queue = new Queue(); // Used for positioning the popover private buttonRef: HTMLButtonElement; constructor(props: any) { super(props); // 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; } // Turn the vocabulary into IReviewCards and queue them this.vocab.forEach((vocab) => { vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue); }); this.state = { input: "", current: this.reviewQueue.dequeue(), toSummary: false, popoverOpen: false, popoverText: "", popoverColor: "red", }; } currentVocab = (id: number) => { return this.vocab.find((el) => el.id === this.state.current.id); } checkInput = () => { // Check if the given answer is somewhere in the german words const { input } = this.state; // Map all possible answers to lowercase ( => ignore casing) const answers = this.state.current.answers.map((el) => el.toLowerCase()); // Calculate the distances to all possible answers const dists = answers.map((el) => levW(input.toLowerCase(), el)); // Find the lowest distance const minDist = Math.min(...dists); // Check if the user's answer was correct if (minDist === 0) { // TODO: Show it's correct? // Show the next vocab word if (this.reviewQueue.size() === 0) { // TODO: Set some data that the summary screen will show this.setState({ toSummary: true, }); } else { // Increase the vocab this.setState({ current: this.reviewQueue.dequeue(), input: "", }); } } else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) { // TODO: Show a hint console.log("Partially correct"); } else { this.setState({ popoverOpen: true, popoverText: "Das war nicht richtig", popoverColor: "red", // TODO: Or maybe don't reset the text input: "", }); } // TODO(?): Show a snackbar for showing the updated score } render() { const { question, qtype } = this.state.current; const questionTitle = `${question} (${reviewQTypeToStr(qtype)})`; return
{ this.state.toSummary ? ( ) : undefined } {questionTitle} this.setState({ input: ev.target.value, })} onKeyPress={(ev) => { // Allow checking of the answer by pressing Enter if (ev.key === "Enter") this.checkInput(); }} /> this.setState({ popoverOpen: false, })} PaperProps={{ style: { backgroundColor: this.state.popoverColor, padding: 10, color: "white" } }}> {this.state.popoverText}
; } };