diff --git a/src/common-components/date-picker/date-picker-spec.js b/src/common-components/date-picker/date-picker-spec.js new file mode 100644 index 000000000..3d0843e10 --- /dev/null +++ b/src/common-components/date-picker/date-picker-spec.js @@ -0,0 +1 @@ +test.todo("some test to be written in the future"); diff --git a/src/common-components/date-picker/date-picker.vue b/src/common-components/date-picker/date-picker.vue new file mode 100644 index 000000000..28d433289 --- /dev/null +++ b/src/common-components/date-picker/date-picker.vue @@ -0,0 +1,459 @@ + + + + + diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 71d517e77..56ee81489 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -83,7 +83,7 @@ export default { this.currentQuestionNum = this.questions[0].questionSequence; // scroll the next question into view this.$nextTick(() => { - document.querySelector('.current-question').scrollIntoView({behavior: "smooth"}); + document.querySelector('.current-question')?.scrollIntoView({behavior: "smooth"}); }) } }, diff --git a/src/constants/application-config.js b/src/constants/application-config.js index f42a2c183..0e185cff4 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -7,6 +7,7 @@ const applicationConfig = { COOKIE_PATH: "/", CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" APPLICATION_NAME: "FixMyGlass", + APPLICATION_ABBREVIATION: "fmg", SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass" }; diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index d0e05919b..7545f38b0 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,10 +1,14 @@ const endpoints = { GetRouteInfo: { - url: "/content/api/v1/content/RouteInfo", + url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, method: "POST", }, GetHomepageInfo: { - url: "/content/api/v1/content/HomepageInfo", + url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + method: "GET", + }, + GetPageData: { + url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, method: "GET", }, GetVehicleYears: { @@ -31,10 +35,6 @@ const endpoints = { url: "/parts/api/v1/parts/damage-options", method: "GET", }, - GetPageData: { - url: "/content/api/v1/content", - method: "GET", - }, LookupVehicleByYmms: { url: "/vehicle/api/v1/vehicle/Lookup", method: "GET", diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index cdb38c58e..39b96c361 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -76,7 +76,6 @@ export default { capabilityQuestionsData: store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS).partsOrQuestions, selectedAnswers: {}, currentQuestionChainIndex: 0, - foundDuplicateQuestions: [], }; }, computed: { @@ -97,7 +96,17 @@ export default { } }, mounted() { - this.loadInitialCapabilityQuestionsData(); + // are there alreadyAnsweredQuestions? + const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers; + + this.capabilityQuestionsData = 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 + this.selectedAnswers[glass.key] = []; + // pass in: glass, i, alreadyAnsweredQuestions + return this.setupInitialData(glass, i, alreadyAnsweredQuestions); + }); }, methods: { showThisQuestionChain(glass, i) { @@ -110,14 +119,13 @@ export default { }, async forwardButtonAction() { const capabilityQuestionsAnswersArray = this.capabilityQuestionsData.map((glass) => { - const selectedAnswerResult1 = glass.answerData.answerResult; - const selectedAnswerResult2 = glass.answerData.answerResult2; + const selectedAnswerResult2 = this.getCorrespondingAnswerResult2(glass.answerData.answerResult); return { glassLocation: glass.glassLocation, glassName: glass.glassName, result: glass.answerData.answerResult, - result1: selectedAnswerResult1, + result1: glass.answerData.answerResult, result2: selectedAnswerResult2, answeredQuestions: glass.answerData.answeredQuestions, isSuppressedPart: glass.isSuppressedPart, @@ -147,7 +155,7 @@ export default { // 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 relevent questions for the current part have been answered) + // all relevant questions for the current part have been answered) /* answer example format: @@ -166,6 +174,7 @@ export default { // 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 @@ -255,7 +264,6 @@ export default { // restore original answerResult if (thisAns.originalAnswerResult) { thisAns.answerResult = thisAns.originalAnswerResult; - thisAns.answerResult1 = thisAns.originalAnswerResult; thisAns.originalAnswerResult = null; } } @@ -270,7 +278,6 @@ export default { thisAns.nextQuestionSequence = null; thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; thisAns.answerResult = matchedAnswer.answerResult; - thisAns.answerResult1 = matchedAnswer.answerResult; } } }); @@ -280,12 +287,12 @@ export default { thisAnsweredCapabilityQuestion.suppressQuestion = true; const thisGlassPart = "glass" + gpIndex; - if (this.foundDuplicateQuestions[thisGlassPart]) { - if (!this.foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredCapabilityQuestion.questionSequence)) { - this.foundDuplicateQuestions[thisGlassPart].push(thisAnsweredCapabilityQuestion.questionSequence); + if (foundDuplicateQuestions[thisGlassPart]) { + if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredCapabilityQuestion.questionSequence)) { + foundDuplicateQuestions[thisGlassPart].push(thisAnsweredCapabilityQuestion.questionSequence); } } else { - this.foundDuplicateQuestions[thisGlassPart] = [thisAnsweredCapabilityQuestion.questionSequence]; + foundDuplicateQuestions[thisGlassPart] = [thisAnsweredCapabilityQuestion.questionSequence]; } // are there any questions left that are not suppressed? @@ -306,7 +313,6 @@ export default { // set the answerData as 'already answered' glass.answerData = { answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, - answerResult1: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, answeredQuestions: [answeredQuestionObj], }; @@ -332,12 +338,12 @@ export default { // EX answeredQuestionIndexes: [1,5,11,13] - // EX this.foundDuplicateQuestions = { + // EX foundDuplicateQuestions = { // "glassPart1": [1], // "glassPart2": [7, 10] // }; - const thisPartsDupes = this.foundDuplicateQuestions["glass" + answer.glassIndex]; + const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; const glassPartAnswered = this.capabilityQuestionsData[answer.glassIndex]; @@ -383,14 +389,9 @@ export default { }); filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a, b) => a.questionNum - b.questionNum); - const selectedAnswerResult1 = answer.answerResult; - const selectedAnswerResult2 = this.getCorrespondingAnswerResult2(selectedAnswerResult1); - // set final answer data for the current answered glass part glassPartAnswered.answerData = { - answerResult: selectedAnswerResult1, - answerResult1: selectedAnswerResult1, - answerResult2: selectedAnswerResult2, + answerResult: answer.answerResult, answeredQuestions: filteredCompleteAnsweredQuestions, } @@ -412,73 +413,6 @@ export default { .answers.find(answer => answer.answerResult == answerResult1) .answerResult2; }, - loadInitialCapabilityQuestionsData() { - // are there alreadyAnsweredQuestions? - const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers; - - this.capabilityQuestionsData = this.pageData.partsOrQuestions.filter(x => x.capabilityQuestions).map((glass, i) => { - glass.key = glass.glassLocation + "-" + glass.glassName; - this.selectedAnswers[glass.key] = []; - if (!alreadyAnsweredQuestions) { - glass.answerData = null; - } - - alreadyAnsweredQuestions?.forEach((savedPart) => { - - if (!savedPart.glassLocation || !savedPart.glassName || !savedPart.answeredQuestions || !savedPart.result) { - return; - } - if (glass.glassLocation === savedPart.glassLocation && glass.glassName === savedPart.glassName) { - let answerString = ""; - - // matches; loop through answeredQuestions for matches - savedPart.answeredQuestions.forEach((aq) => { - if (!aq.questionNum || !aq.selectedAnswerText) { - return; - } - // determine which answer was previously chosen - const theAns = glass.capabilityQuestions[aq.questionNum - 1].answers.find((a) => { - return a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase(); - }); - if (theAns.nextQuestionSequence) { - answerString = `${aq.questionNum}|nextQuestion|${theAns.nextQuestionSequence}|${theAns.answerText}` - } else { - answerString = `${aq.questionNum}|answer|${theAns.answerResult}|${theAns.answerText}` - } - - // mark this partQuestion as answered (question-chain will read this) - glass.capabilityQuestions[aq.questionNum - 1].answerSelected = answerString; - // mark this partQuestion as duplicate if it is (question-chain will read this) - if (aq.suppressQuestion) { - glass.capabilityQuestions[aq.questionNum - 1].suppressQuestion = true; - } - }); - - // advance the currentQuestionChainIndex - this.currentQuestionChainIndex = i; - - // add answerData to current glass - glass.answerData = { - answerResult: savedPart.result, - answerResult1: savedPart.result, - answerResult2: this.getCorrespondingAnswerResult2(savedPart.result), - answeredQuestions: savedPart.answeredQuestions - } - } - - }); - - // Set up watch for each set of glass questions, which gets updated when all questions for a glass have been answered - this.$watch("selectedAnswers." + glass.key, (newValue) => { - if (newValue) { - this.handleAnswerUpdates(newValue); - } - }, { deep: true }) - - return glass; - }); - - }, }, components: { funnelHeader, diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 00e71c917..50cfe42c2 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -94,7 +94,6 @@ export default { moldingQuestionsData: store.getters.pageData(fmgPageValues.MOLDING_QUESTIONS).partsOrQuestions, selectedAnswers: {}, currentGlassIndex: 0, - foundDuplicateQuestions: [], }; }, computed: { @@ -109,7 +108,17 @@ export default { } }, mounted() { - this.LoadInitialData(); + // are there alreadyAnsweredQuestions? + const alreadyAnsweredQuestions = store.getters.damage.moldingQuestionAnswers; + + this.moldingQuestionsData = 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 + this.selectedAnswers[glass.key] = []; + // pass in: glass, i, alreadyAnsweredQuestions + return this.setupInitialData(glass, i, alreadyAnsweredQuestions); + }); }, methods: { arePagePrerequisitesValid() { @@ -153,11 +162,11 @@ export default { this.navigateForward(partsOrQuestions); }, - handleAnswerUpdates(key, answer) { + 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 relevent questions for the current part have been answered) + // all relevant questions for the current part have been answered) /* answer example format: @@ -176,6 +185,7 @@ export default { // 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 @@ -288,12 +298,12 @@ export default { thisAnsweredPartQuestion.suppressQuestion = true; const thisGlassPart = "glass" + gpIndex; - if (this.foundDuplicateQuestions[thisGlassPart]) { - if (!this.foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredPartQuestion.questionSequence)) { - this.foundDuplicateQuestions[thisGlassPart].push(thisAnsweredPartQuestion.questionSequence); + if (foundDuplicateQuestions[thisGlassPart]) { + if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredPartQuestion.questionSequence)) { + foundDuplicateQuestions[thisGlassPart].push(thisAnsweredPartQuestion.questionSequence); } } else { - this.foundDuplicateQuestions[thisGlassPart] = [thisAnsweredPartQuestion.questionSequence]; + foundDuplicateQuestions[thisGlassPart] = [thisAnsweredPartQuestion.questionSequence]; } // are there any questions left that are not suppressed? @@ -341,12 +351,12 @@ export default { // EX answeredQuestionIndexes: [1,5,11,13] - // EX this.foundDuplicateQuestions = { + // EX foundDuplicateQuestions = { // "glassPart1": [1], // "glassPart2": [7, 10] // }; - const thisPartsDupes = this.foundDuplicateQuestions["glass" + answer.glassIndex]; + const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; const glassPartAnswered = this.moldingQuestionsData[answer.glassIndex]; @@ -408,75 +418,6 @@ export default { } }, - LoadInitialData() { - - // are there alreadyAnsweredQuestions? - const alreadyAnsweredQuestions = store.getters.damage.moldingQuestionAnswers; - - this.moldingQuestionsData = this.pageData.partsOrQuestions.filter(x => x.parts[0].childPartQuestions.length).map((glass, i) => { - glass.key = glass.glassLocation + "-" + glass.glassName; - // NOTE: property "questions" can differ between layouts - glass.questions = glass.parts[0].childPartQuestions; - - this.selectedAnswers[glass.key] = []; - if (!alreadyAnsweredQuestions) { - glass.answerData = null; - } - - alreadyAnsweredQuestions?.forEach((savedPart) => { - - if (!savedPart.glassLocation || !savedPart.glassName || !savedPart.answeredQuestions || !savedPart.partNum) { - return; - } - if (glass.glassLocation === savedPart.glassLocation && glass.glassName === savedPart.glassName) { - let answerString = ""; - - // matches; loop through answeredQuestions for matches - savedPart.answeredQuestions.forEach((aq) => { - if (!aq.questionNum || !aq.selectedAnswerText) { - return; - } - // determine which answer was previously chosen - const theAns = glass.questions[aq.questionNum-1].answers.find((a) => { - return a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase(); - }); - if (theAns.nextQuestionSequence) { - answerString = `${aq.questionNum}|nextQuestion|${theAns.nextQuestionSequence}|${theAns.answerText}` - } else { - answerString = `${aq.questionNum}|answer|${theAns.answerResult}|${theAns.answerText}` - } - - // mark this partQuestion as answered (question-chain will read this) - glass.questions[aq.questionNum-1].answerSelected = answerString; - // mark this partQuestion as duplicate if it is (question-chain will read this) - if (aq.suppressQuestion) { - glass.questions[aq.questionNum-1].suppressQuestion = true; - } - }); - - // advance the currentGlassIndex - this.currentGlassIndex = i; - - // add answerData to current glass - glass.answerData = { - answerResult: savedPart.partNum, - answeredQuestions: savedPart.answeredQuestions - } - } - - }); - - // Set up watch for each set of glass questions, which gets updated when all questions for a glass have been answered - this.$watch("selectedAnswers." + glass.key, (newValue) => { - if (newValue) { - this.handleAnswerUpdates(glass.key, newValue); - } - }, {deep: true}) - - return glass; - }); - - }, }, components: { funnelHeader, diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 4906d9526..131a70f44 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -90,10 +90,9 @@ export default { }, data() { return { - partsQuestionsData: store.getters.pageData(fmgPageValues.PART_QUESTIONS).partsOrQuestions, + partsQuestionsData: [], selectedAnswers: {}, currentGlassIndex: 0, - foundDuplicateQuestions: [], }; }, computed: { @@ -109,7 +108,17 @@ export default { }, mixins: [vehicleQuestionsMixin], mounted() { - this.LoadInitialData(); + // are there alreadyAnsweredQuestions? + const alreadyAnsweredQuestions = store.getters.damage.partQuestionAnswers; + + this.partsQuestionsData = 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 + this.selectedAnswers[glass.key] = []; + // pass in: glass, i, alreadyAnsweredQuestions + return this.setupInitialData(glass, i, alreadyAnsweredQuestions); + }); }, methods: { arePagePrerequisitesValid() { @@ -149,11 +158,11 @@ export default { this.navigateForward(glassNameAndPartsForStore); }, - handleAnswerUpdates(key, answer) { + 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 relevent questions for the current part have been answered) + // all relevant questions for the current part have been answered) /* answer example format: @@ -172,6 +181,7 @@ export default { // 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 @@ -284,12 +294,12 @@ export default { thisAnsweredQuestion.suppressQuestion = true; const thisGlassPart = "glass" + gpIndex; - if (this.foundDuplicateQuestions[thisGlassPart]) { - if (!this.foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredQuestion.questionSequence)) { - this.foundDuplicateQuestions[thisGlassPart].push(thisAnsweredQuestion.questionSequence); + if (foundDuplicateQuestions[thisGlassPart]) { + if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredQuestion.questionSequence)) { + foundDuplicateQuestions[thisGlassPart].push(thisAnsweredQuestion.questionSequence); } } else { - this.foundDuplicateQuestions[thisGlassPart] = [thisAnsweredQuestion.questionSequence]; + foundDuplicateQuestions[thisGlassPart] = [thisAnsweredQuestion.questionSequence]; } // are there any questions left that are not suppressed? @@ -337,12 +347,12 @@ export default { // EX answeredQuestionIndexes: [1,5,11,13] - // EX this.foundDuplicateQuestions = { + // EX foundDuplicateQuestions = { // "glassPart1": [1], // "glassPart2": [7, 10] // }; - const thisPartsDupes = this.foundDuplicateQuestions["glass" + answer.glassIndex]; + const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; const glassPartAnswered = this.partsQuestionsData[answer.glassIndex]; @@ -404,75 +414,6 @@ export default { } }, - LoadInitialData() { - - // are there alreadyAnsweredQuestions? - const alreadyAnsweredQuestions = store.getters.damage.partQuestionAnswers; - - this.partsQuestionsData = this.pageData.partsOrQuestions.filter(x => x.partQuestions).map((glass, i) => { - glass.key = glass.glassLocation + "-" + glass.glassName; - // NOTE: property "questions" can differ between layouts - glass.questions = glass.partQuestions; - - this.selectedAnswers[glass.key] = []; - if (!alreadyAnsweredQuestions) { - glass.answerData = null; - } - - alreadyAnsweredQuestions?.forEach((savedPart) => { - - if (!savedPart.glassLocation || !savedPart.glassName || !savedPart.answeredQuestions || !savedPart.result) { - return; - } - if (glass.glassLocation === savedPart.glassLocation && glass.glassName === savedPart.glassName) { - let answerString = ""; - - // matches; loop through answeredQuestions for matches - savedPart.answeredQuestions.forEach((aq) => { - if (!aq.questionNum || !aq.selectedAnswerText) { - return; - } - // determine which answer was previously chosen - const theAns = glass.questions[aq.questionNum-1].answers.find((a) => { - return a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase(); - }); - if (theAns.nextQuestionSequence) { - answerString = `${aq.questionNum}|nextQuestion|${theAns.nextQuestionSequence}|${theAns.answerText}` - } else { - answerString = `${aq.questionNum}|answer|${theAns.answerResult}|${theAns.answerText}` - } - - // mark this question as answered (question-chain will read this) - glass.questions[aq.questionNum-1].answerSelected = answerString; - // mark this question as duplicate if it is (question-chain will read this) - if (aq.suppressQuestion) { - glass.questions[aq.questionNum-1].suppressQuestion = true; - } - }); - - // advance the currentGlassIndex - this.currentGlassIndex = i; - - // add answerData to current glass - glass.answerData = { - answerResult: savedPart.result, - answeredQuestions: savedPart.answeredQuestions - } - } - - }); - - // Set up watch for each set of glass questions, which gets updated when all questions for a glass have been answered - this.$watch("selectedAnswers." + glass.key, (newValue) => { - if (newValue) { - this.handleAnswerUpdates(glass.key, newValue); - } - }, {deep: true}) - - return glass; - }); - - }, }, components: { funnelHeader, diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index c8a10cdeb..a6fe31196 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -64,6 +64,68 @@ export default { currentPageComesAfterPage(currentPage = this.$route.query.fmgPage, fmgPage) { return this.comparePageIndices(currentPage, fmgPage) > 0; }, + setupInitialData(glass, i, alreadyAnsweredQuestions, vm) { + glass.key = glass.glassLocation + "-" + glass.glassName; + const self = vm ?? this; + // clear answerData if no questions are already answered + if (!alreadyAnsweredQuestions) { glass.answerData = null } + + alreadyAnsweredQuestions?.forEach((answeredGlass) => { + // if answeredGlass lacks any of these properties then exit + if (!answeredGlass.glassLocation || + !answeredGlass.glassName || + !answeredGlass.answeredQuestions || + !answeredGlass.result && !answeredGlass.partNum) { return } + + // test if glass parts match + if (glass.glassLocation === answeredGlass.glassLocation && glass.glassName === answeredGlass.glassName) { + let answerString = ""; + + // loop through answeredQuestions for matches + answeredGlass.answeredQuestions.forEach((aq) => { + if (!aq.questionNum || !aq.selectedAnswerText) { return } + // determine which answer was previously chosen + const chosenAns = glass.questions[aq.questionNum-1].answers.find((a) => { + return a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase(); + }); + // set the answerString to use for answerSelected + if (chosenAns.nextQuestionSequence) { + answerString = `${aq.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}` + } else { + answerString = `${aq.questionNum}|answer|${chosenAns.answerResult}|${chosenAns.answerText}` + } + + // mark this question as answered (question-chain will read this) + glass.questions[aq.questionNum-1].answerSelected = answerString; + // mark this question as suppressed if needed (question-chain uses this) + if (aq.suppressQuestion) { glass.questions[aq.questionNum-1].suppressQuestion = true } + }); + + // advance the currentGlassIndex + self.currentGlassIndex = i; + + const answerResult = (answeredGlass.partNum) ? answeredGlass.partNum : answeredGlass.result; + // the above logic for answerResult covers all 3 ___-questions page scenarios + + // add answerData to current glass + glass.answerData = { + answerResult: answerResult, + answeredQuestions: answeredGlass.answeredQuestions + } + } + + }); + + // Set up watch for each set of glass questions + // (updated when all questions for a glass have been answered in question-chain) + self.$watch("selectedAnswers." + glass.key, (newValue) => { + if (newValue) { + self.handleAnswerUpdates(newValue); + } + }, {deep: true}) + + return glass; + }, // Can't use `this` because navigateForward is also called from vin-pages-mixin async navigateForward(partsOrQuestions, vm) { const self = vm ?? this; diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index 306aa60ce..e5a579f02 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -155,6 +155,126 @@ describe("vehicle-questions-mixin", () => { }); }); + describe("hasChildPartQuestions", () => { + test("has no child part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([ + { + parts: [ + { + childPartQuestions: [] + } + ] + } + ]) + + // Assert + expect(hasChildPartQuestions).toBe(false); + }); + + test("has undefined child part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([]) + + // Assert + expect(hasChildPartQuestions).toBe(false); + + }); + + test("has child part questions => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([ + { + parts: [ + { + childPartQuestions: [ + { + "questionSequence": 1, + "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", + "answers": [ + { + "answerResult": "WKT D1106 C", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "WKT D1106 B", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ] + } + ] + } + ]) + + // Assert + expect(hasChildPartQuestions).toBe(true); + }); + }); + + describe("hasCapabilityQuestions", () => { + test("has no capability questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([ + { + parts: [ + { + requiresCapabilityQuestions: false + } + ] + } + ]) + + // Assert + expect(hasCapabilityQuestions).toBe(false); + }); + + test("has undefined capability questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([]) + + // Assert + expect(hasCapabilityQuestions).toBe(false); + }); + + test("has capability questions => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([ + { + parts: [ + { + requiresCapabilityQuestions: true + } + ] + } + ]) + + // Assert + expect(hasCapabilityQuestions).toBe(true); + }); + }); + describe("currentPageComesBeforePage", () => { const testCases = [[fmgPageValues.PART_QUESTIONS, fmgPageValues.VEHICLE_PARTS, true], [fmgPageValues.VEHICLE_PARTS, fmgPageValues.VEHICLE_PARTS, false], @@ -195,6 +315,94 @@ describe("vehicle-questions-mixin", () => { }) }); + describe("setupInitialData", () => { + describe("should always", () => { + test("return glass with new key attribute", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const glass = { + "glassName": "Single", + "glassLocation": "Windshield", + }; + const i = 0; + + // Act + const returnedGlass = await wrapper.vm.setupInitialData(glass, i); + + // Assert + expect(returnedGlass).toMatchObject({"key": "Windshield-Single"}); + }); + }); + + describe("if no alreadyAnsweredQuestions", () => { + test("should return glass with answerData of null", async () => { + // Arrange + const glass = { + "glassName": "Single", + "glassLocation": "Windshield" + }; + const i = 0; + const { wrapper } = setupMocks({}); + + // Act + const returnedGlass = await wrapper.vm.setupInitialData(glass, i); + + // Assert + expect(returnedGlass).toMatchObject({"answerData": null}); + }); + }); + + describe("if alreadyAnsweredQuestions", () => { + test("should return glass with answerResult within answerData", async () => { + // Arrange + const glass = { + "glassName": "Single", + "glassLocation": "Windshield", + "questions": [ + { + "questionSequence": 1, + "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", + "answers": [ + { + "answerResult": "WKT D1106 C", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "WKT D1106 B", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ], + }; + const i = 0; + const alreadyAnsweredQuestions = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "partNum": "WKT D1106 C", + "answeredQuestions": [ + { + "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", + "selectedAnswerText": "Yes", + "questionNum": 1 + } + ] + } + ]; + const { wrapper } = setupMocks({}); + + // Act + const returnedGlass = await wrapper.vm.setupInitialData(glass, i, alreadyAnsweredQuestions); + + // Assert + expect(returnedGlass.answerData).toMatchObject({"answerResult": "WKT D1106 C"}); + }); + }); + }); + describe("navigateForward", () => { describe("should go to parts-questions", () => { test("single glass location has part question => go to parts-questions", async () => { @@ -1160,6 +1368,18 @@ describe("vehicle-questions-mixin", () => { expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}}) }) + test("current page is quote and there are capability questions => go to capability questions", () => { + // Arrange + const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE }); + wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}}) + }) + test("current page is quote and there are part questions and molding questions => go to molding questions", () => { // Arrange const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE }); @@ -1209,7 +1429,15 @@ function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) { const baseMixin = setupMocksForJsFiles({ actionList: [{ actionName: storeActions.GET_CAPABILITY_QUESTIONS, - data: [], + data: [ + { + answers: [ + { + answerResult1: "testing" + } + ] + } + ], }] }); diff --git a/src/router/index.js b/src/router/index.js index 9dd7b2acf..bd546bf5e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -23,6 +23,7 @@ import { applicationConfig } from "../constants/application-config"; // Components import quote from "@/layouts/quote/quote.vue"; +import datePicker from "@/common-components/date-picker/date-picker.vue"; const routes = [ { @@ -30,6 +31,11 @@ const routes = [ name: "quote", component: quote, }, + { + path: "/date-picker", // This is a temporary route for testing. + name: "date-picker", + component: datePicker, + }, { path: "/", name: "root", diff --git a/src/store/index.js b/src/store/index.js index 614d54d4b..7791b91de 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -538,7 +538,7 @@ export const actions = { getRouteInfo(context, { pageName }) { return globalMethods.callHttpClient({ method: endpoints.GetRouteInfo.method, - endpoint: endpoints.GetRouteInfo.url, + endpoint: endpoints.GetRouteInfo.url(applicationConfig.APPLICATION_ABBREVIATION), payload: { pageName: pageName, }, @@ -547,13 +547,13 @@ export const actions = { getHomepageName(context) { return globalMethods.callHttpClient({ method: endpoints.GetHomepageInfo.method, - endpoint: endpoints.GetHomepageInfo.url, + endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION), }); }, getPageData(context, { pageName }) { return globalMethods.callHttpClient({ method: endpoints.GetPageData.method, - endpoint: `${endpoints.GetPageData.url}/${pageName}`, + endpoint: endpoints.GetPageData.url(applicationConfig.APPLICATION_ABBREVIATION, pageName), payload: {}, }); },