Skip to content
This repository was archived by the owner on Dec 8, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
quiz adjustments
  • Loading branch information
net8floz committed Jan 22, 2020
commit 3977286b5e69be9a1c77c09553b36b0a2d1b895e
3 changes: 2 additions & 1 deletion src/api/quiz.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ async function getQuestion() {
}

async function getRank() {
return (await request(routes.questionsapi_get_rank)).rank;
return request(routes.questionsapi_get_rank);
}


async function resetRank() {
await request(routes.questionsapi_rank_reset);
}
Expand Down
1 change: 1 addition & 0 deletions src/api/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default async function request(route, options = {}, tryRefresh = true) {
// return original error
return Promise.reject({
status: err.response.status,
data: err.response.data,
message:
!!err.response.data && !!err.response.data.reason
? err.response.data.reason
Expand Down
251 changes: 149 additions & 102 deletions src/components/QuizAnswer.vue
Original file line number Diff line number Diff line change
@@ -1,115 +1,162 @@
<template>
<div class="quiz-answer">
<v-card flat>
<img src="/images/dragon1-dab.png" v-if="wasCorrect" />
<img src="/images/dragon1.png" v-else />
<v-card-text>
<v-form ref="form" @submit.prevent="submit">
<v-text-field
autocomplete="off"
v-model="fields.answer.value"
v-bind="fields.answer"
:disabled="isDisabled"
@blur="onBlur"
/>
<div class="quiz-answer">
<v-card flat>
<img src="/images/dragon1.png" />
<v-card-text>
<v-form ref="form" @submit.prevent="submit">
<div class="attempts-remaining">
<v-avatar
v-for="i in totalAttempts"
:key="i"
:color="i <= attemptsRemaining ? 'indigo' : 'red'"
class="mx-1"
>
<v-icon dark>{{ (i > attemptsRemaining) ? 'mdi-close' : 'mdi-check'}}</v-icon>
</v-avatar>
</div>
<div v-if="attemptsRemaining > 0">
<v-text-field
autocomplete="off"
v-model="fields.answer.value"
v-bind="fields.answer"
:disabled="isDisabled"
@blur="onBlur"
/>

<v-btn x-large color="primary" :disabled="isDisabled" type="submit"
>Submit</v-btn
>
<v-btn x-large color="primary" :disabled="isDisabled" type="submit">Submit</v-btn>
</div>
<div v-else>
<v-alert color="warning">You are out of attempts. You can answer again in {time}</v-alert>
<v-btn x-large color="primary" disabled type="submit">Submit</v-btn>
</div>
</v-form>
</v-card-text>
</v-card>

<v-btn
v-if="wasCorrect"
x-large
color="primary"
type="submit"
@click="next"
>NEXT</v-btn
>
</v-form>
</v-card-text>
</v-card>
</div>
<v-dialog v-model="showSuccessModal" persistent max-width="400">
<v-card>
<v-card-title class="headline">Your answer was correct!</v-card-title>
<div v-if="Quiz.awaitNextQuestion">
<v-card-text>
Congratulations, {{ User.displayName }}!
<br />
You've conquered Level {{Quiz.rank}}. {{successMessage}}
<br />
<br />
That's all the questions available for now. The next question unlocks {{ Quiz.nextUnlockMoment.fromNow() }}
</v-card-text>
<v-card-actions>
<v-btn block color="primary darken-1" @click="next">OKAY</v-btn>
</v-card-actions>
</div>
<div v-else>
<v-card-text>
Congratulations, {{ User.displayName }}!
<br />
You've conquered Level {{Quiz.rank}}. {{successMessage}}
<br />
<br />
</v-card-text>
<v-card-actions>
<v-btn block color="primary darken-1" @click="next">NEXT QUESTION</v-btn>
</v-card-actions>
</div>
</v-card>
</v-dialog>
</div>
</template>

<script>
import * as api from "@/api";
import { User, Quiz } from "@/store";

export default {
name: "quizAnswer",
props: ["isLoading"],
computed: {
isDisabled() {
return this.isSubmitting || this.isLoading || this.wasCorrect;
}
},
data() {
return {
isSubmitting: false,
wasCorrect: false,
fields: {
answer: {
label: "Your Answer",
value: "",
rules: [v => !!v || "You forgot to include an answer!"],
errorMessages: [],
successMessages: [],
success: false
}
}
};
},
methods: {
onBlur() {
this.fields.answer.errorMessages = [];
if (!this.fields.answer.value) {
this.$refs.form.resetValidation();
}
},
async next() {
try {
this.wasCorrect = false;
this.fields.answer.value = "";
this.fields.answer.successMessages = [];
this.fields.answer.success = false;
this.$refs.form.resetValidation();
this.$emit("next");
} catch (err) {
await this.$store.dispatch("Snackbar/showError", err);
}
},
async submit() {
if (!this.$refs.form.validate()) {
return;
}
name: "quizAnswer",
props: ["isLoading", "rank"],
computed: {
...Quiz.mapState(),
...User.mapState(),
isDisabled() {
return this.isSubmitting || this.isLoading || this.wasCorrect;
},
successMessage() {
return this.successMessages[
Math.floor(Math.random() * this.successMessages.length)
];
}
},
data() {
return {
successMessages: [
"Your coding skills are quite admirable. ",
"You really are the best. "
],
isSubmitting: false,
wasCorrect: false,
attemptsRemaining: 3,
totalAttempts: 3,
showSuccessModal: false,
fields: {
answer: {
label: "Your Answer",
value: "",
rules: [v => !!v || "You forgot to include an answer!"],
errorMessages: [],
successMessages: [],
success: false
}
}
};
},
methods: {
onBlur() {
this.fields.answer.errorMessages = [];
if (!this.fields.answer.value) {
this.$refs.form.resetValidation();
}
},
async next() {
try {
this.showSuccessModal = false;
this.fields.answer.value = "";
this.fields.answer.successMessages = [];
this.fields.answer.success = false;
this.$refs.form.resetValidation();
this.$emit("next");
} catch (err) {
await this.$store.dispatch("Snackbar/showError", err);
}
},
async submit() {
if (!this.$refs.form.validate()) {
return;
}

if (this.isSubmitting) {
return false;
}
this.isSubmitting = true;
try {
const isCorrect = await api.quiz.submit(this.fields.answer.value);
if (this.isSubmitting) {
return false;
}
this.isSubmitting = true;
try {
const isCorrect = await api.quiz.submit(this.fields.answer.value);

if (isCorrect) {
await api.auth.fetchState();
await this.$store.dispatch(
"Snackbar/showSuccess",
"That answer was correct!"
);
this.wasCorrect = true;
this.fields.answer.successMessages = ["Your answer was correct!"];
this.fields.answer.success = true;
} else {
this.$store.dispatch(
"Snackbar/showError",
"That answer was not correct"
);
this.fields.answer.errorMessages = ["That answer was not correct"];
}
} catch (err) {
this.$store.dispatch("Snackbar/showError", err);
}
this.isSubmitting = false;
}
}
if (isCorrect) {
await api.auth.fetchState();
await this.$store.dispatch("Quiz/refresh");
this.showSuccessModal = true;
this.fields.answer.successMessages = ["Your answer was correct!"];
this.fields.answer.success = true;
} else {
this.$store.dispatch(
"Snackbar/showError",
"That answer was not correct"
);
this.fields.answer.errorMessages = ["That answer was not correct"];
}
} catch (err) {
this.$store.dispatch("Snackbar/showError", err);
}
this.isSubmitting = false;
}
}
};
</script>
5 changes: 3 additions & 2 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { auth } from "@/api";

Vue.config.productionTip = false;

(async function() {
auth.onAuthStateChange(function() {
(async function () {
auth.onAuthStateChange(function () {
store.dispatch("User/refresh");
});

await auth.autoLogin();
await store.dispatch('Quiz/refresh');

new Vue({
router,
Expand Down
44 changes: 27 additions & 17 deletions src/plugins/router.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Vue from "vue";
import VueRouter from "vue-router";
import { auth } from "@/api";
import { auth, quiz } from "@/api";
import store from "@/store";

Vue.use(VueRouter);
Expand Down Expand Up @@ -53,37 +53,47 @@ const routes = [
{
path: "/quiz",
name: "quiz",
component: () => import("@/views/Quiz"),
component: () => import("@/views/Quiz/Quiz"),
meta: {
secured: true
},
beforeEnter: (to, from, next) => {
beforeEnter: async (to, from, next) => {
await store.dispatch("Quiz/refresh");

if (!store.state.Quiz.quizHasStarted) {
// quiz has not started
next({ name: 'quiz-countdown' });
return;
}

if (store.state.Quiz.awaitNextQuestion) {
// next question is not unlocked
next({ name: 'quiz-countdown' });
return;
}

if (!store.state.Quiz.hasSeenIntro && store.state.User.rank == 0) {
// user probably should see the intro video
next({ name: "quiz-intro" });
} else {
next();
return;
}

// user is okay to take quiz
next();
}
},
{
path: "/quiz-scores",
name: "quiz-scores",
component: () => import("@/views/QuizScores"),
path: "/quiz/countdown",
name: "quiz-countdown",
component: () => import("@/views/Quiz/QuizCountdown"),
meta: {
secured: true
},
beforeEnter: (to, from, next) => {
if (!store.state.Quiz.hasScores) {
next({ name: "quiz" });
} else {
next();
}
}
},
{
path: "/quiz-intro",
path: "/quiz/intro",
name: "quiz-intro",
component: () => import("@/views/QuizIntro"),
component: () => import("@/views/Quiz/QuizIntro"),
meta: {
secured: true
}
Expand Down
2 changes: 1 addition & 1 deletion src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ export default new Vuex.Store({
}
});

export { User, Snackbar };
export { User, Quiz, Snackbar };
Loading