Merge remote-tracking branch 'origin/develop' into feature/CSR-700
This commit is contained in:
commit
4dc23cbb9f
11 changed files with 134 additions and 190 deletions
|
|
@ -11,13 +11,9 @@ module.exports = {
|
||||||
"!src/constants/*.js",
|
"!src/constants/*.js",
|
||||||
"!src/router/**/*.js",
|
"!src/router/**/*.js",
|
||||||
"!src/helpers/unit-test-helper.js",
|
"!src/helpers/unit-test-helper.js",
|
||||||
"!src/layouts/vehicle-damage/windshield-damage-type-question/windshield-damage-type-question.vue",
|
|
||||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||||
"!src/layouts/part-questions/**/*.vue",
|
"!src/layouts/part-questions/**/*.vue",
|
||||||
"!src/layouts/reveal/**/*.vue",
|
"!src/layouts/reveal/**/*.vue"
|
||||||
// TODO REMOVE THESE AFTER WRITING UNIT TESTS
|
|
||||||
"!src/ux-components/alert/alert.vue",
|
|
||||||
"!src/helpers/validation-rules.js",
|
|
||||||
// END
|
// END
|
||||||
], // ! means exclude from coverage.
|
], // ! means exclude from coverage.
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const maska = jest.fn();
|
||||||
describe("textboxQuestion.vue", () => {
|
describe("textboxQuestion.vue", () => {
|
||||||
|
|
||||||
it("Should render a text input", async () => {
|
it("Should render a text input", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = shallowMount(textboxQuestion, {
|
const wrapper = shallowMount(textboxQuestion, {
|
||||||
global: {
|
global: {
|
||||||
directives: {
|
directives: {
|
||||||
|
|
@ -53,35 +53,7 @@ describe("textboxQuestion.vue", () => {
|
||||||
expect(label.text()).toContain(questionText);
|
expect(label.text()).toContain(questionText);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => {
|
|
||||||
// Arrange
|
|
||||||
const wrapper = shallowMount(textboxQuestion, {
|
|
||||||
global: {
|
|
||||||
directives: {
|
|
||||||
maska: maska,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
disableAutoFill: true,
|
|
||||||
},
|
|
||||||
mixins: [mockMixin]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock CMS content ...
|
|
||||||
// Trust me, the below instance of the string "Question Text" actually has the ⁠ in it. You just can't see it
|
|
||||||
// Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools,
|
|
||||||
// you will see "Q⁠uestion T⁠ext"
|
|
||||||
const expectedQuestionText = "Question Text";
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const label = wrapper.find("label");
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(label.text()).toContain(expectedQuestionText);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return input id as the id of the input field", async () => {
|
it("Should return input id as the id of the input field", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = shallowMount(textboxQuestion, {
|
const wrapper = shallowMount(textboxQuestion, {
|
||||||
|
|
@ -103,7 +75,7 @@ describe("textboxQuestion.vue", () => {
|
||||||
expect(input.attributes().id).toEqual("input ID");
|
expect(input.attributes().id).toEqual("input ID");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should render the 'questionText' data value as the aria-label attribute.", async () => {
|
it("Should render the 'questionText' data value as the aria-label attribute.", async () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -193,6 +165,6 @@ describe("textboxQuestion.vue", () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.handleChange).toHaveBeenCalled;
|
expect(wrapper.vm.handleChange).toHaveBeenCalled;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="textbox-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
<div class="textbox-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
||||||
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
||||||
<!-- See https://stackoverflow.com/a/30976223 for information about "do-not-autofill" -->
|
|
||||||
<input
|
<input
|
||||||
v-model.trim="value"
|
v-model.trim="value"
|
||||||
v-maska="mask"
|
v-maska="mask"
|
||||||
|
|
@ -14,7 +13,6 @@
|
||||||
:aria-disabled="isDisabled"
|
:aria-disabled="isDisabled"
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
autocomplete="do-not-autofill"
|
|
||||||
:class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']"
|
:class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
|
|
@ -46,7 +44,6 @@ export default {
|
||||||
inputId: String,
|
inputId: String,
|
||||||
isDisabled: Boolean,
|
isDisabled: Boolean,
|
||||||
isRequired: Boolean,
|
isRequired: Boolean,
|
||||||
disableAutoFill: Boolean,
|
|
||||||
hasIcon: Boolean, // If input has an icon
|
hasIcon: Boolean, // If input has an icon
|
||||||
iconRight: Boolean, // Place icon on right side of text input, otherwise default is left if hasIcon prop is used
|
iconRight: Boolean, // Place icon on right side of text input, otherwise default is left if hasIcon prop is used
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
|
@ -132,7 +129,7 @@ export default {
|
||||||
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
||||||
if (result.valid) {
|
if (result.valid) {
|
||||||
this.handleChange(newValue); // trigger full validation on this field only
|
this.handleChange(newValue); // trigger full validation on this field only
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export function getDamageString() {
|
||||||
if (damageLocations.length > 1) {
|
if (damageLocations.length > 1) {
|
||||||
returnString = "match"
|
returnString = "match"
|
||||||
} else {
|
} else {
|
||||||
switch(damageLocations[0]?.location) {
|
switch(damageLocations[0]?.glassLocation) {
|
||||||
case "Windshield":
|
case "Windshield":
|
||||||
returnString = "windshield"
|
returnString = "windshield"
|
||||||
break;
|
break;
|
||||||
|
|
@ -36,7 +36,7 @@ export function getDamageString() {
|
||||||
|
|
||||||
export function getIsWindshieldOnly () {
|
export function getIsWindshieldOnly () {
|
||||||
const damageLocations = store.getters.damage.glassToReplace;
|
const damageLocations = store.getters.damage.glassToReplace;
|
||||||
const returnString = damageLocations.length === 1 && damageLocations[0]?.location === "Windshield" ? "windshield" : "glass";
|
const returnString = damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield" ? "windshield" : "glass";
|
||||||
return returnString;
|
return returnString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ export async function isGlassAvailableForCarId(carId){
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const option of currentGlassOptions){
|
for(const option of currentGlassOptions){
|
||||||
if(!newGlassOptions.data[optionsMap[option.location]].availableReplacementOptions.includes(option.name)){
|
if(!newGlassOptions.data[optionsMap[option.glassLocation]].availableReplacementOptions.includes(option.glassName)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
it("Should return match when multiple selected damage options are in the store", () => {
|
it("Should return match when multiple selected damage options are in the store", () => {
|
||||||
|
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}, {location: "Passenger", name: "sideWindow"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}, {glassLocation: "Passenger", glassName: "sideWindow"}];
|
||||||
|
|
||||||
const damage = getDamageString();
|
const damage = getDamageString();
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
it("Should return windshield when Windshield is the only selected damage option in the store", () => {
|
it("Should return windshield when Windshield is the only selected damage option in the store", () => {
|
||||||
|
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}];
|
||||||
|
|
||||||
const damage = getDamageString();
|
const damage = getDamageString();
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => {
|
it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => {
|
||||||
|
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
store.getters.damage.glassToReplace = [{location: "Passenger", name: "sideWindow"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Passenger", glassName: "sideWindow"}];
|
||||||
|
|
||||||
const damage = getDamageString();
|
const damage = getDamageString();
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
it("Should return rear window when Rear is the only selected damage option in the store", () => {
|
it("Should return rear window when Rear is the only selected damage option in the store", () => {
|
||||||
|
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
store.getters.damage.glassToReplace = [{location: "Rear", name: "rear"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Rear", glassName: "rear"}];
|
||||||
|
|
||||||
const damage = getDamageString();
|
const damage = getDamageString();
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
describe("damage-helper.js", () => {
|
describe("damage-helper.js", () => {
|
||||||
it("Should return true if no mismatches between each array exist", async () => {
|
it("Should return true if no mismatches between each array exist", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}];
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const isGlassAvailable = await isGlassAvailableForCarId();
|
const isGlassAvailable = await isGlassAvailableForCarId();
|
||||||
|
|
@ -80,7 +80,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
describe("damage-helper.js", () => {
|
describe("damage-helper.js", () => {
|
||||||
it("Should return false if any mismatches between each array exist", async () => {
|
it("Should return false if any mismatches between each array exist", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "sideWindow"}];
|
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "sideWindow"}];
|
||||||
|
|
||||||
const isGlassAvailable = await isGlassAvailableForCarId();
|
const isGlassAvailable = await isGlassAvailableForCarId();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<loadingModal ref="loadingModal"/>
|
<loadingModal ref="loadingModal"/>
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" ref="vehicleBanner" :displayGenericVehicleImage=false />
|
<vehicleBanner cmsWidgetName="VehicleBannerWidget" ref="vehicleBanner" :displayGenericVehicleImage=false />
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
|
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
|
||||||
<alert ref="alertVinNotFound" v-if="displayVinNotFoundAlert"
|
<alert ref="alertVinNotFound" v-if="displayVinNotFoundAlert"
|
||||||
|
|
@ -24,14 +24,14 @@
|
||||||
:manualCopy="AlertMatchedDifferentVehicleBody"
|
:manualCopy="AlertMatchedDifferentVehicleBody"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertNonServiceableZip" v-if="displayNonServiceableZipAlert"
|
<alert ref="alertNonServiceableZip" v-if="displayNonServiceableZipAlert"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
:manualHeadline="AlertNonServiceableZipHeader"
|
:manualHeadline="AlertNonServiceableZipHeader"
|
||||||
:manualCopy="AlertNonServiceableZipBody"
|
:manualCopy="AlertNonServiceableZipBody"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-if="displayVinLookupByHomeAddressNotAllowedAlert"
|
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-if="displayVinLookupByHomeAddressNotAllowedAlert"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
|
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
|
||||||
|
|
@ -42,11 +42,11 @@
|
||||||
<div class="service-zip-field" v-if="showServiceZipField" aria-live="polite">
|
<div class="service-zip-field" v-if="showServiceZipField" aria-live="polite">
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="ServiceZipQuestionWidget" v-model="serviceZipCode" ref="serviceZip" inputId="7add1b26df344f2caf1678de5797803f" aria-haspopup="" mask="#####" disableAutoFill validationRules="service-zip-required|service-zip-format" />
|
<textboxQuestion cmsWidgetName="ServiceZipQuestionWidget" v-model="serviceZipCode" ref="serviceZip" inputId="7add1b26df344f2caf1678de5797803f" aria-haspopup="" mask="#####" validationRules="service-zip-required|service-zip-format" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<funnel-footer
|
<funnel-footer
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
ref="funnelFooter"
|
ref="funnelFooter"
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
@back-clicked="backButtonAction"
|
@back-clicked="backButtonAction"
|
||||||
:isForwardActionDisabled="!meta.valid"
|
:isForwardActionDisabled="!meta.valid"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -122,14 +122,14 @@ export default {
|
||||||
firstName: this.getRegistrationFirstNameFromStore(),
|
firstName: this.getRegistrationFirstNameFromStore(),
|
||||||
lastName: this.getRegistrationLastNameFromStore(),
|
lastName: this.getRegistrationLastNameFromStore(),
|
||||||
emailAddress: this.getEmailFromStore(),
|
emailAddress: this.getEmailFromStore(),
|
||||||
},
|
},
|
||||||
serviceZipCode: this.getServiceZipFromStore(),
|
serviceZipCode: this.getServiceZipFromStore(),
|
||||||
displayNonServiceableZipAlert: false,
|
displayNonServiceableZipAlert: false,
|
||||||
displayVinNotFoundAlert: false,
|
displayVinNotFoundAlert: false,
|
||||||
displayMatchedDifferentVehicleAlert: false,
|
displayMatchedDifferentVehicleAlert: false,
|
||||||
displayVinLookupByHomeAddressNotAllowedAlert: false,
|
displayVinLookupByHomeAddressNotAllowedAlert: false,
|
||||||
previouslyEnteredCarId: "",
|
previouslyEnteredCarId: "",
|
||||||
isSelectedGlassAvailableForVehicle: false,
|
isSelectedGlassAvailableForVehicle: false,
|
||||||
customAlertData: {},
|
customAlertData: {},
|
||||||
showServiceZipField: this.getServiceZipFromStore(),
|
showServiceZipField: this.getServiceZipFromStore(),
|
||||||
isZipServicable: false,
|
isZipServicable: false,
|
||||||
|
|
@ -150,7 +150,7 @@ export default {
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
attachCustomEvents() {
|
attachCustomEvents() {
|
||||||
this.prependActionToMethod(this, this.forwardButtonAction, () => {
|
this.prependActionToMethod(this, this.forwardButtonAction, () => {
|
||||||
this.pushEventToGA(
|
this.pushEventToGA(
|
||||||
this.$route.query[this.queryStrings.FMG_PAGE],
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
|
|
@ -177,7 +177,7 @@ export default {
|
||||||
},
|
},
|
||||||
getRegistrationLastNameFromStore() {
|
getRegistrationLastNameFromStore() {
|
||||||
return store.getters.vehicle.registration.lastName;
|
return store.getters.vehicle.registration.lastName;
|
||||||
},
|
},
|
||||||
getEmailFromStore() {
|
getEmailFromStore() {
|
||||||
return store.getters.order.customer.emailAddress;
|
return store.getters.order.customer.emailAddress;
|
||||||
},
|
},
|
||||||
|
|
@ -189,9 +189,9 @@ export default {
|
||||||
|
|
||||||
// Lookup VIN(s) with the provided address
|
// Lookup VIN(s) with the provided address
|
||||||
const vinLookupPromise = this.lookupVin(
|
const vinLookupPromise = this.lookupVin(
|
||||||
this.customerQuestions.lastName,
|
this.customerQuestions.lastName,
|
||||||
this.customerQuestions.addressQuestions.streetAddress,
|
this.customerQuestions.addressQuestions.streetAddress,
|
||||||
this.customerQuestions.addressQuestions.zipCode,
|
this.customerQuestions.addressQuestions.zipCode,
|
||||||
this.customerQuestions.addressQuestions.state
|
this.customerQuestions.addressQuestions.state
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -200,8 +200,8 @@ export default {
|
||||||
|
|
||||||
const vinLookupResponse = await vinLookupPromise;
|
const vinLookupResponse = await vinLookupPromise;
|
||||||
const serviceZipValidationResponse = await serviceZipValidationPromise;
|
const serviceZipValidationResponse = await serviceZipValidationPromise;
|
||||||
|
|
||||||
if (!vinLookupResponse.data.isStatePermissible) {
|
if (!vinLookupResponse.data.isStatePermissible) {
|
||||||
// State Restrictions forbid lookup by address
|
// State Restrictions forbid lookup by address
|
||||||
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
|
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
|
@ -210,29 +210,29 @@ export default {
|
||||||
|
|
||||||
// if the neither the registration zip code or service zip code are not serviceable
|
// if the neither the registration zip code or service zip code are not serviceable
|
||||||
this.isZipServicable = serviceZipValidationResponse.data.isServiceable;
|
this.isZipServicable = serviceZipValidationResponse.data.isServiceable;
|
||||||
if (!this.isZipServicable) {
|
if (!this.isZipServicable) {
|
||||||
this.displayNonServiceableZipAlert = true;
|
this.displayNonServiceableZipAlert = true;
|
||||||
this.showServiceZipField = true;
|
this.showServiceZipField = true;
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
} else if (!this.serviceZipCode) {
|
} else if (!this.serviceZipCode) {
|
||||||
// if the registration zip code is servicable and nothing was entered for the service zip code
|
// if the registration zip code is servicable and nothing was entered for the service zip code
|
||||||
// then set the service zip code to the registration zip code
|
// then set the service zip code to the registration zip code
|
||||||
this.serviceZipCode = this.customerQuestions.addressQuestions.zipCode;
|
this.serviceZipCode = this.customerQuestions.addressQuestions.zipCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const carEntered = store.getters.vehicle;
|
const carEntered = store.getters.vehicle;
|
||||||
const carsFound = vinLookupResponse.data.vinVehicles;
|
const carsFound = vinLookupResponse.data.vinVehicles;
|
||||||
|
|
||||||
if (carsFound.length == 0) {
|
if (carsFound.length == 0) {
|
||||||
// No VINs found
|
// No VINs found
|
||||||
this.displayVinNotFoundAlert = true;
|
this.displayVinNotFoundAlert = true;
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
return;
|
return;
|
||||||
} else if (carsFound.length == 1) {
|
} else if (carsFound.length == 1) {
|
||||||
const carFound = carsFound[0].vehicle;
|
const carFound = carsFound[0].vehicle;
|
||||||
this.isCarIdDifferent = carFound.carId !== carEntered.carId;
|
this.isCarIdDifferent = carFound.carId !== carEntered.carId;
|
||||||
|
|
||||||
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
|
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
|
||||||
// Display Alert
|
// Display Alert
|
||||||
this.previouslyEnteredCarId = carFound.carId;
|
this.previouslyEnteredCarId = carFound.carId;
|
||||||
this.customAlertData.vehicleInfo = carFound;
|
this.customAlertData.vehicleInfo = carFound;
|
||||||
|
|
@ -241,12 +241,12 @@ export default {
|
||||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(carFound.carId);
|
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(carFound.carId);
|
||||||
|
|
||||||
// Update button "Continue with..."
|
// Update button "Continue with..."
|
||||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${carFound.year} ${carFound.make} ${carFound.model}`);
|
this.$refs.funnelFooter.updateButtonText(`Continue with ${carFound.year} ${carFound.make} ${carFound.model}`);
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isZipServicable) {
|
if (!this.isZipServicable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -254,21 +254,21 @@ export default {
|
||||||
// update data if the zip or service zip is servicable
|
// update data if the zip or service zip is servicable
|
||||||
this.updateVehicleInfo(carsFound[0].vin, carFound);
|
this.updateVehicleInfo(carsFound[0].vin, carFound);
|
||||||
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
||||||
|
|
||||||
} else if (carsFound.length > 1) {
|
} else if (carsFound.length > 1) {
|
||||||
if (!this.isZipServicable) {
|
if (!this.isZipServicable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if multiple cars were found
|
// if multiple cars were found
|
||||||
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
||||||
if (matchingCars.length === 1) {
|
if (matchingCars.length === 1) {
|
||||||
// and one and only one of them matches the carId entered, save the vehicle info
|
// and one and only one of them matches the carId entered, save the vehicle info
|
||||||
// so we can go to the Heritage Funnel directly
|
// so we can go to the Heritage Funnel directly
|
||||||
const matchingCar = matchingCars[0];
|
const matchingCar = matchingCars[0];
|
||||||
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update data if the zip or service zip is servicable
|
// update data if the zip or service zip is servicable
|
||||||
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
||||||
}
|
}
|
||||||
|
|
@ -277,13 +277,13 @@ export default {
|
||||||
},
|
},
|
||||||
resetWarningsAndErrors() {
|
resetWarningsAndErrors() {
|
||||||
this.displayVinNotFoundAlert = false;
|
this.displayVinNotFoundAlert = false;
|
||||||
this.displayNonServiceableZipAlert = false;
|
this.displayNonServiceableZipAlert = false;
|
||||||
this.displayMatchedDifferentVehicleAlert = false;
|
this.displayMatchedDifferentVehicleAlert = false;
|
||||||
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
|
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
|
||||||
},
|
},
|
||||||
navigateForward(carEntered, carsFound) {
|
navigateForward(carEntered, carsFound) {
|
||||||
this.updateServiceLocationIfNecessary();
|
this.updateServiceLocationIfNecessary();
|
||||||
|
|
||||||
if (carsFound.length == 1) {
|
if (carsFound.length == 1) {
|
||||||
// if a different vehicle is found than the one entered and the selected glass
|
// if a different vehicle is found than the one entered and the selected glass
|
||||||
// is not available for that vehicle
|
// is not available for that vehicle
|
||||||
|
|
@ -297,37 +297,37 @@ export default {
|
||||||
}, {}
|
}, {}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// otherwise
|
// otherwise
|
||||||
this.navigateForwardWithSingleCarMatch();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
}
|
}
|
||||||
} else if (carsFound.length > 1) {
|
} else if (carsFound.length > 1) {
|
||||||
// if multiple cars were found
|
// if multiple cars were found
|
||||||
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
||||||
if (matchingCars.length === 1) {
|
if (matchingCars.length === 1) {
|
||||||
// and one and only of them matches the car id entered
|
// and one and only of them matches the car id entered
|
||||||
const matchingCar = matchingCars[0];
|
const matchingCar = matchingCars[0];
|
||||||
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
||||||
this.navigateForwardWithSingleCarMatch();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
} else {
|
} else {
|
||||||
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page
|
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page
|
||||||
this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
validateZip(zip) {
|
validateZip(zip) {
|
||||||
return this.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.VALIDATE_ZIP,
|
storeActions.VALIDATE_ZIP,
|
||||||
{ zip });
|
{ zip });
|
||||||
},
|
},
|
||||||
lookupVin(lastName, streetAddress, zip, state) {
|
lookupVin(lastName, streetAddress, zip, state) {
|
||||||
return this.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.LOOKUP_VIN_BY_ADDRESS,
|
storeActions.LOOKUP_VIN_BY_ADDRESS,
|
||||||
{
|
{
|
||||||
licenseLastName: lastName,
|
licenseLastName: lastName,
|
||||||
licenseStreetAddress: streetAddress,
|
licenseStreetAddress: streetAddress,
|
||||||
licenseZip: zip,
|
licenseZip: zip,
|
||||||
licenseState: state
|
licenseState: state
|
||||||
}, false
|
}, false
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -342,7 +342,7 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, vehicleInfo.imageUrl);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, vehicleInfo.imageUrl);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicleInfo.imageVifNumber);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicleInfo.imageVifNumber);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicleInfo.imageColor);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicleInfo.imageColor);
|
||||||
},
|
},
|
||||||
updateCustomerInfo(serviceState) {
|
updateCustomerInfo(serviceState) {
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_ADDRESS, this.customerQuestions.addressQuestions.streetAddress);
|
store.commit(storeMutations.UPDATE_REGISTRATION_ADDRESS, this.customerQuestions.addressQuestions.streetAddress);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_CITY, this.customerQuestions.addressQuestions.city);
|
store.commit(storeMutations.UPDATE_REGISTRATION_CITY, this.customerQuestions.addressQuestions.city);
|
||||||
|
|
@ -350,10 +350,10 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, this.customerQuestions.addressQuestions.zipCode);
|
store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, this.customerQuestions.addressQuestions.zipCode);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_FIRST_NAME, this.customerQuestions.firstName);
|
store.commit(storeMutations.UPDATE_REGISTRATION_FIRST_NAME, this.customerQuestions.firstName);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_LAST_NAME, this.customerQuestions.lastName);
|
store.commit(storeMutations.UPDATE_REGISTRATION_LAST_NAME, this.customerQuestions.lastName);
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZipCode);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZipCode);
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, serviceState);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, serviceState);
|
||||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
|
||||||
},
|
},
|
||||||
updateServiceLocationIfNecessary() {
|
updateServiceLocationIfNecessary() {
|
||||||
const serviceLocation = store.getters.order.serviceLocation;
|
const serviceLocation = store.getters.order.serviceLocation;
|
||||||
|
|
||||||
|
|
@ -373,7 +373,7 @@ export default {
|
||||||
},
|
},
|
||||||
AlertNonServiceableZipBody() {
|
AlertNonServiceableZipBody() {
|
||||||
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
|
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
|
||||||
},
|
},
|
||||||
AlertMatchedDifferentVehicleHeader() {
|
AlertMatchedDifferentVehicleHeader() {
|
||||||
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "HeadlineText").replaceAll("{custom:glassText}", getDamageString());
|
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "HeadlineText").replaceAll("{custom:glassText}", getDamageString());
|
||||||
return text;
|
return text;
|
||||||
|
|
@ -386,13 +386,13 @@ export default {
|
||||||
const content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
|
const content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
|
||||||
.replaceAll("{custom:glassText}", getDamageString())
|
.replaceAll("{custom:glassText}", getDamageString())
|
||||||
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
|
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
|
||||||
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
|
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
handler(newValue) {
|
handler(newValue) {
|
||||||
// if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to “Get my personalized quote”
|
// if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to “Get my personalized quote”
|
||||||
this.$refs.funnelFooter.updateButtonText(this.getCmsContent("FunnelFooterWidget", "ForwardButtonText"));
|
this.$refs.funnelFooter.updateButtonText(this.getCmsContent("FunnelFooterWidget", "ForwardButtonText"));
|
||||||
|
|
@ -412,8 +412,8 @@ export default {
|
||||||
// if the Service Zip Code field is ever hidden, clear out it's value
|
// if the Service Zip Code field is ever hidden, clear out it's value
|
||||||
if (!newValue) {
|
if (!newValue) {
|
||||||
this.serviceZipCode = null;
|
this.serviceZipCode = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js";
|
import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js";
|
||||||
// Define Validation Rules
|
// Define Validation Rules
|
||||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
@ -94,21 +95,22 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
forwardButtonAction() {
|
forwardButtonAction() {
|
||||||
if (this.selectedValues[0]===vinLookupMethodSelections.MANUALVIN) {
|
if (this.selectedValues[0] === vinLookupMethodSelections.MANUALVIN) {
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
this.navigationScenarios.SELECTED_MANUAL_VIN,
|
this.navigationScenarios.SELECTED_MANUAL_VIN,
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.selectedValues[0]===vinLookupMethodSelections.LICENSEPLATE) {
|
if (this.selectedValues[0] === vinLookupMethodSelections.LICENSEPLATE) {
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
this.navigationScenarios.SELECTED_LICENSE_PLATE,
|
this.navigationScenarios.SELECTED_LICENSE_PLATE,
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.selectedValues[0]===vinLookupMethodSelections.HOMEADDRESS) {
|
if (this.selectedValues[0] === vinLookupMethodSelections.HOMEADDRESS) {
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
this.navigationScenarios.SELECTED_HOME_ADDRESS,
|
this.navigationScenarios.SELECTED_HOME_ADDRESS,
|
||||||
this.$route
|
this.$route
|
||||||
|
|
|
||||||
|
|
@ -267,8 +267,7 @@ export default {
|
||||||
`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`
|
`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`
|
||||||
);
|
);
|
||||||
this.isVinValid = true;
|
this.isVinValid = true;
|
||||||
this.isSelectedGlassAvailableForVehicle =
|
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.vehicle.carId);
|
||||||
await isGlassAvailableForCarId(vinLookup.data.vehicle.carId);
|
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ describe("vehicle-damage.vue", () => {
|
||||||
|
|
||||||
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }, { location: "Driver", name: "Back" },
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
||||||
{ location: "Passenger", name: "Quarter" }, { location: "Rear", name: "Stationary" }];
|
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
vehicleDamage.beforeRouteEnter.call(
|
vehicleDamage.beforeRouteEnter.call(
|
||||||
|
|
@ -237,7 +237,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
selectedWindshieldDamageType: ["Replace"]
|
selectedWindshieldDamageType: ["Replace"]
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" },];
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" },];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
vehicleDamage.beforeRouteEnter.call(
|
vehicleDamage.beforeRouteEnter.call(
|
||||||
|
|
|
||||||
|
|
@ -314,25 +314,25 @@ export default {
|
||||||
const selectedGlassToReplace = [];
|
const selectedGlassToReplace = [];
|
||||||
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){
|
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){
|
||||||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => {
|
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.WINDSHIELD, name: wsItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.WINDSHIELD, glassName: wsItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDriverSideReplace){
|
if (this.isDriverSideReplace){
|
||||||
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => {
|
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.DRIVER, name: driverItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.DRIVER, glassName: driverItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isPassengerSideReplace){
|
if (this.isPassengerSideReplace){
|
||||||
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => {
|
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.PASSENGER, name: passengerItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.PASSENGER, glassName: passengerItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isRearWindowDamageLocation) {
|
if (this.isRearWindowDamageLocation) {
|
||||||
this.selectedRearReplaceOptions.forEach(rearItem => {
|
this.selectedRearReplaceOptions.forEach(rearItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.REAR, name: rearItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.REAR, glassName: rearItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@
|
||||||
isRequired
|
isRequired
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="vin-required|vin-format"
|
validationRules="vin-required|vin-format"
|
||||||
:isDisabled="isVinFieldReadOnly"
|
:isDisabled="vinPopulatedOnPageLoad"
|
||||||
maxLength="17"
|
maxLength="17"
|
||||||
:mask="vinMask"
|
:mask="vinMask"
|
||||||
@focus="setVinTouched"
|
|
||||||
@maska="rawVinValue = $event.target.dataset.maskRawValue"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -70,10 +68,10 @@
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-4"
|
class="my-4"
|
||||||
:manualHeadline="PerfectMatchNewVinAlertReadOnlyHeader"
|
:manualHeadline="PerfectMatchInsuranceVerifiedAlertHeader"
|
||||||
:manualCopy="PerfectMatchNewVinAlertReadOnlyBody"
|
:manualCopy="PerfectMatchInsuranceVerifiedAlertBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="isVinFieldReadOnly"
|
v-if="vinPopulatedOnPageLoad && isInsuranceVerified"
|
||||||
alertClass="alert-success"
|
alertClass="alert-success"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
|
|
@ -101,10 +99,10 @@
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-4"
|
class="my-4"
|
||||||
:manualHeadline="PerfectMatchNewVinAlertHeader"
|
:manualHeadline="PerfectMatchInsuranceNotVerifiedAlertHeader"
|
||||||
:manualCopy="PerfectMatchNewVinAlertBody"
|
:manualCopy="PerfectMatchInsuranceNotVerifiedAlertBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="perfectMatchNewVinAlert && !noServiceZip && !vinNotFound && meta.valid && !isVinFieldReadOnly"
|
v-if="vinPopulatedOnPageLoad && !isInsuranceVerified"
|
||||||
alertClass="alert-success"
|
alertClass="alert-success"
|
||||||
/>
|
/>
|
||||||
<funnelFooter
|
<funnelFooter
|
||||||
|
|
@ -140,10 +138,8 @@ import { errorMessages } from "@/constants/error-messages";
|
||||||
import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||||
import { required, regex } from "@/helpers/validation-rules";
|
import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
import { StatusCodes } from 'http-status-codes';
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||||
|
|
@ -187,15 +183,14 @@ export default {
|
||||||
previouslyEnteredCarId: '',
|
previouslyEnteredCarId: '',
|
||||||
invalidZip: '',
|
invalidZip: '',
|
||||||
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
||||||
initialVin: this.getVinFromStore(),
|
isInsuranceVerified: false,
|
||||||
vinTouched: false,
|
|
||||||
rawVinValue: "",
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.attachCustomEvents();
|
this.attachCustomEvents();
|
||||||
if (this.vinPopulatedOnPageLoad) {
|
if (this.vinPopulatedOnPageLoad) {
|
||||||
this.setupVinMask();
|
this.setupVinMask();
|
||||||
|
this.isInsuranceVerified = store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
@ -210,12 +205,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
perfectMatchNewVinAlert() {
|
|
||||||
const vinToCheck = this.vinTouched ? this.rawVinValue : this.initialVin;
|
|
||||||
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && vinToCheck === this.getVinFromStore();
|
|
||||||
this.updateIsCarIdDifferent(isVinPerfectMatch);
|
|
||||||
return isVinPerfectMatch;
|
|
||||||
},
|
|
||||||
MatchedDifferentVehicleAlertHeader(){
|
MatchedDifferentVehicleAlertHeader(){
|
||||||
const text = this.getCmsContent("MatchedDifferentVehicle",
|
const text = this.getCmsContent("MatchedDifferentVehicle",
|
||||||
"HeadlineText").replaceAll("{custom:damage}", getDamageString());
|
"HeadlineText").replaceAll("{custom:damage}", getDamageString());
|
||||||
|
|
@ -231,41 +220,29 @@ export default {
|
||||||
},
|
},
|
||||||
NoServiceZipHeader(){
|
NoServiceZipHeader(){
|
||||||
const text = this.getCmsContent("NoServiceZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.invalidZip);
|
const text = this.getCmsContent("NoServiceZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.invalidZip);
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
NoServiceZipBody(){
|
NoServiceZipBody(){
|
||||||
return this.getCmsContent("NoServiceZipWidget", "BodyText");
|
return this.getCmsContent("NoServiceZipWidget", "BodyText");
|
||||||
},
|
},
|
||||||
PerfectMatchNewVinAlertHeader() {
|
PerfectMatchInsuranceNotVerifiedAlertHeader() {
|
||||||
return this.getCmsContent("PerfectMatchNewVinAlert", "HeadlineText");
|
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "HeadlineText");
|
||||||
},
|
},
|
||||||
PerfectMatchNewVinAlertBody() {
|
PerfectMatchInsuranceNotVerifiedAlertBody() {
|
||||||
return this.getCmsContent("PerfectMatchNewVinAlert", "BodyText").replaceAll("{custom:damage}",
|
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
|
||||||
getDamageString())
|
getDamageString())
|
||||||
},
|
},
|
||||||
PerfectMatchNewVinAlertReadOnlyHeader () {
|
PerfectMatchInsuranceVerifiedAlertHeader () {
|
||||||
return this.getCmsContent("PerfectMatchNewVinAlertReadOnly", "HeadlineText");
|
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "HeadlineText");
|
||||||
},
|
},
|
||||||
PerfectMatchNewVinAlertReadOnlyBody () {
|
PerfectMatchInsuranceVerifiedAlertBody () {
|
||||||
return this.getCmsContent("PerfectMatchNewVinAlertReadOnly", "BodyText").replaceAll("{custom:damage}",
|
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
|
||||||
getIsWindshieldOnly())
|
getIsWindshieldOnly())
|
||||||
},
|
},
|
||||||
isVinFieldReadOnly(){
|
|
||||||
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setVinTouched() {
|
|
||||||
if (!this.vinTouched) {
|
|
||||||
this.vinMask = "XXXXXXXXXXXXXXXXX";
|
|
||||||
this.vin = this.initialVin;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.vinTouched = true;
|
|
||||||
},
|
|
||||||
setupVinMask() {
|
setupVinMask() {
|
||||||
const lastSixChars = this.initialVin.substring(11, this.initialVin.length);
|
const lastSixChars = this.vin.substring(11, this.vin.length);
|
||||||
this.vinMask = `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
|
this.vinMask = `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
|
||||||
},
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
|
|
@ -315,17 +292,16 @@ export default {
|
||||||
let vehicleLookupResponse;
|
let vehicleLookupResponse;
|
||||||
|
|
||||||
const zipValidation = this.validateZip(this.zip);
|
const zipValidation = this.validateZip(this.zip);
|
||||||
|
|
||||||
if (this.vinTouched && this.vin != this.initialVin) {
|
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
|
||||||
// If the user has clicked on the VIN field, either they are doing a new VIN lookup or changing the VIN previously matched.
|
if (!this.vinPopulatedOnPageLoad) {
|
||||||
// Therefore we need to do a Vehicle Lookup
|
// Perform Zip Validation
|
||||||
const vinToLookup = this.vinTouched ? this.vin : this.initialVin;
|
|
||||||
const vehicleLookup = this.lookupVehicle(vinToLookup);
|
|
||||||
|
|
||||||
zipValidationResponse = await zipValidation;
|
zipValidationResponse = await zipValidation;
|
||||||
|
|
||||||
|
// Perform Vehicle Lookup
|
||||||
|
const vehicleLookup = this.lookupVehicle(this.vin);
|
||||||
vehicleLookupResponse = await vehicleLookup.catch(() => {
|
vehicleLookupResponse = await vehicleLookup.catch(() => {
|
||||||
this.vinNotFound = true;
|
this.vinNotFound = true;
|
||||||
this.$refs.funnelFooter.removeLoader();
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -335,44 +311,46 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vehicleLookupResponse || !zipValidationResponse.data.isServiceable) {
|
if (!vehicleLookupResponse || !zipValidationResponse.data.isServiceable) {
|
||||||
|
// If either lookup fails, remove the loader and stop processing the page.
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
||||||
|
|
||||||
|
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
||||||
|
this.previouslyEnteredCarId = vehicleLookupResponse.data.carId;
|
||||||
|
this.noServiceZip = false;
|
||||||
|
this.customAlertData.vehicleInfo = vehicleLookupResponse.data;
|
||||||
|
this.$refs.funnelFooter.updateButtonText(`Continue with ${vehicleLookupResponse.data.year} ${vehicleLookupResponse.data.make} ${vehicleLookupResponse.data.model}`);
|
||||||
|
this.isVinValid = true;
|
||||||
|
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vehicleLookupResponse.data.carId);
|
||||||
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
this.isCarIdDifferent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
||||||
|
this.navigateForward();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// If a VIN has already been found. Validate the Service Zip (in case of changes)
|
||||||
const zipValidationResponse = await zipValidation;
|
const zipValidationResponse = await zipValidation;
|
||||||
|
|
||||||
// Check if Service Zip entered is serviceable, if not display an alert
|
// Check if Service Zip entered is serviceable
|
||||||
if (!zipValidationResponse.data.isServiceable) {
|
if (zipValidationResponse.data.isServiceable) {
|
||||||
|
// If the Service Zip entered is serviceable then save the Zip Info and Email Address and navigate forward
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.zip);
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, zipValidationResponse.data.state);
|
||||||
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
||||||
|
this.navigateForward();
|
||||||
|
} else {
|
||||||
|
// If the Service Zip is NOT serviceable then show an alert
|
||||||
this.setupUiForNonServiceableZip(this.zip);
|
this.setupUiForNonServiceableZip(this.zip);
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.navigateForward();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vehicleLookupResponse) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
|
||||||
|
|
||||||
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
|
||||||
this.previouslyEnteredCarId = vehicleLookupResponse.data.carId;
|
|
||||||
this.noServiceZip = false;
|
|
||||||
this.customAlertData.vehicleInfo = vehicleLookupResponse.data;
|
|
||||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${vehicleLookupResponse.data.year} ${vehicleLookupResponse.data.make} ${vehicleLookupResponse.data.model}`);
|
|
||||||
this.isVinValid = true;
|
|
||||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vehicleLookupResponse.data.carId);
|
|
||||||
this.$refs.funnelFooter.removeLoader();
|
|
||||||
this.isCarIdDifferent = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
|
||||||
this.navigateForward();
|
|
||||||
|
|
||||||
},
|
},
|
||||||
navigateForward(){
|
navigateForward(){
|
||||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue