spanish-quizzer

An app to quiz you on Spanish vocabulary and verb conjugations
git clone https://git.ashermorgan.net/spanish-quizzer/
Log | Files | Refs | README

commit 56e217ac1b15cdfb8f8956391c01cb50fe24d479
parent 8e4c16eabf743fb97ac185c946db358c69d49626
Author: AsherMorgan <59518073+AsherMorgan@users.noreply.github.com>
Date:   Thu, 25 Feb 2021 18:39:25 -0800

Improve resume session feature
Move resume link to home page and make /quizzer auto-resume last session

Diffstat:
Mcss/filtersPage.css | 16+++++-----------
Mjs/app.js | 19++++++++++++++++++-
Mjs/filtersPage.js | 44+++++++-------------------------------------
Mjs/quizzer.js | 31+++++++++++++++++++++++++++----
Mtests/test.filtersPage.js | 12+++++++++++-
5 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/css/filtersPage.css b/css/filtersPage.css @@ -96,24 +96,18 @@ align-items: center; } -/* Start/Resume Buttons */ -.settingButtons { +/* Start button */ +.settingsStart { margin-top: 20px; margin-bottom: 10px; -} -.settingButtons button { width: 100px; height: 40px; font-size: 18px; - margin: 0px 5px; } @media only screen and (max-width: 510px) { - /* Expand Start/Resume buttons */ - .settingButtons { - width: calc(100% - 10px); - } - .settingButtons button { - width: calc(50% - 15px); + /* Expand start button */ + .settingsStart { + width: calc(100% - 20px); height: 50px; } } diff --git a/js/app.js b/js/app.js @@ -26,6 +26,9 @@ const pageHeader = Vue.component("pageHeader", { // App pages const homePage = Vue.component("homePage", { + data: function() { + return {isResumable: false}; + }, methods: { /** * Handle a keyup event (implements keyboard shortcuts). @@ -35,9 +38,22 @@ const homePage = Vue.component("homePage", { if (this._inactive) return; if (e.key === "c") this.$router.push("verbs"); if (e.key === "v") this.$router.push("vocab"); - if (e.key === "r") this.$router.push("reference"); + if (e.key === "t") this.$router.push("reference"); + if (e.key === "r") this.$router.push("quizzer"); }, }, + activated: function() { + // Update isResumable property + try { + // Get last session + let { prompts, index } = JSON.parse(localStorage.getItem("last-session")); + + // Validate prompts and promptIndex + if (prompts && !isNaN(index) && index >= 0 && index < prompts.length) { + this.isResumable = true; + } + } catch {} + }, created: function() { // Add keyup handler window.addEventListener("keyup", this.keyup); @@ -56,6 +72,7 @@ const homePage = Vue.component("homePage", { <router-link tag="button" to="/vocab">Study Vocab</router-link> <router-link tag="button" to="/reference">Reference Tables</router-link> </div> + <router-link v-if="isResumable" to="/quizzer">Resume previous session</router-link> </main> </div> `, diff --git a/js/filtersPage.js b/js/filtersPage.js @@ -409,8 +409,9 @@ let filtersPage = Vue.component("filtersPage", { /** * Start a new quizzer session */ - CreateSession: function() { + StartSession: function() { // Get prompts + let prompts; if (this.category === "vocab") { prompts = Shuffle(ApplyFilters(this.$root.$data.data.vocab, GetVocabFilters(this.filters), this.settings)); } @@ -420,40 +421,13 @@ let filtersPage = Vue.component("filtersPage", { } // Set progress - promptIndex = 0; + let promptIndex = 0; - // Start quizzer - this.StartSession(prompts, promptIndex); - }, - - /** - * Resume the previous quizzer session. - */ - ResumeSession: function() { - // Load prompts and progress - let { prompts, index } = JSON.parse(localStorage.getItem("last-session")); - - // Start quizzer - this.StartSession(prompts, index); - }, - - /** - * Perform validation checks and then start the quizzer. - */ - StartSession: function(prompts, promptIndex) { - // Validate prompts and promptIndex - if (!prompts) { - alert("An error occured while resuming the previous session."); - return; - } - else if (prompts.length === 0) { + // Validate prompts + if (prompts.length === 0) { alert("You must have at least one filter."); return; } - else if (isNaN(promptIndex) || promptIndex < 0 || promptIndex >= prompts.length) { - alert("An error occured while resuming the previous session."); - return; - } // Validate browser for voice input if (this.settings.inputType !== "Text") { @@ -480,8 +454,7 @@ let filtersPage = Vue.component("filtersPage", { */ keyup: function(e) { if (this._inactive) return; - if (e.key === "s") this.CreateSession(); - if (e.key === "r") this.ResumeSession(); + if (e.key === "s") this.StartSession(); } }, @@ -501,10 +474,7 @@ let filtersPage = Vue.component("filtersPage", { <main> <filter-input :category="category" v-model="filters"></filter-input> <settings-input v-model="settings"></settings-input> - <div class="settingButtons"> - <button class="settingsStart" @click="CreateSession();">Start</button> - <button class="settingsResume" @click="ResumeSession();">Resume</button> - </div> + <button class="settingsStart" @click="StartSession();">Start</button> </main> </div> `, diff --git a/js/quizzer.js b/js/quizzer.js @@ -331,6 +331,13 @@ const quizzerPage = Vue.component("quizzerPage", { } }, + data: function() { + return { + prompts: this.startingPrompts, + index: this.startingIndex, + } + }, + methods: { /** * Update the user's progress in localStorage. @@ -343,9 +350,25 @@ const quizzerPage = Vue.component("quizzerPage", { } }, - mounted: function() { - if (this.startingPrompts == null || this.startingIndex == null || this.settings == null) { - this.$router.replace({name:this.referer}); + created: function() { + // Try to resume session if props are missing + if (this.prompts == undefined || this.index == undefined) { + try { + // Get last session + let { prompts, index } = JSON.parse(localStorage.getItem("last-session")); + + // Validate prompts and promptIndex + if (prompts && !isNaN(index) && index >= 0 && index < prompts.length) { + this.prompts = prompts; + this.index = index; + } + } catch {} + } + + // Go back if props are missing + if (this.prompts == undefined || this.index == undefined) { + alert("Unable to resume the previous session"); + this.$emit("back", this.referer); } }, @@ -353,7 +376,7 @@ const quizzerPage = Vue.component("quizzerPage", { <div class="quizzer-page"> <page-header @back="$emit('back', referer);" image="images/x.svg"></page-header> <main> - <quizzer :starting-prompts="startingPrompts" :starting-index="startingIndex" :settings="settings" + <quizzer :starting-prompts="prompts" :starting-index="index" :settings="settings" @new-prompt="updateProgress" @finished-prompts="$emit('back', referer);"> </quizzer> </main> diff --git a/tests/test.filtersPage.js b/tests/test.filtersPage.js @@ -459,12 +459,22 @@ describe("FiltersPage", function() { push_args = args; }}; + // Override $root.$data.data property + FiltersPage.$root = {$data: {data: {vocab: [ + ["English","Spanish","Type","Category"], + ["Hello","Hola","Type","Category"], + ]}}}; + // Initialize variables + FiltersPage.category = "vocab"; FiltersPage.settings = { promptType: "Text", // Required to prevent browser validation alerts inputType: "Text", // Required to prevent browser validation alerts testSetting: "testValue", }; + FiltersPage.filters = [ + {category:"All Categories", type:"All Types", direction:"Eng. → Esp."} + ]; // Call StartSession FiltersPage.StartSession([1, 2, 3], 0); @@ -473,7 +483,7 @@ describe("FiltersPage", function() { expect(push_args).to.deep.equal({ name: "quizzer", params: { - startingPrompts: [1, 2, 3], + startingPrompts: [["English", "Hello", "Spanish", "Hola"]], startingIndex: 0, settings: { promptType: "Text", // Required to prevent browser validation alerts