From 7fc1d8a0588575bff68f56a39e817bf443402d24 Mon Sep 17 00:00:00 2001 From: Alexander Polynomdivision Date: Wed, 3 Oct 2018 14:02:20 +0200 Subject: [PATCH] feat: Show training wheels --- frontend/src/actions/index.ts | 8 +++ frontend/src/config.ts | 3 + frontend/src/containers/Review.ts | 4 +- frontend/src/pages/review.tsx | 114 +++++++++++++++++++++++++++++- frontend/src/reducers/index.ts | 8 +++ 5 files changed, 135 insertions(+), 2 deletions(-) diff --git a/frontend/src/actions/index.ts b/frontend/src/actions/index.ts index 3f6185d..779250a 100644 --- a/frontend/src/actions/index.ts +++ b/frontend/src/actions/index.ts @@ -200,3 +200,11 @@ export function setLevelListSnackbar(state: boolean) { state, }; }; + +export const REVIEW_SET_HELP = "REVIEW_SET_HELP"; +export function setReviewHelp(state: boolean) { + return { + type: REVIEW_SET_HELP, + state, + }; +}; diff --git a/frontend/src/config.ts b/frontend/src/config.ts index 4bb76bd..2af4fce 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -6,3 +6,6 @@ export const BACKEND_URL = "https://192.168.178.100"; // How often a wrongly answered group will be readded to the review queue export const MAX_ERROR_THRESHOLD = 2; + +// After how many failed attempts should we help the user +export const REVIEW_HELP_MOD = 3; diff --git a/frontend/src/containers/Review.ts b/frontend/src/containers/Review.ts index 4476240..bee5bfd 100644 --- a/frontend/src/containers/Review.ts +++ b/frontend/src/containers/Review.ts @@ -2,7 +2,7 @@ import { connect } from "react-redux"; import { setDrawerButton, setReviewPopover, setReviewSummary, - setReview, setReviewLoading, setReviewDialog + setReview, setReviewLoading, setReviewDialog, setReviewHelp } from "../actions"; import { IReviewMetadata } from "../models/review"; @@ -20,6 +20,7 @@ const mapStateToProps = state => { popoverColor: state.review.popoverColor, popoverTextColor: state.review.popoverTextColor, loading: state.review.loading, + showHelp: state.review.showHelp, }; }; const mapDispatchToProps = dispatch => { @@ -30,6 +31,7 @@ const mapDispatchToProps = dispatch => { setReview: (current: IVocab, meta: IReviewMetadata) => dispatch(setReview(current, meta)), setLoading: (state: boolean) => dispatch(setReviewLoading(state)), setReviewDialog: (state: boolean) => dispatch(setReviewDialog(state)), + setShowHelp: (state: boolean) => dispatch(setReviewHelp(state)), }; }; diff --git a/frontend/src/pages/review.tsx b/frontend/src/pages/review.tsx index c6e122a..3c0a971 100644 --- a/frontend/src/pages/review.tsx +++ b/frontend/src/pages/review.tsx @@ -27,7 +27,10 @@ import { import { ReviewType, IReviewMetadata } from "../models/review"; import { levW } from "../algorithms/levenshtein"; -import { LEVENSHTEIN_MAX_DISTANCE, MAX_ERROR_THRESHOLD } from "../config"; +import { + LEVENSHTEIN_MAX_DISTANCE, MAX_ERROR_THRESHOLD, + REVIEW_HELP_MOD +} from "../config"; import { Queue } from "../utils/queue"; @@ -49,6 +52,7 @@ interface IProps { popoverText: string; popoverColor: string; popoverTextColor: string; + showHelp: boolean; setReviewDialog: (state: boolean) => void; setSummary: (state: boolean) => void; @@ -56,6 +60,7 @@ interface IProps { drawerButtonState: (state: boolean) => void; setReview: (curent: IReviewCard, meta: IReviewMetadata) => void; setLoading: (state: boolean) => void; + setShowHelp: (state: boolean) => void; } const ReviewPageWithRouter = withRouter( @@ -132,6 +137,10 @@ const ReviewPageWithRouter = withRouter( this.props.history.push("/dashboard"); } + closeHelp = () => { + this.props.setShowHelp(false); + } + increaseMeta = (correct: number, wrong: number): IReviewMetadata => { const { metadata } = this.props; @@ -239,6 +248,9 @@ const ReviewPageWithRouter = withRouter( // NOTE: We don't need to force a re-render, as the state // will be updated since we need to show the popover. vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue); + } else if (this.error_data[current.id] % REVIEW_HELP_MOD === 0) { + // Help the user + this.props.setShowHelp(true); } this.props.setReview(this.props.current, this.increaseMeta(0, 1)); @@ -246,6 +258,101 @@ const ReviewPageWithRouter = withRouter( } } + vocabSpecificInformation(vocab: IVocab) { + switch (vocab.type) { + case VocabType.NOMEN: + const nData = vocab.latin as INomenData; + return
+ + Genitiv: {nData.genitiv} + + + Genus: {nData.genus} + +
; + case VocabType.VERB: + const vData = vocab.latin as IVerbData; + return
+ + 1. Person Präsens: {vData.praesens} + + + 1. Person Perfekt: {vData.perfekt} + +
; + case VocabType.ADJEKTIV: + const aData = vocab.latin as IAdjektivData; + return
+ + Endung feminin: {aData.endung_f} + + + Endung neutrum: {aData.endung_n} + +
; + case VocabType.ADVERB: + return
; + } + } + + helpDialog = () => { + // Find the vocabulary + // TODO: if (!vocab) + const vocab = this.vocab.find(el => el.id === this.props.current.id) as IVocab; + + // TODO: This should be shared with LevelPage + return + Wiederholung von {vocab.latin.grundform} + + + {vocab.german.join(", ")} + + {this.vocabSpecificInformation(vocab)} + { + vocab.hint ? ( +
+ + Tipp: + + + {vocab.hint} + +
+ ) : undefined + } + { + vocab.mnemonic ? ( +
+ + Eselsbrücke: + + + {vocab.mnemonic} + +
+ ) : undefined + } +
+ + + +
; + } + render() { if (this.props.loading) { return
@@ -368,6 +475,11 @@ const ReviewPageWithRouter = withRouter( + { + this.props.showHelp ? ( + this.helpDialog() + ) : undefined + } diff --git a/frontend/src/reducers/index.ts b/frontend/src/reducers/index.ts index 9b4048b..a4c92fd 100644 --- a/frontend/src/reducers/index.ts +++ b/frontend/src/reducers/index.ts @@ -52,6 +52,7 @@ interface IState { popoverText: string; popoverColor: string; popoverTextColor: string; + showHelp: boolean; }; topTen: ILearner[]; @@ -110,6 +111,7 @@ const initialState: IState = { popoverText: "", popoverColor: "", popoverTextColor: "", + showHelp: false, }, nextLevel: {} as ILevel, @@ -256,6 +258,12 @@ export function LateinicusApp(state: IState = initialState, action: any) { snackbar: action.state, }), }); + case Actions.REVIEW_SET_HELP: + return Object.assign({}, state, { + review: Object.assign({}, state.review, { + showHelp: action.state, + }), + }); default: // Ignore the initialization call to the reducer. By that we can // catch all actions that are not implemented