CSR-108: refactor question-chain component to allow for multiple questions shown on single page
This commit is contained in:
parent
f47af0e2fc
commit
e856c90243
3 changed files with 102 additions and 76 deletions
|
|
@ -13,6 +13,7 @@ module.exports = {
|
||||||
"!src/helpers/unit-test-helper.js",
|
"!src/helpers/unit-test-helper.js",
|
||||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||||
"!src/layouts/part-questions/**/*.vue",
|
"!src/layouts/part-questions/**/*.vue",
|
||||||
|
"!src/common-components/question-chain/**/*.vue",
|
||||||
"!src/layouts/reveal/**/*.vue"
|
"!src/layouts/reveal/**/*.vue"
|
||||||
// END
|
// END
|
||||||
], // ! means exclude from coverage.
|
], // ! means exclude from coverage.
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
<div v-for="(q, i) in questions" :key="i">
|
<div v-for="(q, i) in questions" :key="i">
|
||||||
<transition appear name="fade" mode="out-in">
|
<transition appear name="fade" mode="out-in">
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
v-if="q.questionSequence === currentQuestion"
|
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
|
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
|
||||||
:questionText="q.questionText"
|
:questionText="q.questionText"
|
||||||
:answers="q.answers"
|
:answers="q.answers"
|
||||||
:groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`"
|
:groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`"
|
||||||
textPosition="text-start"
|
v-model="selectedValuesArray"
|
||||||
v-model="selectedValue"
|
|
||||||
:isRequired=true
|
:isRequired=true
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:clearOnUnmount=false
|
:clearOnUnmount=false
|
||||||
|
|
@ -24,8 +24,8 @@ export default {
|
||||||
name: "questionChain",
|
name: "questionChain",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentQuestion: 1,
|
currentQuestionNum: 1,
|
||||||
answeredQuestions: [],
|
questions: [{ "BlankObject": "NOT USED... placeholder for question #0"}],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -33,88 +33,113 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
modelValue: Array,
|
modelValue: Array,
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.questionData.partQuestions.map((q, i) => {
|
||||||
|
let answerPair = [];
|
||||||
|
const eachQuestion = {
|
||||||
|
questionText: q.questionText,
|
||||||
|
questionSequence: q.questionSequence,
|
||||||
|
answers: q.answers.map((a) => {
|
||||||
|
answerPair.push(a.nextQuestionSequence ? a.nextQuestionSequence : a.answerResult);
|
||||||
|
return {
|
||||||
|
Text: 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
|
||||||
|
Name: a.nextQuestionSequence ?
|
||||||
|
q.questionSequence + "|nextQuestion|" + a.nextQuestionSequence + "|" + a.answerText :
|
||||||
|
q.questionSequence + "|answer|" + a.answerResult + "|" + a.answerText,
|
||||||
|
nextQuestionSequence: a.nextQuestionSequence,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
answerSelected: "",
|
||||||
|
};
|
||||||
|
eachQuestion.answerPair = answerPair;
|
||||||
|
this.questions.push(eachQuestion);
|
||||||
|
});
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
selectedValuesArray: {
|
||||||
questions() {
|
|
||||||
console.log("answeredQuestions: ", this.answeredQuestions)
|
|
||||||
const questions = this.questionData.partQuestions.map((q, i) => {
|
|
||||||
return {
|
|
||||||
questionText: q.questionText,
|
|
||||||
questionSequence: q.questionSequence,
|
|
||||||
answers: q.answers.map((a) => {
|
|
||||||
return {
|
|
||||||
Text: a.answerText,
|
|
||||||
// Name will either be nextQuestionSequence or answerResult
|
|
||||||
Name: a.nextQuestionSequence ? a.nextQuestionSequence : "answer-" + a.answerResult,
|
|
||||||
nextQuestionSequence: a.nextQuestionSequence,
|
|
||||||
answerResult: a.answerResult,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// add an empty item to be array[0] since we start with 1
|
|
||||||
questions.unshift({ "DeliberatelyBlankObject": "This object has been added as a placeholder only for question #0"});
|
|
||||||
return questions;
|
|
||||||
},
|
|
||||||
selectedValue: {
|
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.modelValue;
|
return [];
|
||||||
},
|
},
|
||||||
set: function(returnedAnswer) {
|
set: function(returnedAnswerArray) {
|
||||||
const isNewModelValueComplete = this.getNewModelValue(returnedAnswer);
|
const returnedAnswer = returnedAnswerArray[returnedAnswerArray.length-1];
|
||||||
|
const isQuestionChainComplete = this.handleReturnedAnswer(returnedAnswer);
|
||||||
|
|
||||||
if (isNewModelValueComplete) {
|
if (isQuestionChainComplete) {
|
||||||
this.$emit("update:modelValue", isNewModelValueComplete);
|
this.$emit("update:modelValue", isQuestionChainComplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
currentQuestion() {
|
||||||
|
return this.questions[this.currentQuestionNum];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleReturnedAnswer(returnedAnswer) { // returns 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 = returnedAnswerArray[0];
|
||||||
|
const questionType = returnedAnswerArray[1];
|
||||||
|
const questionAnswer = returnedAnswerArray[2];
|
||||||
|
const questionAnswerText = returnedAnswerArray[3];
|
||||||
|
|
||||||
|
// remove all previous answers after the index of this one in questions
|
||||||
|
this.questions.map((q) => {
|
||||||
|
if ((q.questionSequence > questionNum) || (q.answerPair?.includes(questionAnswer))) {
|
||||||
|
q.answerSelected = "";
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
});
|
||||||
|
|
||||||
|
// set this question as "answered"
|
||||||
|
this.questions[questionNum].answerSelected = questionAnswerText;
|
||||||
|
|
||||||
|
// update to next question index
|
||||||
|
this.currentQuestionNum = questionType === "nextQuestion" ? parseInt(questionAnswer) : parseInt(questionNum); // update count to display next question
|
||||||
|
|
||||||
|
// return false if there's a nextQuestion... or return an object with "final" answers
|
||||||
|
if (questionType === "nextQuestion") {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
const answeredQuestions = [];
|
||||||
|
this.questions.forEach(( q ) => {
|
||||||
|
if (q.answerSelected) {
|
||||||
|
answeredQuestions.push({
|
||||||
|
questionText: q.questionText,
|
||||||
|
selectedAnswerText: q.answerSelected,
|
||||||
|
questionNum: questionNum,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
answerResult: questionAnswer,
|
||||||
|
answeredQuestions: answeredQuestions,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
watch: {
|
||||||
getNewModelValue(returnedAnswer) {
|
currentQuestion: {
|
||||||
if (!returnedAnswer || !Array.isArray(returnedAnswer)) { return false }
|
handler() {
|
||||||
const lastAnswer = returnedAnswer[returnedAnswer.length - 1];
|
// scrolls page to next active question
|
||||||
const currentQuestion = this.questions[this.currentQuestion];
|
this.$nextTick(() => {
|
||||||
|
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
|
||||||
if (lastAnswer.indexOf("answer-") === 0) {
|
})
|
||||||
// if it is an answerResult
|
},
|
||||||
const finalAnswer = lastAnswer.slice(7);
|
deep: true
|
||||||
|
|
||||||
const currentQuestionSelectedAnswer = currentQuestion.answers.find(
|
|
||||||
({ answerResult }) => answerResult === finalAnswer
|
|
||||||
);
|
|
||||||
|
|
||||||
// add current item to list of answered questions
|
|
||||||
this.answeredQuestions.push(
|
|
||||||
{
|
|
||||||
questionText: currentQuestion.questionText,
|
|
||||||
selectedAnswerText: currentQuestionSelectedAnswer.Text,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
answerResult: finalAnswer,
|
|
||||||
answeredQuestions: this.answeredQuestions,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const currentQuestionSelectedAnswer = currentQuestion.answers.find(
|
|
||||||
({ nextQuestionSequence }) => nextQuestionSequence === parseInt(lastAnswer)
|
|
||||||
);
|
|
||||||
|
|
||||||
// add current item to list of answered questions
|
|
||||||
this.answeredQuestions.push(
|
|
||||||
{
|
|
||||||
questionText: currentQuestion.questionText,
|
|
||||||
selectedAnswerText: currentQuestionSelectedAnswer.Text,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this.currentQuestion = parseInt(lastAnswer); // update count to display next question
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue