diff --git a/src/common-components/button-question/button-question.vue b/src/common-components/button-question/button-question.vue index f2f87931e..b46d933c0 100644 --- a/src/common-components/button-question/button-question.vue +++ b/src/common-components/button-question/button-question.vue @@ -37,8 +37,8 @@ -
- +
+
@@ -133,9 +133,10 @@ export default { if(this.isMultiSelect && this.selectedValues) { // Add or remove item to array of data to emit const newSelectedValues = this.selectedValues; + if(Array.isArray(this.selectedValues)) { val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1); - this.selectedValues = newSelectedValues; + this.selectedValues = newSelectedValues; } } else { this.selectedValues = [val.value]; @@ -154,11 +155,11 @@ export default { diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index d46841b6a..f54909d06 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -20,7 +20,19 @@ export default { }, savePageDataToStore(page, data){ store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data }); - } + }, + onSubmit() {}, // DO NOT REMOVE; needed to prevent default form submit behavior + onInvalidSubmit({ values, errors, results }) { + // identify the first error field and put focus on it + // get error names array + const errorNames = errors ? Object.keys(errors) : []; + const firstErrorEl = errorNames[0]; + if (firstErrorEl) { + const qsString = "[data-focus-target='" + firstErrorEl + "']"; + const el = document.querySelector(qsString); + el && el.focus(); + } + }, }, computed: { storeActions() { diff --git a/src/mixins/base-mixin.spec.js b/src/mixins/base-mixin.spec.js index da684af1b..d32163469 100644 --- a/src/mixins/base-mixin.spec.js +++ b/src/mixins/base-mixin.spec.js @@ -3,6 +3,7 @@ import { storeActions } from "@/constants/store-actions.js"; import { widgetNames } from "@/constants/widget-names.js"; import { storeMutations } from "@/constants/store-mutations.js"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; +import { vehicleCategories } from "@/constants/vehicle-categories.js"; import store from "@/store"; describe("baseMixin.js", () => { @@ -77,6 +78,36 @@ describe("baseMixin.js", () => { // Assert expect(widgetNamesForTest).toEqual(widgetNames); }); + + test("computed: vehicleCategories should be equal to import object", () => { + // Arrange + const mixIn = getMixInInstance({}); + + // Act + let vehicleCategoriesForTest = mixIn.computed.vehicleCategories(); + + // Assert + expect(vehicleCategoriesForTest).toEqual(vehicleCategories); + }); + + test("onInvalidSubmit: puts focus on first error", () => { + // Arrange + const mixIn = getMixInInstance({}); + const validationData = { + errors: { + fieldOne: 'error message 1', + fieldTwo: 'error message 2', + } + }; + + global.document.querySelector = jest.fn(); + + // Act + mixIn.methods.onInvalidSubmit(validationData); + + // Assert + expect(global.document.querySelector).toBeCalledWith("[data-focus-target='fieldOne']"); + }); }); function getMixInInstance({ isDispatchSuccess = true }) { @@ -101,6 +132,7 @@ function getMixInInstance({ isDispatchSuccess = true }) { baseMixIn.methods.$route = route; baseMixIn.methods.storeActions = storeActions; baseMixIn.methods.widgetNames = widgetNames; + baseMixIn.methods.vehicleCategories = vehicleCategories; store.dispatch = storeDispatch; store.commit = jest.fn(); diff --git a/src/router/router-constants/fmgPage-values.js b/src/router/router-constants/fmgPage-values.js index 7421984cb..d77f11ff8 100644 --- a/src/router/router-constants/fmgPage-values.js +++ b/src/router/router-constants/fmgPage-values.js @@ -5,9 +5,10 @@ const fmgPageValues = { VEHICLE_STYLE: "vehicle-style", VEHICLE_DAMAGE: "vehicle-damage", ADDRESS_LOOKUP: "address-lookup", + VIN_LOOKUP: "vin-lookup", VEHICLE_PARTS: "vehicle-parts", PART_QUESTIONS: "part-questions", REVEAL : "reveal", }; -export { fmgPageValues }; \ No newline at end of file +export { fmgPageValues }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index c9dc7ba4d..584796a61 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -84,6 +84,32 @@ const routingTable = [ }, ], }, + { + fmgPageValue: fmgPageValues.REVEAL, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, + }, + { + scenario: navigationScenarios.SELECTED_PARTS, + destinationFmgPageValue: fmgPageValues.VIN_LOOKUP, + }, + ], + }, + { + fmgPageValue: fmgPageValues.VIN_LOOKUP, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, + }, + { + scenario: navigationScenarios.VIN_LOOKUP, + destinationFmgPageValue: fmgPageValues.PART_QUESTIONS, + }, + ], + }, ]; export { routingTable }; diff --git a/src/store/index.js b/src/store/index.js index 4b0e06eb4..53e977114 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -19,6 +19,21 @@ export const state = { imageUrl: null, imageVifNumber: null, imageColor: null, + registration: { + licensePlate: null, + address: null, + city: null, + state: null, + zipCode: null, + firstName: null, + lastName: null, + }, + }, + serviceLocation: { + zip: null, + }, + customer: { + emailAddress: null, }, damage: { isRepair: null, @@ -81,6 +96,33 @@ export const mutations = { updatePageData(state, pageData){ state.applicationUser.pageData[pageData.page] = pageData.data; }, + updateRegistrationAddress(state, registrationAddress){ + state.order.vehicle.registration.address = registrationAddress; + }, + updateRegistrationCity(state, registrationCity){ + state.order.vehicle.registration.city = registrationCity; + }, + updateRegistrationState(state, registrationState){ + state.order.vehicle.registration.state = registrationState; + }, + updateRegistrationZipCode(state, registrationZipCode){ + state.order.vehicle.registration.zipCode = registrationZipCode; + }, + updateRegistrationFirstName(state, registrationFirstName){ + state.order.vehicle.registration.firstName = registrationFirstName; + }, + updateRegistrationLastName(state, registrationLastName){ + state.order.vehicle.registration.lastName = registrationLastName; + }, + updateRegistrationLicensePlate(state, registrationLicensePlate){ + state.order.vehicle.registration.licensePlate = registrationLicensePlate; + }, + updateServiceLocationZip(state, serviceLocationZip){ + state.order.vehicle.serviceLocation.zip = serviceLocationZip; + }, + updateCustomerEmailAddress(state, customerEmailAddress){ + state.order.vehicle.customer.emailAddress = customerEmailAddress; + }, // EVENT BUS MUTATIONS addEventToBus(state, event) { @@ -112,14 +154,16 @@ export const mutations = { resetDamageState(state) { state.order.damage.isRepair = null; state.order.damage.numberOfChips = null; - state.order.damage.windshieldGlassToReplace = null; - state.order.damage.driverSideGlassToReplace = null; - state.order.damage.passengerSideGlassToReplace = null; - state.order.damage.rearGlassToReplace = null; - + state.order.damage.glassToReplace = null; }, resetRegistrationState(state) { - + state.order.vehicle.registration.licensePlate = null; + state.order.vehicle.registration.address = null; + state.order.vehicle.registration.city = null; + state.order.vehicle.registration.state = null; + state.order.vehicle.registration.zipCode = null; + state.order.vehicle.registration.firstName = null; + state.order.vehicle.registration.lastName = null; }, resetPartsState(state) { state.order.lineItems.glassParts = null; @@ -292,4 +336,4 @@ export default createStore({ mutations, getters, actions, -}); \ No newline at end of file +}); diff --git a/src/store/store.spec.js b/src/store/store.spec.js index ccb715e50..a3f8a5cb5 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -139,19 +139,13 @@ describe("Mutations", () => { storeState.order.damage = { isRepair: true, numberOfChips: 2, - windshieldGlassToReplace: "Front", - driverSideGlassToReplace: "Rear", - passengerSideGlassToReplace: "Rear", - rearGlassToReplace: "Slider" + glassToReplace: [{location: 'Rear', name: 'Stationary'}] } // Expect expect(storeState.order.damage.isRepair).toEqual(true); expect(storeState.order.damage.numberOfChips).toEqual(2); - expect(storeState.order.damage.windshieldGlassToReplace).toEqual("Front"); - expect(storeState.order.damage.driverSideGlassToReplace).toEqual("Rear"); - expect(storeState.order.damage.passengerSideGlassToReplace).toEqual("Rear"); - expect(storeState.order.damage.rearGlassToReplace).toEqual("Slider"); + expect(storeState.order.damage.glassToReplace).toStrictEqual([{location: 'Rear', name: 'Stationary'}]); // Act mutations.resetDamageState(storeState); @@ -159,11 +153,7 @@ describe("Mutations", () => { // Expect expect(storeState.order.damage.isRepair).toEqual(null); expect(storeState.order.damage.numberOfChips).toEqual(null); - expect(storeState.order.damage.windshieldGlassToReplace).toEqual(null); - expect(storeState.order.damage.driverSideGlassToReplace).toEqual(null); - expect(storeState.order.damage.passengerSideGlassToReplace).toEqual(null); - expect(storeState.order.damage.rearGlassToReplace).toEqual(null); - + expect(storeState.order.damage.glassToReplace).toEqual(null); }); it("Updates number of chips in state", () => { diff --git a/src/styles/common-styles.scss b/src/styles/common-styles.scss index 47ea0815d..8425a3021 100644 --- a/src/styles/common-styles.scss +++ b/src/styles/common-styles.scss @@ -3,6 +3,7 @@ body { font-size: 16px; background-color: #fff; + color: #4D5151; .container-fluid { max-width: 576px; //Remove once desktop app is complete &.container-shadow { @@ -22,7 +23,7 @@ body { } .container, .container-fluid { - overflow-x: hidden; + overflow-x: hidden !important; } .sr-only { @@ -34,4 +35,3 @@ body { overflow: hidden; } } -// Hide horizontal scrollbar diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 83dadd34a..88d95030e 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -107,6 +107,9 @@ $theme-colors: ( "dark": $dark ); +//Default font color +$body-color: $gray-600; + //Fonts $font-family-sans-serif: Roboto, Arial, Helvetica, sans-serif; $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; diff --git a/src/ux-components/alert/alert.spec.js b/src/ux-components/alert/alert.spec.js index 3d0843e10..be6dc8df7 100644 --- a/src/ux-components/alert/alert.spec.js +++ b/src/ux-components/alert/alert.spec.js @@ -1 +1,30 @@ -test.todo("some test to be written in the future"); +import { shallowMount } from "@vue/test-utils"; +import alert from "./alert"; + +describe("alert.vue", () => { + + it("Should set isMultiParagraph to true if alertCopy is an array of strings", async () => { + // Arrange + const wrapper = shallowMount(alert, { + propsData: { + alertCopy: ["one", "two"] + }, + }); + + // Assert + expect(wrapper.vm.isMultiParagraph).toBe(true); + }); + + it("Should set isMultiParagraph to false if alertCopy is a single string", async () => { + // Arrange + const wrapper = shallowMount(alert, { + propsData: { + alertCopy: "three" + }, + }); + + // Assert + expect(wrapper.vm.isMultiParagraph).toBe(false); + }); + +}); diff --git a/src/ux-components/alert/alert.vue b/src/ux-components/alert/alert.vue index 89bd366a3..56e97cb4d 100644 --- a/src/ux-components/alert/alert.vue +++ b/src/ux-components/alert/alert.vue @@ -5,7 +5,12 @@ :class="[isDismissible ? 'alert-dismissible' : '', this.alertClass]" >

{{ alertHeadline }}

-

{{ alertCopy }}

+ +

+ {{ para }} +

+
+

{{ alertCopy }}