From 977f5df9ddd8b5c3fce0d0c26cb1415cb705239c Mon Sep 17 00:00:00 2001 From: Alexander Polynomdivision Date: Mon, 1 Oct 2018 19:21:57 +0200 Subject: [PATCH] feat: Points for doing reviews --- backend/src/api/user.ts | 5 ++++- frontend/shit.sh | 2 +- frontend/src/actions/index.ts | 8 ++++++++ frontend/src/components/app.tsx | 7 +++++-- frontend/src/containers/Application.ts | 6 +++++- frontend/src/pages/review.tsx | 18 ++++++------------ frontend/src/reducers/index.ts | 6 ++++++ 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/backend/src/api/user.ts b/backend/src/api/user.ts index 1f7311b..c798c45 100644 --- a/backend/src/api/user.ts +++ b/backend/src/api/user.ts @@ -130,7 +130,7 @@ function dateInNDays(n: number): number { userRouter.post("/lastReview", async (req: LRequest, res) => { // Check if we get the needed data - if (!req.body || !("meta" in req.body) || !("sm2" in req.body)) { + if (!req.body || !("meta" in req.body) || !("sm2" in req.body) || !("delta" in req.body)) { res.send({ error: "400", data: { @@ -152,6 +152,8 @@ userRouter.post("/lastReview", async (req: LRequest, res) => { return; } + user.score += parseInt(req.body.delta); + Object.keys(req.body.sm2).forEach((id: string) => { const vocabId = parseInt(id); const correct: boolean = req.body.sm2[id]; @@ -184,6 +186,7 @@ userRouter.post("/lastReview", async (req: LRequest, res) => { $set: { lastReview: user.lastReview, vocabMetadata: user.vocabMetadata, + score: user.score, }, }); diff --git a/frontend/shit.sh b/frontend/shit.sh index 3dd8bba..167a91c 100644 --- a/frontend/shit.sh +++ b/frontend/shit.sh @@ -5,4 +5,4 @@ rm -rf dist/ chmod 705 dist dist/app chmod 604 dist/app/* -#sed "s/\/src/\/app\/src/" dist/app/index.html +sed -e "s/\/src/\/app\/src/g" --in-place dist/app/index.html diff --git a/frontend/src/actions/index.ts b/frontend/src/actions/index.ts index c2e5f84..e7526d7 100644 --- a/frontend/src/actions/index.ts +++ b/frontend/src/actions/index.ts @@ -120,6 +120,14 @@ export function setLastReview(metadata: IReviewMetadata) { }; }; +export const SET_USER_SCORE_DELTA = "SET_USER_SCORE_DELTA"; +export function setUserScoreDelta(delta: number) { + return { + type: SET_USER_SCORE_DELTA, + delta, + }; +}; + export const SET_REVIEW = "SET_REVIEW"; export function setReview(current: IReviewCard, meta: IReviewMetadata) { return { diff --git a/frontend/src/components/app.tsx b/frontend/src/components/app.tsx index b5885d3..3332f98 100644 --- a/frontend/src/components/app.tsx +++ b/frontend/src/components/app.tsx @@ -31,7 +31,8 @@ interface IProps { setAuthenticated: (status: boolean) => void; setDidLogin: (status: boolean) => void; setUser: (user: IUser) => void; - setLastReview: (meta: IReviewMetadata) => void; + setLastReview: (meta: IReviewMetadata, delta: number) => void; + setUserScoreDelta: (delta: number) => void; }; // TODO: Replace the sessionStorage with localStorage? @@ -107,9 +108,10 @@ export default class Application extends React.Component { } // TODO: Type? - setLastReview = (meta: IReviewMetadata, sm2: any) => { + setLastReview = (meta: IReviewMetadata, sm2: any, delta: number) => { // Update the state this.props.setLastReview(meta); + this.props.setUserScoreDelta(delta); // Tell the server about the last review fetch(`${BACKEND_URL}/api/user/lastReview`, { @@ -121,6 +123,7 @@ export default class Application extends React.Component { body: JSON.stringify({ meta, sm2, + delta, }), }).then(resp => resp.json(), err => { console.log("Application::setLastReview: POSTing last results failed"); diff --git a/frontend/src/containers/Application.ts b/frontend/src/containers/Application.ts index 9382e0c..74bf835 100644 --- a/frontend/src/containers/Application.ts +++ b/frontend/src/containers/Application.ts @@ -4,7 +4,10 @@ import { IUser } from "../models/user"; import Application from "../components/app"; -import { setAuthenticated, setUser, setDidLogin, setLastReview } from "../actions"; +import { + setAuthenticated, setUser, setDidLogin, setLastReview, + setUserScoreDelta +} from "../actions"; import { IReviewMetadata } from "../models/review"; @@ -20,6 +23,7 @@ const mapDispatchToProps = dispatch => { setDidLogin: (state: boolean) => dispatch(setDidLogin(state)), setUser: (user: IUser) => dispatch(setUser(user)), setLastReview: (meta: IReviewMetadata) => dispatch(setLastReview(meta)), + setUserScoreDelta: (delta: number) => dispatch(setUserScoreDelta(delta)), }; }; diff --git a/frontend/src/pages/review.tsx b/frontend/src/pages/review.tsx index a6671f6..335ed75 100644 --- a/frontend/src/pages/review.tsx +++ b/frontend/src/pages/review.tsx @@ -33,7 +33,7 @@ interface IProps { levelId?: number; vocabByLevel?: (level: number) => Promise; vocabByQueue?: () => Promise; - setLastReview: (meta: IReviewMetadata, sm2: any) => void; + setLastReview: (meta: IReviewMetadata, sm2: any, delta: number) => void; reviewType: ReviewType; history: any; @@ -65,6 +65,7 @@ const ReviewPageWithRouter = withRouter( private inputRef: HTMLInputElement; // Mapping: Vocab Id -> Correctly answered private sm2_metadata: any = {}; + private score_delta = 0; constructor(props: any) { super(props); @@ -189,13 +190,15 @@ const ReviewPageWithRouter = withRouter( // Check if the user's answer was correct if (minDist === 0) { this.updateGroupSM2(true); + // TODO: Is this correct? + this.score_delta += 1; // TODO: Show it's correct? // Show the next vocab word if (this.reviewQueue.size() === 0) { // Update the metadata this.props.setReview(this.props.current, this.increaseMeta(1, 0)); - this.props.setLastReview(this.props.metadata, this.sm2_metadata); + this.props.setLastReview(this.props.metadata, this.sm2_metadata, this.score_delta); this.props.setLoading(true); // Show the drawer button again @@ -213,18 +216,9 @@ const ReviewPageWithRouter = withRouter( } else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) { this.props.setPopover(true, "Das war fast richtig", "yellow", "black"); } 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"); - * } - */ // Update the metadata this.updateGroupSM2(false); + this.score_delta -= 1; this.props.setReview(this.props.current, this.increaseMeta(0, 1)); this.props.setPopover(true, "Das war nicht richtig", "red", "white"); } diff --git a/frontend/src/reducers/index.ts b/frontend/src/reducers/index.ts index a7eb5ec..2ec1f47 100644 --- a/frontend/src/reducers/index.ts +++ b/frontend/src/reducers/index.ts @@ -202,6 +202,12 @@ export function LateinicusApp(state: IState = initialState, action: any) { return Object.assign({}, state, { lastReview: action.metadata, }); + case Actions.SET_USER_SCORE_DELTA: + return Object.assign({}, state, { + user: Object.assign({}, state.user, { + score: state.user.score + action.delta, + }), + }); case Actions.REVIEW_SET_LOADING: return Object.assign({}, state, { review: Object.assign({}, state.review, {