From bca24f17c10b154e5fab5ee8615845ac31e9db05 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 1 Jul 2024 21:27:50 -0700 Subject: [PATCH 1/6] redirect to quiz creation root if page initially loads to replacements --- .../src/views/plan/CreateExamPage/index.vue | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue index 553e5dd36d..005d2da13c 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue @@ -219,6 +219,23 @@ }); }, }, + beforeRouteEnter(to, from, next) { + if (!from.params?.quizId) { + if (to.name === PageNames.QUIZ_REPLACE_QUESTIONS) { + next({ + name: PageNames.EXAM_CREATION_ROOT, + params: { + classId: to.params.classId, + quizId: to.params.quizId, + }, + }); + } else { + next(); + } + } else { + next(); + } + }, beforeRouteLeave(to, from, next) { if (this.quizHasChanged && !this.closeConfirmationToRoute) { this.closeConfirmationToRoute = to; @@ -231,10 +248,27 @@ this.$store.dispatch('notLoading'); }, async created() { + if (this.$route.name === PageNames.QUIZ_REPLACE_QUESTIONS) { + this.$router.replace({ + name: PageNames.EXAM_CREATION_ROOT, + params: { + classId: this.$route.params.classId, + quizId: this.$route.params.quizId, + }, + }); + } + window.addEventListener('beforeunload', this.beforeUnload); await this.initializeQuiz(this.$route.params.classId, this.$route.params.quizId); this.quizInitialized = true; }, methods: { + beforeUnload(e) { + if (this.quizHasChanged) { + if (!window.confirm(this.closeConfirmationTitle$())) { + e.preventDefault(); + } + } + }, saveQuizAndRedirect(close = true) { this.saveQuiz() .then(exam => { From 0c93448d69f4713d6549e81b45c81168323cbba5 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Mon, 1 Jul 2024 21:53:06 -0700 Subject: [PATCH 2/6] cleanup --- .../src/views/plan/CreateExamPage/index.vue | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue index 005d2da13c..1c609d294a 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue @@ -220,18 +220,16 @@ }, }, beforeRouteEnter(to, from, next) { - if (!from.params?.quizId) { - if (to.name === PageNames.QUIZ_REPLACE_QUESTIONS) { - next({ - name: PageNames.EXAM_CREATION_ROOT, - params: { - classId: to.params.classId, - quizId: to.params.quizId, - }, - }); - } else { - next(); - } + // If we're coming from no quizId and going to replace questions, redirect to exam creation + // then we're coming from another page altogether OR we're coming back from a refresh + if (!from.params?.quizId && to.name === PageNames.QUIZ_REPLACE_QUESTIONS) { + next({ + name: PageNames.EXAM_CREATION_ROOT, + params: { + classId: to.params.classId, + quizId: to.params.quizId, + }, + }); } else { next(); } From 3b60c29a992ab1e8e7dd96841a4d3e23274cb67d Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Tue, 2 Jul 2024 17:03:38 -0700 Subject: [PATCH 3/6] remove duplicate useless code --- .../coach/assets/src/views/plan/CreateExamPage/index.vue | 9 --------- 1 file changed, 9 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue index 1c609d294a..bd50709c4a 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue @@ -246,15 +246,6 @@ this.$store.dispatch('notLoading'); }, async created() { - if (this.$route.name === PageNames.QUIZ_REPLACE_QUESTIONS) { - this.$router.replace({ - name: PageNames.EXAM_CREATION_ROOT, - params: { - classId: this.$route.params.classId, - quizId: this.$route.params.quizId, - }, - }); - } window.addEventListener('beforeunload', this.beforeUnload); await this.initializeQuiz(this.$route.params.classId, this.$route.params.quizId); this.quizInitialized = true; From 42afcd469ed1d6ab320ecd00457434c5298f775b Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Wed, 3 Jul 2024 16:10:12 -0700 Subject: [PATCH 4/6] ensure we go to the 0th section if someone tries to go to nonexistant section --- .../src/views/plan/CreateExamPage/index.vue | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue index bd50709c4a..3da3e75c3f 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue @@ -132,8 +132,15 @@ setup() { const closeConfirmationToRoute = ref(null); const { classId, groups } = useCoreCoach(); - const { quizHasChanged, quiz, updateQuiz, saveQuiz, initializeQuiz, allSectionsEmpty } = - useQuizCreation(); + const { + quizHasChanged, + quiz, + updateQuiz, + saveQuiz, + initializeQuiz, + allSectionsEmpty, + allSections, + } = useQuizCreation(); const showError = ref(false); const quizInitialized = ref(false); @@ -162,6 +169,7 @@ updateQuiz, initializeQuiz, quizInitialized, + allSections, allSectionsEmpty, allSectionsEmptyWarning$, saveAndClose$, @@ -234,6 +242,20 @@ next(); } }, + beforeRouteUpdate(to, from, next) { + if (to.params.sectionIndex >= this.allSections.length) { + next({ + name: PageNames.EXAM_CREATION_ROOT, + params: { + classId: to.params.classId, + quizId: to.params.quizId, + sectionIndex: 0, + }, + }); + } else { + next(); + } + }, beforeRouteLeave(to, from, next) { if (this.quizHasChanged && !this.closeConfirmationToRoute) { this.closeConfirmationToRoute = to; @@ -248,6 +270,19 @@ async created() { window.addEventListener('beforeunload', this.beforeUnload); await this.initializeQuiz(this.$route.params.classId, this.$route.params.quizId); + // If the section index doesn't exist, redirect to the first section; we also do this in + // beforeRouteUpdate. We do this here to avoid fully initializing the quiz if we're going to + // redirect anyway. + if (this.$route.params.sectionIndex >= this.allSections.length) { + this.$router.replace({ + name: PageNames.EXAM_CREATION_ROOT, + params: { + classId: this.$route.params.classId, + quizId: this.$route.params.quizId, + sectionIndex: 0, + }, + }); + } this.quizInitialized = true; }, methods: { From 062df76508e545c198eefc720ae140e11b74a092 Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Wed, 3 Jul 2024 16:14:20 -0700 Subject: [PATCH 5/6] URL params are strings :) --- .../coach/assets/src/views/plan/CreateExamPage/index.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue index 3da3e75c3f..4ed8d0e920 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/index.vue @@ -249,7 +249,7 @@ params: { classId: to.params.classId, quizId: to.params.quizId, - sectionIndex: 0, + sectionIndex: '0', }, }); } else { @@ -279,7 +279,7 @@ params: { classId: this.$route.params.classId, quizId: this.$route.params.quizId, - sectionIndex: 0, + sectionIndex: '0', }, }); } From 4a943069ac3a718ee1a364f267d400f201b2c42b Mon Sep 17 00:00:00 2001 From: Jacob Pierce Date: Wed, 3 Jul 2024 16:40:42 -0700 Subject: [PATCH 6/6] conditionalize property getters on activeSection; add defaults --- .../assets/src/views/plan/CreateExamPage/SectionEditor.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue index 33db5d1ada..eed8568857 100644 --- a/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue +++ b/kolibri/plugins/coach/assets/src/views/plan/CreateExamPage/SectionEditor.vue @@ -305,9 +305,9 @@ } /* Note that the use of snake_case here is to map directly to the API */ - const learners_see_fixed_order = ref(activeSection.value.learners_see_fixed_order); - const description = ref(activeSection.value.description); - const section_title = ref(activeSection.value.section_title.trim()); + const learners_see_fixed_order = ref(activeSection?.value?.learners_see_fixed_order || false); + const description = ref(activeSection?.value?.description || ''); + const section_title = ref(activeSection?.value?.section_title?.trim() || ''); const sectionTitleInvalidText = computed(() => { if (section_title.value.trim() === '') {