CSR-416 Add address-lookup tests

This commit is contained in:
Katie 2022-05-27 17:06:04 -04:00
parent 50c2b787e0
commit 9bed77d2a0
4 changed files with 1040 additions and 632 deletions

View file

@ -24,14 +24,13 @@ export function getMountOptions(mockData) {
mocks.logEvent = jest.fn(); mocks.logEvent = jest.fn();
mocks.pushExperimentsToDataLayer = jest.fn(); mocks.pushExperimentsToDataLayer = jest.fn();
mocks.prependActionToMethod = jest.fn(); mocks.prependActionToMethod = jest.fn();
mocks.dispatchStoreAction = jest.fn(); mocks.dispatchStoreAction = jest.fn();
mocks.dispatchStoreAction.mockImplementation((actionName) => { mocks.dispatchStoreAction.mockImplementation((actionName) => {
let actionFilterResult = mockData.actionList.filter( let actionFilterResult = mockData.actionList.filter(
(x) => x.actionName == actionName (x) => x.actionName == actionName
); );
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { if (actionFilterResult.length === 1) {
return Promise.resolve({ return Promise.resolve({
data: actionFilterResult[0].data, data: actionFilterResult[0].data,
}); });

View file

@ -0,0 +1,505 @@
// Components
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
import funnelHeader from "@/common-components/funnel-header/funnel-header";
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
import router from "@/router";
// Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js";
import baseMixin from "@/mixins/base-mixin";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { mount, flushPromises, shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { maska } from 'maska';
import { nextTick } from "vue";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import store from "@/store";
import { validate } from "vee-validate";
import { isGlassAvailableForCarId } from "@/helpers/damage-helper.js"
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { EXPECTATION_FAILED } from "http-status-codes";
// Mock our module for promises.
// jest.mock("@/helpers/layout-helper.js", () => ({
// settleAllPromises: jest.fn(),
// }));
// // Mock fetchCmsContentForPage
// jest.mock("@/helpers/cms-content-helper", () => ({
// fetchCmsContentForPage: jest.fn(),
// }));
jest.mock("@/helpers/damage-helper", () => ({
isGlassAvailableForCarId: jest.fn().mockImplementation(() => true),
getDamageString: jest.fn()
}));
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateAfterSaveToHeritageFunnel: jest.fn()
}));
// const questionText = "Question Text";
// const mockMixin = {
// methods: {
// getCmsContent: jest.fn().mockImplementation(() => {
// return questionText;
// })
// }
// }
describe("address-lookup.vue", () => {
describe("registration and service zips", () => {
describe("if registration zip is serviceable", () => {
test("if registration address is provided => update service address on successful continue", async () => {
// Arrange
const mockRegistrationAddress = {
streetAddress: "1234 Main St",
city: "Columbus",
state: "OH",
zipCode: "43215"
}
const { wrapper } = setupMocks(addressLookup,{
isZipServiceable: true
});
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
}
})
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
});
});
describe("if registration zip is not serviceable", () => {
test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => {
// Arrange
const mockRegistrationAddress = {
streetAddress: "1234 Main St",
city: "Columbus",
state: "OH",
zipCode: "43215"
}
const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: false
});
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
}
})
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(false);
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true);
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(true);
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
});
test("if registration address is provided user clicks continue => show service zip field on continue click", async () => {
// Arrange
const mockRegistrationAddress = {
streetAddress: "1234 Main St",
city: "Columbus",
state: "OH",
zipCode: "43215"
}
const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: false
}
);
expect(wrapper.vm.showServiceZipField).toBeFalsy();
expect(wrapper.findComponent({ ref: "serviceZip" }).exists()).toBe(false);
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
}
})
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.showServiceZipField).toBe(true);
expect(wrapper.findComponent({ ref: "serviceZip" }).isVisible()).toBe(true);
});
test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => {
// Arrange
const mockRegistrationAddress = {
streetAddress: "1234 Main St",
city: "Columbus",
state: "OH",
zipCode: "43215"
}
const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: false
}
);
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
}
})
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
});
test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => {
// Arrange
const mockRegistrationAddress = {
streetAddress: "1234 Main St",
city: "Columbus",
state: "OH",
zipCode: "43215"
}
const { wrapper } = setupMocks(addressLookup, {});
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
baseMixin.methods.dispatchStoreAction = jest.fn();
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
let data = {};
if (actionName == storeActions.VALIDATE_ZIP) {
if (value == "43215") {
data = {
isServiceable: false
};
}
else {
data = {
isServiceable: true
}
}
}
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
data = {
isStatePermissible: true,
vinVehicles: [{
vin: "TEST_VIN",
vehicle: {
carId: "CARID"
}
}]
}
}
return Promise.resolve({ data });
})
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
}
})
await wrapper.vm.forwardButtonAction();
await wrapper.setData({
serviceZipCode: "12345"
})
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode);
expect(store.getters.vehicle.registration.zipCode).toEqual("43215");
expect(store.getters.order.serviceLocation.zipCode).toEqual("12345");
});
});
});
describe.skip("initialization", () => {
test("Page header is initialized with api data", async (done) => {
//Arrange
const pageHeaderWidgetHeaderText = "Select Damage";
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText,
});
//Act
addressLookup.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "address-lookup" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
apiPromise.finally(() => {
expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith(
pageHeaderWidgetHeaderText
);
done();
});
});
test("Customer Questions component is initialized with api data", async (done) => {
//Arrange
const StreetAddressQuestionWidget = { QuestionText: "test" };
const CityQuestionWidget = { QuestionText: "test" };
const StateQuestionWidget = { QuestionText: "test" };
const ZipQuestionWidget = { QuestionText: "test" };
const FirstNameQuestionWidget = { QuestionText: "test" };
const LastNameQuestionWidget = { QuestionText: "test" };
const EmailAddressQuestionWidget = { QuestionText: "test" };
const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" };
const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" };
const widgets = [
StreetAddressQuestionWidget,
CityQuestionWidget,
StateQuestionWidget,
ZipQuestionWidget,
AlertVerificationWarningWidget,
AlertNoMatchWarningWidget,
FirstNameQuestionWidget,
LastNameQuestionWidget,
EmailAddressQuestionWidget,
];
const { wrapper, apiPromise } = setupMocks({
cmsContent: widgets,
});
//Act
addressLookup.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "address-lookup" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
apiPromise.finally(() => {
expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith(
widgets
);
done();
});
});
});
});
function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) {
store.commit(storeMutations.RESET_STATE);
console.log(isZipServiceable)
const wrapper = shallowMount(addressLookup, getMountOptions({
...mountOptions,
actionList: [
{
actionName: storeActions.VALIDATE_ZIP,
data: {
isServiceable: isZipServiceable
}
},
{
actionName: storeActions.LOOKUP_VIN_BY_ADDRESS,
data: lookupVinbyAddressResponse ? lookupVinbyAddressResponse : {
isStatePermissible: true,
vinVehicles: [{
vin: "TEST_VIN",
vehicle: {
carId: "CARID"
}
}]
}
}
],
router: {
navigate: jest.fn(),
navigateAfterSave: jest.fn()
},
}));
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
// jest.mock("@/store", () => ({
// commit: jest.fn(),
// dispatch: jest.fn(),
// getters: {
// vehicle: {
// carId: "CARID"
// }
// },
// }));
return { wrapper };
}
// function setupMocks({
// pageHeaderWidgetHeaderText = {},
// mountOptionsMockData = {
// router: {
// navigate: jest.fn(),
// },
// store: {
// getters: {
// vehicle: {},
// },
// },
// },
// }) {
// //Mock api responses
// baseMixin.methods.dispatchStoreAction = jest.fn();
// const apiResponses = {
// cmsContent: {
// FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
// VehicleBannerWidget: {
// GenericVehicleImage:
// "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
// },
// FunnelHeaderWidget: {
// LogoImage:
// "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
// },
// StreetAddressQuestionWidget: {
// QuestionText:
// "test"
// },
// CityQuestionWidget: {
// QuestionText:
// "test"
// },
// StateQuestionWidget: {
// QuestionText:
// "test"
// },
// ZipQuestionWidget: {
// QuestionText:
// "test"
// },
// FirstNameQuestionWidget: {
// QuestionText:
// "test"
// },
// LastNameQuestionWidget: {
// QuestionText:
// "test"
// },
// EmailAddressQuestionWidget: {
// QuestionText:
// "test"
// },
// AlertVerificationWarningWidget: {
// HeaderText:
// "test",
// BodyText:
// "test",
// },
// AlertNoMatchWarningWidget: {
// HeaderText:
// "test",
// BodyText:
// "test",
// },
// },
// };
// const apiPromise = Promise.resolve(apiResponses);
// settleAllPromises.mockImplementation(() => apiPromise);
// fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
// //Mock damage initialize methods
// funnelHeader.methods = {
// initializeComponent: jest.fn(),
// };
// vehicleBanner.methods = {
// initializeComponent: jest.fn(),
// };
// funnelSubHeader.methods = {
// initializeComponent: jest.fn(),
// };
// funnelFooter.methods = {
// initializeComponent: jest.fn(),
// };
// customerQuestions.methods = {
// initializeComponent: jest.fn(),
// };
// addressQuestions.methods = {
// initializeComponent: jest.fn(),
// setupAddressLookup: jest.fn(),
// };
// const mountOptions = getMountOptions(mountOptionsMockData);
// mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
// mountOptions.global.directives = {
// maska: maska
// };
// const wrapper = mount(addressLookup, mountOptions);
// const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" });
// funnelHeaderWrapper.vm.initializeComponent =
// funnelHeader.methods.initializeComponent;
// const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" });
// vehicleBannerWrapper.vm.initializeComponent =
// vehicleBanner.methods.initializeComponent;
// const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" });
// funnelSubHeaderWrapper.vm.initializeComponent =
// funnelSubHeader.methods.initializeComponent;
// const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" });
// funnelFooterWrapper.vm.initializeComponent =
// funnelFooter.methods.initializeComponent;
// const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" });
// customerQuestionsWrapper.vm.initializeComponent =
// customerQuestions.methods.initializeComponent;
// const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" });
// addressQuestionsWrapper.vm.initializeComponent =
// addressQuestions.methods.initializeComponent;
// addressQuestionsWrapper.vm.setupAddressLookup =
// addressQuestions.methods.setupAddressLookup;
// return { wrapper, apiPromise };
// }

