diff --git a/src/common-components/layouts/questions-page-layout/questions-page-layout.vue b/src/common-components/layouts/questions-page-layout/questions-page-layout.vue index d2d6aaab2..1ab40a7b0 100644 --- a/src/common-components/layouts/questions-page-layout/questions-page-layout.vue +++ b/src/common-components/layouts/questions-page-layout/questions-page-layout.vue @@ -27,7 +27,7 @@ ref="funnelFooter" cmsWidgetName="FunnelFooterWidget" :isForwardActionDisabled="!isMetaValid" - @back-clicked="handleBackButtonClicked" + @back-clicked="handleBackButtonAction" @ForwardClicked="handleForwardButtonAction" /> diff --git a/src/common-components/modal/modal.vue b/src/common-components/modal/modal.vue index 9a8e6c211..e965b3e3f 100644 --- a/src/common-components/modal/modal.vue +++ b/src/common-components/modal/modal.vue @@ -60,11 +60,16 @@ export default { return this.getCmsContent(this.cmsWidgetName, "FooterText"); }, }, + methods: { + setupModalEventListener() { + const modal = document.querySelector("#" + this.cmsWidgetName); + modal.addEventListener("hidden.bs.modal", (event) => { + this.$refs.buttonMain.resetButtonStyle(); + }); + }, + }, mounted() { - const modal = document.querySelector("#" + this.cmsWidgetName); - modal.addEventListener("hidden.bs.modal", (event) => { - this.$refs.buttonMain.resetButtonStyle(); - }); + this.setupModalEventListener(); }, components: { buttonMain, diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 11874670b..bf68a4363 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -100,7 +100,7 @@ export default { return false; } - // Example returnedAnswers: + // returnedAnswer examples: // "1|nextQuestion|3|No" // "5|answer|DW02104|Yes" @@ -108,15 +108,12 @@ export default { const questionNum = parseInt(returnedAnswerArray[0]); const questionType = returnedAnswerArray[1]; const questionAnswer = returnedAnswerArray[2]; - const questionAnswerText = returnedAnswerArray[3]; const answeredQuestions = []; this.questions.forEach((q) => { // find this question and mark it as "answered" by populating answerSelected if (q.questionSequence === questionNum) { q.answerSelected = returnedAnswer; - q.answerNumber = questionNum; - q.selectedAnswerText = questionAnswerText; } // remove all answers AFTER this question... // (needed in case user is changing previously answered questions) @@ -126,6 +123,7 @@ export default { if (q.answerSelected) { answeredQuestions.push({ questionText: q.questionText, + selectedAnswer: q.answerSelected, selectedAnswerText: q.answerSelected.split("|")[3], questionNum: q.questionSequence, }); diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index bfc65da16..d5d1de4e6 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -53,7 +53,7 @@ describe("textboxQuestion.vue", () => { expect(paragraph.attributes("class")).toContain("rounded-pill"); }); - it.only("Should return form-control class", async () => { + it("Should return form-control class", async () => { // Act const wrapper = shallowMount(textboxQuestion, { global: { diff --git a/src/constants/experiments.js b/src/constants/experiments.js index f2e5d4928..f6d25f1a7 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -4,6 +4,7 @@ const experimentUniverses = { const experimentSettings = { GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index", + SUPPRESS_VIN_CAPTURE: "SuppressVinCapture", }; const experimentTriggers = { diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 8c94ef63c..d023db8c3 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -68,6 +68,9 @@ const storeActions = { SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers", SAVE_IS_INSURANCE: "saveIsInsurance", SAVE_QUOTE_PAGE_SELECTIONS: "saveQuotePageSelections", + SAVE_PAYMENT_TYPE: "savePaymentType", + SAVE_SUPPORTING_ITEMS: "saveSupportingItems", + SAVE_VAPS: "saveVaps", }; export { storeActions }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index ca3ea642e..4760a98a3 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -56,8 +56,6 @@ const storeMutations = { RESET_DAMAGE_STATE: "resetDamageState", RESET_REGISTRATION_STATE: "resetRegistrationState", RESET_GLASS_PARTS_STATE: "resetGlassPartsState", - RESET_SUPPORTING_ITEMS_STATE: "resetSupportingItemsState", - RESET_VAPS_STATE: "resetVapsState", RESET_STATE: "resetState", RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise", diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index b65156881..090abac64 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -5,6 +5,8 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { storeActions } from "@/constants/store-actions.js"; import { settleAllPromises } from "@/helpers/layout-helper"; +import experimentMixin from "@/mixins/experiment-mixin"; +import { experimentSettings } from "@/constants/experiments"; import store from "@/store"; import router from "@/router"; @@ -104,12 +106,18 @@ async function getLatestPageForRedirection() { } else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.PART_QUESTIONS; } else if ( + // capture vin vinLookupComponent.methods.arePagePrerequisitesValid() && !store.getters.damage.isRepair && - !isVinOptionalVehicle + !isVinOptionalVehicle && + experimentMixin.methods.hasSettingEqualTo( + experimentSettings.SUPPRESS_VIN_CAPTURE, + false + ) ) { return fmgPageValues.VIN_LOOKUP; } else { + // do not capture vin return fmgPageValues.ESTIMATE; } } diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index 263fd054f..430f1df22 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -144,6 +144,16 @@ describe("getPageToRouteExistingOrderTo", () => { store.commit(storeMutations.UPDATE_IS_REPAIR, false); store.commit(storeMutations.UPDATE_MAKE, "acura"); + const mockExperimentsList = [ + { + universeName: "ConceptFunnel", + settings: { + SuppressVinCapture: false, + }, + }, + ]; + store.commit(storeMutations.UPDATE_EXPERIMENTS, mockExperimentsList); + // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ [fmgPageValues.VEHICLE_MAKE]: true, diff --git a/src/layouts/capability-questions/capability-questions.spec.js b/src/layouts/capability-questions/capability-questions.spec.js index c59857182..31fc63af8 100644 --- a/src/layouts/capability-questions/capability-questions.spec.js +++ b/src/layouts/capability-questions/capability-questions.spec.js @@ -84,12 +84,14 @@ const baseStoreGettersDamage = () => { { questionText: "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswer: "2|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, @@ -166,10 +168,10 @@ describe("capabilityQuestions.vue", () => { }); describe("watch on selectedAnswers should be set up...", () => { - test("Should trigger handleAnswerUpdates if watched data changes", async () => { + test("Should trigger handleCompletedQuestionChainAnswers if watched data changes", async () => { // Arrange const { wrapper } = setupMocks({}); - const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers"); // Act wrapper.setData({ @@ -180,12 +182,14 @@ describe("capabilityQuestions.vue", () => { { questionText: "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswer: "2|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index c3122b9a3..ffef2f6fa 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -112,7 +112,7 @@ export default { "selectedAnswers." + glass.answerKey, (newValue) => { if (newValue && Object.keys(newValue).length > 0) { - this.handleAnswerUpdates(newValue, glass.answerKey); + this.handleCompletedQuestionChainAnswers(newValue, glass.answerKey); } }, { deep: true } diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index 4e533bb70..3a0869828 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -221,16 +221,29 @@ describe("estimate.vue", () => { describe("skipVinLookup", () => { const skipOptions = [ - [true, true, true], - [true, false, true], - [false, true, true], - [false, false, false], + [true, true, true, true], + [true, false, false, true], + [false, true, true, true], + [false, false, false, false], ]; test.each(skipOptions)( - "isRepair %s and isVinOptional %s should return %s", - async (isRepair, isVinOptionalVehicle, expectedVinSkip) => { - const { wrapper } = setupMocks({ isVinOptionalVehicle: isVinOptionalVehicle }); + "isRepair %s, isVinOptional %s and suppressVinCapture %s should return %s", + async (isRepair, isVinOptionalVehicle, suppressVinCapture, expectedVinSkip) => { + const { wrapper } = setupMocks({}); + await wrapper.setData({ + isVinOptionalVehicle: isVinOptionalVehicle, + }); + store.commit(storeMutations.UPDATE_IS_REPAIR, isRepair); + const mockExperimentsList = [ + { + universeName: "ConceptFunnel", + settings: { + SuppressVinCapture: suppressVinCapture, + }, + }, + ]; + store.commit(storeMutations.UPDATE_EXPERIMENTS, mockExperimentsList); expect(wrapper.vm.skipVinLookup).toEqual(expectedVinSkip); } diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 4aa5db241..f951a7608 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -104,6 +104,9 @@ import store from "@/store"; import { storeActions } from "@/constants/store-actions"; import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import experimentMixin from "@/mixins/experiment-mixin"; +import { experimentSettings } from "@/constants/experiments"; +import vinPagesMixin from "@/mixins/vin-pages-mixin"; // Define Validation Rules defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); @@ -120,6 +123,7 @@ defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); export default { name: "estimate", + mixins: [vinPagesMixin], data() { return { selectedVinLookupMethod: null, @@ -205,13 +209,17 @@ export default { const payment = this.$store.getters.payment; // TODO KO If coverageStatus is null, they haven't gone to heritage yet... I think - if (payment.isInsurance && payment.insuranceCoverage.coverageStatus) { + const vehicleChangedDuringPolicyLookupInHeritage = payment.isInsurance && payment.insuranceCoverage.coverageStatus; + if (vehicleChangedDuringPolicyLookupInHeritage) { navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal }); - } else { + } else if (this.isRepair) { return this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS, this.$route ); + } else { + // if we're skipping the vin-lookup but it's not a repair, we still need to get the parts + await this.navigateForwardWithSingleCarMatch(); } } @@ -256,10 +264,22 @@ export default { return store.getters.damage.isRepair; }, skipVinLookup() { - return this.isRepair || this.isVinOptionalVehicle; + return ( + this.isRepair || + this.isVinOptionalVehicle || + experimentMixin.methods.hasSettingEqualTo( + experimentSettings.SUPPRESS_VIN_CAPTURE, + true + ) + ); }, alertInfo() { - return this.isVinOptionalVehicle && !this.isRepair + return (this.isVinOptionalVehicle || + experimentMixin.methods.hasSettingEqualTo( + experimentSettings.SUPPRESS_VIN_CAPTURE, + true + )) && + !this.isRepair ? "AlertQuoteVinOptional" : "AlertQuoteReady"; }, diff --git a/src/layouts/molding-questions/molding-questions.spec.js b/src/layouts/molding-questions/molding-questions.spec.js index a408a406f..cff119c73 100644 --- a/src/layouts/molding-questions/molding-questions.spec.js +++ b/src/layouts/molding-questions/molding-questions.spec.js @@ -88,12 +88,14 @@ const baseStoreGettersDamage = () => { { questionText: "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswer: "2|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, @@ -170,10 +172,10 @@ describe("moldingQuestions.vue", () => { }); describe("watch on selectedAnswers should be set up...", () => { - test("Should trigger handleAnswerUpdates if watched data changes", async () => { + test("Should trigger handleCompletedQuestionChainAnswers if watched data changes", async () => { // Arrange const { wrapper } = setupMocks({}); - const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers"); // Act wrapper.setData({ @@ -184,12 +186,14 @@ describe("moldingQuestions.vue", () => { { questionText: "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswer: "2|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index b0e767b21..53a010d72 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -111,7 +111,7 @@ export default { "selectedAnswers." + glass.answerKey, (newValue) => { if (newValue && Object.keys(newValue).length > 0) { - this.handleAnswerUpdates(newValue, glass.answerKey); + this.handleCompletedQuestionChainAnswers(newValue, glass.answerKey); } }, { deep: true } diff --git a/src/layouts/part-questions/part-questions.spec.js b/src/layouts/part-questions/part-questions.spec.js index a6d0423a4..e8adef4ff 100644 --- a/src/layouts/part-questions/part-questions.spec.js +++ b/src/layouts/part-questions/part-questions.spec.js @@ -78,12 +78,14 @@ const baseStoreGettersDamage = () => { { questionText: "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, @@ -152,14 +154,14 @@ describe("partQuestions.vue...", () => { }); describe("watch on selectedAnswers should be set up...", () => { - test("Should trigger handleAnswerUpdates if watched data changes", async () => { + test("Should trigger handleCompletedQuestionChainAnswers if watched data changes", async () => { // Arrange store.getters = { pageData: baseStoreGettersPageData, damage: baseStoreGettersDamage, }; const { wrapper } = setupMocks({}); - const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers"); // Act wrapper.setData({ @@ -169,11 +171,13 @@ describe("partQuestions.vue...", () => { answeredQuestions: [ { questionText: "One?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 1, }, { questionText: "Two?", + selectedAnswer: "1|nextQuestion|3|Yes", selectedAnswerText: "Yes", questionNum: 2, }, diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 8f942ccfd..770c8443f 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -109,7 +109,7 @@ export default { "selectedAnswers." + glass.answerKey, (newValue) => { if (newValue && Object.keys(newValue).length > 0) { - this.handleAnswerUpdates(newValue, glass.answerKey); + this.handleCompletedQuestionChainAnswers(newValue, glass.answerKey); } }, { deep: true } diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 1dd79be4b..21b2290e2 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -23,10 +23,11 @@ ref="servicePackage" cashCmsWidgetName="CashServicePackageQuestionWidget" insuranceCmsWidgetName="InsuranceServicePackageQuestionWidget" - v-model="selectedPackage" groupName="ServicePackageQuestion" :availableLineItems="availableLineItems" - :isInsuranceSelected="isInsuranceSelected" /> + :isInsuranceSelected="isInsuranceSelected" + @vapsItemsSelected="vapsItemsSelectedAction" /> + 0); + return ( + store.getters.order.damage.isRepair || + (store.getters.order.lineItems?.glassParts != null && + store.getters.order.lineItems.glassParts.length > 0) + ); }, getDefaultIsInsuranceSelectedValue() { const defaultIsInsuranceSelectedValue = this.$store.getters.order.payment.isInsurance; @@ -197,19 +201,24 @@ export default { : null; } }, + vapsItemsSelectedAction(vapsItemsSelected) { + this.selectedVaps = vapsItemsSelected; + }, backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); }, - async forwardButtonAction() { - await this.dispatchStoreAction( - this.storeActions.SAVE_QUOTE_PAGE_SELECTIONS, - { - isInsuranceSelected: this.isInsuranceSelected, - vapsItemsToAdd: this.selectedPackage, - supportingItemsToAdd: this.supportingItems, - }, + forwardButtonAction() { + this.dispatchStoreAction( + this.storeActions.SAVE_PAYMENT_TYPE, + this.isInsuranceSelected, false ); + this.dispatchStoreAction( + this.storeActions.SAVE_SUPPORTING_ITEMS, + this.supportingItems, + false + ); + this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal }); }, diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index e0608e713..cd10b893f 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -58,7 +58,7 @@ describe("service-package-question.vue", () => { await nextTick(); // Assert - expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([ + expect(wrapper.emitted()["vapsItemsSelected"][0][0]).toEqual([ { description: null, partNumber: "RAIN DEFENSE", diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 70f32269f..371e0787a 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -6,6 +6,8 @@ :buttonTypeObject="servicePackageRadio" v-model="selectedPackageName" isRequired /> + servicePackageAnswers: {{servicePackageAnswers}}
+ selectedPackageName: {{selectedPackageName}}