DigitalConsumer.FixMyGlass/src/common-components/question-chain/question-chain.vue
2022-10-07 15:50:52 -04:00

161 lines
6.4 KiB
Vue

<template>
<div v-for="(q, i) in questions" :key="i">
<transition appear name="fade" mode="out-in">
<buttonQuestion
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
class="radioQuestion"
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
:questionText="q.questionText"
:answers="q.answers"
:groupName="`question-${glassIndex}-${q.questionSequence}`"
:modelValue="q.answerSelected"
@update:modelValue="handleAnswer(q, $event)"
isRequired
:validationRules="validationRules"
/>
</transition>
</div>
</template>
<script>
import buttonQuestion from "@/common-components/button-question/button-question";
import { useValidateForm } from "vee-validate";
export default {
name: "questionChain",
data() {
return {
currentQuestionNum: 0,
questions: [],
};
},
props: {
questionData: Object,
validationRules: String,
modelValue: Array,
glassIndex: Number,
},
async created() {
// do a test validation check upon create to prevent out of sync / incorrect valid states
await useValidateForm(); // NOTE: needs to have async/await here; tested and won't work without it
this.questionData.map((q, i) => {
const question = {
questionText: q.questionText,
questionSequence: q.questionSequence,
answers: q.answers.map((a) => {
return {
buttonLabel: a.answerText,
// Name will either be nextQuestionSequence or answerResult
// Name will be used by list-button as the input value.
// It must be a single string or number, so concatenating together a string with
// 4 pieces of data separated by pipe characters:
// question number|type of answer|answer value|answer text
value: a.nextQuestionSequence ?
q.questionSequence + "|nextQuestion|" + a.nextQuestionSequence + "|" + a.answerText :
q.questionSequence + "|answer|" + a.answerResult + "|" + a.answerText,
nextQuestionSequence: a.nextQuestionSequence,
answerResult: a.answerResult,
questionSequence: q.questionSequence,
questionType: a.nextQuestionSequence ? "nextQuestion" : "answer",
}
}),
answerSelected: q.answerSelected || "",
};
if (!q.suppressQuestion) {
this.questions.push(question);
}
});
if (!this.modelValue?.length > 0 && this.questions.length > 0) {
// set this.currentQuestionNum to first valid question
this.currentQuestionNum = this.questions[0].questionSequence;
// scroll the next question into view
this.$nextTick(() => {
document.querySelector('.current-question')?.scrollIntoView({behavior: "smooth"});
})
}
},
methods: {
handleAnswer(question, returnedAnswer) {
question.answerSelected = returnedAnswer;
/*
returnedAnswer example format:
{
"checkValue": "1|answer|DD11132|Yes",
"value": "1|answer|DD11132|Yes",
"buttonId": "Driver-Front-1-1|answer|DD11132|Yes"
}
*/
const isQuestionChainComplete = this.getQuestionChainAnswerIfComplete(returnedAnswer);
if (isQuestionChainComplete) {
this.$emit("update:modelValue", isQuestionChainComplete);
}
},
getQuestionChainAnswerIfComplete(returnedAnswer) { // this method will return either a final answer or Boolean false
if (!returnedAnswer) { return false }
// Example returnedAnswers:
// "1|nextQuestion|3|No"
// "5|answer|DW02104|Yes"
const returnedAnswerArray = returnedAnswer.split("|");
const questionNum = parseInt(returnedAnswerArray[0]);
const questionType = returnedAnswerArray[1];
const questionAnswer = returnedAnswerArray[2];
const questionAnswerText = returnedAnswerArray[3];
const answeredQuestions = [];
this.questions.forEach((q) => {
// find this question and mark it as "answered" by populating answerSelected
if (q.questionSequence === questionNum) {
q.answerSelected = returnedAnswer;
q.answerNumber = questionNum;
q.selectedAnswerText = questionAnswerText;
}
// remove all answers AFTER this question...
// (needed in case user is changing previously answered questions)
if ((q.questionSequence > questionNum)) {
delete q.answerSelected;
}
if (q.answerSelected) {
answeredQuestions.push({
questionText: q.questionText,
selectedAnswerText: q.answerSelected.split("|")[3],
questionNum: q.questionSequence,
});
}
});
// return false if there's a nextQuestion... or return an object with final answers (truthy)
if (questionType === "nextQuestion") {
// update to next question index
this.currentQuestionNum = parseInt(questionAnswer); // update count to display next question
// scroll the next question into view
this.$nextTick(() => {
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
})
return false;
} else {
// reset current question index (removes .current-question class)
this.currentQuestionNum = 0; // reset count
// return an object with the part answer, all the answered questions, and the part index
return {
answerResult: questionAnswer,
answeredQuestions: answeredQuestions,
glassIndex: this.glassIndex,
};
}
},
},
components: {
buttonQuestion,
},
};
</script>