CSR-111 Fix answer change issue

This commit is contained in:
Katie 2022-08-24 15:30:11 -04:00
parent f266fce3f5
commit 9c40093144
5 changed files with 342 additions and 194 deletions

View file

@ -1,23 +1,18 @@
<template>
<div>
Hallo<br/>{{questions}}
<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">
<buttonQuestion
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
class="radioQuestion"
<buttonQuestion v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
class="radioQuestion"
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
:questionText="q.questionText"
:questionText="q.questionText"
:answers="q.answers"
:groupName="`${keyString}-${q.questionSequence}`"
:groupName="`${keyString}-${q.questionSequence}`"
v-model="q.answerSelected"
@isCheckedChanged="handleAnswer"
isRequired
:validationRules="validationRules"
/>
isRequired
:validationRules="validationRules" />
</transition>
</div>
</div>
</template>
<script>
@ -25,65 +20,76 @@ 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,
partIndex: Number,
keyString: String,
},
async created() {
// validate form upon create to prevent out of sync / persistent valid states
await useValidateForm(); // do a test validation check, without triggering full validation
name: "questionChain",
data() {
return {
currentQuestionNum: 0,
questions: [],
};
},
props: {
questionData: Object,
validationRules: String,
modelValue: Array,
partIndex: Number,
keyString: String,
},
async created() {
await this.setupQuestionChain();
},
methods: {
async setupQuestionChain(validate = true) {
// validate form upon create to prevent out of sync / persistent valid states
if (validate)
await useValidateForm(); // do a test validation check, without triggering full validation
this.questionData.map((q, i) => {
let answerPair = [];
const question = {
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,
answerResult: a.answerResult,
questionSequence: q.questionSequence,
questionType: a.nextQuestionSequence ? "nextQuestion" : "answer",
this.questionData.map((q, i) => {
let answerPair = [];
const question = {
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,
answerResult: a.answerResult,
questionSequence: q.questionSequence,
questionType: a.nextQuestionSequence ? "nextQuestion" : "answer",
}
}),
answerSelected: q.answerSelected || "",
};
console.log("answerSelected set")
question.answerPair = answerPair;
if (!q.suppressQuestion) {
this.questions.push(question);
}
this.$watch("questions", (newValue, oldValue) => {
console.log("QUESTIONS CHANGED")
console.log("newValues: ", newValue)
console.log("oldValue: ", oldValue)
}, { deep: true })
});
if (!this.modelValue?.length > 0) {
// set this.currentQuestionNum to first valid question
this.currentQuestionNum = this.questions[0]?.questionSequence ?? 0;
// scroll the next question into view
this.$nextTick(() => {
document.querySelector('.current-question').scrollIntoView({ behavior: "smooth" });
})
}
}),
answerSelected: q.answerSelected || "",
};
question.answerPair = answerPair;
if (!q.suppressQuestion) {
this.questions.push(question);
}
});
if (!this.modelValue?.length > 0) {
// set this.currentQuestionNum to first valid question
this.currentQuestionNum = this.questions[0]?.questionSequence ?? 0;
// scroll the next question into view
this.$nextTick(() => {
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
})
}
},
methods: {
},
handleAnswer(returnedAnswer) {
/*
returnedAnswer example format:
@ -93,7 +99,7 @@ export default {
"buttonId": "Driver-Front-1-1|answer|DD11132|Yes"
}
*/
const isQuestionChainComplete = this.getQuestionChainAnswerIfComplete(returnedAnswer.checkValue);
const isQuestionChainComplete = this.getQuestionChainAnswerIfComplete(returnedAnswer.value);
if (isQuestionChainComplete) {
this.$emit("update:modelValue", isQuestionChainComplete);
@ -113,16 +119,21 @@ export default {
const questionAnswerText = returnedAnswerArray[3];
const answeredQuestions = [];
console.log(questionAnswerText)
console.log(returnedAnswerArray)
this.questions.forEach((q) => {
// find this question and mark it as "answered" by populating answerSelected
if (q.questionSequence === questionNum) {
q.answerSelected = returnedAnswer;
// q.answerSelected = returnedAnswer;
console.log("answerSelected set")
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)) {
console.log("deleting answerSelected")
delete q.answerSelected;
}
if (q.answerSelected) {
@ -141,7 +152,7 @@ export default {
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"});
document.querySelector('.current-question').scrollIntoView({ behavior: "smooth" });
})
return false;
@ -149,7 +160,7 @@ export default {
// 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,
@ -163,5 +174,8 @@ export default {
components: {
buttonQuestion,
},
watch: {
}
};
</script>

View file

@ -9,13 +9,12 @@
<alert ref="alertFewMoreQuestions" class="my-5" alertClass="alert-warning"
:manualHeadline="AlertFewMoreQuestionsHeader" :manualCopy="AlertFewMoreQuestionsCopy"
v-bind:isDismissible="false" />
<div v-for="(part, i) in capabilityQuestionsData" :key="i">
{{ part.capabilityQuestions }}<br/><br/>
{{ showThisPartQuestionChain(part, i) }}
<div v-for="(part, i) in capabilityQuestionsData" :key="part.key">
<questionChain ref="questionChain" :keyString="part.key"
v-model="selectedAnswers[part.glassLocation + '-' + part.glassName]"
:questionData="part.capabilityQuestions" :partIndex="i"
v-if="showThisPartQuestionChain(part, i)" validationRules="questions-required" />
v-if="showThisPartQuestionChain(part, i)"
validationRules="questions-required" />
</div>
<funnel-footer ref="funnelFooter" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" @back-clicked="backButtonAction"
@ -145,7 +144,7 @@ export default {
const correspondingPart = partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === answer.glassLocation);
const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, answer.glassLocation, false)).data;
partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === damageLocationsSelected.WINDSHIELD).parts = partFromCapabilityQuestionAnswer;
partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === answer.glassLocation).parts = partFromCapabilityQuestionAnswer;
}
console.log(partsOrQuestions)
@ -171,7 +170,7 @@ export default {
// let partsOrQuestions = this.pageData.partsOrQuestions;
// partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === damageLocationsSelected.WINDSHIELD).parts = partFromCapabilityQuestionAnswer;
// this.navigateForward(partsOrQuestions);
this.navigateForward(partsOrQuestions);
},
handleAnswerUpdates(answer) {
// only runs when all questions in a question-chain have been answered
@ -292,6 +291,7 @@ export default {
// restore original answerResult
if (thisAns.originalAnswerResult) {
thisAns.answerResult = thisAns.originalAnswerResult;
thisAns.answerResult1 = thisAns.originalAnswerResult;
thisAns.originalAnswerResult = null;
}
}
@ -306,6 +306,7 @@ export default {
thisAns.nextQuestionSequence = null;
thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult;
thisAns.answerResult = matchedAnswer.answerResult;
thisAns.answerResult1 = matchedAnswer.answerResult;
}
}
});
@ -341,6 +342,7 @@ export default {
// set the answerData as 'already answered'
glassPart.answerData = {
answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult,
answerResult1: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult,
answeredQuestions: [answeredQuestionObj],
};
@ -354,13 +356,22 @@ export default {
// Update the key to re-render this part's question-chain component
this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].glassLocation + this.capabilityQuestionsData[gpIndex].glassName + Date.now().toString();
console.log("rerendering")
console.log(this.capabilityQuestionsData[gpIndex])
}
});
});
// Need to clear questions for subsequent glassParts as well
console.log(this.capabilityQuestionsData)
// for (let i = currentQuestionChainIndex; i < this.capabilityQuestionsData.length; i++) {
// this.capabilityQuestionsData.map(data => ({
// ...data,
// }))
// }
// DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART
// look through all (this part's) part questions for any duplicates that were suppressed;
@ -410,6 +421,7 @@ export default {
});
});
console.log(this.capabilityQuestionsData[1].capabilityQuestions[0].answerSelected)
// make sure there are no duplicated dupes in the list...
const foundInCompleteAnsweredQuestions = new Set();
let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => {
@ -430,15 +442,17 @@ export default {
answeredQuestions: filteredCompleteAnsweredQuestions,
}
console.log(this.capabilityQuestionsData[1].capabilityQuestions[0].answerSelected)
// this part has been fully answered, so advance to next part's question chain
for (let i = answer.partIndex + 1; i < this.capabilityQuestionsData.length; i++) {
// if this part has not yet been fully answered, then make it the current part
if (!this.capabilityQuestionsData[i].answerData?.answerSelected) {
if (!this.capabilityQuestionsData[i].answerData?.answerResult) {
this.currentQuestionChainIndex = i;
break;
}
}
console.log(this.capabilityQuestionsData[1].capabilityQuestions[0].answerSelected)
},
// TODO I'm sure there's a better/simplier way to do this that I'm missing but my brain's fried
// Find the part that has some answer that has an answerResult matching the selected answerResult, then get the corresponding answerResult2
@ -450,7 +464,6 @@ export default {
.answerResult2;
},
loadInitialCapabilityQuestionsData() {
// are there alreadyAnsweredQuestions?
const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers;
@ -486,6 +499,7 @@ export default {
// mark this partQuestion as answered (question-chain will read this)
part.capabilityQuestions[aq.questionNum - 1].answerSelected = answerString;
console.log("answerSelected set")
// mark this partQuestion as duplicate if it is (question-chain will read this)
if (aq.suppressQuestion) {
part.capabilityQuestions[aq.questionNum - 1].suppressQuestion = true;
@ -506,6 +520,8 @@ export default {
});
console.log("AHHHHH", this.capabilityQuestionsData[1].capabilityQuestions[0].answerSelected)
// Set up watch for each set of part questions, which gets updated when all questions for a part have been answered
this.$watch("selectedAnswers." + part.key, (newValue) => {
if (newValue) {

View file

@ -20,7 +20,7 @@
:manualCopy="AlertFewMoreQuestionsCopy"
v-bind:isDismissible="false"
/>
<div v-for="(part, i) in partsQuestionsData" :key="i">
<div v-for="(part, i) in partsQuestionsData" :key="part.key">
<questionChain
ref="questionChain"
:keyString="part.key"

View file

@ -91,6 +91,61 @@ export default {
// if has capability questions
// go to capability-questions page and pass the partsData
// partsOrQuestions = [
// {
// "glassName": "Single",
// "glassLocation": "Windshield",
// "parts": [
// {
// "partNumber": "A",
// "description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
// "color": "Green Tint, Blue Shade",
// "requiresRecalibration": true,
// "requiresCapabilityQuestions": true,
// "recalibrationType": null,
// "childParts": null,
// "childPartQuestions": []
// },
// ],
// "partQuestions": null
// },
// {
// "glassName": "Front",
// "glassLocation": "Driver",
// "parts": [
// {
// "partNumber": "B",
// "description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
// "color": "Green Tint, Blue Shade",
// "requiresRecalibration": true,
// "requiresCapabilityQuestions": true,
// "recalibrationType": null,
// "childParts": null,
// "childPartQuestions": []
// },
// ],
// "partQuestions": null
// },
// {
// "glassName": "Rear",
// "glassLocation": "Driver",
// "parts": [
// {
// "partNumber": "C",
// "description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
// "color": "Green Tint, Blue Shade",
// "requiresRecalibration": true,
// "requiresCapabilityQuestions": false,
// "recalibrationType": null,
// "childParts": null,
// "childPartQuestions": []
// },
// ],
// "partQuestions": null
// }
// ]
partsOrQuestions = [
{
"glassName": "Single",
@ -105,9 +160,31 @@ export default {
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
},
}
],
"partQuestions": null
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the first question?",
"answers": [
{
"answerResult1": "DYNAMIC",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DYNAMIC"
},
{
"answerResult1": "Unknown",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Unknown"
}
]
}
]
},
{
"glassName": "Front",
@ -122,15 +199,36 @@ export default {
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
},
}
],
"partQuestions": null
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the second question?",
"answers": [
{
"answerResult1": "Oh yeah",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "Oh yeah"
},
{
"answerResult1": "Maybe",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Maybe"
}
]
}
]
},
{
"glassName": "Rear",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "C",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
@ -140,110 +238,12 @@ export default {
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
},
}
],
"partQuestions": null
}
]
partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "A",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": true,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the first question?",
"answers": [
{
"answerResult1": "DYNAMIC",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DYNAMIC"
},
{
"answerResult1": "Unknown",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Unknown"
}
]
}
]
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "B",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": true,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the second question?",
"answers": [
{
"answerResult1": "Oh yeah",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "Oh yeah"
},
{
"answerResult1": "Maybe",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Maybe"
}
]
}
]
},
{
"glassName": "Rear",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "C",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": false,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null
}
]
for (let partOrQuestion of partsOrQuestions) {
if (this.hasCapabilityQuestions([partOrQuestion])) {
let capabilityQuestionsForGlassLocation = (await baseMixin.methods.dispatchStoreAction(storeActions.GET_CAPABILITY_QUESTIONS, {
@ -264,7 +264,117 @@ export default {
}
}
partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "A",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": true,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the first question?",
"answers": [
{
"answerResult1": "DYNAMIC",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DYNAMIC"
},
{
"answerResult1": "Unknown",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Unknown"
}
]
}
]
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "B",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": true,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null,
"capabilityQuestions": [
{
"questionSequence": 1,
"questionText": "Is this the second question?",
"answers": [
{
"answerResult1": "Oh yeah",
"answerResult2": "1",
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "Oh yeah"
},
{
"answerResult1": "Maybe",
"answerResult2": "0",
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "Maybe"
}
]
}
]
},
{
"glassName": "Rear",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "C",
"description": "rain sensor, solar, 3rd visor band, soundproofing, high beam sensor",
"color": "Green Tint, Blue Shade",
"requiresRecalibration": true,
"requiresCapabilityQuestions": false,
"recalibrationType": null,
"childParts": null,
"childPartQuestions": []
}
],
"partQuestions": null
}
]
store.commit(storeMutations.UPDATE_PAGE_DATA, {
page: "capability-questions",
data: [{
partsOrQuestions: partsOrQuestions
}],
})
self.$router.navigateWithSaving(self.navigationScenarios.HAS_CAPABILITY_QUESTIONS, self.$route, {}, {}, { partsOrQuestions });
} else {
@ -273,8 +383,8 @@ export default {
// save to store lineItems.glassParts
self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
self.$refs.loadingModal.showModal();
navigateToHeritageFunnel();
// self.$refs.loadingModal.showModal();
// navigateToHeritageFunnel();
// For quote pages MVP release
// self.$router.navigate(self.navigationScenarios.HAS_NO_MORE_QUESTIONS, self.$route);

View file

@ -91,6 +91,7 @@ export default {
},
mounted() {
if (Array.isArray(this.validateValue)) {
console.log("LB mounted array")
this.checkValue = this.isValueSelectedByArray(this.selectedValues);
const isSelectedByValidator = this.isValueSelectedByArray(this.validateValue);
@ -99,7 +100,10 @@ export default {
}
}
else {
console.log("LB mounted NOT ")
console.log("selectedValues: ", this.selectedValues)
this.checkValue = this.selectedValues == this.value;
console.log(this.checkValue)
}
},
methods: {
@ -134,6 +138,10 @@ export default {
value: this.value.toString(),
buttonId: this.buttonID && this.buttonID.toString(),
};
console.log("handleCheckChange: ", emitEvent)
console.log("selectedValues: ", this.selectedValues)
this.handleChange(this.value);
this.$emit("isCheckedChanged", emitEvent);
this.$emit("update:modelValue", emitEvent);