DigitalConsumer.ISS/src/layouts/vin-lookup/vin-lookup.vue
2026-07-14 14:28:10 -04:00

345 lines
14 KiB
Vue

<template>
<Form
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="iss-heritage-container-width">
<div class="vin-lookup-container iss-heritage-content-container-width">
<div class="select-car-form rounded">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<vinQuestion
v-model="vin"
ref="vin-question"
class="mt-4"
:mask="vinMask"
:isDisabled="vinPopulatedOnPageLoad"
textPosition="left" />
<vinLocationInformation @vin-location-detail-shown="handleVinLocationDetailShown" />
<vinLookupAlerts
:activeAlertType="activeVehicleLookupAlertType" />
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
:isForwardButtonNavigationDisabled="isForwardNavigationDisabled"
class="mt-5"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
import { computed } from 'vue';
import { experimentSettings } from '@/constants/experiments';
import vehicleLookupAlertTypes from '@/constants/vehicle-lookup-alert-types';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { isGlassAvailableForCarId } from '@/helpers/damage-helper';
import settleAllPromises from '@/helpers/layout-helper';
import routerParams from '@/router/router-constants/router-params';
import { useMainStore } from '@/store';
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
// Import Component
import baseFormMixin from '@/mixins/base-form-mixin';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vinLocationInformation from '@/layouts/vin-lookup/vin-location-information/vin-location-information.vue';
import vinLookupAlerts from '@/layouts/vin-lookup/vin-lookup-alerts/vin-lookup-alerts.vue';
import vinQuestion from '@/layouts/vin-lookup/vin-question/vin-question.vue';
import bailoutMessage from '@/constants/bailoutMessage';
export default {
name: 'vin-lookup',
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
vinLocationInformation,
vinLookupAlerts,
vinQuestion
},
mixins: [baseFormMixin, vehicleQuestionsMixin],
provide() {
return {
vehicleFromLookup: computed(() => this.vehicleFromLookup)
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
const vin = this.getVinFromStore();
return {
activeVehicleLookupAlertType:
vin?.length > 0 && !this.hasValidCarId()
? vehicleLookupAlertTypes.NOT_FOUND
: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vinWithNonMatchingCarId: vin?.length > 0 && !this.hasValidCarId(),
vin,
forwardButtonCarStyle: '',
vinPopulatedOnPageLoad: vin?.length > 0 && this.hasValidCarId()
};
},
computed: {
isForwardNavigationDisabled() {
return this.needToLookupVehicle;
},
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null
&& this.hasValidCarId()
&& this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
},
isTwoIdenticalYMMVehicleFound() {
if (this.vehicleFromLookup === null) {
return false;
}
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return vinYmmFound.toLowerCase() === vinYmmExpected.toLowerCase();
},
vinMask() {
// TODO: Side effects in computed.
if (this.vinPopulatedOnPageLoad) {
// TODO: Modify to remove side effects in computed
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.PERFECT_MATCH;
this.needToLookupVehicle = false;
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
return '*****************';
}
},
watch: {
vin() {
this.resetActiveAlert();
this.$refs.siteFooter.enableForwardAction();
this.needToLookupVehicle = true;
this.$refs.siteFooter.updateButtonText(this.getCmsContent('SiteFooterWidget', 'ForwardButtonText'));
}
},
methods: {
arePagePrerequisiteValid() {
return true;
},
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
hasValidCarId() {
return (
this.mainStore.vehicle.carId
&& this.mainStore.vehicle.carId !== '0'
);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetActiveAlert();
this.mainStore.resetBailout();
// Temp solution to reset the 'disabled' style on the Continue button
this.$refs.siteFooter.enableForwardAction();
showIssLoadingModal(true);
const ymmsBailoutEnabled = this.getSettingValue(experimentSettings.ISS_YMMS_VIN_REQUIRED_BAILOUT_ENABLED) === 'true';
if (ymmsBailoutEnabled && this.mainStore.order.vehicle.vinRequired) {
this.mainStore.order.vehicle.vin = this.vin;
this.mainStore.setBailout(bailoutMessage.YMMNotFound());
return this.$router.navigate(
this.navigationScenarios.BAILOUT,
this.$route
);
}
if (this.needToLookupVehicle) {
try {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin);
this.pushEventToGA("policy_vehicle", "VIN_lookup", "SUCCESS", true, null, '1');
if (!vehicleLookupResponse.data.canSafeliteService) {
this.mainStore.setBailout(bailoutMessage.HeavyTruckVehicle(vehicleLookupResponse.data.carId));
this.resetVehicleFromLookup();
showIssLoadingModal(false);
return this.navigateForward();
}
// Add vin bcs the response from the service doesn't contain vin
this.vehicleFromLookup = Object.assign(
vehicleLookupResponse.data,
{
vin: this.vin
}
);
} catch (e) {
this.pushEventToGA("policy_vehicle", "VIN_lookup", "FAIL", true, null, '0');
if (e.status === 404) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_FOUND;
this.resetVehicleFromLookup();
// Temp solution to turn on 'disabled' style on the Continue button
// because the form itself actually passes its client-side validation.
// SSR-189 Scenario #4.
this.$refs.siteFooter.enableForwardAction();
showIssLoadingModal(false);
return;
}
throw e;
}
}
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
if (this.isTwoIdenticalYMMVehicleFound) {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.TWO_IDENTICAL_YMM_MATCHED;
this.forwardButtonCarStyle = this.vehicleFromLookup.style;
} else {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.NOT_MATCHED;
}
const vehicleYearMakeModelStyle = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model} ${this.forwardButtonCarStyle}`;
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModelStyle}`);
this.needToLookupVehicle = false;
showIssLoadingModal(false);
return;
}
let isSelectedGlassAvailableForVehicle = true;
if (this.isCarIdDifferentFromTheStore) {
isSelectedGlassAvailableForVehicle =
await isGlassAvailableForCarId(this.vehicleFromLookup.carId);
}
// navigate back to vehicle-damage
if (this.isCarIdDifferentFromTheStore && !isSelectedGlassAvailableForVehicle) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.mainStore.resetDamageState();
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
// navigate() doesn't stop the processing flow
return;
}
// save vehicle to store if it hasn't already been saved
if (!this.vinPopulatedOnPageLoad) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
if (this.vinWithNonMatchingCarId) {
this.$router.navigate(
this.navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
this.$route
);
return;
}
/*
* If the vehicle is vinRequired, we need to call getPartsOrQuestionsVinRequired() to get the parts or questions.
* If the vehicle is not vinRequired, we can call getPartsOrQuestions() to get the parts or questions.
*/
/*
if (this.mainStore.order.vehicle.vinRequired) {
try {
const partsOrQuestionsResponse = await this.getPartsOrQuestionsVinRequired();
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
} catch (e) {
this.mainStore.setBailout(bailoutMessage.HeavyTruckVehicle(this.vehicleFromLookup.carId));
this.$router.navigate(
this.navigationScenarios.BAILOUT,
this.$route
);
throw e;
}
return;
}
*/
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
},
async lookupVehicleByVin(vin) {
return this.mainStore.lookupVehicleByVin(vin);
},
handleVinLocationDetailShown() {
if (!this.vin) {
this.pushEventToGA("VehicleDamage", "Where_Is_VIN", "VIN_Empty", true);
}
else if (this.checkVinForErrors()) {
this.pushEventToGA("VehicleDamage", "Where_Is_VIN", "VIN_Error", true);
}
else {
this.pushEventToGA("VehicleDamage", "Where_Is_VIN", "VIN_Field_Active", true);
}
},
resetActiveAlert() {
this.activeVehicleLookupAlertType = null;
},
resetVehicleFromLookup() {
this.vehicleFromLookup = null;
},
checkVinForErrors() {
return this.$refs['vin-question'].hasErrors;
},
resetDependentState() {}
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.vin-lookup-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
</style>