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
	 Alexander Polynomdivision
						Alexander Polynomdivision