fix: Go to the summary page
This commit is contained in:
parent
882ca5a9e3
commit
2dc9aa3a53
@ -110,14 +110,6 @@ export function setReviewPopover(state: boolean, text: string, color: string) {
|
||||
};
|
||||
};
|
||||
|
||||
export const REVIEW_SET_SUMMARY = "REVIEW_SET_SUMMARY";
|
||||
export function setReviewSummary(state: boolean) {
|
||||
return {
|
||||
type: REVIEW_SET_SUMMARY,
|
||||
state,
|
||||
};
|
||||
};
|
||||
|
||||
export const REVIEW_SET_LOADING = "REVIEW_SET_LOADING";
|
||||
export function setReviewLoading(state: boolean) {
|
||||
return {
|
||||
|
@ -11,7 +11,7 @@ import LinearProgress from "@material-ui/core/LinearProgress";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { withRouter } from "react-router-dom";
|
||||
|
||||
import { IVocab, IReviewCard, vocabToReviewCard, reviewQTypeToStr } from "../models/vocab";
|
||||
import { ReviewType, IReviewMetadata } from "../models/review";
|
||||
@ -26,12 +26,13 @@ interface IProps {
|
||||
vocabByLevel?: (level: number) => Promise<IVocab[]>;
|
||||
vocabByQueue?: () => Promise<IVocab[]>;
|
||||
|
||||
history: any;
|
||||
|
||||
reviewType: ReviewType;
|
||||
|
||||
loading: boolean;
|
||||
vocab: IVocab[];
|
||||
current: IReviewCard;
|
||||
toSummary: boolean;
|
||||
popoverOpen: boolean;
|
||||
popoverText: string;
|
||||
popoverColor: string;
|
||||
@ -44,219 +45,205 @@ interface IProps {
|
||||
setLoading: (state: boolean) => void;
|
||||
}
|
||||
|
||||
export default class ReviewPage extends React.Component<IProps> {
|
||||
private vocab: IVocab[] = [];
|
||||
private reviewQueue: Queue<IReviewCard> = new Queue();
|
||||
// Used for positioning the popover
|
||||
private buttonRef: HTMLButtonElement;
|
||||
private inputRef: HTMLInputElement;
|
||||
private metadata: IReviewMetadata = { correct: 0, wrong: 0 };
|
||||
const ReviewPageWithRouter = withRouter(
|
||||
class ReviewPage extends React.Component<IProps> {
|
||||
private vocab: IVocab[] = [];
|
||||
private reviewQueue: Queue<IReviewCard> = new Queue();
|
||||
// Used for positioning the popover
|
||||
private buttonRef: HTMLButtonElement;
|
||||
private inputRef: HTMLInputElement;
|
||||
private metadata: IReviewMetadata = { correct: 0, wrong: 0 };
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
// Hide the drawer button
|
||||
this.props.drawerButtonState(false);
|
||||
// Hide the drawer button
|
||||
this.props.drawerButtonState(false);
|
||||
|
||||
const vocToQueue = () => {
|
||||
this.vocab.forEach((vocab) => {
|
||||
vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
|
||||
});
|
||||
this.props.setReview(this.reviewQueue.dequeue(), {
|
||||
correct: 0,
|
||||
wrong: 0,
|
||||
});
|
||||
this.props.setLoading(false);
|
||||
};
|
||||
const vocToQueue = () => {
|
||||
this.vocab.forEach((vocab) => {
|
||||
vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
|
||||
});
|
||||
this.props.setReview(this.reviewQueue.dequeue(), {
|
||||
correct: 0,
|
||||
wrong: 0,
|
||||
});
|
||||
this.props.setLoading(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 {
|
||||
vocabByLevel(levelId).then(res => {
|
||||
this.vocab = res;
|
||||
vocToQueue();
|
||||
});
|
||||
}
|
||||
// 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 {
|
||||
vocabByLevel(levelId).then(res => {
|
||||
this.vocab = res;
|
||||
vocToQueue();
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case ReviewType.QUEUE:
|
||||
if (!vocabByQueue) {
|
||||
alert("[ReviewPage::constructor] vocabByQueue undefined");
|
||||
} else {
|
||||
vocabByQueue().then(res => {
|
||||
this.vocab = res;
|
||||
vocToQueue();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case ReviewType.QUEUE:
|
||||
if (!vocabByQueue) {
|
||||
alert("[ReviewPage::constructor] vocabByQueue undefined");
|
||||
} else {
|
||||
vocabByQueue().then(res => {
|
||||
this.vocab = res;
|
||||
vocToQueue();
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
increaseMeta = (correct: number, wrong: number): IReviewMetadata => {
|
||||
const { metadata } = this;
|
||||
|
||||
return {
|
||||
wrong: metadata.wrong + wrong,
|
||||
correct: metadata.correct + correct,
|
||||
};
|
||||
}
|
||||
|
||||
vocabFromId = (id: number) => {
|
||||
return this.vocab.find((el) => el.id === this.props.current.id);
|
||||
}
|
||||
|
||||
checkInput = () => {
|
||||
// Check if the given answer is somewhere in the german words
|
||||
const input = this.inputRef.value || "";
|
||||
|
||||
// Map all possible answers to lowercase ( => ignore casing)
|
||||
const answers = this.props.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);
|
||||
|
||||
console.log("Review Queue size:", this.reviewQueue.size());
|
||||
|
||||
// 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) {
|
||||
// Go to the summary screen
|
||||
this.props.setLastReview(this.metadata);
|
||||
this.props.setSummary(true);
|
||||
} else {
|
||||
// Increase the vocab
|
||||
this.props.setReview(this.reviewQueue.dequeue(), this.increaseMeta(1, 0));
|
||||
this.inputRef.value = "";
|
||||
break;
|
||||
}
|
||||
} else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) {
|
||||
// TODO: Show a hint
|
||||
console.log("Partially correct");
|
||||
} else {
|
||||
// Find the IVocab item
|
||||
const vocab = this.vocabFromId(this.props.current.id);
|
||||
if (vocab) {
|
||||
// Re-Add the vocabulary item to the review queue
|
||||
// TODO: Only re-add when it when it's not re-queued
|
||||
// vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
|
||||
} else {
|
||||
console.log("[ReviewPage::checkInput] Could not find IVocab item for wrong IReviewCard");
|
||||
}
|
||||
|
||||
this.props.setPopover(true, "Das war nicht richtig", "red");
|
||||
}
|
||||
|
||||
// TODO(?): Show a snackbar for showing the updated score
|
||||
}
|
||||
increaseMeta = (correct: number, wrong: number): IReviewMetadata => {
|
||||
const { metadata } = this;
|
||||
|
||||
return {
|
||||
wrong: metadata.wrong + wrong,
|
||||
correct: metadata.correct + correct,
|
||||
};
|
||||
}
|
||||
|
||||
vocabFromId = (id: number) => {
|
||||
return this.vocab.find((el) => el.id === this.props.current.id);
|
||||
}
|
||||
|
||||
checkInput = () => {
|
||||
// Check if the given answer is somewhere in the german words
|
||||
const input = this.inputRef.value || "";
|
||||
|
||||
// Map all possible answers to lowercase ( => ignore casing)
|
||||
const answers = this.props.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);
|
||||
|
||||
console.log("Review Queue size:", this.reviewQueue.size());
|
||||
|
||||
// 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) {
|
||||
// Go to the summary screen
|
||||
this.props.setLastReview(this.metadata);
|
||||
this.props.history.push("/review/summary");
|
||||
} else {
|
||||
// Increase the vocab
|
||||
this.props.setReview(this.reviewQueue.dequeue(), this.increaseMeta(1, 0));
|
||||
this.inputRef.value = "";
|
||||
}
|
||||
} else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) {
|
||||
// TODO: Show a hint
|
||||
console.log("Partially correct");
|
||||
} else {
|
||||
// Find the IVocab item
|
||||
const vocab = this.vocabFromId(this.props.current.id);
|
||||
if (vocab) {
|
||||
// Re-Add the vocabulary item to the review queue
|
||||
// TODO: Only re-add when it when it's not re-queued
|
||||
// vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
|
||||
} else {
|
||||
console.log("[ReviewPage::checkInput] Could not find IVocab item for wrong IReviewCard");
|
||||
}
|
||||
|
||||
this.props.setPopover(true, "Das war nicht richtig", "red");
|
||||
}
|
||||
|
||||
// TODO(?): Show a snackbar for showing the updated score
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.loading) {
|
||||
return <div>
|
||||
<Grid
|
||||
container
|
||||
spacing={0}
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justify="center"
|
||||
style={{ minHeight: '100vh' }}>
|
||||
<Grid item xs={12}>
|
||||
<Paper className="paper">
|
||||
<Grid container direction="column" spacing={8}>
|
||||
<CircularProgress />
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
const { question, qtype } = this.props.current;
|
||||
const questionTitle = `${question} (${reviewQTypeToStr(qtype)})`;
|
||||
// TODO:
|
||||
const progress = 50;
|
||||
|
||||
render() {
|
||||
if (this.props.loading) {
|
||||
return <div>
|
||||
{/*
|
||||
* This would be the case when the user presses the "to
|
||||
* review" button. That is because we need the state of loading
|
||||
* to be true, when this page gets called
|
||||
* TODO:?
|
||||
*/}
|
||||
{
|
||||
this.props.toSummary ? (
|
||||
<Redirect to="/review/summary" />
|
||||
) : undefined
|
||||
}
|
||||
|
||||
<Grid
|
||||
container
|
||||
spacing={0}
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justify="center"
|
||||
style={{ minHeight: '100vh' }}>
|
||||
<Grid item xs={12}>
|
||||
<Paper className="paper">
|
||||
<Grid container direction="column" spacing={8}>
|
||||
<CircularProgress />
|
||||
</Grid>
|
||||
</Paper>
|
||||
<Grid container justify="center">
|
||||
<Grid item style={{ width: "100%" }}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container direction="column">
|
||||
<Typography variant="display2">
|
||||
{questionTitle}
|
||||
</Typography>
|
||||
<TextField
|
||||
margin="normal"
|
||||
fullWidth={true}
|
||||
inputRef={node => this.inputRef = node}
|
||||
onKeyPress={(ev) => {
|
||||
// Allow checking of the answer by pressing Enter
|
||||
if (ev.key === "Enter")
|
||||
this.checkInput();
|
||||
}} />
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress} />
|
||||
<Popover
|
||||
open={this.props.popoverOpen}
|
||||
anchorOrigin={{
|
||||
vertical: "center",
|
||||
horizontal: "center"
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center"
|
||||
}}
|
||||
anchorEl={this.buttonRef}
|
||||
onClose={() => this.props.setPopover(false, "", "")}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: this.props.popoverColor,
|
||||
padding: 10,
|
||||
color: "white"
|
||||
}
|
||||
}}>
|
||||
<Typography
|
||||
variant="button"
|
||||
color="inherit">
|
||||
{this.props.popoverText}
|
||||
</Typography>
|
||||
</Popover>
|
||||
<Button
|
||||
onClick={this.checkInput}
|
||||
buttonRef={node => this.buttonRef = node}>
|
||||
Prüfen
|
||||
</Button>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
const { question, qtype } = this.props.current;
|
||||
const questionTitle = `${question} (${reviewQTypeToStr(qtype)})`;
|
||||
// TODO:
|
||||
const progress = 50;
|
||||
|
||||
return <div>
|
||||
{
|
||||
this.props.toSummary ? (
|
||||
<Redirect to="/review/summary" />
|
||||
) : undefined
|
||||
}
|
||||
<Grid container justify="center">
|
||||
<Grid item style={{ width: "100%" }}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container direction="column">
|
||||
<Typography variant="display2">
|
||||
{questionTitle}
|
||||
</Typography>
|
||||
<TextField
|
||||
margin="normal"
|
||||
fullWidth={true}
|
||||
inputRef={node => this.inputRef = node}
|
||||
onKeyPress={(ev) => {
|
||||
// Allow checking of the answer by pressing Enter
|
||||
if (ev.key === "Enter")
|
||||
this.checkInput();
|
||||
}} />
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress} />
|
||||
<Popover
|
||||
open={this.props.popoverOpen}
|
||||
anchorOrigin={{
|
||||
vertical: "center",
|
||||
horizontal: "center"
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center"
|
||||
}}
|
||||
anchorEl={this.buttonRef}
|
||||
onClose={() => this.props.setPopover(false, "", "")}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: this.props.popoverColor,
|
||||
padding: 10,
|
||||
color: "white"
|
||||
}
|
||||
}}>
|
||||
<Typography
|
||||
variant="button"
|
||||
color="inherit">
|
||||
{this.props.popoverText}
|
||||
</Typography>
|
||||
</Popover>
|
||||
<Button
|
||||
onClick={this.checkInput}
|
||||
buttonRef={node => this.buttonRef = node}>
|
||||
Prüfen
|
||||
</Button>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>;
|
||||
}
|
||||
};
|
||||
);
|
||||
export default ReviewPageWithRouter;
|
||||
|
@ -37,7 +37,6 @@ interface IState {
|
||||
loading: boolean;
|
||||
vocab: IVocab[];
|
||||
metadata: IReviewMetadata;
|
||||
toSummary: boolean;
|
||||
popoverOpen: boolean;
|
||||
popoverText: string;
|
||||
popoverColor: string;
|
||||
@ -82,7 +81,6 @@ const initialState: IState = {
|
||||
loading: true,
|
||||
vocab: [],
|
||||
metadata: {} as IReviewMetadata,
|
||||
toSummary: false,
|
||||
popoverOpen: false,
|
||||
popoverText: "",
|
||||
popoverColor: "",
|
||||
@ -193,12 +191,6 @@ export function LateinicusApp(state: IState = initialState, action: any) {
|
||||
loading: action.state,
|
||||
}),
|
||||
});
|
||||
case Actions.REVIEW_SET_SUMMARY:
|
||||
return Object.assign({}, state, {
|
||||
review: Object.assign({}, state.review, {
|
||||
toSummary: action.state,
|
||||
}),
|
||||
});
|
||||
default:
|
||||
if (action.type) {
|
||||
console.log("Reducer not implemented:", action.type);
|
||||
|
Reference in New Issue
Block a user