View file

@ -1,244 +0,0 @@
// Components
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
import funnelHeader from "@/common-components/funnel-header/funnel-header";
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
// Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js";
import baseMixin from "@/mixins/base-mixin";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { mount, flushPromises } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { maska } from 'maska';
import { nextTick } from "vue";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import store from "@/store";
import { validate } from "vee-validate";
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
describe("address-lookup.vue", () => {
test("Page header is initialized with api data", async (done) => {
//Arrange
const pageHeaderWidgetHeaderText = "Select Damage";
const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText,
});
//Act
addressLookup.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "address-lookup" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
apiPromise.finally(() => {
expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith(
pageHeaderWidgetHeaderText
);
done();
});
});
test("Customer Questions component is initialized with api data", async (done) => {
//Arrange
const StreetAddressQuestionWidget = { QuestionText: "test" };
const CityQuestionWidget = { QuestionText: "test" };
const StateQuestionWidget = { QuestionText: "test" };
const ZipQuestionWidget = { QuestionText: "test" };
const FirstNameQuestionWidget = { QuestionText: "test" };
const LastNameQuestionWidget = { QuestionText: "test" };
const EmailAddressQuestionWidget = { QuestionText: "test" };
const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" };
const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" };
const widgets = [
StreetAddressQuestionWidget,
CityQuestionWidget,
StateQuestionWidget,
ZipQuestionWidget,
AlertVerificationWarningWidget,
AlertNoMatchWarningWidget,
FirstNameQuestionWidget,
LastNameQuestionWidget,
EmailAddressQuestionWidget,
];
const { wrapper, apiPromise } = setupMocks({
cmsContent: widgets,
});
//Act
addressLookup.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "address-lookup" } },
undefined,
(c) => c(wrapper.vm)
);
//Assert
apiPromise.finally(() => {
expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith(
widgets
);
done();
});
});
});
function setupMocks({
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {
router: {
navigate: jest.fn(),
},
store: {
getters: {
vehicle: {},
},
},
},
}) {
//Mock api responses
baseMixin.methods.dispatchStoreAction = jest.fn();
const apiResponses = {
cmsContent: {
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleBannerWidget: {
GenericVehicleImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
},
FunnelHeaderWidget: {
LogoImage:
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
},
StreetAddressQuestionWidget: {
QuestionText:
"test"
},
CityQuestionWidget: {
QuestionText:
"test"
},
StateQuestionWidget: {
QuestionText:
"test"
},
ZipQuestionWidget: {
QuestionText:
"test"
},
FirstNameQuestionWidget: {
QuestionText:
"test"
},
LastNameQuestionWidget: {
QuestionText:
"test"
},
EmailAddressQuestionWidget: {
QuestionText:
"test"
},
AlertVerificationWarningWidget: {
HeaderText:
"test",
BodyText:
"test",
},
AlertNoMatchWarningWidget: {
HeaderText:
"test",
BodyText:
"test",
},
},
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock damage initialize methods
funnelHeader.methods = {
initializeComponent: jest.fn(),
};
vehicleBanner.methods = {
initializeComponent: jest.fn(),
};
funnelSubHeader.methods = {
initializeComponent: jest.fn(),
};
funnelFooter.methods = {
initializeComponent: jest.fn(),
};
customerQuestions.methods = {
initializeComponent: jest.fn(),
};
addressQuestions.methods = {
initializeComponent: jest.fn(),
setupAddressLookup: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData);
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
mountOptions.global.directives = {
maska: maska
};
const wrapper = mount(addressLookup, mountOptions);
const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" });
funnelHeaderWrapper.vm.initializeComponent =
funnelHeader.methods.initializeComponent;
const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" });
vehicleBannerWrapper.vm.initializeComponent =
vehicleBanner.methods.initializeComponent;
const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" });
funnelSubHeaderWrapper.vm.initializeComponent =
funnelSubHeader.methods.initializeComponent;
const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" });
funnelFooterWrapper.vm.initializeComponent =
funnelFooter.methods.initializeComponent;
const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" });
customerQuestionsWrapper.vm.initializeComponent =
customerQuestions.methods.initializeComponent;
const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" });
addressQuestionsWrapper.vm.initializeComponent =
addressQuestions.methods.initializeComponent;
addressQuestionsWrapper.vm.setupAddressLookup =
addressQuestions.methods.setupAddressLookup;
return { wrapper, apiPromise };
}

View file

@ -1,67 +1,101 @@
<template> <template>
<Form <Form
@submit="onSubmit" @submit="onSubmit"
@invalid-submit="onInvalidSubmit" @invalid-submit="onInvalidSubmit"
ref="theForm" ref="theForm"
v-slot="{ meta }" v-slot="{ meta }"
autocomplete="off" > autocomplete="off"
<div class="page-container-grouped-styles"> >
<loadingModal ref="loadingModal"/> <div class="page-container-grouped-styles">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> <loadingModal ref="loadingModal" />
<vehicleBanner cmsWidgetName="VehicleBannerWidget" ref="vehicleBanner" :displayGenericVehicleImage=false /> <funnelHeader
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" /> cmsWidgetName="FunnelHeaderWidget"
<div class="fade-on-route-transition sub-container make-tall"> ref="funnelHeader"
<customerQuestions ref="customerQuestions" v-model="customerQuestions" /> />
<alert ref="alertVinNotFound" v-if="displayVinNotFoundAlert" <vehicleBanner
class="mb-4" cmsWidgetName="VehicleBannerWidget"
cmsWidgetName="AlertVinNotFoundWidget" ref="vehicleBanner"
alertClass="alert-danger" :displayGenericVehicleImage="false"
v-bind:isDismissible="false" />
/> <funnelSubHeader
<alert ref="alertMatchedDifferentVehicle" v-if="displayMatchedDifferentVehicleAlert" cmsWidgetName="FunnelSubHeaderWidget"
class="mb-4" ref="funnelSubHeader"
:manualHeadline="AlertMatchedDifferentVehicleHeader" />
:manualCopy="AlertMatchedDifferentVehicleBody" <div class="fade-on-route-transition sub-container make-tall">
alertClass="alert-warning" <customerQuestions
v-bind:isDismissible="false" ref="customerQuestions"
/> v-model="customerQuestions"
<alert ref="alertNonServiceableZip" v-if="displayNonServiceableZipAlert" />
class="mb-4" <alert
alertClass="alert-danger" ref="alertVinNotFound"
:manualHeadline="AlertNonServiceableZipHeader" v-if="displayVinNotFoundAlert"
:manualCopy="AlertNonServiceableZipBody" class="mb-4"
v-bind:isDismissible="false" cmsWidgetName="AlertVinNotFoundWidget"
/> alertClass="alert-danger"
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-if="displayVinLookupByHomeAddressNotAllowedAlert" v-bind:isDismissible="false"
class="mb-4" />
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget" <alert
alertClass="alert-danger" ref="alertMatchedDifferentVehicle"
v-bind:isDismissible="false" v-if="displayMatchedDifferentVehicleAlert"
/> class="mb-4"
<transition name="fade" mode="out-in"> :manualHeadline="AlertMatchedDifferentVehicleHeader"
<div class="service-zip-field" v-if="showServiceZipField" aria-live="polite"> :manualCopy="AlertMatchedDifferentVehicleBody"
<div class="row mb-4"> alertClass="alert-warning"
<div class="col"> v-bind:isDismissible="false"
<textboxQuestion cmsWidgetName="ServiceZipQuestionWidget" v-model="serviceZipCode" ref="serviceZip" inputId="7add1b26df344f2caf1678de5797803f" aria-haspopup="" mask="#####" disableAutoFill validationRules="service-zip-required|service-zip-format" /> />
</div> <alert
</div> ref="alertNonServiceableZip"
</div> v-if="displayNonServiceableZipAlert"
</transition> class="mb-4"
<funnel-footer alertClass="alert-danger"
cmsWidgetName="FunnelFooterWidget" :manualHeadline="AlertNonServiceableZipHeader"
ref="funnelFooter" :manualCopy="AlertNonServiceableZipBody"
:isDisabled="!meta.valid" v-bind:isDismissible="false"
@ForwardClicked="forwardButtonAction" />
@back-clicked="backButtonAction" <alert
:isForwardActionDisabled="!meta.valid" ref="alertVinLookupsByHomeAddressNotAllowed"
/> v-if="displayVinLookupByHomeAddressNotAllowedAlert"
</div> class="mb-4"
</div> cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
</Form> alertClass="alert-danger"
v-bind:isDismissible="false"
/>
<transition name="fade" mode="out-in">
<div
class="service-zip-field"
v-if="showServiceZipField"
aria-live="polite"
>
<div class="row mb-4">
<div class="col">
<textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode"
ref="serviceZip"
inputId="7add1b26df344f2caf1678de5797803f"
aria-haspopup=""
mask="#####"
disableAutoFill
validationRules="service-zip-required|service-zip-format"
/>
</div>
</div>
</div>
</transition>
<funnel-footer
cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter"
:isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid"
/>
</div>
</div>
</Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/common-components/funnel-header/funnel-header"; import funnelHeader from "@/common-components/funnel-header/funnel-header";
import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
@ -70,7 +104,7 @@ import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-he
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/common-components/textbox-question/textbox-question"; import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import loadingModal from '@/common-components/loading-modal/loading-modal.vue'; import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate"; import { Form, defineRule } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules"; import { required, regex } from "@/helpers/validation-rules";
@ -84,353 +118,467 @@ import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import baseMixin from "@/mixins/base-mixin"; import baseMixin from "@/mixins/base-mixin";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper"; import {
getDamageString,
isGlassAvailableForCarId,
} from "@/helpers/damage-helper";
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule(
defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); "service-zip-required",
required(errorMessages.SERVICE_ZIP_REQUIRED)
);
defineRule(
"service-zip-format",
regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)
);
export default { export default {
name: "address-lookup", name: "address-lookup",
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
// Settle promises and get results // Settle promises and get results
const promiseResultMap = [ const promiseResultMap = [
{ {
resultKey: "cmsContent", resultKey: "cmsContent",
promise: cmsContentPromise, promise: cmsContentPromise,
}, },
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page. // Call the "next" function to complete the transition to this page.
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
}); });
}, },
data() { data() {
return { return {
customerQuestions: { customerQuestions: {
addressQuestions: { addressQuestions: {
streetAddress: this.getRegistrationAddressFromStore(), streetAddress: this.getRegistrationAddressFromStore(),
city: this.getRegistrationCityFromStore(), city: this.getRegistrationCityFromStore(),
state: this.getRegistrationStateFromStore(), state: this.getRegistrationStateFromStore(),
zipCode: this.getRegistrationZipFromStore(), zipCode: this.getRegistrationZipFromStore(),
}, },
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,
} };
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
return store.getters.vehicle.carId !== null; return store.getters.vehicle.carId !== null;
}, },
resetDependentState() { resetDependentState() {
store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, null); store.commit(
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE,
}, null
backButtonAction() { );
// route to move backwards store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
this.$router.navigate( },
this.navigationScenarios.CLICKED_BACK, backButtonAction() {
this.$route // route to move backwards
); this.$router.navigate(
}, this.navigationScenarios.CLICKED_BACK,
attachCustomEvents() { this.$route
this.prependActionToMethod(this, this.forwardButtonAction, () => { );
this.pushEventToGA( },
this.$route.query[this.queryStrings.FMG_PAGE], attachCustomEvents() {
this.GaActions.SUBMITTED, this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.GaLabels.ADDRESS_LOOKUP, this.pushEventToGA(
true this.$route.query[this.queryStrings.FMG_PAGE],
); this.GaActions.SUBMITTED,
}); this.GaLabels.ADDRESS_LOOKUP,
}, true
getRegistrationAddressFromStore() { );
return store.getters.vehicle.registration.address; });
}, },
getRegistrationCityFromStore() { getRegistrationAddressFromStore() {
return store.getters.vehicle.registration.city; return store.getters.vehicle.registration.address;
}, },
getRegistrationStateFromStore() { getRegistrationCityFromStore() {
return store.getters.vehicle.registration.state; return store.getters.vehicle.registration.city;
}, },
getRegistrationZipFromStore() { getRegistrationStateFromStore() {
return store.getters.vehicle.registration.zipCode; return store.getters.vehicle.registration.state;
}, },
getRegistrationFirstNameFromStore() { getRegistrationZipFromStore() {
return store.getters.vehicle.registration.firstName; return store.getters.vehicle.registration.zipCode;
}, },
getRegistrationLastNameFromStore() { getRegistrationFirstNameFromStore() {
return store.getters.vehicle.registration.lastName; return store.getters.vehicle.registration.firstName;
}, },
getEmailFromStore() { getRegistrationLastNameFromStore() {
return store.getters.order.customer.emailAddress; return store.getters.vehicle.registration.lastName;
}, },
getServiceZipFromStore() { getEmailFromStore() {
return store.getters.order.serviceLocation.zipCode; return store.getters.order.customer.emailAddress;
}, },
async forwardButtonAction() { getServiceZipFromStore() {
this.resetWarningsAndErrors(); return store.getters.order.serviceLocation.zipCode;
},
async forwardButtonAction() {
this.resetWarningsAndErrors();
// 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
); );
// Verify if the service zip code or registration zip code provided is serviceable // Verify if the service zip code or registration zip code provided is serviceable
const serviceZipValidationPromise = this.serviceZipCode ? this.validateZip(this.serviceZipCode) : this.validateZip(this.customerQuestions.addressQuestions.zipCode); const serviceZipValidationPromise = this.serviceZipCode
? this.validateZip(this.serviceZipCode)
: this.validateZip(
this.customerQuestions.addressQuestions.zipCode
);
const vinLookupResponse = await vinLookupPromise; const vinLookupResponse = await vinLookupPromise;
const serviceZipValidationResponse = await serviceZipValidationPromise; const serviceZipValidationResponse =
await serviceZipValidationPromise;
if (!vinLookupResponse.data.isStatePermissible) {
// State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
this.$refs.funnelFooter.removeLoader();
return;
}
// if the neither the registration zip code or service zip code are not serviceable
this.isZipServicable = serviceZipValidationResponse.data.isServiceable;
if (!this.isZipServicable) {
this.displayNonServiceableZipAlert = true;
this.showServiceZipField = true;
this.$refs.funnelFooter.removeLoader();
} else if (!this.serviceZipCode) {
// 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
this.serviceZipCode = this.customerQuestions.addressQuestions.zipCode;
}
const carEntered = store.getters.vehicle; if (!vinLookupResponse.data.isStatePermissible) {
const carsFound = vinLookupResponse.data.vinVehicles; // State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
this.$refs.funnelFooter.removeLoader();
return;
}
if (carsFound.length == 0) { // if the neither the registration zip code or service zip code are not serviceable
// No VINs found this.isZipServicable =
this.displayVinNotFoundAlert = true; serviceZipValidationResponse.data.isServiceable;
this.$refs.funnelFooter.removeLoader(); if (!this.isZipServicable) {
return; this.displayNonServiceableZipAlert = true;
} else if (carsFound.length == 1) { this.showServiceZipField = true;
const carFound = carsFound[0].vehicle; this.$refs.funnelFooter.removeLoader();
this.isCarIdDifferent = carFound.carId !== carEntered.carId; } else if (!this.serviceZipCode) {
// 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
this.serviceZipCode =
this.customerQuestions.addressQuestions.zipCode;
}
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) { const carEntered = store.getters.vehicle;
// Display Alert const carsFound = vinLookupResponse.data.vinVehicles;
this.previouslyEnteredCarId = carFound.carId;
this.customAlertData.vehicleInfo = carFound;
this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(carFound.carId); if (carsFound.length == 0) {
// No VINs found
this.displayVinNotFoundAlert = true;
this.$refs.funnelFooter.removeLoader();
return;
} else if (carsFound.length == 1) {
const carFound = carsFound[0].vehicle;
this.isCarIdDifferent = carFound.carId !== carEntered.carId;
// Update button "Continue with..." if (
this.$refs.funnelFooter.updateButtonText(`Continue with ${carFound.year} ${carFound.make} ${carFound.model}`); this.isCarIdDifferent &&
this.$refs.funnelFooter.removeLoader(); carFound.carId !== this.previouslyEnteredCarId
) {
return; // Display Alert
} this.previouslyEnteredCarId = carFound.carId;
this.customAlertData.vehicleInfo = carFound;
if (!this.isZipServicable) { this.displayMatchedDifferentVehicleAlert = true;
return;
}
// update data if the zip or service zip is servicable this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(carFound.carId);
this.updateVehicleInfo(carsFound[0].vin, carFound);
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
} else if (carsFound.length > 1) {
if (!this.isZipServicable) {
return;
}
// if multiple cars were found // Update button "Continue with..."
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId); this.$refs.funnelFooter.updateButtonText(
if (matchingCars.length === 1) { `Continue with ${carFound.year} ${carFound.make} ${carFound.model}`
// and one and only one of them matches the carId entered, save the vehicle info );
// so we can go to the Heritage Funnel directly this.$refs.funnelFooter.removeLoader();
const matchingCar = matchingCars[0];
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
}
// update data if the zip or service zip is servicable
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
}
this.navigateForward(carEntered, carsFound); return;
}, }
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayNonServiceableZipAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
},
navigateForward(carEntered, carsFound) {
this.updateServiceLocationIfNecessary();
if (carsFound.length == 1) {
// if a different vehicle is found than the one entered and the selected glass
// is not available for that vehicle
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigateAfterSave(
// then navigate back to "vehicle-damage", and display vehicle changed alert
// on that page
this.navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS,
this.$route, {}, {
displayVehicleChangeAlert: true
}, {}
);
} else {
// otherwise
this.$refs.loadingModal.showModal();
navigateAfterSaveToHeritageFunnel(this.$route);
}
} else if (carsFound.length > 1) {
// if multiple cars were found
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
if (matchingCars.length === 1) {
this.$refs.loadingModal.showModal();
// and one and only of them matches the car id entered if (!this.isZipServicable) {
const matchingCar = matchingCars[0]; return;
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle); }
navigateAfterSaveToHeritageFunnel(this.$route);
} else {
// 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);
}
}
}, // update data if the zip or service zip is servicable
validateZip(zip) { this.updateVehicleInfo(carsFound[0].vin, carFound);
return baseMixin.methods.dispatchStoreAction( this.updateCustomerInfo(
storeActions.VALIDATE_ZIP, serviceZipValidationResponse.data.state
{ zip }); );
}, } else if (carsFound.length > 1) {
lookupVin(lastName, streetAddress, zip, state) { if (!this.isZipServicable) {
return baseMixin.methods.dispatchStoreAction( return;
storeActions.LOOKUP_VIN_BY_ADDRESS, }
{
licenseLastName: lastName,
licenseStreetAddress: streetAddress,
licenseZip: zip,
licenseState: state
}, false
);
},
updateVehicleInfo(vin, vehicleInfo) {
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year);
store.commit(storeMutations.UPDATE_MAKE, vehicleInfo.make);
store.commit(storeMutations.UPDATE_MODEL, vehicleInfo.model);
store.commit(storeMutations.UPDATE_STYLE, vehicleInfo.style);
store.commit(storeMutations.UPDATE_CAR_ID, vehicleInfo.carId);
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, vehicleInfo.category);
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_COLOR, vehicleInfo.imageColor);
},
updateCustomerInfo(serviceState) {
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_STATE, this.customerQuestions.addressQuestions.state);
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_LAST_NAME, this.customerQuestions.lastName);
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZipCode);
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, serviceState);
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
},
updateServiceLocationIfNecessary() {
const serviceLocation = store.getters.order.serviceLocation;
if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) { // if multiple cars were found
baseMixin.methods.dispatchStoreAction( let matchingCars = carsFound.filter(
storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION (car) => car.vehicle.carId === carEntered.carId
); );
} if (matchingCars.length === 1) {
} // and one and only one of them matches the carId entered, save the vehicle info
}, // so we can go to the Heritage Funnel directly
mounted() { const matchingCar = matchingCars[0];
this.attachCustomEvents(); this.updateVehicleInfo(
}, matchingCar.vin,
computed: { matchingCar.vehicle
AlertNonServiceableZipHeader(){ );
const zipCode = this.serviceZipCode ? this.serviceZipCode : this.customerQuestions.addressQuestions.zipCode; }
const text = this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", zipCode);
return text;
},
AlertNonServiceableZipBody(){
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
},
AlertMatchedDifferentVehicleHeader(){
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "HeadlineText").replaceAll("{custom:glassText}", getDamageString());
return text;
},
AlertMatchedDifferentVehicleBody(){
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`; // update data if the zip or service zip is servicable
const vinYmmExpected = `${store.getters.vehicle.year} ${store.getters.vehicle.make} ${store.getters.vehicle.model}`; this.updateCustomerInfo(
serviceZipValidationResponse.data.state
);
}
const content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText") this.navigateForward(carEntered, carsFound);
.replaceAll("{custom:glassText}", getDamageString()) },
.replaceAll("{custom:vinYmmFound}", vinYmmFound) resetWarningsAndErrors() {
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected); this.displayVinNotFoundAlert = false;
this.displayNonServiceableZipAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
},
navigateForward(carEntered, carsFound) {
this.updateServiceLocationIfNecessary();
return content; if (carsFound.length == 1) {
}, // if a different vehicle is found than the one entered and the selected glass
}, // is not available for that vehicle
watch: { if (
customerQuestions: { this.isCarIdDifferent &&
handler(newValue) { !this.isSelectedGlassAvailableForVehicle
// 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.$router.navigateAfterSave(
this.showServiceZipField = false; // then navigate back to "vehicle-damage", and display vehicle changed alert
this.resetWarningsAndErrors(); // on that page
}, this.navigationScenarios
deep: true .CONTINUING_WITH_DIFFERENT_GLASS,
}, this.$route,
serviceZipCode: { {},
handler(newValue) { {
// if they modify the service zip code, then hide the error message displayVehicleChangeAlert: true,
this.displayNonServiceableZipAlert = false; },
}, {}
}, );
showServiceZipField: { } else {
handler(newValue) { // otherwise
// if the Service Zip Code field is ever hidden, clear out it's value this.$refs.loadingModal.showModal();
if (!newValue) { navigateAfterSaveToHeritageFunnel(this.$route);
this.serviceZipCode = null; }
} } else if (carsFound.length > 1) {
}, // if multiple cars were found
} let matchingCars = carsFound.filter(
}, (car) => car.vehicle.carId === carEntered.carId
components: { );
funnelHeader, if (matchingCars.length === 1) {
funnelFooter, this.$refs.loadingModal.showModal();
vehicleBanner,
funnelSubHeader, // and one and only of them matches the car id entered
customerQuestions, const matchingCar = matchingCars[0];
textboxQuestion, this.updateVehicleInfo(
alert, matchingCar.vin,
loadingModal, matchingCar.vehicle
Form );
}, navigateAfterSaveToHeritageFunnel(this.$route);
} else {
// 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
);
}
}
},
validateZip(zip) {
return baseMixin.methods.dispatchStoreAction(
storeActions.VALIDATE_ZIP,
{ zip }
);
},
lookupVin(lastName, streetAddress, zip, state) {
return baseMixin.methods.dispatchStoreAction(
storeActions.LOOKUP_VIN_BY_ADDRESS,
{
licenseLastName: lastName,
licenseStreetAddress: streetAddress,
licenseZip: zip,
licenseState: state,
},
false
);
},
updateVehicleInfo(vin, vehicleInfo) {
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year);
store.commit(storeMutations.UPDATE_MAKE, vehicleInfo.make);
store.commit(storeMutations.UPDATE_MODEL, vehicleInfo.model);
store.commit(storeMutations.UPDATE_STYLE, vehicleInfo.style);
store.commit(storeMutations.UPDATE_CAR_ID, vehicleInfo.carId);
store.commit(
storeMutations.UPDATE_VEHICLE_CATEGORY,
vehicleInfo.category
);
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_COLOR,
vehicleInfo.imageColor
);
},
updateCustomerInfo(serviceState) {
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_STATE,
this.customerQuestions.addressQuestions.state
);
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_LAST_NAME,
this.customerQuestions.lastName
);
store.commit(
storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE,
this.serviceZipCode
);
store.commit(
storeMutations.UPDATE_SERVICE_LOCATION_STATE,
serviceState
);
store.commit(
storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS,
this.customerQuestions.emailAddress
);
},
updateServiceLocationIfNecessary() {
const serviceLocation = store.getters.order.serviceLocation;
if (
!serviceLocation.address &&
serviceLocation.zipCode &&
serviceLocation.zipCode ==
store.getters.vehicle.registration.zipCode
) {
baseMixin.methods.dispatchStoreAction(
storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION
);
}
},
},
mounted() {
this.attachCustomEvents();
},
computed: {
AlertNonServiceableZipHeader() {
const zipCode = this.serviceZipCode
? this.serviceZipCode
: this.customerQuestions.addressQuestions.zipCode;
const text = this.getCmsContent(
"AlertNonServiceableZipWidget",
"HeadlineText"
).replaceAll("{custom:serviceZip}", zipCode);
return text;
},
AlertNonServiceableZipBody() {
return this.getCmsContent(
"AlertNonServiceableZipWidget",
"BodyText"
);
},
AlertMatchedDifferentVehicleHeader() {
const text = this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"HeadlineText"
).replaceAll("{custom:glassText}", getDamageString());
return text;
},
AlertMatchedDifferentVehicleBody() {
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${store.getters.vehicle.year} ${store.getters.vehicle.make} ${store.getters.vehicle.model}`;
const content = this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"BodyText"
)
.replaceAll("{custom:glassText}", getDamageString())
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
return content;
},
},
watch: {
customerQuestions: {
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
this.$refs.funnelFooter.updateButtonText(
this.getCmsContent(
"FunnelFooterWidget",
"ForwardButtonText"
)
);
this.showServiceZipField = false;
this.resetWarningsAndErrors();
},
deep: true,
},
serviceZipCode: {
handler(newValue) {
// if they modify the service zip code, then hide the error message
this.displayNonServiceableZipAlert = false;
},
},
showServiceZipField: {
handler(newValue) {
// if the Service Zip Code field is ever hidden, clear out it's value
if (!newValue) {
this.serviceZipCode = null;
}
},
},
},
components: {
funnelHeader,
funnelFooter,
vehicleBanner,
funnelSubHeader,
customerQuestions,
textboxQuestion,
alert,
loadingModal,
Form,
},
}; };
</script> </script>