diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 2c132af9b..f9a15a6e8 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -9,7 +9,7 @@ -
+
x.capabilityQuestions).map((glass, i) => { + this.questionsData = this.pageData.partsOrQuestions.filter(x => x.capabilityQuestions).map((glass, i) => { // NOTE: questions for property "questions" can differ between layouts glass.questions = glass.capabilityQuestions; // reset selectedAnswers for this glass @@ -103,16 +101,16 @@ export default { }); }, methods: { - showThisQuestionChain(glass, i) { - if (!glass.capabilityQuestions || glass.capabilityQuestions?.length < 1 || glass.isSuppressedPart) { return false; } // return false if no capabilityQuestions or if suppressed - return this.currentQuestionChainIndex === i || glass.answerData?.answerResult?.length > 0; - }, arePagePrerequisitesValid() { const capabilityQuestionsPageData = store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); return capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0; }, + showThisQuestionChain(glass, i) { + if (!glass.capabilityQuestions || glass.capabilityQuestions?.length < 1 || glass.isSuppressedPart) { return false; } // return false if no capabilityQuestions or if suppressed + return this.currentQuestionChainIndex === i || glass.answerData?.answerResult?.length > 0; + }, async forwardButtonAction() { - const capabilityQuestionsAnswersArray = this.capabilityQuestionsData.map((glass) => { + const capabilityQuestionsAnswersArray = this.questionsData.map((glass) => { const selectedAnswerResult2 = this.getCorrespondingAnswerResult2(glass.answerData.answerResult); return { @@ -127,7 +125,7 @@ export default { }); // clear out answerData for future page loads; must occur prior to store save - this.capabilityQuestionsData.forEach((glass) => { + this.questionsData.forEach((glass) => { glass.answerData = {}; }); @@ -138,270 +136,17 @@ export default { let partsOrQuestions = this.pageData.partsOrQuestions; for (let answer of capabilityQuestionsAnswersArray) { 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; + const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(this.storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, answer.glassLocation, false)).data; partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === answer.glassLocation).parts = partFromCapabilityQuestionAnswer; } this.navigateForward(partsOrQuestions); }, - handleAnswerUpdates(answer) { - // only runs when all questions in a question-chain have been answered - // when selectedAnswers updates, user has completed this part's question chain and has a final answer - // (does not get run for each invididual question's answer, only when - // all relevant questions for the current part have been answered) - - /* - answer example format: - { - "answerResult": "DD11132", - "answeredQuestions": [ - { - "questionText": "Is your Grand Cherokee the Laredo model?", - "selectedAnswerText": "Yes", - "questionNum": 1, - } - ], - "glassIndex": 0 - } - */ - - // collect a list of the answered questions' numbers, needed later below - const answeredQuestionIndexes = []; - const foundDuplicateQuestions = []; - - // if user has answered a question differently than anything that was preloaded, - // we need to clear out any preloaded answers - this.selectedAnswers = {}; - - // loop through every answered question on the currently answered glass part - answer.answeredQuestions?.forEach((aq) => { - - // keep track of this question number - answeredQuestionIndexes.push(aq.questionNum); - - const answeredQuestionText = aq.questionText.toUpperCase(); - const answeredQuestionAnswer = aq.selectedAnswerText.toUpperCase(); - - // HANDLE DUPLICATE QUESTIONS - - // loop through all glass parts data - this.capabilityQuestionsData.forEach((glass, gpIndex) => { - - // only look for duplicates forward... to parts that follow after the currently being answered part - if (gpIndex > answer.glass) { - - let suppressUntil; - // reset this glass part, in case user is changing their previous answers - glass.answerData = null; - glass.isSuppressedPart = null; - - // loop through this glass part's part questions, looking for a questionText match - glass.capabilityQuestions.forEach((pq, pqIndex) => { - - // clear out any previously set answers - pq.answerSelected = null; - - // clear or set suppressQuestion property for each question - if (suppressUntil) { - // if suppressUntil has been set, then suppress this question if before it - if (pqIndex + 1 < suppressUntil) { - pq.suppressQuestion = true; - } else { - pq.suppressQuestion = null; - } - } else { - pq.suppressQuestion = null; - } - - // if these match then we have a duplicate question - if (pq.questionText.toUpperCase() === answeredQuestionText) { - - const thisAnsweredCapabilityQuestion = glass.capabilityQuestions[pqIndex]; - let matchedAnswer; - let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... - - // which one of this capabilityQuestions' answers matches our answer? - pq.answers.forEach((ans) => { - if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { - matchedAnswer = ans; - ans.selected = true; - } else { - rejectedAnswers.push(ans); - ans.selected = null; - } - }); - - // 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(); - - // handle suppressing downstream in this question chain - - if (matchedAnswer.nextQuestionSequence) { - // ensure that the question that the accepted answer has set to be next is NOT suppressed - glass.capabilityQuestions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; - // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number - if (pqIndex === 0) { - if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - } - } - - // handle suppressing upstream in this question chain - glass.capabilityQuestions.forEach((q) => { - q.answers.forEach((thisAns) => { - // restore any of the answers that formerly led to the duplicated question - if (thisAns.originalNextQuestionSequence === pq.questionSequence) { - // restore original nextQuestionSequence - thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; - this.originalNextQuestionSequence = null; - // restore original answerResult - if (thisAns.originalAnswerResult) { - thisAns.answerResult = thisAns.originalAnswerResult; - thisAns.originalAnswerResult = null; - } - } - // search for any answers that lead to the duplicated question - if (thisAns.nextQuestionSequence === pq.questionSequence) { - // update either the nextQuestionSequence or the answerResult - if (matchedAnswer.nextQuestionSequence) { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; - } else { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = null; - thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; - thisAns.answerResult = matchedAnswer.answerResult; - } - } - }); - }); - - // suppress current question - thisAnsweredCapabilityQuestion.suppressQuestion = true; - - const thisGlassPart = "glass" + gpIndex; - if (foundDuplicateQuestions[thisGlassPart]) { - if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredCapabilityQuestion.questionSequence)) { - foundDuplicateQuestions[thisGlassPart].push(thisAnsweredCapabilityQuestion.questionSequence); - } - } else { - foundDuplicateQuestions[thisGlassPart] = [thisAnsweredCapabilityQuestion.questionSequence]; - } - - // are there any questions left that are not suppressed? - const remainingQuestions = glass.capabilityQuestions.filter((q) => { - return !q.suppressQuestion; - }); - - if (remainingQuestions.length < 1) { - // this is the final answer for this glass part - - // mark this part as completely answered by adding answerData - const answeredQuestionObj = { - questionText: pq.questionText, - selectedAnswerText: matchedAnswer.answerText, - questionNum: pq.questionSequence, - suppressQuestion: pq.suppressQuestion, - }; - // set the answerData as 'already answered' - glass.answerData = { - answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, - answeredQuestions: [answeredQuestionObj], - }; - - // suppress this glass because it has an answer - glass.isSuppressedPart = true; - } - - } - - }); - - // 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(); - - } - }); - }); - - // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART - - // look through all (this part's) part questions for any duplicates that were suppressed; - // add them to the list of answered questions if found - - // EX answeredQuestionIndexes: [1,5,11,13] - - // EX foundDuplicateQuestions = { - // "glassPart1": [1], - // "glassPart2": [7, 10] - // }; - - const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; - const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; - const glassPartAnswered = this.capabilityQuestionsData[answer.glassIndex]; - - thisPartsDupes?.forEach((dupe) => { - // dupe is a single integer - const dupeQuestion = glassPartAnswered.capabilityQuestions[dupe - 1]; - const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true); - - glassPartAnswered.capabilityQuestions.forEach((q) => { - let includeThisDupeInAnsweredQuestions = false; - - // did one of the answers of this question point to the duplicated question? - q.answers.forEach((a) => { - if ((dupe === a.originalNextQuestionSequence) && - (answeredQuestionIndexes.includes(q.questionSequence)) && - (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { - includeThisDupeInAnsweredQuestions = true; - } - }); - - // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? - if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { - includeThisDupeInAnsweredQuestions = true; - } - - if (includeThisDupeInAnsweredQuestions) { - completeAnsweredQuestions.push({ - questionNum: dupeQuestion.questionSequence, - questionText: dupeQuestion.questionText, - selectedAnswerText: dupeQuestionAnswer.answerText, - suppressQuestion: dupeQuestion.suppressQuestion, - }); - } - }); - }); - - // make sure there are no duplicated dupes in the list... - const foundInCompleteAnsweredQuestions = new Set(); - let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { - const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); - foundInCompleteAnsweredQuestions.add(el.questionText); - return !duplicate; - }); - filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a, b) => a.questionNum - b.questionNum); - - // set final answer data for the current answered glass part - glassPartAnswered.answerData = { - answerResult: answer.answerResult, - answeredQuestions: filteredCompleteAnsweredQuestions, - } - - // this part has been fully answered, so advance to next part's question chain - for (let i = answer.glassIndex + 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?.answerResult) { - this.currentQuestionChainIndex = i; - break; - } - } - }, // 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 getCorrespondingAnswerResult2(answerResult1) { - return this.capabilityQuestionsData + return this.questionsData .find(part => part.capabilityQuestions.some(question => question.answers.some(answer => answer.answerResult == answerResult1))) // found part .capabilityQuestions.find(question => question.answers.some(answer => answer.answerResult == answerResult1)) // found question .answers.find(answer => answer.answerResult == answerResult1) diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 50cfe42c2..b60e4dd5f 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -20,7 +20,7 @@ :manualCopy="AlertFewMoreQuestionsCopy" v-bind:isDismissible="false" /> -
+
x.parts[0].childPartQuestions.length).map((glass, i) => { + this.questionsData = this.pageData.partsOrQuestions.filter(x => x.parts[0].childPartQuestions.length).map((glass, i) => { // NOTE: questions for property "questions" can differ between layouts glass.questions = glass.parts[0].childPartQuestions; // reset selectedAnswers for this glass @@ -130,7 +128,7 @@ export default { return this.currentGlassIndex === i || glass.answerData?.answerResult?.length > 0; }, async forwardButtonAction() { - const questionAnswersArray = this.moldingQuestionsData.map((glass) => { + const questionAnswersArray = this.questionsData.map((glass) => { return { glassLocation: glass.glassLocation, glassName: glass.glassName, @@ -141,7 +139,7 @@ export default { }); // clear out answerData for future page loads; must occur prior to store save - this.moldingQuestionsData.forEach((glass) => { + this.questionsData.forEach((glass) => { glass.answerData = {}; }); @@ -162,262 +160,6 @@ export default { this.navigateForward(partsOrQuestions); }, - handleAnswerUpdates(answer) { - // only runs when all questions in a question-chain have been answered - // when selectedAnswers updates, user has completed this part's question chain and has a final answer - // (does not get run for each invididual question's answer, only when - // all relevant questions for the current part have been answered) - - /* - answer example format: - { - "answerResult": "DD11132", - "answeredQuestions": [ - { - "questionText": "Is your Grand Cherokee the Laredo model?", - "selectedAnswerText": "Yes", - "questionNum": 1, - } - ], - "glassIndex": 0 - } - */ - - // collect a list of the answered questions' numbers, needed later below - const answeredQuestionIndexes = []; - const foundDuplicateQuestions = []; - - // if user has answered a question differently than anything that was preloaded, - // we need to clear out any preloaded answers - this.selectedAnswers = {}; - - // loop through every answered question on the currently answered glass part - answer.answeredQuestions?.forEach((aq) => { - - // keep track of this question number - answeredQuestionIndexes.push(aq.questionNum); - - const answeredQuestionText = aq.questionText.toUpperCase(); - const answeredQuestionAnswer = aq.selectedAnswerText.toUpperCase(); - - // HANDLE DUPLICATE QUESTIONS - - // loop through all glass parts data - this.moldingQuestionsData.forEach((glass, gpIndex) => { - - // only look for duplicates forward... to parts that follow after the currently being answered part - if (gpIndex > answer.glassIndex) { - - let suppressUntil; - // reset this glass part, in case user is changing their previous answers - glass.answerData = null; - glass.isSuppressedPart = null; - - // loop through this glass part's part questions, looking for a questionText match - glass.questions.forEach((pq, pqIndex) => { - - // clear out any previously set answers - pq.answerSelected = null; - - // clear or set suppressQuestion property for each question - if (suppressUntil) { - // if suppressUntil has been set, then suppress this question if before it - if (pqIndex + 1 < suppressUntil) { - pq.suppressQuestion = true; - } else { - pq.suppressQuestion = null; - } - } else { - pq.suppressQuestion = null; - } - - // if these match then we have a duplicate question - if (pq.questionText.toUpperCase() === answeredQuestionText) { - - const thisAnsweredPartQuestion = glass.questions[pqIndex]; - let matchedAnswer; - let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... - - // which one of this questions' answers matches our answer? - pq.answers.forEach((ans) => { - if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { - matchedAnswer = ans; - ans.selected = true; - } else { - rejectedAnswers.push(ans); - ans.selected = null; - } - }); - - // Update the key to re-render this part's question-chain component - this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].glassLocation + this.moldingQuestionsData[gpIndex].glassName + Date.now().toString(); - - // handle suppressing downstream in this question chain - - if (matchedAnswer.nextQuestionSequence) { - // ensure that the question that the accepted answer has set to be next is NOT suppressed - glass.questions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; - // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number - if (pqIndex === 0) { - if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence} - } - } - - // handle suppressing upstream in this question chain - glass.questions.forEach((q) => { - q.answers.forEach((thisAns) => { - // restore any of the answers that formerly led to the duplicated question - if (thisAns.originalNextQuestionSequence === pq.questionSequence) { - // restore original nextQuestionSequence - thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; - this.originalNextQuestionSequence = null; - // restore original answerResult - if (thisAns.originalAnswerResult) { - thisAns.answerResult = thisAns.originalAnswerResult; - thisAns.originalAnswerResult = null; - } - } - // search for any answers that lead to the duplicated question - if (thisAns.nextQuestionSequence === pq.questionSequence) { - // update either the nextQuestionSequence or the answerResult - if (matchedAnswer.nextQuestionSequence) { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; - } else { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = null; - thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; - thisAns.answerResult = matchedAnswer.answerResult; - } - } - }); - }); - - // suppress current question - thisAnsweredPartQuestion.suppressQuestion = true; - - const thisGlassPart = "glass" + gpIndex; - if (foundDuplicateQuestions[thisGlassPart]) { - if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredPartQuestion.questionSequence)) { - foundDuplicateQuestions[thisGlassPart].push(thisAnsweredPartQuestion.questionSequence); - } - } else { - foundDuplicateQuestions[thisGlassPart] = [thisAnsweredPartQuestion.questionSequence]; - } - - // are there any questions left that are not suppressed? - const remainingQuestions = glass.questions.filter((q) => { - return !q.suppressQuestion; - }); - - if (remainingQuestions.length < 1) { - // this is the final answer for this glass part - - // mark this part as completely answered by adding answerData - const answeredQuestionObj = { - questionText: pq.questionText, - selectedAnswerText: matchedAnswer.answerText, - questionNum: pq.questionSequence, - suppressQuestion: pq.suppressQuestion, - }; - // set the answerData as 'already answered' - glass.answerData = { - answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, - answeredQuestions: [answeredQuestionObj], - }; - - // suppress this glass because it has an answer - glass.isSuppressedPart = true; - } - - } - - }); - - // Update the key to re-render this part's question-chain component - this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].glassLocation + this.moldingQuestionsData[gpIndex].glassName + Date.now().toString(); - - } - - }); - - }); - - // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART - - // look through all (this part's) part questions for any duplicates that were suppressed; - // add them to the list of answered questions if found - - // EX answeredQuestionIndexes: [1,5,11,13] - - // EX foundDuplicateQuestions = { - // "glassPart1": [1], - // "glassPart2": [7, 10] - // }; - - const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; - const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; - const glassPartAnswered = this.moldingQuestionsData[answer.glassIndex]; - - thisPartsDupes?.forEach((dupe) => { - // dupe is a single integer - const dupeQuestion = glassPartAnswered.questions[dupe - 1]; - const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true); - - glassPartAnswered.questions.forEach((q) => { - let includeThisDupeInAnsweredQuestions = false; - - // did one of the answers of this question point to the duplicated question? - q.answers.forEach((a) => { - if ((dupe === a.originalNextQuestionSequence) && - (answeredQuestionIndexes.includes(q.questionSequence)) && - (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { - includeThisDupeInAnsweredQuestions = true; - } - }); - - // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? - if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { - includeThisDupeInAnsweredQuestions = true; - } - - if (includeThisDupeInAnsweredQuestions) { - completeAnsweredQuestions.push({ - questionNum: dupeQuestion.questionSequence, - questionText: dupeQuestion.questionText, - selectedAnswerText: dupeQuestionAnswer.answerText, - suppressQuestion: dupeQuestion.suppressQuestion, - }); - } - }); - }); - - // make sure there are no duplicated dupes in the list... - const foundInCompleteAnsweredQuestions = new Set(); - let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { - const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); - foundInCompleteAnsweredQuestions.add(el.questionText); - return !duplicate; - }); - filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum); - - // set final answer data for the current answered glass part - glassPartAnswered.answerData = { - answerResult: answer.answerResult, - answeredQuestions: filteredCompleteAnsweredQuestions, - } - - // this part has been fully answered, so advance to next molding question chain - for (let i = answer.glassIndex + 1; i < this.moldingQuestionsData.length; i++) { - // if this part has not yet been fully answered, then make it the current part - if (!this.moldingQuestionsData[i].answerData?.answerResult) { - this.currentGlassIndex = i; - break; - } - } - - }, }, components: { funnelHeader, diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 131a70f44..d5e79540b 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -20,7 +20,7 @@ :manualCopy="AlertFewMoreQuestionsCopy" v-bind:isDismissible="false" /> -
+
x.partQuestions).map((glass, i) => { + this.questionsData = this.pageData.partsOrQuestions.filter(x => x.partQuestions).map((glass, i) => { // NOTE: questions for property "questions" can differ between layouts glass.questions = glass.partQuestions; // reset selectedAnswers for this glass @@ -130,7 +128,7 @@ export default { return this.currentGlassIndex === i || glass.answerData?.answerResult?.length > 0; }, async forwardButtonAction() { - const questionAnswersArray = this.partsQuestionsData.map((glass) => { + const questionAnswersArray = this.questionsData.map((glass) => { return { glassLocation: glass.glassLocation, glassName: glass.glassName, @@ -141,7 +139,7 @@ export default { }); // clear out answerData for future page loads; must occur prior to store save - this.partsQuestionsData.forEach((glass) => { + this.questionsData.forEach((glass) => { glass.answerData = {}; }); @@ -149,7 +147,7 @@ export default { await this.dispatchStoreAction(this.storeActions.SAVE_PART_QUESTION_ANSWERS, questionAnswersArray, false); // call API parts method - const partsLookup = await this.dispatchStoreAction(storeActions.GET_PARTS) + const partsLookup = await this.dispatchStoreAction(this.storeActions.GET_PARTS) .catch(() => { return this.$refs.funnelFooter.removeLoader(); }); @@ -158,262 +156,6 @@ export default { this.navigateForward(glassNameAndPartsForStore); }, - handleAnswerUpdates(answer) { - // only runs when all questions in a question-chain have been answered - // when selectedAnswers updates, user has completed this part's question chain and has a final answer - // (does not get run for each invididual question's answer, only when - // all relevant questions for the current part have been answered) - - /* - answer example format: - { - "answerResult": "DD11132", - "answeredQuestions": [ - { - "questionText": "Is your Grand Cherokee the Laredo model?", - "selectedAnswerText": "Yes", - "questionNum": 1, - } - ], - "glassIndex": 0 - } - */ - - // collect a list of the answered questions' numbers, needed later below - const answeredQuestionIndexes = []; - const foundDuplicateQuestions = []; - - // if user has answered a question differently than anything that was preloaded, - // we need to clear out any preloaded answers - this.selectedAnswers = {}; - - // loop through every answered question on the currently answered glass part - answer.answeredQuestions?.forEach((aq) => { - - // keep track of this question number - answeredQuestionIndexes.push(aq.questionNum); - - const answeredQuestionText = aq.questionText.toUpperCase(); - const answeredQuestionAnswer = aq.selectedAnswerText.toUpperCase(); - - // HANDLE DUPLICATE QUESTIONS - - // loop through all glass parts data - this.partsQuestionsData.forEach((glass, gpIndex) => { - - // only look for duplicates forward... to parts that follow after the currently being answered part - if (gpIndex > answer.glassIndex) { - - let suppressUntil; - // reset this glass part, in case user is changing their previous answers - glass.answerData = null; - glass.isSuppressedPart = null; - - // loop through this glass part's questions, looking for a questionText match - glass.questions.forEach((pq, pqIndex) => { - - // clear out any previously set answers - pq.answerSelected = null; - - // clear or set suppressQuestion property for each question - if (suppressUntil) { - // if suppressUntil has been set, then suppress this question if before it - if (pqIndex + 1 < suppressUntil) { - pq.suppressQuestion = true; - } else { - pq.suppressQuestion = null; - } - } else { - pq.suppressQuestion = null; - } - - // if these match then we have a duplicate question - if (pq.questionText.toUpperCase() === answeredQuestionText) { - - const thisAnsweredQuestion = glass.questions[pqIndex]; - let matchedAnswer; - let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... - - // which one of this questions' answers matches our answer? - pq.answers.forEach((ans) => { - if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { - matchedAnswer = ans; - ans.selected = true; - } else { - rejectedAnswers.push(ans); - ans.selected = null; - } - }); - - // Update the key to re-render this part's question-chain component - this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].glassLocation + this.partsQuestionsData[gpIndex].glassName + Date.now().toString(); - - // handle suppressing downstream in this question chain - - if (matchedAnswer.nextQuestionSequence) { - // ensure that the question that the accepted answer has set to be next is NOT suppressed - glass.questions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; - // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number - if (pqIndex === 0) { - if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence} - } - } - - // handle suppressing upstream in this question chain - glass.questions.forEach((q) => { - q.answers.forEach((thisAns) => { - // restore any of the answers that formerly led to the duplicated question - if (thisAns.originalNextQuestionSequence === pq.questionSequence) { - // restore original nextQuestionSequence - thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; - this.originalNextQuestionSequence = null; - // restore original answerResult - if (thisAns.originalAnswerResult) { - thisAns.answerResult = thisAns.originalAnswerResult; - thisAns.originalAnswerResult = null; - } - } - // search for any answers that lead to the duplicated question - if (thisAns.nextQuestionSequence === pq.questionSequence) { - // update either the nextQuestionSequence or the answerResult - if (matchedAnswer.nextQuestionSequence) { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; - } else { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = null; - thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; - thisAns.answerResult = matchedAnswer.answerResult; - } - } - }); - }); - - // suppress current question - thisAnsweredQuestion.suppressQuestion = true; - - const thisGlassPart = "glass" + gpIndex; - if (foundDuplicateQuestions[thisGlassPart]) { - if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredQuestion.questionSequence)) { - foundDuplicateQuestions[thisGlassPart].push(thisAnsweredQuestion.questionSequence); - } - } else { - foundDuplicateQuestions[thisGlassPart] = [thisAnsweredQuestion.questionSequence]; - } - - // are there any questions left that are not suppressed? - const remainingQuestions = glass.questions.filter((q) => { - return !q.suppressQuestion; - }); - - if (remainingQuestions.length < 1) { - // this is the final answer for this glass part - - // mark this part as completely answered by adding answerData - const answeredQuestionObj = { - questionText: pq.questionText, - selectedAnswerText: matchedAnswer.answerText, - questionNum: pq.questionSequence, - suppressQuestion: pq.suppressQuestion, - }; - // set the answerData as 'already answered' - glass.answerData = { - answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, - answeredQuestions: [answeredQuestionObj], - }; - - // suppress this glass because it has an answer - glass.isSuppressedPart = true; - } - - } - - }); - - // Update the key to re-render this part's question-chain component - this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].glassLocation + this.partsQuestionsData[gpIndex].glassName + Date.now().toString(); - - } - - }); - - }); - - // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART - - // look through all (this part's) part questions for any duplicates that were suppressed; - // add them to the list of answered questions if found - - // EX answeredQuestionIndexes: [1,5,11,13] - - // EX foundDuplicateQuestions = { - // "glassPart1": [1], - // "glassPart2": [7, 10] - // }; - - const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; - const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; - const glassPartAnswered = this.partsQuestionsData[answer.glassIndex]; - - thisPartsDupes?.forEach((dupe) => { - // dupe is a single integer - const dupeQuestion = glassPartAnswered.questions[dupe - 1]; - const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true); - - glassPartAnswered.questions.forEach((q) => { - let includeThisDupeInAnsweredQuestions = false; - - // did one of the answers of this question point to the duplicated question? - q.answers.forEach((a) => { - if ((dupe === a.originalNextQuestionSequence) && - (answeredQuestionIndexes.includes(q.questionSequence)) && - (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { - includeThisDupeInAnsweredQuestions = true; - } - }); - - // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? - if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { - includeThisDupeInAnsweredQuestions = true; - } - - if (includeThisDupeInAnsweredQuestions) { - completeAnsweredQuestions.push({ - questionNum: dupeQuestion.questionSequence, - questionText: dupeQuestion.questionText, - selectedAnswerText: dupeQuestionAnswer.answerText, - suppressQuestion: dupeQuestion.suppressQuestion, - }); - } - }); - }); - - // make sure there are no duplicated dupes in the list... - const foundInCompleteAnsweredQuestions = new Set(); - let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { - const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); - foundInCompleteAnsweredQuestions.add(el.questionText); - return !duplicate; - }); - filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum); - - // set final answer data for the current answered glass part - glassPartAnswered.answerData = { - answerResult: answer.answerResult, - answeredQuestions: filteredCompleteAnsweredQuestions, - } - - // this part has been fully answered, so advance to next part's question chain - for (let i = answer.glassIndex + 1; i < this.partsQuestionsData.length; i++) { - // if this part has not yet been fully answered, then make it the current part - if (!this.partsQuestionsData[i].answerData?.answerResult) { - this.currentGlassIndex = i; - break; - } - } - - }, }, components: { funnelHeader, diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 415fa1e6d..a34107970 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -126,6 +126,263 @@ export default { return glass; }, + handleAnswerUpdates(answer, vm) { + // only runs when all questions in a question-chain have been answered + // when selectedAnswers updates, user has completed this part's question chain and has a final answer + // (does not get run for each invididual question's answer, only when + // all relevant questions for the current part have been answered) + + /* answer example format: + { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Is your Grand Cherokee the Laredo model?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "glassIndex": 0 + } + */ + + const self = vm ?? this; + + // collect a list of the answered questions' numbers, needed later below + const answeredQuestionIndexes = []; + const foundDuplicateQuestions = []; + + // if user has answered a question differently than anything that was preloaded, + // we need to clear out any preloaded answers + self.selectedAnswers = {}; + + // loop through every answered question on the currently answered glass part + answer.answeredQuestions?.forEach((aq) => { + + // keep track of this question number + answeredQuestionIndexes.push(aq.questionNum); + + const answeredQuestionText = aq.questionText.toUpperCase(); + const answeredQuestionAnswer = aq.selectedAnswerText.toUpperCase(); + + // HANDLE DUPLICATE QUESTIONS + + // loop through all glass parts data + self.questionsData.forEach((glass, gpIndex) => { + + // only look for duplicates forward... to parts that follow after the currently being answered part + if (gpIndex > answer.glassIndex) { + + let suppressUntil; + // reset this glass part, in case user is changing their previous answers + glass.answerData = null; + glass.isSuppressedPart = null; + + // loop through this glass part's questions, looking for a questionText match + glass.questions.forEach((pq, pqIndex) => { + + // clear out any previously set answers + pq.answerSelected = null; + + // clear or set suppressQuestion property for each question + if (suppressUntil) { + // if suppressUntil has been set, then suppress this question if before it + if (pqIndex + 1 < suppressUntil) { + pq.suppressQuestion = true; + } else { + pq.suppressQuestion = null; + } + } else { + pq.suppressQuestion = null; + } + + // if these match then we have a duplicate question + if (pq.questionText.toUpperCase() === answeredQuestionText) { + + const thisAnsweredQuestion = glass.questions[pqIndex]; + let matchedAnswer; + let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... + + // which one of this questions' answers matches our answer? + pq.answers.forEach((ans) => { + if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { + matchedAnswer = ans; + ans.selected = true; + } else { + rejectedAnswers.push(ans); + ans.selected = null; + } + }); + + // Update the key to re-render this part's question-chain component + self.questionsData[gpIndex].key = self.questionsData[gpIndex].glassLocation + self.questionsData[gpIndex].glassName + Date.now().toString(); + + // handle suppressing downstream in this question chain + + if (matchedAnswer.nextQuestionSequence) { + // ensure that the question that the accepted answer has set to be next is NOT suppressed + glass.questions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; + // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number + if (pqIndex === 0) { + if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } + if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence} + } + } + + // handle suppressing upstream in this question chain + glass.questions.forEach((q) => { + q.answers.forEach((thisAns) => { + // restore any of the answers that formerly led to the duplicated question + if (thisAns.originalNextQuestionSequence === pq.questionSequence) { + // restore original nextQuestionSequence + thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; + self.originalNextQuestionSequence = null; + // restore original answerResult + if (thisAns.originalAnswerResult) { + thisAns.answerResult = thisAns.originalAnswerResult; + thisAns.originalAnswerResult = null; + } + } + // search for any answers that lead to the duplicated question + if (thisAns.nextQuestionSequence === pq.questionSequence) { + // update either the nextQuestionSequence or the answerResult + if (matchedAnswer.nextQuestionSequence) { + thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; + thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; + } else { + thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; + thisAns.nextQuestionSequence = null; + thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; + thisAns.answerResult = matchedAnswer.answerResult; + } + } + }); + }); + + // suppress current question + thisAnsweredQuestion.suppressQuestion = true; + + const thisGlassPart = "glass" + gpIndex; + if (foundDuplicateQuestions[thisGlassPart]) { + if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredQuestion.questionSequence)) { + foundDuplicateQuestions[thisGlassPart].push(thisAnsweredQuestion.questionSequence); + } + } else { + foundDuplicateQuestions[thisGlassPart] = [thisAnsweredQuestion.questionSequence]; + } + + // are there any questions left that are not suppressed? + const remainingQuestions = glass.questions.filter((q) => { + return !q.suppressQuestion; + }); + + if (remainingQuestions.length < 1) { + // this is the final answer for this glass part + + // mark this part as completely answered by adding answerData + const answeredQuestionObj = { + questionText: pq.questionText, + selectedAnswerText: matchedAnswer.answerText, + questionNum: pq.questionSequence, + suppressQuestion: pq.suppressQuestion, + }; + // set the answerData as 'already answered' + glass.answerData = { + answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, + answeredQuestions: [answeredQuestionObj], + }; + + // suppress this glass because it has an answer + glass.isSuppressedPart = true; + } + + } + + }); + + // Update the key to re-render this part's question-chain component + self.questionsData[gpIndex].key = self.questionsData[gpIndex].glassLocation + self.questionsData[gpIndex].glassName + Date.now().toString(); + + } + + }); + + }); + + // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART + + // look through all (this part's) part questions for any duplicates that were suppressed; + // add them to the list of answered questions if found + + // EX answeredQuestionIndexes: [1,5,11,13] + + // EX foundDuplicateQuestions = { + // "glassPart1": [1], + // "glassPart2": [7, 10] + // }; + + const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; + const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; + const glassPartAnswered = self.questionsData[answer.glassIndex]; + + thisPartsDupes?.forEach((dupe) => { + // dupe is a single integer + const dupeQuestion = glassPartAnswered.questions[dupe - 1]; + const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true); + + glassPartAnswered.questions.forEach((q) => { + let includeThisDupeInAnsweredQuestions = false; + + // did one of the answers of this question point to the duplicated question? + q.answers.forEach((a) => { + if ((dupe === a.originalNextQuestionSequence) && + (answeredQuestionIndexes.includes(q.questionSequence)) && + (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { + includeThisDupeInAnsweredQuestions = true; + } + }); + + // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? + if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { + includeThisDupeInAnsweredQuestions = true; + } + + if (includeThisDupeInAnsweredQuestions) { + completeAnsweredQuestions.push({ + questionNum: dupeQuestion.questionSequence, + questionText: dupeQuestion.questionText, + selectedAnswerText: dupeQuestionAnswer.answerText, + suppressQuestion: dupeQuestion.suppressQuestion, + }); + } + }); + }); + + // make sure there are no duplicated dupes in the list... + const foundInCompleteAnsweredQuestions = new Set(); + let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { + const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); + foundInCompleteAnsweredQuestions.add(el.questionText); + return !duplicate; + }); + filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum); + + // set final answer data for the current answered glass part + glassPartAnswered.answerData = { + answerResult: answer.answerResult, + answeredQuestions: filteredCompleteAnsweredQuestions, + } + + // this part has been fully answered, so advance to next part's question chain + for (let i = answer.glassIndex + 1; i < self.questionsData.length; i++) { + // if this part has not yet been fully answered, then make it the current part + if (!self.questionsData[i].answerData?.answerResult) { + self.currentGlassIndex = i; + break; + } + } + + }, // Can't use `this` because navigateForward is also called from vin-pages-mixin async navigateForward(partsOrQuestions, vm) { const self = vm ?? this;