vin-lookup: added 'Invalid Zip' alert' and refactored to make it more similar to address-lookup

This commit is contained in:
Leah Schumann 2022-07-12 08:55:36 -04:00
parent d7e2f1e0cb
commit e452928c77
3 changed files with 294 additions and 270 deletions

View file

@ -24,9 +24,8 @@
<alert ref="alertInvalidZip" <alert ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="mb-4" class="mb-4"
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
:manualHeadline="AlertInvalidZipHeader"
:manualCopy="AlertInvalidZipBody"
v-bind:isDismissible="false" v-bind:isDismissible="false"
/> />
<alert ref="alertNonServiceableZip" <alert ref="alertNonServiceableZip"
@ -70,20 +69,21 @@ 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";
import {errorMessages} from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
// Supporting files // Supporting files
import {fetchCmsContentForPage} from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import {settleAllPromises} from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import {storeActions} from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import {routerParams} from "@/router/router-constants/router-params"; import { routerParams } from "@/router/router-constants/router-params";
import {getDamageString,isGlassAvailableForCarId} from "@/helpers/damage-helper"; import { getDamageString, isGlassAvailableForCarId} from "@/helpers/damage-helper";
import store from "@/store"; import store from "@/store";
import vinPagesMixin from "@/mixins/vin-pages-mixin"; import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES - Note: Additional rules are defined in Customer Questions and Address Questions components
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
@ -126,8 +126,10 @@ export default {
displayMatchedDifferentVehicleAlert: false, displayMatchedDifferentVehicleAlert: false,
displayVinLookupByHomeAddressNotAllowedAlert: false, displayVinLookupByHomeAddressNotAllowedAlert: false,
previouslyEnteredCarId: "", previouslyEnteredCarId: "",
isCarIdDifferent: false,
isSelectedGlassAvailableForVehicle: false, isSelectedGlassAvailableForVehicle: false,
customAlertData: {}, customAlertData: {},
displayInvalidZipAlert: false,
showServiceZipField: this.getServiceZipFromStore(), showServiceZipField: this.getServiceZipFromStore(),
isZipServiceable: false, isZipServiceable: false,
} }
@ -241,6 +243,7 @@ export default {
// 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}`);
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
// update data if the zip or service zip is serviceable // update data if the zip or service zip is serviceable
@ -262,7 +265,7 @@ export default {
} }
// If the neither the registration zip code or service zip code are not serviceable // If the either the registration zip code or service zip code are not serviceable
this.isZipServiceable = resultMap.serviceZipValidationResponse.isServiceable; this.isZipServiceable = resultMap.serviceZipValidationResponse.isServiceable;
if (!this.isZipServiceable) { if (!this.isZipServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
@ -297,6 +300,7 @@ export default {
}, false); }, false);
return await this.navigateForward(carsFound); return await this.navigateForward(carsFound);
}, },
async navigateForward(carsFound) { async navigateForward(carsFound) {
// Match vehicles found to vehicles in state. // Match vehicles found to vehicles in state.
@ -304,7 +308,6 @@ export default {
// If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage" // If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
// display vehicle changed alert on that page. // display vehicle changed alert on that page.
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle && matchingCars.length === 1) { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle && matchingCars.length === 1) {
this.$router.navigate(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, {[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true}); this.$router.navigate(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, {[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true});
} else if (matchingCars.length === 1) { } else if (matchingCars.length === 1) {
@ -312,12 +315,14 @@ export default {
} else { } else {
this.$router.navigate(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound); this.$router.navigate(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
} }
}, },
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;
}, },
}, },
mounted() { mounted() {

View file

@ -46,37 +46,46 @@
/> />
</div> </div>
</div> </div>
<alert ref="alertInvalidZip" v-if="displayInvalidZipAlert" class="my-3" alertClass="alert-danger" :manualHeadline="AlertInvalidZipHeader" :manualCopy="AlertInvalidZipBody" v-bind:isDismissible="false" /> <alert
v-if="displayInvalidZipAlert"
class="my-3"
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false"
/>
<alert <alert
v-if="displayNonServiceableZipAlert"
class="my-3" class="my-3"
:manualHeadline="NoServiceZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="NoServiceZipBody" :manualCopy="AlertNonServiceableZipBody"
v-if="!isRegistrationZipServiceable && isVinValid && !isCarIdDifferent"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false"
/> />
<div class="row my-2"> <div class="row my-2">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
v-if="!isRegistrationZipServiceable" v-if="showServiceZipField"
cmsWidgetName="ServiceZip" cmsWidgetName="ServiceZip"
v-model="serviceZip" v-model="serviceZipCode"
inputId="serviceZip" inputId="serviceZipCode"
validationRules="zip-required|zip-format" validationRules="zip-required|zip-format"
/> />
</div> </div>
</div> </div>
<alert <alert
v-if="displayVinNotFoundAlert"
class="my-3" class="my-3"
cmsWidgetName="NoMatchAlertWidget" cmsWidgetName="NoMatchAlertWidget"
v-if="!isVinValid"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false"
/> />
<alert <alert
v-if="displayMatchedDifferentVehicleAlert"
class="my-3" class="my-3"
:manualHeadline="MatchedDifferentVehicleAlertHeader" :manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="MatchedDifferentVehicleAlertBody" :manualCopy="AlertMatchedDifferentVehicleBody"
v-if="isCarIdDifferent"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false"
/> />
<funnelFooter <funnelFooter
ref="funnelFooter" ref="funnelFooter"
@ -105,35 +114,20 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import { getDamageString,isGlassAvailableForCarId} from "@/helpers/damage-helper"; import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
import { routerParams } from "@/router/router-constants/router-params"; import { routerParams } from "@/router/router-constants/router-params";
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 vinPagesMixin from "@/mixins/vin-pages-mixin";
import store from "@/store"; import store from "@/store";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule( defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
"license-plate-required",
required(errorMessages.LICENSE_PLATE_REQUIRED)
);
defineRule("zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED));
defineRule( defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
"zip-format", defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT) defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
);
defineRule(
"email-address-required",
required(errorMessages.EMAIL_ADDRESS_REQUIRED)
);
defineRule(
"email-address-format",
regex(
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
export default { export default {
name: "license-plate-lookup", name: "license-plate-lookup",
@ -147,8 +141,8 @@ export default {
{ {
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) => {
@ -160,52 +154,33 @@ export default {
}, },
data() { data() {
return { return {
isRegistrationZipServiceable: true,
isVinValid: true,
isCarIdDifferent: false,
licensePlate: this.getLicensePlateFromStore(), licensePlate: this.getLicensePlateFromStore(),
registrationZip: this.getRegistrationZipFromStore(), registrationZip: this.getRegistrationZipFromStore(),
email: this.getEmailFromStore(), email: this.getEmailFromStore(),
serviceZip: this.getServiceZipFromStore(), serviceZipCode: this.getServiceZipFromStore(),
displayNonServiceableZipAlert: false,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
previouslyEnteredCarId: "", previouslyEnteredCarId: "",
isSelectedGlassAvailableForVehicle: false,
isCarIdDifferent: false,
customAlertData: {}, customAlertData: {},
isSelectedGlassAvailableForVehicle: true, displayInvalidZipAlert: false,
zipToDisplay: this.getRegistrationZipFromStore(), showServiceZipField: this.getServiceZipFromStore(),
displayInvalidZipAlert: false, isZipServiceable: false,
}; };
}, },
mounted() {
this.attachCustomEvents();
},
computed: {
MatchedDifferentVehicleAlertHeader() {
return this.getCmsContent("MatchedDifferentVehicleAlertWidget", "HeadlineText").replaceAll("{custom:damage}", getDamageString());
},
MatchedDifferentVehicleAlertBody() {
return this.getCmsContent("MatchedDifferentVehicleAlertWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year)
.replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make)
.replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model);
},
AlertInvalidZipHeader() {
return this.getCmsContent("AlertInvalidZipWidget","HeadlineText");
},
AlertInvalidZipBody() {
return this.getCmsContent("AlertInvalidZipWidget", "BodyText");
},
NoServiceZipHeader() {
return this.getCmsContent("NoServiceZipWidget","HeadlineText")
.replaceAll("{custom:zip}", this.zipToDisplay);
},
NoServiceZipBody() {
return this.getCmsContent("NoServiceZipWidget", "BodyText");
},
},
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
return store.getters.vehicle.carId !== null; return store.getters.vehicle.carId !== null;
}, },
backButtonAction() {
// route to move backwards
this.$router.navigate(
this.navigationScenarios.CLICKED_BACK,
this.$route
);
},
attachCustomEvents() { attachCustomEvents() {
this.prependActionToMethod(this, this.forwardButtonAction, () => { this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.pushEventToGA( this.pushEventToGA(
@ -228,10 +203,9 @@ export default {
getServiceZipFromStore() { getServiceZipFromStore() {
return this.$store.getters.order.serviceLocation.zipCode; return this.$store.getters.order.serviceLocation.zipCode;
}, },
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() { async forwardButtonAction() {
this.resetWarningsAndErrors();
const registrationZipValidationResponse = this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.registrationZip }); const registrationZipValidationResponse = this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.registrationZip });
// Settle promises and get results // Settle promises and get results
@ -242,81 +216,118 @@ export default {
}, },
{ {
resultKey: "serviceZipValidationResponse", resultKey: "serviceZipValidationResponse",
promise: this.serviceZip ? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.serviceZip }) : registrationZipValidationResponse, promise: this.serviceZipCode ? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.serviceZipCode }) : registrationZipValidationResponse,
} }
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
// Lookup vin
const vinLookup = await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_PLATE, {licensePlate: this.licensePlate, licenseState: resultMap.registrationZipValidationResponse.state}, false)
.catch(() => {
// No VINS found.
this.displayVinNotFoundAlert = true;
return this.$refs.funnelFooter.removeLoader();
});
// If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert // If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
const isZipValid = resultMap.serviceZipValidationResponse.isValid; const isZipValid = resultMap.serviceZipValidationResponse.isValid;
if (this.serviceZip && !isZipValid) { if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
// Handle service zip validations
if (!resultMap.serviceZipValidationResponse.isServiceable) {
this.isVinValid = true;
this.isRegistrationZipServiceable = false;
this.isCarIdDifferent = false;
this.zipToDisplay = this.serviceZip ? this.serviceZip : this.registrationZip;
return this.$refs.funnelFooter.removeLoader();
}
if (!this.serviceZip) {
this.serviceZip = this.registrationZip;
}
// Lookup vin
const vinLookup = await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_PLATE, {licensePlate: this.licensePlate, licenseState: resultMap.registrationZipValidationResponse.state}, false)
.catch(() => {
this.isVinValid = false;
this.isCarIdDifferent = false;
return this.$refs.funnelFooter.removeLoader();
});
// Check if the CarId has changed. // Check if the CarId has changed.
this.isCarIdDifferent = vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId; this.isCarIdDifferent = vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId;
//Handle changing car // Handle changing car
if (this.isCarIdDifferent && vinLookup.data.vehicle.carId !== this.previouslyEnteredCarId) { if (this.isCarIdDifferent && vinLookup.data.vehicle.carId !== this.previouslyEnteredCarId) {
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.vehicle.carId); // Display Alert
this.$refs.funnelFooter.updateButtonText(`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`);
this.previouslyEnteredCarId = vinLookup.data.vehicle.carId; this.previouslyEnteredCarId = vinLookup.data.vehicle.carId;
this.customAlertData.vehicleInfo = vinLookup.data.vehicle; this.customAlertData.vehicleInfo = vinLookup.data.vehicle;
this.isVinValid = true; this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.vehicle.carId);
// Update button "Continue with..."
this.$refs.funnelFooter.updateButtonText(`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`);
return this.$refs.funnelFooter.removeLoader();
}
// If the either the registration zip code or service zip code are not serviceable
this.isZipServiceable = resultMap.serviceZipValidationResponse.isServiceable;
if (!this.isZipServiceable) {
this.displayNonServiceableZipAlert = true;
this.showServiceZipField = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
// Save vin, vehicle, customer, service and registration information // If the registration zip code is serviceable and nothing was entered for the service zip code
await this.dispatchStoreAction(storeActions.SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP, { // then set the service zip code to the registration zip code
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle, if (!this.serviceZipCode) {
vehicleInfo: Object.assign(vinLookup.data.vehicle, { vin: vinLookup.data.vin }), this.serviceZipCode = this.registrationZip;
registrationInfo: { }
licensePlate: this.licensePlate,
state: resultMap.registrationZipValidationResponse.state,
zipCode: this.registrationZip,
}
}, false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.email, false); // Save vin, vehicle, customer, service and registration information
await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, { await this.dispatchStoreAction(storeActions.SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP, {
zipCode: this.serviceZip, isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
state: resultMap.serviceZipValidationResponse.state, vehicleInfo: Object.assign(vinLookup.data.vehicle, { vin: vinLookup.data.vin }),
}, false); registrationInfo: {
licensePlate: this.licensePlate,
state: resultMap.registrationZipValidationResponse.state,
zipCode: this.registrationZip,
}
}, false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.email, false);
await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, {
zipCode: this.serviceZipCode,
state: resultMap.serviceZipValidationResponse.state,
}, false);
return await this.navigateForward(); return await this.navigateForward();
}, },
async navigateForward() { async navigateForward() {
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD,this.$route,{}, {[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }); this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route, {}, { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true });
} else { } else {
await this.navigateForwardWithSingleCarMatch(); await this.navigateForwardWithSingleCarMatch();
} }
},
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayNonServiceableZipAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
},
},
mounted() {
this.attachCustomEvents();
},
computed: {
AlertNonServiceableZipHeader() {
const zipCode = this.serviceZipCode ? this.serviceZipCode : this.registrationZipCode;
const text = this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", zipCode);
return text;
},
AlertNonServiceableZipBody() {
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
},
AlertMatchedDifferentVehicleHeader() {
return this.getCmsContent("MatchedDifferentVehicleAlertWidget", "HeadlineText").replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedDifferentVehicleBody() {
return this.getCmsContent("MatchedDifferentVehicleAlertWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year)
.replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make)
.replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model);
}, },
}, },
watch: { watch: {
@ -330,21 +341,21 @@ export default {
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
serviceZip() { serviceZipCode() {
this.$refs.funnelFooter.updateButtonText( this.$refs.funnelFooter.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
}, },
components: { components: {
Form,
funnelHeader, funnelHeader,
funnelFooter,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
textboxQuestion, textboxQuestion,
alert, alert,
funnelFooter, loadingModal,
loadingModal, Form
}, },
}; };
</script> </script>

View file

@ -6,18 +6,15 @@
v-slot="{ meta }" v-slot="{ meta }"
> >
<div class="page-container-grouped-styles"> <div class="page-container-grouped-styles">
<loadingModal ref="loadingModal"/> <loadingModal ref="loadingModal" />
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<vehicleBanner <vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall"> <div class="fade-on-route-transition sub-container make-tall">
<div class="row mt-2"> <div class="row mt-2">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="VinNumber" cmsWidgetName="VinNumberQuestionWidget"
v-model="vin" v-model="vin"
inputId="vin" inputId="vin"
isRequired isRequired
@ -37,9 +34,9 @@
<div class="row my-2"> <div class="row my-2">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZIP" cmsWidgetName="ServiceZipQuestionWidget"
v-model="zip" v-model="serviceZipCode"
inputId="zip" inputId="serviceZipCode"
mask="#####" mask="#####"
isRequired isRequired
disableAutoFill disableAutoFill
@ -50,50 +47,57 @@
<div class="row my-2"> <div class="row my-2">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddress" cmsWidgetName="EmailAddressQuestionWidget"
v-model="email" v-model="emailAddress"
inputId="email" inputId="emailAddress"
isRequired isRequired
disableAutoFill disableAutoFill
validationRules="email-address-required|email-address-format" validationRules="email-address-required|email-address-format"
/> />
</div> </div>
</div> </div>
<alert ref="alertInvalidZip"
v-if="displayInvalidZipAlert"
class="my-4"
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false"
/>
<alert <alert
class="my-4" class="my-4"
:manualHeadline="PerfectMatchInsuranceVerifiedAlertHeader" :manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader"
:manualCopy="PerfectMatchInsuranceVerifiedAlertBody" :manualCopy="AlertPerfectMatchInsuranceVerifiedBody"
v-model="customAlertData" v-model="customAlertData"
v-if="vinPopulatedOnPageLoad && isInsuranceVerified" v-if="vinPopulatedOnPageLoad && isInsuranceVerified"
alertClass="alert-success" alertClass="alert-success"
/> />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="MatchedDifferentVehicleAlertHeader" :manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="MatchedDifferentVehicleAlertBody" :manualCopy="AlertMatchedDifferentVehicleBody"
v-model="customAlertData" v-model="customAlertData"
v-if="isCarIdDifferent && !vinNotFound && !perfectMatchNewVinAlert" v-if="displayMatchedDifferentVehicleAlert"
alertClass="alert-warning" alertClass="alert-warning"
/> />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="NoServiceZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="NoServiceZipBody" :manualCopy="AlertNonServiceableZipBody"
v-model="customAlertData" v-model="customAlertData"
v-if="noServiceZip" v-if="displayNonServiceableZipAlert"
alertClass="alert-danger" alertClass="alert-danger"
/> />
<alert <alert
class="my-4" class="my-4"
v-model="customAlertData" v-model="customAlertData"
v-if="vinNotFound" v-if="displayVinNotFoundAlert"
alertClass="alert-danger" alertClass="alert-danger"
cmsWidgetName="VinNotFound" cmsWidgetName="AlertVinNotFoundWidget"
/> />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="PerfectMatchInsuranceNotVerifiedAlertHeader" :manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader"
:manualCopy="PerfectMatchInsuranceNotVerifiedAlertBody" :manualCopy="AlertPerfectMatchInsuranceNotVerifiedBody"
v-model="customAlertData" v-model="customAlertData"
v-if="vinPopulatedOnPageLoad && !isInsuranceVerified" v-if="vinPopulatedOnPageLoad && !isInsuranceVerified"
alertClass="alert-success" alertClass="alert-success"
@ -167,79 +171,20 @@ export default {
}, },
data() { data() {
return { return {
isCarIdDifferent: false,
noServiceZip: false,
vinNotFound: false,
vin: this.getVinFromStore(), vin: this.getVinFromStore(),
zip: this.getZipFromStore(), serviceZipCode: this.getZipFromStore(),
email: this.getEmailFromStore(), emailAddress: this.getEmailFromStore(),
isCarIdDifferent: false,
customAlertData: {}, customAlertData: {},
previouslyEnteredCarId: '', previouslyEnteredCarId: '',
invalidZip: '',
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0, vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
isSelectedGlassAvailableForVehicle: true isSelectedGlassAvailableForVehicle: false,
displayInvalidZipAlert: false,
displayNonServiceableZipAlert: false,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
}; };
}, },
mounted() {
this.attachCustomEvents();
},
watch: {
vin() {
this.vinNotFound = false;
this.$refs.funnelFooter.updateButtonText(this.getCmsContent("FunnelFooterWidget", "ForwardButtonText"));
},
zip() {
this.noServiceZip = false;
},
},
computed: {
MatchedDifferentVehicleAlertHeader(){
const text = this.getCmsContent("MatchedDifferentVehicle",
"HeadlineText").replaceAll("{custom:damage}", getDamageString());
return text;
},
MatchedDifferentVehicleAlertBody(){
const text = this.getCmsContent("MatchedDifferentVehicle",
"BodyText").replaceAll("{custom:damage}", getDamageString()).replaceAll("{custom:vinlookupYear}", this.customAlertData?.vehicleInfo?.year).replaceAll("{custom:vinlookupMake}", this.customAlertData?.vehicleInfo?.make).replaceAll("{custom:vinlookupModel}",
this.customAlertData?.vehicleInfo?.model);
return text;
},
NoServiceZipHeader(){
const text = this.getCmsContent("NoServiceZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.invalidZip);
return text;
},
NoServiceZipBody(){
return this.getCmsContent("NoServiceZipWidget", "BodyText");
},
PerfectMatchInsuranceNotVerifiedAlertHeader() {
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "HeadlineText");
},
PerfectMatchInsuranceNotVerifiedAlertBody() {
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
getDamageString())
},
PerfectMatchInsuranceVerifiedAlertHeader () {
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "HeadlineText");
},
PerfectMatchInsuranceVerifiedAlertBody () {
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
getIsWindshieldOnly())
},
isInsuranceVerified() {
return store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
},
vinMask() {
if (this.vinPopulatedOnPageLoad) {
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
else {
return 'XXXXXXXXXXXXXXXXX';
}
},
},
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
return store.getters.vehicle.carId !== null; return store.getters.vehicle.carId !== null;
@ -262,11 +207,7 @@ export default {
true true
); );
}); });
},
updateIsCarIdDifferent(isVinPerfectMatch){
if (isVinPerfectMatch) {
this.isCarIdDifferent = false;
}
}, },
backButtonAction() { backButtonAction() {
if (this.$store.getters.vehicle.vin) { if (this.$store.getters.vehicle.vin) {
@ -275,18 +216,19 @@ export default {
else { else {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
} }
}, },
async forwardButtonAction() { async forwardButtonAction() {
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation // If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
if (!this.vinPopulatedOnPageLoad) { if (!this.vinPopulatedOnPageLoad) {
const validateZipResponse = this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.zip}); const serviceZipValidationResponse = this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { zip: this.serviceZipCode });
const vehicleLookupResponse = this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, { vin: this.vin }); const vehicleLookupResponse = this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, { vin: this.vin });
// Settle promises and get results // Settle promises and get results
const promiseResultMap = [ const promiseResultMap = [
{ {
resultKey: "validateZipResponse", resultKey: "serviceZipValidationResponse",
promise: validateZipResponse, promise: serviceZipValidationResponse,
}, },
{ {
resultKey: "vehicleLookupResponse", resultKey: "vehicleLookupResponse",
@ -295,37 +237,46 @@ export default {
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
// If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
const isZipValid = resultMap.serviceZipValidationResponse.isValid;
if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader();
}
this.displayInvalidZipAlert = false;
// If either lookup fails, remove the loader and stop processing the page. // If either lookup fails, remove the loader and stop processing the page.
if (!resultMap.vehicleLookupResponse || !resultMap.validateZipResponse.isServiceable) { if (!resultMap.vehicleLookupResponse || !resultMap.serviceZipValidationResponse.isServiceable) {
// If the vehicle result is undefined, the vin entered was invalid.
if(!resultMap.vehicleLookupResponse) {
this.displayVinNotFoundAlert = true;
}
// If the vehicle result is undefined, the vin entered was invalid. // Check if Service Zip entered is serviceable, if not display an alert
if(!resultMap.vehicleLookupResponse) { if (!resultMap.serviceZipValidationResponse.isServiceable) {
this.vinNotFound = true; this.displayNonServiceableZipAlert = true;
} }
// Check if Service Zip entered is serviceable, if not display an alert // Remove loader and stop processing the page.
if (!resultMap.validateZipResponse.isServiceable) { return this.$refs.funnelFooter.removeLoader();
this.setupUiForNonServiceableZip(this.zip);
}
// Remove loader and stop processing the page.
return this.$refs.funnelFooter.removeLoader();
} }
// Check if the CarId is different from the lookup vs what is in state currently. // Check if the CarId is different from the lookup vs what is in state currently.
this.isCarIdDifferent = resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId; this.isCarIdDifferent = resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId;
if (this.isCarIdDifferent && (resultMap.vehicleLookupResponse.carId !== this.previouslyEnteredCarId)) { if (this.isCarIdDifferent && (resultMap.vehicleLookupResponse.carId !== this.previouslyEnteredCarId)) {
this.previouslyEnteredCarId = resultMap.vehicleLookupResponse.carId; this.previouslyEnteredCarId = resultMap.vehicleLookupResponse.carId;
this.customAlertData.vehicleInfo = resultMap.vehicleLookupResponse; this.customAlertData.vehicleInfo = resultMap.vehicleLookupResponse;
this.$refs.funnelFooter.updateButtonText(`Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}`); this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(resultMap.vehicleLookupResponse.carId); this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(resultMap.vehicleLookupResponse.carId);
this.noServiceZip = false; // Update button "Continue with..."
this.isVinValid = true; this.$refs.funnelFooter.updateButtonText(`Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}`);
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
// Save vin, vehicle, customer and service information // Save vin, vehicle, customer and service information
@ -334,60 +285,117 @@ export default {
vehicleInfo: Object.assign(resultMap.vehicleLookupResponse, { vin: this.vin }) vehicleInfo: Object.assign(resultMap.vehicleLookupResponse, { vin: this.vin })
}, false); }, false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.email, false); await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, { await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, {
zipCode: this.zip, zipCode: this.serviceZipCode,
state: resultMap.validateZipResponse.state, state: resultMap.serviceZipValidationResponse.state,
}, false); }, false);
return await this.navigateForward(); return await this.navigateForward();
} }
// If a VIN has already been found. Validate the Service Zip (in case of changes) // If a VIN has already been found. Validate the Service Zip (in case of changes)
const zipValidationResponse = await this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.zip}); const zipValidationResponse = await this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {zip: this.serviceZipCode});
// Check if Service Zip entered is serviceable // 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 // If the Service Zip entered is serviceable then save the Zip Info and Email Address and navigate forward
await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, { await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, {
zipCode: this.zip, zipCode: this.serviceZipCode,
state: zipValidationResponse.data.state state: zipValidationResponse.data.state
}, false); }, false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.email, false); await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
return await this.navigateForward(); return await this.navigateForward();
} }
// If the Service Zip is NOT serviceable then show an alert // If the Service Zip is NOT serviceable then show an alert
this.setupUiForNonServiceableZip(this.zip); this.displayNonServiceableZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
}, },
async navigateForward(){ async navigateForward(){
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigate(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }); this.$router.navigate(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true });
} else { } else {
await this.navigateForwardWithSingleCarMatch(); await this.navigateForwardWithSingleCarMatch();
} }
}, },
setupUiForNonServiceableZip(zip) { },
this.customAlertData.zip = zip; mounted() {
this.invalidZip = zip; this.attachCustomEvents();
this.noServiceZip = true; },
computed: {
AlertMatchedDifferentVehicleHeader(){
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget",
"HeadlineText").replaceAll("{custom:damage}", getDamageString());
return text;
},
AlertMatchedDifferentVehicleBody(){
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget",
"BodyText").replaceAll("{custom:damage}", getDamageString()).replaceAll("{custom:vinlookupYear}", this.customAlertData?.vehicleInfo?.year).replaceAll("{custom:vinlookupMake}", this.customAlertData?.vehicleInfo?.make).replaceAll("{custom:vinlookupModel}",
this.customAlertData?.vehicleInfo?.model);
return text;
},
AlertNonServiceableZipHeader(){
const text = this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.serviceZipCode);
return text;
},
AlertNonServiceableZipBody(){
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
},
AlertPerfectMatchInsuranceNotVerifiedHeader() {
return this.getCmsContent("AlertPerfectMatchInsuranceNotVerified", "HeadlineText");
},
AlertPerfectMatchInsuranceNotVerifiedBody() {
return this.getCmsContent("AlertPerfectMatchInsuranceNotVerified", "BodyText").replaceAll("{custom:damage}",
getDamageString())
},
AlertPerfectMatchInsuranceVerifiedHeader () {
return this.getCmsContent("AlertPerfectMatchInsuranceVerified", "HeadlineText");
},
AlertPerfectMatchInsuranceVerifiedBody () {
return this.getCmsContent("AlertPerfectMatchInsuranceVerified", "BodyText").replaceAll("{custom:damage}",
getIsWindshieldOnly())
},
isInsuranceVerified() {
return store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
},
vinMask() {
if (this.vinPopulatedOnPageLoad) {
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
else {
return 'XXXXXXXXXXXXXXXXX';
}
},
},
watch: {
vin() {
this.displayVinNotFoundAlert = false;
this.$refs.funnelFooter.updateButtonText(this.getCmsContent("FunnelFooterWidget", "ForwardButtonText"));
},
serviceZipCode() {
this.displayNonServiceableZipAlert = false;
}, },
}, },
components: { components: {
Form,
funnelHeader, funnelHeader,
funnelFooter,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
textboxQuestion, textboxQuestion,
alert, alert,
funnelFooter,
vinInformation, vinInformation,
loadingModal, loadingModal,
Form,
}, },
}; };
</script> </script>