feat: Show training wheels
This commit is contained in:
parent
4ba879c531
commit
7fc1d8a058
@ -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,
|
||||
};
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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)),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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 <div>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Genitiv:</b> {nData.genitiv}
|
||||
</Typography>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Genus:</b> {nData.genus}
|
||||
</Typography>
|
||||
</div>;
|
||||
case VocabType.VERB:
|
||||
const vData = vocab.latin as IVerbData;
|
||||
return <div>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>1. Person Präsens:</b> {vData.praesens}
|
||||
</Typography>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>1. Person Perfekt:</b> {vData.perfekt}
|
||||
</Typography>
|
||||
</div>;
|
||||
case VocabType.ADJEKTIV:
|
||||
const aData = vocab.latin as IAdjektivData;
|
||||
return <div>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Endung feminin:</b> {aData.endung_f}
|
||||
</Typography>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Endung neutrum:</b> {aData.endung_n}
|
||||
</Typography>
|
||||
</div>;
|
||||
case VocabType.ADVERB:
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
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 <Dialog
|
||||
open={this.props.showHelp}
|
||||
onClose={this.closeHelp}>
|
||||
<DialogTitle>Wiederholung von {vocab.latin.grundform}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography gutterBottom variant="headline" component="h3">
|
||||
{vocab.german.join(", ")}
|
||||
</Typography>
|
||||
{this.vocabSpecificInformation(vocab)}
|
||||
{
|
||||
vocab.hint ? (
|
||||
<div style={{
|
||||
border: "dashed",
|
||||
borderColor: "red",
|
||||
padding: 12,
|
||||
}}>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Tipp:</b>
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
{vocab.hint}
|
||||
</Typography>
|
||||
</div>
|
||||
) : undefined
|
||||
}
|
||||
{
|
||||
vocab.mnemonic ? (
|
||||
<div style={{
|
||||
border: "dashed",
|
||||
borderColor: "#f1c40f",
|
||||
marginTop: 12,
|
||||
padding: 12,
|
||||
}}>
|
||||
<Typography variant="subheading" component="p">
|
||||
<b>Eselsbrücke:</b>
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
{vocab.mnemonic}
|
||||
</Typography>
|
||||
</div>
|
||||
) : undefined
|
||||
}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={this.closeHelp}>
|
||||
Zurück zur Wiederholung
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.loading) {
|
||||
return <div>
|
||||
@ -368,6 +475,11 @@ const ReviewPageWithRouter = withRouter(
|
||||
<CloseIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{
|
||||
this.props.showHelp ? (
|
||||
this.helpDialog()
|
||||
) : undefined
|
||||
}
|
||||
<Dialog
|
||||
open={this.props.dialogOpen}
|
||||
onClose={this.closeDialog}>
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user