diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 9d7d3ea6a..00a2dffea 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -62,6 +62,7 @@ const storeActions = { SAVE_VEHICLE_MAKE: "saveVehicleMake", SAVE_VEHICLE_MODEL: "saveVehicleModel", SAVE_VEHICLE_STYLE: "saveVehicleStyle", + SAVE_VEHICLE: "saveVehicle", SAVE_VEHICLE_DAMAGE: "saveVehicleDamage", SAVE_VIN_LOOKUP: "saveVinLookup", SAVE_SERVICE_ZIP_CODE_INFO: "saveServiceZipCodeInfo", diff --git a/src/digital-components/dropdown-question/dropdown-question.vue b/src/digital-components/dropdown-question/dropdown-question.vue index 7c0dd0d3b..6c032b740 100644 --- a/src/digital-components/dropdown-question/dropdown-question.vue +++ b/src/digital-components/dropdown-question/dropdown-question.vue @@ -16,9 +16,13 @@ :disabled="isDisabled" :aria-required="isRequired" :validationRules="validationRules" - :placeHolderText="placeHolderText"> + :placeHolderText="placeHolderText" + :valueAsKey="valueAsKey"> - @@ -47,6 +51,11 @@ export default { placeHolderText: String, cmsWidgetName: String, hasError: Boolean, + valueAsKey: { + type: Boolean, + required: false, + default: false, + }, }, setup(props) { const uuid = uuidv4(); diff --git a/src/layouts/vehicle/vehicle-question/vehicle-question.vue b/src/layouts/vehicle/vehicle-question/vehicle-question.vue index 283f26811..79b58bfaa 100644 --- a/src/layouts/vehicle/vehicle-question/vehicle-question.vue +++ b/src/layouts/vehicle/vehicle-question/vehicle-question.vue @@ -1,9 +1,5 @@ diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index bea1fdd8e..24ae0d215 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -15,8 +15,9 @@ ref="vehicleYearQuestion" class="mb-2 mt-4" v-model="selectedYear" + :isDisabled="!yearOptions.length" + :options="yearOptions" cmsWidgetName="VehicleYearQuestion" - :updateValues="updateYearValues" validationRules="year-required" placeHolderText="Select year" inputId="yearQuestionField" /> @@ -25,8 +26,9 @@ ref="vehicleMakeQuestion" class="mb-2 mt-4" v-model="selectedMake" + :isDisabled="!makeOptions.length" + :options="makeOptions" cmsWidgetName="VehicleMakeQuestion" - :updateValues="updateMakeValues" validationRules="make-required" placeHolderText="Select make" inputId="makeQuestionField" /> @@ -36,7 +38,8 @@ class="mb-2 mt-4" v-model="selectedModel" cmsWidgetName="VehicleModelQuestion" - :updateValues="updateModelValues" + :isDisabled="!modelOptions.length" + :options="modelOptions" validationRules="model-required" placeHolderText="Select model" inputId="modelQuestionField" /> @@ -46,7 +49,8 @@ class="mb-2 mt-4" v-model="selectedStyle" cmsWidgetName="VehicleStyleQuestion" - :updateValues="updateStyleValues" + :isDisabled="!styleOptions.length" + :options="styleOptions" validationRules="style-required" placeHolderText="Select style" inputId="styleQuestionField" /> @@ -101,10 +105,14 @@ export default { name: "vehicle", data() { return { - selectedYear: null, - selectedMake: null, - selectedModel: null, - selectedStyle: null, + selectedYear: this.selectedYearfromStore(), + selectedMake: this.selectedMakefromStore(), + selectedModel: this.selectedModelfromStore(), + selectedStyle: this.selectedStylefromStore(), + yearOptions: [], + makeOptions: [], + modelOptions: [], + styleOptions: [], }; }, @@ -113,10 +121,6 @@ export default { validationRules: String, }, - mounted() { - this.$refs["vehicleYearQuestion"].getNewValues(this.selectedYearfromStore); - }, - async beforeRouteEnter(to, from, next) { // Call APIs @@ -124,6 +128,43 @@ export default { const experimentForLogging = store.getters.applicationUser.experiments.find( (e) => e.universeName === experimentUniverses.CONCEPT_FUNNEL ); + const yearQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_VEHICLE_YEARS, + {} + ); + var makeQuestionInitialDataPromise = null; + var modelQuestionInitialDataPromise = null; + var styleQuestionInitialDataPromise = null; + + if ( + store.getters.order.vehicle.make && + store.getters.order.vehicle.model && + store.getters.order.vehicle.style + ) { + makeQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_VEHICLE_MAKES, + { + year: store.getters.order.vehicle.year, + } + ); + + modelQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_VEHICLE_MODELS, + { + year: store.getters.order.vehicle.year, + make: store.getters.order.vehicle.make, + } + ); + + styleQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_VEHICLE_STYLES, + { + year: store.getters.order.vehicle.year, + make: store.getters.order.vehicle.make, + model: store.getters.order.vehicle.model, + } + ); + } // If the concept funnel experiment is found, as it should be when coming from safelite.com, then log the experiment exposure. if (experimentForLogging !== undefined) { @@ -146,6 +187,22 @@ export default { resultKey: "cmsContent", promise: cmsContentPromise, }, + { + resultKey: "yearQuestionInitialData", + promise: yearQuestionInitialDataPromise, + }, + { + resultKey: "makeQuestionInitialData", + promise: makeQuestionInitialDataPromise, + }, + { + resultKey: "modelQuestionInitialData", + promise: modelQuestionInitialDataPromise, + }, + { + resultKey: "styleQuestionInitialData", + promise: styleQuestionInitialDataPromise, + }, ]; let resultMap = await settleAllPromises(promiseResultMap); @@ -153,48 +210,74 @@ export default { // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); + vm.initializeYearComponent(resultMap.yearQuestionInitialData); + + if ( + makeQuestionInitialDataPromise && + modelQuestionInitialDataPromise && + styleQuestionInitialDataPromise + ) + vm.initializeMMSComponent( + resultMap.makeQuestionInitialData, + resultMap.modelQuestionInitialData, + resultMap.styleQuestionInitialData + ); }); }, watch: { - selectedYear(year) { - const parsedYear = parseInt(year); - this.dispatchStoreAction(storeActions.SAVE_VEHICLE_YEAR, parsedYear); + async selectedYear(year) { if (year) { - this.$refs["vehicleMakeQuestion"].getNewValues(this.selectedMakefromStore); + const result = await this.getMakeOptions(year); + this.makeOptions = result?.data; + if (this.selectedYearfromStore() !== year) { + this.selectedMake = null; + this.selectedModel = null; + this.selectedStyle = null; + } } else { - this.$refs["vehicleMakeQuestion"].clearValues(); + this.makeOptions = []; } }, - selectedMake(make) { - this.dispatchStoreAction(storeActions.SAVE_VEHICLE_MAKE, make, false); + async selectedMake(make) { if (make) { - this.$refs["vehicleModelQuestion"].getNewValues(this.selectedModelfromStore); + const result = await this.getModelOptions(this.selectedYear, make); + this.modelOptions = result?.data; + if (this.selectedMakefromStore() !== make) { + this.selectedModel = null; + this.selectedStyle = null; + } } else { - this.$refs["vehicleModelQuestion"].clearValues(); + this.modelOptions = []; } }, - selectedModel(model) { - this.dispatchStoreAction(storeActions.SAVE_VEHICLE_MODEL, model, false); + async selectedModel(model) { if (model) { - this.$refs["vehicleStyleQuestion"].getNewValues(this.selectedStylefromStore); + const result = await this.getStyleOptions( + this.selectedYear, + this.selectedMake, + model + ); + this.styleOptions = result?.data; + if (this.selectedModelfromStore() !== model) { + this.selectedStyle = null; + } } else { - this.$refs["vehicleStyleQuestion"].clearValues(); + this.styleOptions = []; } }, selectedStyle(style) { - this.dispatchStoreAction(storeActions.SAVE_VEHICLE_STYLE, style, false); - this.setVehicle(); + this.setVehicle(this.selectedYear, this.selectedMake, this.selectedModel, style); }, }, methods: { - setVehicle() { + setVehicle(year, make, model, style) { return this.dispatchStoreAction(this.storeActions.SET_VEHICLE, { - year: this.$store.getters.vehicle.year, - make: this.$store.getters.vehicle.make, - model: this.$store.getters.vehicle.model, - style: this.$store.getters.vehicle.style, + year: year, + make: make, + model: model, + style: style, }); }, @@ -207,42 +290,29 @@ export default { }, navigateForward() { + this.dispatchStoreAction( + storeActions.SAVE_VEHICLE, + { + year: this.selectedYear, + make: this.selectedMake, + model: this.selectedModel, + style: this.selectedStyle, + }, + false + ); this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); }, - async updateYearValues() { - return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_YEARS, {}); + initializeYearComponent(initialData) { + this.yearOptions = initialData; }, - - async updateMakeValues() { - return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MAKES, { - year: store.getters.vehicle.year, - }); - }, - - async updateModelValues() { - return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MODELS, { - year: store.getters.vehicle.year, - - make: store.getters.vehicle.make, - }); - }, - - async updateStyleValues() { - return baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_STYLES, { - year: store.getters.vehicle.year, - make: store.getters.vehicle.make, - model: store.getters.vehicle.model, - }); - }, - }, - - computed: { - displayGeneric() { - return !this.selectedStyle; + initializeMMSComponent(makeOptions, modelOptions, styleOptions) { + this.makeOptions = makeOptions; + this.modelOptions = modelOptions; + this.styleOptions = styleOptions; }, selectedYearfromStore() { - return store.getters.vehicle.year; + return store.getters.vehicle.year?.toString(); }, selectedMakefromStore() { return store.getters.vehicle.make; @@ -253,6 +323,32 @@ export default { selectedStylefromStore() { return store.getters.vehicle.style; }, + async getMakeOptions(year) { + return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MAKES, { + year: year, + }); + }, + + async getModelOptions(year, make) { + return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MODELS, { + year: year, + make: make, + }); + }, + + async getStyleOptions(year, make, model) { + return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_STYLES, { + year: year, + make: make, + model: model, + }); + }, + }, + + computed: { + displayGeneric() { + return !this.selectedStyle; + }, }, components: { diff --git a/src/store/index.js b/src/store/index.js index fb86b61c3..41ca166c1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1619,6 +1619,25 @@ export const actions = { } }, + saveVehicle(context, { year, make, model, style }) { + context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); + context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); + context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); + + if (context.state.order.vehicle.year !== year) { + context.commit(storeMutations.UPDATE_YEAR, year); + } + if (context.state.order.vehicle.make !== make) { + context.commit(storeMutations.UPDATE_MAKE, make); + } + if (context.state.order.vehicle.model !== model) { + context.commit(storeMutations.UPDATE_MODEL, model); + } + if (context.state.order.vehicle.style !== style) { + context.commit(storeMutations.UPDATE_STYLE, style); + } + }, + saveVehicleDamage( context, { isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount } diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 4a6788433..08aa406c9 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1702,6 +1702,59 @@ describe("Actions", () => { expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); }); + it("saveVehicle, should save vehicle info", () => { + // Arrange + const context = state; + + context.state = { + order: { + vehicle: { + year: "2016", + make: "Toyota", + model: "Accord", + style: "SUV", + }, + }, + }; + + const commit = jest.fn(); + const dispatch = jest.fn(); + + context.commit = commit; + context.dispatch = dispatch; + + //Act + const payload = { + year: "2015", + make: "Honda", + model: "Civic", + style: "Sedan", + }; + actions.saveVehicle(context, payload); + + //Assert + expect(dispatch).toHaveBeenNthCalledWith( + 1, + storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES + ); + expect(dispatch).toHaveBeenNthCalledWith( + 2, + storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES + ); + if (context.state.order.vehicle.year !== payload.year) { + expect(commit).toBeCalledWith(storeMutations.UPDATE_YEAR, payload.year); + } + if (context.state.order.vehicle.make !== payload.make) { + expect(commit).toBeCalledWith(storeMutations.UPDATE_MAKE, payload.make); + } + if (context.state.order.vehicle.model !== payload.model) { + expect(commit).toBeCalledWith(storeMutations.UPDATE_MODEL, payload.model); + } + if (context.state.order.vehicle.style !== payload.style) { + expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, payload.style); + } + }); + it("saveVehicleDamage, should wipe out damage if different", () => { // Arrange const context = state;