390 lines
14 KiB
Vue
390 lines
14 KiB
Vue
<template>
|
|
<Form
|
|
@submit="onSubmit"
|
|
@invalid-submit="onInvalidSubmit"
|
|
ref="theForm"
|
|
v-slot="{ meta }"
|
|
autocomplete="off" >
|
|
<div class="page-container-grouped-styles">
|
|
<loadingModal ref="loadingModal"/>
|
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
|
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
|
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
|
|
<div class="fade-on-route-transition sub-container make-tall">
|
|
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
|
|
<alert ref="alertVinNotFound" v-show="displayVinNotFoundAlert"
|
|
class="my-3"
|
|
cmsWidgetName="AlertVinNotFoundWidget"
|
|
alertClass="alert-danger"
|
|
v-bind:isDismissible="false"
|
|
/>
|
|
<alert ref="alertMatchedDifferentVehicle" v-show="displayMatchedDifferentVehicleAlert"
|
|
class="my-3"
|
|
:manualHeadline="AlertMatchedDifferentVehicleHeader"
|
|
:manualCopy="AlertMatchedDifferentVehicleBody"
|
|
alertClass="alert-warning"
|
|
v-bind:isDismissible="false"
|
|
/>
|
|
<alert ref="alertNonServiceableZip" v-show="displayNonServiceableZipAlert"
|
|
class="my-3"
|
|
alertClass="alert-danger"
|
|
:manualHeadline="AlertNonServiceableZipHeader"
|
|
:manualCopy="AlertNonServiceableZipBody"
|
|
v-bind:isDismissible="false"
|
|
/>
|
|
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-show="displayVinLookupByHomeAddressNotAllowedAlert"
|
|
class="my-3"
|
|
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
|
|
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 my-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"
|
|
:isForwardActionDisabled="!meta.valid"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
// Components
|
|
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 alert from "@/ux-components/alert/alert";
|
|
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
|
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
|
|
|
import { Form } from "vee-validate";
|
|
import { defineRule } from "vee-validate";
|
|
import { required } from "@/helpers/validation-rules";
|
|
import { regex } from "@/helpers/validation-rules";
|
|
import { errorMessages } from "@/constants/error-messages";
|
|
|
|
// Supporting files
|
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
import store from "@/store";
|
|
import { storeActions } from "@/constants/store-actions";
|
|
import { storeMutations } from "@/constants/store-mutations";
|
|
import baseMixin from "@/mixins/base-mixin";
|
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
|
|
|
defineRule("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 {
|
|
name: "address-lookup",
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
|
|
|
// Settle promises and get results
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: "cmsContent",
|
|
promise: cmsContentPromise,
|
|
},
|
|
];
|
|
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
|
|
// Call the "next" function to complete the transition to this page.
|
|
next((vm) => {
|
|
vm.setCmsContent(resultMap.cmsContent);
|
|
});
|
|
},
|
|
data() {
|
|
return {
|
|
customerQuestions: {
|
|
addressQuestions: {
|
|
streetAddress: this.getRegistrationAddressFromStore(),
|
|
city: this.getRegistrationCityFromStore(),
|
|
state: this.getRegistrationStateFromStore(),
|
|
zipCode: this.getRegistrationZipFromStore(),
|
|
},
|
|
firstName: this.getRegistrationFirstNameFromStore(),
|
|
lastName: this.getRegistrationLastNameFromStore(),
|
|
emailAddress: this.getEmailFromStore(),
|
|
},
|
|
serviceZipCode: this.getServiceZipFromStore(),
|
|
displayNonServiceableZipAlert: false,
|
|
displayVinNotFoundAlert: false,
|
|
displayMatchedDifferentVehicleAlert: false,
|
|
displayVinLookupByHomeAddressNotAllowedAlert: false,
|
|
previouslyEnteredCarId: "",
|
|
isSelectedGlassAvailableForVehicle: false,
|
|
customAlertData: {},
|
|
showServiceZipField: this.getServiceZipFromStore(),
|
|
isZipServicable: false,
|
|
}
|
|
},
|
|
methods: {
|
|
arePagePrerequisitesValid() {
|
|
return store.getters.vehicle.carId !== null;
|
|
},
|
|
resetDependentState() {
|
|
store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, null);
|
|
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
|
},
|
|
backButtonAction() {
|
|
// route to move backwards
|
|
this.$router.navigate(
|
|
this.navigationScenarios.CLICKED_BACK,
|
|
this.$route
|
|
);
|
|
},
|
|
getRegistrationAddressFromStore() {
|
|
return store.getters.vehicle.registration.address;
|
|
},
|
|
getRegistrationCityFromStore() {
|
|
return store.getters.vehicle.registration.city;
|
|
},
|
|
getRegistrationStateFromStore() {
|
|
return store.getters.vehicle.registration.state;
|
|
},
|
|
getRegistrationZipFromStore() {
|
|
return store.getters.vehicle.registration.zipCode;
|
|
},
|
|
getRegistrationFirstNameFromStore() {
|
|
return store.getters.vehicle.registration.firstName;
|
|
},
|
|
getRegistrationLastNameFromStore() {
|
|
return store.getters.vehicle.registration.lastName;
|
|
},
|
|
getEmailFromStore() {
|
|
return store.getters.order.customer.emailAddress;
|
|
},
|
|
getServiceZipFromStore() {
|
|
return store.getters.order.serviceLocation.zipCode;
|
|
},
|
|
async forwardButtonAction() {
|
|
this.resetWarningsAndErrors();
|
|
|
|
// Lookup VIN(s) with the provided address
|
|
const vinLookup = this.lookupVin(
|
|
this.customerQuestions.lastName,
|
|
this.customerQuestions.addressQuestions.streetAddress,
|
|
this.customerQuestions.addressQuestions.zipCode,
|
|
this.customerQuestions.addressQuestions.state
|
|
);
|
|
|
|
const zipValidation = this.serviceZipCode ? this.validateZip(this.serviceZipCode) : this.validateZip(this.customerQuestions.addressQuestions.zipCode);
|
|
|
|
const vinLookupResponse = await vinLookup;
|
|
const zipValidationResponse = await zipValidation;
|
|
|
|
if (!vinLookupResponse.data.isStatePermissible) {
|
|
// State Restrictions forbid lookup by address
|
|
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
|
|
this.$refs.funnelFooter.removeLoader();
|
|
return;
|
|
}
|
|
|
|
// Validate if the original or service zip provided is serviceable
|
|
this.isZipServicable = zipValidationResponse.data.isServiceable;
|
|
if (!this.isZipServicable) {
|
|
this.displayNonServiceableZipAlert = true;
|
|
this.showServiceZipField = true;
|
|
this.$refs.funnelFooter.removeLoader();
|
|
}
|
|
|
|
const carEntered = store.getters.vehicle;
|
|
const carsFound = vinLookupResponse.data.vinVehicles;
|
|
|
|
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;
|
|
|
|
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
|
|
// Display Alert
|
|
this.previouslyEnteredCarId = carFound.carId;
|
|
this.customAlertData.vehicleInfo = carFound;
|
|
this.displayMatchedDifferentVehicleAlert = true;
|
|
|
|
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(carFound.carId);
|
|
|
|
// Update button "Continue with..."
|
|
this.$refs.funnelFooter.updateButtonText(`Continue with ${carFound.year} ${carFound.make} ${carFound.model}`);
|
|
this.$refs.funnelFooter.removeLoader();
|
|
|
|
return;
|
|
}
|
|
|
|
if (!this.isZipServicable) {
|
|
return;
|
|
}
|
|
|
|
// update data if the zip or service zip is servicable
|
|
this.updateVehicleInfo(carsFound[0].vin, carFound);
|
|
this.updateCustomerInfo();
|
|
|
|
} else if (carsFound.length > 1) {
|
|
if (!this.isZipServicable) {
|
|
return;
|
|
}
|
|
|
|
// update data if the zip or service zip is servicable
|
|
this.updateCustomerInfo();
|
|
}
|
|
|
|
this.navigateForward(carEntered, carsFound);
|
|
},
|
|
resetWarningsAndErrors() {
|
|
this.displayVinNotFoundAlert = false;
|
|
this.displayNonServiceableZipAlert = false;
|
|
this.displayMatchedDifferentVehicleAlert = false;
|
|
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
|
|
},
|
|
navigateForward(carEntered, carsFound) {
|
|
if (carsFound.length == 1) {
|
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
|
this.$router.navigateAfterSave(
|
|
this.navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS,
|
|
this.$route, {}, {
|
|
displayVehicleChangeAlert: true
|
|
}, {}
|
|
);
|
|
} else {
|
|
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
}
|
|
} else if (carsFound.length > 1) {
|
|
// if multiple cars were found
|
|
if (carsFound.find(car => car.carId === carEntered.carId)) {
|
|
// and one of them matches the car id entered
|
|
this.$refs.loadingModal.showModal();
|
|
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
} else {
|
|
// and there is no match, 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() {
|
|
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_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
|
|
},
|
|
|
|
},
|
|
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(){
|
|
let content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText");
|
|
content = content.replaceAll("{custom:glassText}", getDamageString());
|
|
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}`;
|
|
|
|
content = content.replaceAll("{custom:vinYmmFound}", vinYmmFound);
|
|
content = content.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>
|