WIP update grid on each page.

This commit is contained in:
Bryan Mauger 2023-09-19 09:54:02 -04:00
parent 68e0929c7d
commit 7906d0d13d
12 changed files with 1015 additions and 1004 deletions

View file

@ -1,27 +1,34 @@
<template> <template>
<Form <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" autocomplete="off">
@submit="onSubmit"
@invalid-submit="onInvalidSubmit" <div class="container-fluid">
ref="theForm" <div class="row">
v-slot="{ meta }" <div class="col">
autocomplete="off"> <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
<div class="page-container-grouped-styles"> </div>
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> </div>
<vehicleBanner <div class="row">
cmsWidgetName="VehicleBannerWidget" <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
ref="vehicleBanner" <div class="col-md-8 col-lg-6">
:displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" /> <vehicleBanner
<div class="fade-on-route-transition sub-container make-tall"> cmsWidgetName="VehicleBannerWidget"
<customerQuestions ref="customerQuestions" v-model="customerQuestions" /> ref="vehicleBanner"
<alert :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<alert
ref="alertVinNotFound" ref="alertVinNotFound"
v-if="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
class="mb-4" class="mb-4"
cmsWidgetName="AlertVinNotFoundWidget" cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert
<alert
ref="alertMatchedDifferentVehicle" ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
class="mb-4" class="mb-4"
@ -29,14 +36,16 @@
:manualCopy="AlertMatchedDifferentVehicleBody" :manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert
<alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="mb-4" class="mb-4"
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert
<alert
ref="alertNonServiceableZip" ref="alertNonServiceableZip"
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
class="mb-4" class="mb-4"
@ -44,18 +53,22 @@
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert
<alert
ref="alertVinLookupsByHomeAddressNotAllowed" ref="alertVinLookupsByHomeAddressNotAllowed"
v-if="displayVinLookupByHomeAddressNotAllowedAlert" v-if="displayVinLookupByHomeAddressNotAllowedAlert"
class="mb-4" class="mb-4"
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget" cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<transition name="fade" mode="out-in">
<div class="service-zip-field" v-if="showServiceZipField" aria-live="polite"> <transition name="fade" mode="out-in">
<div class="row mt-4 mb-1">
<div class="col"> <div class="service-zip-field" v-if="showServiceZipField" aria-live="polite">
<textboxQuestion
<div class="row mt-4 mb-1">
<div class="col">
<textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
ref="serviceZip" ref="serviceZip"
@ -63,17 +76,21 @@
aria-haspopup="" aria-haspopup=""
mask="#####" mask="#####"
validationRules="service-zip-required|service-zip-format" /> validationRules="service-zip-required|service-zip-format" />
</div>
</div> </div>
</div> </div>
</div> </transition>
</transition> <navbar
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isDisabled="!meta.valid" :isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid" /> :isForwardActionDisabled="!meta.valid" />
</div>
<div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
@ -227,12 +244,12 @@ export default {
{ {
resultKey: "serviceZipValidationResponse", resultKey: "serviceZipValidationResponse",
promise: this.serviceZipCode promise: this.serviceZipCode
? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { ? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.serviceZipCode, zip: this.serviceZipCode,
}) })
: this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { : this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.customerQuestions.addressQuestions.zipCode, zip: this.customerQuestions.addressQuestions.zipCode,
}), }),
}, },
]; ];
@ -317,9 +334,9 @@ export default {
{ {
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle, isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo: vehicleInfo:
Object.keys(vehicleInfoToCommit).length === 0 Object.keys(vehicleInfoToCommit).length === 0
? this.$store.getters.vehicle ? this.$store.getters.vehicle
: vehicleInfoToCommit, : vehicleInfoToCommit,
customerInfo: { customerInfo: {
firstName: this.customerQuestions.firstName, firstName: this.customerQuestions.firstName,
lastName: this.customerQuestions.lastName, lastName: this.customerQuestions.lastName,
@ -389,8 +406,8 @@ export default {
computed: { computed: {
AlertNonServiceableZipHeader() { AlertNonServiceableZipHeader() {
const zipCode = this.serviceZipCode const zipCode = this.serviceZipCode
? this.serviceZipCode ? this.serviceZipCode
: this.customerQuestions.addressQuestions.zipCode; : this.customerQuestions.addressQuestions.zipCode;
const text = this.getCmsContent( const text = this.getCmsContent(
"AlertNonServiceableZipWidget", "AlertNonServiceableZipWidget",
"HeadlineText" "HeadlineText"
@ -411,9 +428,9 @@ export default {
const vinYmmExpected = `${this.$store.getters.vehicle.year} ${this.$store.getters.vehicle.make} ${this.$store.getters.vehicle.model}`; const vinYmmExpected = `${this.$store.getters.vehicle.year} ${this.$store.getters.vehicle.make} ${this.$store.getters.vehicle.model}`;
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText") return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:glassText}", getDamageString()) .replaceAll("{custom:glassText}", getDamageString())
.replaceAll("{custom:vinYmmFound}", vinYmmFound) .replaceAll("{custom:vinYmmFound}", vinYmmFound)
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected); .replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
}, },
}, },
watch: { watch: {

View file

@ -7,64 +7,62 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="my-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="my-5" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
cmsWidgetName="FirstNameWidget" cmsWidgetName="FirstNameWidget"
v-model="firstName" v-model="firstName"
ref="firstName" ref="firstName"
customInputId="firstName" customInputId="firstName"
validationRules="first-name-required" /> validationRules="first-name-required" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
cmsWidgetName="LastNameWidget" cmsWidgetName="LastNameWidget"
v-model="lastName" v-model="lastName"
ref="lastName" ref="lastName"
customInputId="lastName" customInputId="lastName"
validationRules="last-name-required" /> validationRules="last-name-required" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
cmsWidgetName="emailQuestionWidget" cmsWidgetName="emailQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
inputId="email" inputId="email"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
<phoneNumberQuestion <phoneNumberQuestion
class="mb-4" class="mb-4"
cmsWidgetName="PhoneNumberQuestionWidget" cmsWidgetName="PhoneNumberQuestionWidget"
v-model="phoneNumber" v-model="phoneNumber"
isRequired isRequired
validationRules="phone-number-required" /> validationRules="phone-number-required" />
<checkboxQuestion <checkboxQuestion
class="mb-5" class="mb-5"
cmsWidgetName="TextMeQuestionWidget" cmsWidgetName="TextMeQuestionWidget"
v-model="isSmsOptIn" /> v-model="isSmsOptIn" />
<textareaQuestion <textareaQuestion
class="mb-4" class="mb-4"
v-model="techNotes" v-model="techNotes"
cmsWidgetName="TextAreaContentWidget" cmsWidgetName="TextAreaContentWidget"
maxLength="250" /> maxLength="250" />
<textBlock cmsWidgetName="DisclaimerCopyWidget" typeStyle="caption" /> <textBlock cmsWidgetName="DisclaimerCopyWidget" typeStyle="caption" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
</template> </template>

View file

@ -8,81 +8,79 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" /> <vehicleBanner cmsWidgetName="VehicleBannerWidget" />
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
<div v-if="!skipVin"> <div v-if="!skipVin">
<div class="vinlookupquestion" v-html="this.VinLookupQuestionText"></div> <div class="vinlookupquestion" v-html="this.VinLookupQuestionText"></div>
<buttonQuestion <buttonQuestion
cmsWidgetName="VinLookupMethod" cmsWidgetName="VinLookupMethod"
:answers="answersFromCms" :answers="answersFromCms"
groupName="vinLookupMethodOption" groupName="vinLookupMethodOption"
buttonTypeString="listButton" buttonTypeString="listButton"
v-model="selectedVinLookupMethod" v-model="selectedVinLookupMethod"
isRequired isRequired
validationRules="option-required" validationRules="option-required"
:logDisplayedValuesEvent="true" /> :logDisplayedValuesEvent="true" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div v-else> <div v-else>
<alert <alert
class="my-4" class="my-4"
:cmsWidgetName="alertInfo" :cmsWidgetName="alertInfo"
alertClass="alert-info" alertClass="alert-info"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
inputId="serviceZipCode" inputId="serviceZipCode"
mask="#####" mask="#####"
isRequired isRequired
validationRules="zip-required|zip-format" /> validationRules="zip-required|zip-format" />
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
inputId="emailAddress" inputId="emailAddress"
isRequired isRequired
disableAutoFill disableAutoFill
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
<textBlock <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
cmsWidgetName="QuoteEmailTextBlockWidget"
typeStyle="caption" />
<alert <alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="my-4" class="my-4"
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
v-model="customAlertData" v-model="customAlertData"
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
@ -161,8 +159,8 @@ export default {
} }
const zip = lowerCaseParams.get(queryStrings.ZIP_CODE) const zip = lowerCaseParams.get(queryStrings.ZIP_CODE)
? lowerCaseParams.get(queryStrings.ZIP_CODE) ? lowerCaseParams.get(queryStrings.ZIP_CODE)
: store.getters.order.serviceLocation.zipCode; : store.getters.order.serviceLocation.zipCode;
var vinByAddressPromise; var vinByAddressPromise;
if (zip) { if (zip) {
@ -180,10 +178,10 @@ export default {
promise: cmsContentPromise, promise: cmsContentPromise,
}, },
zip != null && zip != null &&
zip != undefined && { zip != undefined && {
resultKey: "vinByAddress", resultKey: "vinByAddress",
promise: vinByAddressPromise, promise: vinByAddressPromise,
}, },
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
@ -195,13 +193,13 @@ export default {
vm.skipVinNotRepair = skipVinNotRepair; vm.skipVinNotRepair = skipVinNotRepair;
if (resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.includes("|")) { if (resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.includes("|")) {
const forwardTextOption = const forwardTextOption =
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.split("|"); resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.split("|");
if (skipVin) { if (skipVin) {
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText = resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText =
forwardTextOption[1]; forwardTextOption[1];
} else { } else {
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText = resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText =
forwardTextOption[0]; forwardTextOption[0];
} }
} }
@ -259,7 +257,7 @@ export default {
const payment = this.$store.getters.payment; const payment = this.$store.getters.payment;
const vehicleChangedDuringPolicyLookupInHeritage = const vehicleChangedDuringPolicyLookupInHeritage =
payment.isInsurance && payment.insuranceCoverage.coverageStatus; payment.isInsurance && payment.insuranceCoverage.coverageStatus;
if (vehicleChangedDuringPolicyLookupInHeritage) { if (vehicleChangedDuringPolicyLookupInHeritage) {
navigateToHeritageFunnel({ navigateToHeritageFunnel({
shouldSaveSession: true, shouldSaveSession: true,

View file

@ -7,90 +7,87 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<textboxQuestion <textboxQuestion
cmsWidgetName="LicensePlateNumberQuestionWidget" cmsWidgetName="LicensePlateNumberQuestionWidget"
v-model="licensePlate" v-model="licensePlate"
isRequired isRequired
customInputId="licensePlate" customInputId="licensePlate"
validationRules="license-plate-required" /> validationRules="license-plate-required" />
<textboxQuestion <textboxQuestion
cmsWidgetName="RegistrationZipQuestionWidget" cmsWidgetName="RegistrationZipQuestionWidget"
v-model="registrationZipCode" v-model="registrationZipCode"
customInputId="zip" customInputId="zip"
mask="#####" mask="#####"
validationRules="registration-zip-required|zip-format" /> validationRules="registration-zip-required|zip-format" />
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="email" v-model="email"
customInputId="email" customInputId="email"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" /> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
<alert <alert
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="my-3" class="my-3"
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
class="my-3" class="my-3"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<div class="row mt-2" v-if="showServiceZipField"> <div class="row mt-2" v-if="showServiceZipField">
<div class="col mb-1"> <div class="col mb-1">
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
inputId="serviceZipCode" inputId="serviceZipCode"
validationRules="zip-required|zip-format" validationRules="zip-required|zip-format"
mask="#####" /> mask="#####" />
</div> </div>
</div> </div>
<alert <alert
v-if="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
class="my-3" class="my-3"
cmsWidgetName="AlertVinNotFoundWidget" cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
class="my-3" class="my-3"
:manualHeadline="AlertMatchedDifferentVehicleHeader" :manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody" :manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<navbar <navbar
ref="navbar" ref="navbar"
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
</template> </template>
@ -220,10 +217,10 @@ export default {
// If serviceZipCode is not set, then sets the response to the registrationZipValidationResponse. Calls VALIDATE_ZIP if the serviceZipCode is set. // If serviceZipCode is not set, then sets the response to the registrationZipValidationResponse. Calls VALIDATE_ZIP if the serviceZipCode is set.
resultKey: "serviceZipValidationResponse", resultKey: "serviceZipValidationResponse",
promise: this.serviceZipCode promise: this.serviceZipCode
? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { ? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.serviceZipCode, zip: this.serviceZipCode,
}) })
: registrationZipValidationResponse, : registrationZipValidationResponse,
}, },
]; ];
@ -253,7 +250,7 @@ export default {
// Check if the CarId has changed. // Check if the CarId has changed.
this.isCarIdDifferent = this.isCarIdDifferent =
vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId; vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId;
// Handle changing car // Handle changing car
if ( if (
@ -365,10 +362,10 @@ export default {
}, },
AlertMatchedDifferentVehicleBody() { AlertMatchedDifferentVehicleBody() {
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText") return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString()) .replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year) .replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year)
.replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make) .replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make)
.replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model); .replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model);
}, },
}, },
watch: { watch: {

View file

@ -8,37 +8,37 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" />
<cashOrInsuranceQuestion <cashOrInsuranceQuestion
ref="cashOrInsurance" ref="cashOrInsurance"
cmsWidgetName="CashOrInsuranceQuestionWidget" cmsWidgetName="CashOrInsuranceQuestionWidget"
v-model="isInsuranceSelected" v-model="isInsuranceSelected"
groupName="CashOrInsuranceQuestion" /> groupName="CashOrInsuranceQuestion" />
<servicePackageQuestion <servicePackageQuestion
ref="servicePackage" ref="servicePackage"
cashCmsWidgetName="CashServicePackageQuestionWidget" cashCmsWidgetName="CashServicePackageQuestionWidget"
insuranceCmsWidgetName="InsuranceServicePackageQuestionWidget" insuranceCmsWidgetName="InsuranceServicePackageQuestionWidget"
groupName="ServicePackageQuestion" groupName="ServicePackageQuestion"
:availableLineItems="availableLineItems" :availableLineItems="availableLineItems"
:isInsuranceSelected="isInsuranceSelected" :isInsuranceSelected="isInsuranceSelected"
@vapsItemsSelected="vapsItemsSelectedAction" @vapsItemsSelected="vapsItemsSelectedAction"
v-on="{ 'buttonEvent.openModal': openModalAction }" v-on="{ 'buttonEvent.openModal': openModalAction }"
validationRules="option-required" validationRules="option-required"
isRequired /> isRequired />
<textBlock <textBlock
cmsWidgetName="quoteDisclaimer" cmsWidgetName="quoteDisclaimer"
justifyText="left" justifyText="left"
typeStyle="caption" typeStyle="caption"
class="mt-4" /> class="mt-4" />
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" /> <contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
<contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" /> <contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
@ -46,13 +46,13 @@
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" /> <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton" :isBackButtonHidden="shouldHideBackButton"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
@ -117,8 +117,8 @@ export default {
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
const clonedGlassParts = store.getters.order.lineItems.glassParts const clonedGlassParts = store.getters.order.lineItems.glassParts
? JSON.parse(JSON.stringify(store.getters.order.lineItems.glassParts)) ? JSON.parse(JSON.stringify(store.getters.order.lineItems.glassParts))
: []; : [];
const availableLineItems = [ const availableLineItems = [
resultMap.rainDefense, resultMap.rainDefense,
...resultMap.supportingItems, ...resultMap.supportingItems,
@ -169,101 +169,101 @@ export default {
(store.getters.order.damage.isRepair || (store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null && (store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0)) && store.getters.order.lineItems.glassParts.length > 0)) &&
store.getters.order.referralNumber?.length !== 6 store.getters.order.referralNumber?.length !== 6
); );
}, },
getDefaultIsInsuranceSelectedValue(availableLineItems) { getDefaultIsInsuranceSelectedValue(availableLineItems) {
const serviceLocationState = store.getters.order.serviceLocation.state; const serviceLocationState = store.getters.order.serviceLocation.state;
// Override if coming back from QuoteDetails. Remove override after Quote release // Override if coming back from QuoteDetails. Remove override after Quote release
const isInsuranceOverrideValue = this.$route.query?.isInsurance; const isInsuranceOverrideValue = this.$route.query?.isInsurance;
const defaultIsInsuranceSelectedValue = this.$store.getters.order.payment.isInsurance; const defaultIsInsuranceSelectedValue = this.$store.getters.order.payment.isInsurance;
//Default to Insurance Tab if user Service zip is from certain States //Default to Insurance Tab if user Service zip is from certain States
if ( if (
serviceLocationState != null && serviceLocationState != null &&
payWithInsuranceStates.find((item) => item === serviceLocationState) payWithInsuranceStates.find((item) => item === serviceLocationState)
) )
return true; return true;
else if (isInsuranceOverrideValue != null) { else if (isInsuranceOverrideValue != null) {
return isInsuranceOverrideValue == "true"; return isInsuranceOverrideValue == "true";
} else if (defaultIsInsuranceSelectedValue != null) { } else if (defaultIsInsuranceSelectedValue != null) {
return defaultIsInsuranceSelectedValue; return defaultIsInsuranceSelectedValue;
} else { } else {
return availableLineItems return availableLineItems
? baseMixin.methods.getTierOnePackagePrice( ? baseMixin.methods.getTierOnePackagePrice(
baseMixin.methods.filterOutFees(availableLineItems) baseMixin.methods.filterOutFees(availableLineItems)
) > 300 ) > 300
: null; : null;
} }
}, },
vapsItemsSelectedAction(vapsItemsSelected) { vapsItemsSelectedAction(vapsItemsSelected) {
this.selectedVaps = vapsItemsSelected; this.selectedVaps = vapsItemsSelected;
}, },
backButtonAction() { backButtonAction() {
vehicleQuestionsMixin.methods.navigateBack(this); vehicleQuestionsMixin.methods.navigateBack(this);
}, },
forwardButtonAction() { forwardButtonAction() {
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_PAYMENT_TYPE, this.storeActions.SAVE_PAYMENT_TYPE,
this.isInsuranceSelected, this.isInsuranceSelected,
false false
); );
if (!this.isInsuranceSelected) { if (!this.isInsuranceSelected) {
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_PARENT_ACCOUNT_NUMBER, this.storeActions.SAVE_PARENT_ACCOUNT_NUMBER,
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
false false
); );
} }
if ( if (
this.$store.getters.order.payment.parentAccountNumber != this.$store.getters.order.payment.parentAccountNumber !=
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
) { ) {
this.supportingItems = this.filterOutFees(this.supportingItems); this.supportingItems = this.filterOutFees(this.supportingItems);
} }
if (this.pricedGlassParts.length > 0) { if (this.pricedGlassParts.length > 0) {
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_GLASS_PART_PRICES, this.storeActions.SAVE_GLASS_PART_PRICES,
this.pricedGlassParts, this.pricedGlassParts,
false false
); );
} }
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
const payment = this.$store.getters.payment; const payment = this.$store.getters.payment;
if (payment.isInsurance) { if (payment.isInsurance) {
navigateToHeritageFunnel({ navigateToHeritageFunnel({
shouldSaveSession: true, shouldSaveSession: true,
loadingModal: this.$refs.loadingModal, loadingModal: this.$refs.loadingModal,
}); });
} else { } else {
this.$router.navigateWithSaving( this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_CASH, this.navigationScenarios.CLICKED_FORWARD_WITH_CASH,
this.$route this.$route
); );
} }
}, },
}, },
components: { components: {
funnelHeader, funnelHeader,
navbar, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
Form, Form,
textBlock, textBlock,
cashOrInsuranceQuestion, cashOrInsuranceQuestion,
servicePackageQuestion, servicePackageQuestion,
contentGroupModal, contentGroupModal,
loadingModal, loadingModal,
}, },
}; };
</script> </script>
<style scoped> <style scoped>
.text-block { .text-block {
display: block; display: block;
} }
</style> </style>

View file

@ -8,7 +8,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
@ -100,11 +100,10 @@
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div>
<div class="col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
<div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div>
</Form> </Form>
</template> </template>

View file

@ -1,63 +1,66 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
<template v-if="ChangeShopLink.length"> <template v-if="ChangeShopLink.length">
<textBlock <textBlock
cmsWidgetName="ChangeShopLink" cmsWidgetName="ChangeShopLink"
justifyText="center" justifyText="center"
class="mb-3 text-link-small" class="mb-3 text-link-small"
marginTopSizeOverride="1" /> marginTopSizeOverride="1" />
</template> </template>
<locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" /> <locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
<datePicker <datePicker
customComponentId="dateQuestion" customComponentId="dateQuestion"
selectableDatesSetting="custom" selectableDatesSetting="custom"
ref="datePicker" ref="datePicker"
v-model="selectedDate" v-model="selectedDate"
class="text-link-small" class="text-link-small"
:customSelectableDatesCallback="getAvailableDatesMethod" :customSelectableDatesCallback="getAvailableDatesMethod"
validationRules="date-required" validationRules="date-required"
@date-clicked="openInshopTimeSlotsModal" /> @date-clicked="openInshopTimeSlotsModal" />
<timeSlotModalQuestion <timeSlotModalQuestion
ref="timeSlotModalQuestion" ref="timeSlotModalQuestion"
customComponentId="timeSlotModalQuestion" customComponentId="timeSlotModalQuestion"
v-model="selectedTimeSlotInfo" v-model="selectedTimeSlotInfo"
cmsWidgetName="TimeSlotModalQuestion" cmsWidgetName="TimeSlotModalQuestion"
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal" mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
mobileCmsWidgetName="MobileTimeSlotModal" mobileCmsWidgetName="MobileTimeSlotModal"
dropoffCmsWidgetName="DropOffTimeSlotModal" dropoffCmsWidgetName="DropOffTimeSlotModal"
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal" sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal" overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
:selectedDate="selectedDate" :selectedDate="selectedDate"
:appointmentType="appointmentType" :appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee" :premiumAppointmentFee="mobilePremiumAppointmentFee"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate" :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:estimatedServiceMinutesMinimum="selectableDatesData.estimatedServiceMinutesMinimum" :estimatedServiceMinutesMinimum="
:estimatedServiceMinutesMaximum="selectableDatesData.estimatedServiceMinutesMaximum" selectableDatesData.estimatedServiceMinutesMinimum
@time-slot-modal-closed="timeSlotModalClosed" "
validationRules="time-slot-selection-required" /> :estimatedServiceMinutesMaximum="
<navbar selectableDatesData.estimatedServiceMinutesMaximum
cmsWidgetName="FunnelFooterWidget" "
ref="navbar" @time-slot-modal-closed="timeSlotModalClosed"
:isForwardActionDisabled="!meta.valid" validationRules="time-slot-selection-required" />
@back-clicked="backButtonAction" <navbar
@ForwardClicked="forwardButtonAction" /> cmsWidgetName="FunnelFooterWidget"
ref="navbar"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
<div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </Form>
</Form>
</template> </template>
<script> <script>
@ -80,9 +83,9 @@ import { settleAllPromises } from "@/helpers/layout-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper"; import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
import { import {
calcDaysBetweenDates, calcDaysBetweenDates,
convertDateStringToDate, convertDateStringToDate,
sumDateString, sumDateString,
} from "@/layouts/schedule/helpers/schedule-helper"; } from "@/layouts/schedule/helpers/schedule-helper";
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants"; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
@ -92,431 +95,431 @@ import store from "@/store";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("date-required", required(errorMessages.DATE_REQUIRED)); defineRule("date-required", required(errorMessages.DATE_REQUIRED));
defineRule("time-slot-selection-required", (value) => { defineRule("time-slot-selection-required", (value) => {
if (value?.timeSlot?.routeCode == null) { if (value?.timeSlot?.routeCode == null) {
return errorMessages.DATE_REQUIRED; return errorMessages.DATE_REQUIRED;
} }
return true; return true;
}); });
// Define constants // Define constants
const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work) const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work)
const getAvailableDates = async ( const getAvailableDates = async (
startDateString, startDateString,
endDateString, endDateString,
appointmentType, appointmentType,
providerNumber providerNumber
) => { ) => {
const apiEndDateLimit = sumDateString(startDateString, TIME_SLOTS_CALL_DAYS_LIMIT); const apiEndDateLimit = sumDateString(startDateString, TIME_SLOTS_CALL_DAYS_LIMIT);
const difference = calcDaysBetweenDates(startDateString, endDateString); const difference = calcDaysBetweenDates(startDateString, endDateString);
const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT); const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT);
const storeActionConfigs = []; const storeActionConfigs = [];
const timeSlotsData = {}; const timeSlotsData = {};
timeSlotsData.days = []; timeSlotsData.days = [];
let apiStartDate = startDateString; let apiStartDate = startDateString;
let apiEndDate = endDateString; let apiEndDate = endDateString;
for (let i = 1; i <= apiCallsCount; i++) { for (let i = 1; i <= apiCallsCount; i++) {
let storeActionConfig; let storeActionConfig;
if (i > 1) { if (i > 1) {
apiStartDate = sumDateString(apiEndDate, 1); apiStartDate = sumDateString(apiEndDate, 1);
apiEndDate = sumDateString(apiStartDate, TIME_SLOTS_CALL_DAYS_LIMIT); apiEndDate = sumDateString(apiStartDate, TIME_SLOTS_CALL_DAYS_LIMIT);
if (i === apiCallsCount) { if (i === apiCallsCount) {
apiEndDate = endDateString; apiEndDate = endDateString;
}
} else {
if (apiEndDate > apiEndDateLimit) {
apiEndDate = apiEndDateLimit;
}
} }
} else {
if (apiEndDate > apiEndDateLimit) { if (appointmentType === AppointmentTypeStrings.MOBILE) {
apiEndDate = apiEndDateLimit; storeActionConfig = {
storeAction: storeActions.GET_MOBILE_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
},
};
} else {
storeActionConfig = {
storeAction: storeActions.GET_SHOP_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
shopAppointmentType: appointmentType,
providerNumber: providerNumber,
},
};
} }
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
} }
if (appointmentType === AppointmentTypeStrings.MOBILE) { const timeSlotsResponsesData = {
storeActionConfig = { days: [],
storeAction: storeActions.GET_MOBILE_TIME_SLOTS, };
payload: {
startDate: apiStartDate, function compareDayStrings(a, b) {
endDate: apiEndDate, if (a.date < b.date) return -1;
}, if (a.date > b.date) return 1;
}; return 0;
} else {
storeActionConfig = {
storeAction: storeActions.GET_SHOP_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
shopAppointmentType: appointmentType,
providerNumber: providerNumber,
},
};
} }
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
}
const timeSlotsResponsesData = { const makeParallelCalls = async () => {
days: [], await Promise.all(
}; storeActionConfigs.map(async (storeAction) => {
const timeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
storeAction.storeAction,
storeAction.payload,
false
);
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
timeSlotsResponse.data.estimatedServiceMinutesMinimum;
timeSlotsResponsesData.estimatedServiceMinutesMaximum =
timeSlotsResponse.data.estimatedServiceMinutesMaximum;
timeSlotsResponsesData.days = [
...timeSlotsResponsesData.days,
...timeSlotsResponse.data.days,
];
})
);
};
function compareDayStrings(a, b) { return makeParallelCalls().then(() => {
if (a.date < b.date) return -1; // sort days chronologically
if (a.date > b.date) return 1; timeSlotsResponsesData.days.sort(compareDayStrings);
return 0; return timeSlotsResponsesData;
} });
const makeParallelCalls = async () => {
await Promise.all(
storeActionConfigs.map(async (storeAction) => {
const timeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
storeAction.storeAction,
storeAction.payload,
false
);
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
timeSlotsResponse.data.estimatedServiceMinutesMinimum;
timeSlotsResponsesData.estimatedServiceMinutesMaximum =
timeSlotsResponse.data.estimatedServiceMinutesMaximum;
timeSlotsResponsesData.days = [
...timeSlotsResponsesData.days,
...timeSlotsResponse.data.days,
];
})
);
};
return makeParallelCalls().then(() => {
// sort days chronologically
timeSlotsResponsesData.days.sort(compareDayStrings);
return timeSlotsResponsesData;
});
}; };
export default { export default {
name: "schedule", name: "schedule",
data() { data() {
return { return {
selectedDate: this.getSelectedDate(), selectedDate: this.getSelectedDate(),
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
selectableDatesData: [], selectableDatesData: [],
mobilePremiumAppointmentFee: null, mobilePremiumAppointmentFee: null,
};
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
let preSelectedDate = await store.getters.order.schedule.date;
if (!preSelectedDate || preSelectedDate.startTime === null) {
preSelectedDate = null;
}
const datePickerInitialDataPromise = await datePicker.methods.loadInitialData({
// setup config options for date-picker
selectableDatesSetting: "custom",
initialViewRowsToShow: 5,
customSelectableDatesCallback: getAvailableDates,
preSelectedDate: preSelectedDate,
});
const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_PREMIUM_FEE
);
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return baseMixin.methods.dispatchStoreAction(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: [result.data],
},
false
);
} else {
return result.data;
}
});
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
store.getters.order.serviceLocation.zipCodeCtu,
store.getters.order.serviceLocation.provider?.address?.zipCodeCtu
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "alertReasons",
promise: alertReasonsPromise,
},
{
resultKey: "datePickerInitialData",
promise: datePickerInitialDataPromise,
},
{
resultKey: "premiumFeeWithPrice",
promise: premiumFeeWithPricePromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice
? resultMap.premiumFeeWithPrice[0]
: null;
vm.updateFooterButtonText(vm.selectedTimeSlotInfo);
});
},
computed: {
ChangeShopLinkText() {
return this.getCmsContent("ChangeShopLink", "Text");
},
ChangeShopLink() {
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
},
appointmentType() {
return this.$store.getters.order.serviceLocation.appointmentType;
},
timeSlotsForSelectedDate() {
if (!this.selectedDate) {
return null;
}
return this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.date === this.selectedDate
);
},
},
methods: {
splitCopyOnCMSPlaceHolder,
arePagePrerequisitesValid() {
const serviceLocation = store.getters.order.serviceLocation;
const serviceLocationPreReqs =
serviceLocation.zipCode &&
serviceLocation.zipCodeCtu &&
serviceLocation.appointmentType &&
(serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE ||
serviceLocation.provider.providerNumber);
const paymentInfo = store.getters.payment.isInsurance !== null;
const supportingItems = store.getters.lineItems.supportingItems !== null;
const damageInfo =
store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0);
return serviceLocationPreReqs && paymentInfo && supportingItems && damageInfo;
},
async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.appointmentType,
this.$store.getters.order.serviceLocation.provider.providerNumber
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat(
newShopTimeSlots.days
);
return newShopTimeSlots;
},
getAvailableDates,
getServiceZipCtuCodeFromStore() {
return store.getters.order.serviceLocation.zipCodeCtu;
},
openInshopTimeSlotsModal() {
this.$refs["timeSlotModalQuestion"].openModal();
},
getSelectedDate() {
return store.getters.order.schedule.date;
},
getSelectedTimeSlotInfo() {
const supportingItems = this.getSupportingItems();
const isPremiumAppointment =
!!supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE)
.length > 0;
const selectedTimeSlotInfo = {
timeSlot: store.getters.order.schedule,
isPremiumAppointment: isPremiumAppointment,
}; };
return selectedTimeSlotInfo;
}, },
getSupportingItems() { async beforeRouteEnter(to, from, next) {
return store.getters.lineItems.supportingItems; // Call APIs
}, const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
timeSlotModalClosed() { let preSelectedDate = await store.getters.order.schedule.date;
// Clear the selectedDate if no timeSlot has been selected if (!preSelectedDate || preSelectedDate.startTime === null) {
if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) { preSelectedDate = null;
this.selectedDate = null;
}
},
updateFooterButtonText(timeSlotInfo) {
let navbarButtonText;
if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
navbarButtonText = "Continue";
} else {
navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(
timeSlotInfo.timeSlot.date
)}`;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime
)}`;
} else if (
this.appointmentType === AppointmentTypeStrings.MOBILE &&
!timeSlotInfo.isPremiumAppointment
) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime,
true
)} - ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.endTime,
true
)}`;
}
}
this.$refs.navbar.updateButtonText(navbarButtonText);
},
convertSelectedDateToShortMonthAndDay(selectedDate) {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(selectedDate);
// Ex: April 25
return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
},
getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
// Expected input: "HH:MM"
let hours = parseInt(militaryTimeInput.split(":")[0]);
const minutes = militaryTimeInput.split(":")[1];
const meridianNotation = hours > 11 ? "PM" : "AM";
if (hours > 12) {
hours -= 12;
} }
if (shouldTrimMinutesIfEmpty && minutes === "00") { const datePickerInitialDataPromise = await datePicker.methods.loadInitialData({
return `${hours} ${meridianNotation}`; // setup config options for date-picker
} else { selectableDatesSetting: "custom",
return `${hours}:${minutes} ${meridianNotation}`; initialViewRowsToShow: 5,
} customSelectableDatesCallback: getAvailableDates,
}, preSelectedDate: preSelectedDate,
backButtonAction() { });
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
forwardButtonAction() {
this.updateSupportingItems();
this.dispatchStoreAction( const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
this.storeActions.SAVE_SCHEDULE, storeActions.GET_MOBILE_PREMIUM_FEE
this.selectedTimeSlotInfo.timeSlot,
false
); );
this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
}, if (result.data) {
updateSupportingItems() { return baseMixin.methods.dispatchStoreAction(
const supportingItems = this.getSupportingItems(); storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
// if we have a premium fee(early bird), then save/update supporting items availableLineItems: [result.data],
if ( },
this.appointmentType === AppointmentTypeStrings.MOBILE && false
this.selectedTimeSlotInfo?.isPremiumAppointment );
) {
const earlyBirdIndex = supportingItems.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
);
if (earlyBirdIndex >= 0) {
supportingItems[earlyBirdIndex].laborAmount =
this.mobilePremiumAppointmentFee.laborAmount;
supportingItems[earlyBirdIndex].selingPrice =
this.mobilePremiumAppointmentFee.selingPrice;
supportingItems[earlyBirdIndex].kitPrice =
this.mobilePremiumAppointmentFee.kitPrice;
} else { } else {
supportingItems.push(this.mobilePremiumAppointmentFee); return result.data;
} }
});
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
store.getters.order.serviceLocation.zipCodeCtu,
store.getters.order.serviceLocation.provider?.address?.zipCodeCtu
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "alertReasons",
promise: alertReasonsPromise,
},
{
resultKey: "datePickerInitialData",
promise: datePickerInitialDataPromise,
},
{
resultKey: "premiumFeeWithPrice",
promise: premiumFeeWithPricePromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice
? resultMap.premiumFeeWithPrice[0]
: null;
vm.updateFooterButtonText(vm.selectedTimeSlotInfo);
});
},
computed: {
ChangeShopLinkText() {
return this.getCmsContent("ChangeShopLink", "Text");
},
ChangeShopLink() {
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
},
appointmentType() {
return this.$store.getters.order.serviceLocation.appointmentType;
},
timeSlotsForSelectedDate() {
if (!this.selectedDate) {
return null;
}
return this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.date === this.selectedDate
);
},
},
methods: {
splitCopyOnCMSPlaceHolder,
arePagePrerequisitesValid() {
const serviceLocation = store.getters.order.serviceLocation;
const serviceLocationPreReqs =
serviceLocation.zipCode &&
serviceLocation.zipCodeCtu &&
serviceLocation.appointmentType &&
(serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE ||
serviceLocation.provider.providerNumber);
const paymentInfo = store.getters.payment.isInsurance !== null;
const supportingItems = store.getters.lineItems.supportingItems !== null;
const damageInfo =
store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0);
return serviceLocationPreReqs && paymentInfo && supportingItems && damageInfo;
},
async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.appointmentType,
this.$store.getters.order.serviceLocation.provider.providerNumber
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat(
newShopTimeSlots.days
);
return newShopTimeSlots;
},
getAvailableDates,
getServiceZipCtuCodeFromStore() {
return store.getters.order.serviceLocation.zipCodeCtu;
},
openInshopTimeSlotsModal() {
this.$refs["timeSlotModalQuestion"].openModal();
},
getSelectedDate() {
return store.getters.order.schedule.date;
},
getSelectedTimeSlotInfo() {
const supportingItems = this.getSupportingItems();
const isPremiumAppointment =
!!supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE)
.length > 0;
const selectedTimeSlotInfo = {
timeSlot: store.getters.order.schedule,
isPremiumAppointment: isPremiumAppointment,
};
return selectedTimeSlotInfo;
},
getSupportingItems() {
return store.getters.lineItems.supportingItems;
},
timeSlotModalClosed() {
// Clear the selectedDate if no timeSlot has been selected
if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) {
this.selectedDate = null;
}
},
updateFooterButtonText(timeSlotInfo) {
let navbarButtonText;
if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
navbarButtonText = "Continue";
} else {
navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(
timeSlotInfo.timeSlot.date
)}`;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime
)}`;
} else if (
this.appointmentType === AppointmentTypeStrings.MOBILE &&
!timeSlotInfo.isPremiumAppointment
) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime,
true
)} - ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.endTime,
true
)}`;
}
}
this.$refs.navbar.updateButtonText(navbarButtonText);
},
convertSelectedDateToShortMonthAndDay(selectedDate) {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(selectedDate);
// Ex: April 25
return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
},
getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
// Expected input: "HH:MM"
let hours = parseInt(militaryTimeInput.split(":")[0]);
const minutes = militaryTimeInput.split(":")[1];
const meridianNotation = hours > 11 ? "PM" : "AM";
if (hours > 12) {
hours -= 12;
}
if (shouldTrimMinutesIfEmpty && minutes === "00") {
return `${hours} ${meridianNotation}`;
} else {
return `${hours}:${minutes} ${meridianNotation}`;
}
},
backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
forwardButtonAction() {
this.updateSupportingItems();
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING, this.storeActions.SAVE_SCHEDULE,
supportingItems, this.selectedTimeSlotInfo.timeSlot,
false false
); );
} else {
// if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added
const removeEarlyBirdIndex = supportingItems.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
);
if (removeEarlyBirdIndex >= 0) { this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route);
supportingItems.splice(removeEarlyBirdIndex, 1); },
updateSupportingItems() {
const supportingItems = this.getSupportingItems();
// if we have a premium fee(early bird), then save/update supporting items
if (
this.appointmentType === AppointmentTypeStrings.MOBILE &&
this.selectedTimeSlotInfo?.isPremiumAppointment
) {
const earlyBirdIndex = supportingItems.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
);
if (earlyBirdIndex >= 0) {
supportingItems[earlyBirdIndex].laborAmount =
this.mobilePremiumAppointmentFee.laborAmount;
supportingItems[earlyBirdIndex].selingPrice =
this.mobilePremiumAppointmentFee.selingPrice;
supportingItems[earlyBirdIndex].kitPrice =
this.mobilePremiumAppointmentFee.kitPrice;
} else {
supportingItems.push(this.mobilePremiumAppointmentFee);
}
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING, this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
supportingItems, supportingItems,
false false
); );
} else {
// if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added
const removeEarlyBirdIndex = supportingItems.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
);
if (removeEarlyBirdIndex >= 0) {
supportingItems.splice(removeEarlyBirdIndex, 1);
this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
supportingItems,
false
);
}
} }
} },
}, },
}, watch: {
watch: { selectedDate(newValue, oldValue) {
selectedDate(newValue, oldValue) { // Clear time slot selection if date selected changes
// Clear time slot selection if date selected changes if (newValue !== oldValue) {
if (newValue !== oldValue) { this.selectedTimeSlotInfo = {
this.selectedTimeSlotInfo = { timeSlot: {
timeSlot: { date: null,
date: null, routeCode: null,
routeCode: null, startTime: null,
startTime: null, endTime: null,
endTime: null, jobMaxMinutes: null,
jobMaxMinutes: null, jobMinMinutes: null,
jobMinMinutes: null, },
}, isPremiumAppointment: null,
isPremiumAppointment: null, };
}; }
} },
selectedTimeSlotInfo(newValue) {
this.updateFooterButtonText(newValue);
},
}, },
selectedTimeSlotInfo(newValue) { components: {
this.updateFooterButtonText(newValue); funnelHeader,
navbar,
funnelSubHeader,
Form,
loadingModal,
datePicker,
locationAlerts,
timeSlotModalQuestion,
textBlock,
}, },
},
components: {
funnelHeader,
navbar,
funnelSubHeader,
Form,
loadingModal,
datePicker,
locationAlerts,
timeSlotModalQuestion,
textBlock,
},
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.text-link-small { .text-link-small {
a, a,
.btn-link { .btn-link {
font-size: 0.875rem; font-size: 0.875rem;
line-height: 1.5; line-height: 1.5;
} }
} }
.funnel-sub-header { .funnel-sub-header {
h5.dark-header { h5.dark-header {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
} }
</style> </style>

View file

@ -8,101 +8,100 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
<serviceZipModalQuestion <serviceZipModalQuestion
v-model="serviceZipCodeQuestion" v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion" ref="serviceZipCodeQuestion"
:mobileFeePart="mobileFeePart" :mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart" @updated-mobile-fee-part="setMobileFeePart"
@updated-serviceability="setServiceabilityDetails" @updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase" @updated-contains-military-base="setContainsMilitaryBase"
linkWidgetName="ServiceZipLinkWidget" linkWidgetName="ServiceZipLinkWidget"
modalWidgetName="ServiceZipModalWidget" modalWidgetName="ServiceZipModalWidget"
:onZipUpdateCallback="reloadShopData" /> :onZipUpdateCallback="reloadShopData" />
<alert <alert
ref="alertMilitaryBaseZip" ref="alertMilitaryBaseZip"
class="my-5" class="my-5"
cmsWidgetName="AlertMilitaryBaseZipWidget" cmsWidgetName="AlertMilitaryBaseZipWidget"
v-if="displayMilitaryZipAlert" v-if="displayMilitaryZipAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertMobileOnly" ref="alertMobileOnly"
class="my-5" class="my-5"
cmsWidgetName="AlertMobileOnlyWidget" cmsWidgetName="AlertMobileOnlyWidget"
v-if="displayServiceableMobileOnly" v-if="displayServiceableMobileOnly"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertRecalNoMobile" ref="alertRecalNoMobile"
class="my-5" class="my-5"
cmsWidgetName="AlertRecalNoMobileWidget" cmsWidgetName="AlertRecalNoMobileWidget"
v-if="displayRecalibrationWarning" v-if="displayRecalibrationWarning"
@text-link-clicked="openModalAction" @text-link-clicked="openModalAction"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertInshopOnly" ref="alertInshopOnly"
class="my-5" class="my-5"
cmsWidgetName="AlertInshopOnlyWidget" cmsWidgetName="AlertInshopOnlyWidget"
v-if="displayServiceableInshopOnly" v-if="displayServiceableInshopOnly"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertNoShops" ref="alertNoShops"
class="my-5" class="my-5"
cmsWidgetName="AlertNoShopsWidget" cmsWidgetName="AlertNoShopsWidget"
v-if="displayNoShopsAlert" v-if="displayNoShopsAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<appointmentTypeQuestion <appointmentTypeQuestion
v-model="selectedAppointmentType" v-model="selectedAppointmentType"
v-show="isAppointmentTypeDisplayed" v-show="isAppointmentTypeDisplayed"
:isServiceableMobile="isServiceableMobile" :isServiceableMobile="isServiceableMobile"
:isServiceableInshop="isServiceableInshop" :isServiceableInshop="isServiceableInshop"
:isDisplayed="isAppointmentTypeDisplayed" :isDisplayed="isAppointmentTypeDisplayed"
ref="appointmentTypeQuestion" ref="appointmentTypeQuestion"
groupName="appointmentTypeQuestion" groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget" cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" /> validationRules="option-required" />
<mobileLocationModalQuestions <mobileLocationModalQuestions
customComponentId="mobileLocationQuestions" customComponentId="mobileLocationQuestions"
v-if="selectedAppointmentType === 'Mobile'" v-if="selectedAppointmentType === 'Mobile'"
v-model="mobileLocationQuestions" v-model="mobileLocationQuestions"
:mobileFeePart="mobileFeePart" :mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart" @updated-mobile-fee-part="setMobileFeePart"
@updated-serviceability="setServiceabilityDetails" @updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase" @updated-contains-military-base="setContainsMilitaryBase"
validationRules="mobile-location-required" validationRules="mobile-location-required"
ref="mobileLocationQuestions" ref="mobileLocationQuestions"
linkWidgetName="MobileLocationLinkWidget" linkWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget" modalWidgetName="MobileLocationModalWidget"
:onZipUpdateCallback="reloadShopData" /> :onZipUpdateCallback="reloadShopData" />
<shopQuestion <shopQuestion
ref="shopQuestion" ref="shopQuestion"
v-show="isShopQuestionDisplayed" v-show="isShopQuestionDisplayed"
v-model="selectedProvider" v-model="selectedProvider"
:selectedAppointmentType="selectedAppointmentType" :selectedAppointmentType="selectedAppointmentType"
:isDisplayed="isShopQuestionDisplayed" :isDisplayed="isShopQuestionDisplayed"
cmsWidgetName="ShopQuestionWidget" /> cmsWidgetName="ShopQuestionWidget" />
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" /> <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid || displayNoShopsAlert" :isForwardActionDisabled="!meta.valid || displayNoShopsAlert"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
@ -262,7 +261,7 @@ export default {
set: function (newValue) { set: function (newValue) {
this.streetAddress = newValue.addressQuestions.streetAddress; this.streetAddress = newValue.addressQuestions.streetAddress;
this.apartmentNumberOrBusinessName = this.apartmentNumberOrBusinessName =
newValue.addressQuestions.apartmentNumberOrBusinessName; newValue.addressQuestions.apartmentNumberOrBusinessName;
this.city = newValue.addressQuestions.city; this.city = newValue.addressQuestions.city;
this.state = newValue.addressQuestions.state; this.state = newValue.addressQuestions.state;
this.zipCode = newValue.addressQuestions.zipCode; this.zipCode = newValue.addressQuestions.zipCode;
@ -391,10 +390,10 @@ export default {
setServiceabilityDetails(serviceabilityDetails) { setServiceabilityDetails(serviceabilityDetails) {
this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop; this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
this.isRecalibrationServiceableInshop = this.isRecalibrationServiceableInshop =
serviceabilityDetails.isRecalibrationServiceableInshop; serviceabilityDetails.isRecalibrationServiceableInshop;
this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile; this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
this.isRecalibrationServiceableMobile = this.isRecalibrationServiceableMobile =
serviceabilityDetails.isRecalibrationServiceableMobile; serviceabilityDetails.isRecalibrationServiceableMobile;
}, },
backButtonAction() { backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);

View file

@ -6,16 +6,16 @@
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<alert <alert
ref="vehicleChangeAlert" ref="vehicleChangeAlert"
v-if="shouldDisplayVehicleChangeAlert" v-if="shouldDisplayVehicleChangeAlert"
class="mt-5 mb-0" class="mt-5 mb-0"
@ -23,27 +23,27 @@
alertClass="alert-warning" alertClass="alert-warning"
:isDismissible="false" /> :isDismissible="false" />
<damageLocationQuestion <damageLocationQuestion
ref="damageLocation" ref="damageLocation"
cmsWidgetName="DamageLocationQuestion" cmsWidgetName="DamageLocationQuestion"
v-model="selectedDamageLocations" v-model="selectedDamageLocations"
groupName="DamageLocationQuestion" /> groupName="DamageLocationQuestion" />
<windshieldOptions <windshieldOptions
ref="windshieldOptions" ref="windshieldOptions"
v-model="selectedWindshieldOptions" v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict" :hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict" :hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" /> :selectedDamageLocations="selectedDamageLocations" />
<alert <alert
v-if="hasRepairReplaceConflict" v-if="hasRepairReplaceConflict"
class="my-5" class="my-5"
cmsWidgetName="HasReplacementConflict" cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger" alertClass="alert-danger"
:isDismissible="false" /> :isDismissible="false" />
<sideDoorOptions <sideDoorOptions
ref="sideDoorOptions" ref="sideDoorOptions"
cmsWidgetName="SideDoorSideQuestion" cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion" groupName="SideDoorSideQuestion"
@ -51,7 +51,7 @@
v-show="!hasRepairReplaceConflict" v-show="!hasRepairReplaceConflict"
:selectedDamageLocations="selectedDamageLocations" /> :selectedDamageLocations="selectedDamageLocations" />
<replaceOptionsQuestion <replaceOptionsQuestion
ref="backGlassOptions" ref="backGlassOptions"
cmsWidgetName="RearReplaceOptionsQuestion" cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict" :isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
@ -59,16 +59,16 @@
groupName="BackGlassReplaceOptionsQuestion" groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" /> validationRules="replace-options-required" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton" :isBackButtonHidden="shouldHideBackButton"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div>
<div class="col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
<div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
@ -235,7 +235,7 @@ export default {
}) })
) { ) {
windShieldOptions.selectedWindshieldDamageType = windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE; damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push( windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.SINGLE damageLocationsSelected.SINGLE
); );
@ -250,7 +250,7 @@ export default {
}) })
) { ) {
windShieldOptions.selectedWindshieldDamageType = windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE; damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push( windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.DRIVER damageLocationsSelected.DRIVER
); );
@ -265,7 +265,7 @@ export default {
}) })
) { ) {
windShieldOptions.selectedWindshieldDamageType = windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE; damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push( windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.PASSENGER damageLocationsSelected.PASSENGER
); );
@ -335,7 +335,7 @@ export default {
isWindshieldRepair: this.isWindshieldRepair, isWindshieldRepair: this.isWindshieldRepair,
selectedGlassToReplace: this.selectedGlassToReplace(), selectedGlassToReplace: this.selectedGlassToReplace(),
selectedWindshieldChipCount: selectedWindshieldChipCount:
this.selectedWindshieldOptions.selectedWindshieldChipCount, this.selectedWindshieldOptions.selectedWindshieldChipCount,
}, },
false false
); );
@ -358,9 +358,9 @@ export default {
const payment = this.$store.getters.payment; const payment = this.$store.getters.payment;
const vehicleChangedDuringPolicyLookupInHeritage = const vehicleChangedDuringPolicyLookupInHeritage =
payment.isInsurance && payment.isInsurance &&
payment.insuranceCoverage.coverageStatus && payment.insuranceCoverage.coverageStatus &&
payment.insuranceCoverage.coverageStatus !== ""; payment.insuranceCoverage.coverageStatus !== "";
if (vehicleChangedDuringPolicyLookupInHeritage) { if (vehicleChangedDuringPolicyLookupInHeritage) {
if (store.getters.damage.isRepair) { if (store.getters.damage.isRepair) {
this.$router.navigateWithSaving( this.$router.navigateWithSaving(
@ -370,7 +370,7 @@ export default {
} else { } else {
this.$router.navigateWithSaving( this.$router.navigateWithSaving(
this.navigationScenarios this.navigationScenarios
.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE, .CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE,
this.$route this.$route
); );
} }
@ -452,7 +452,7 @@ export default {
return ( return (
this.isWindshieldDamageLocation && this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType === this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR damageLocationsSelected.REPAIR
); );
}, },
isDriverSideReplace() { isDriverSideReplace() {
@ -480,10 +480,10 @@ export default {
if ( if (
!this.selectedDamageLocations?.includes("Windshield") || !this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType === this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR || damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions !this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
) )
return false; return false;
return ( return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some( this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
@ -502,14 +502,14 @@ export default {
); );
} }
) || ) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some( this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => { (selectedPassengerWindshield) => {
return ( return (
selectedPassengerWindshield.toUpperCase() === selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase() damageLocationsSelected.PASSENGER.toUpperCase()
); );
} }
)) ))
); );
}, },
shouldDisplayVehicleChangeAlert() { shouldDisplayVehicleChangeAlert() {

View file

@ -9,44 +9,48 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
ref="vehicleBanner" ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader ref="funnelSubHeader" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader
<div class="prevent-squish my-5"> ref="funnelSubHeader"
<div class="row"> cmsWidgetName="FunnelSubHeaderWidget" />
<div class="col pb-0"> <div class="prevent-squish my-5">
<alert <div class="row">
class="rounded border-0 shadow-sm" <div class="col pb-0">
alertClass="alert-warning" <alert
cmsWidgetName="AlertWidget" class="rounded border-0 shadow-sm"
:isDismissible="false" /> alertClass="alert-warning"
</div> cmsWidgetName="AlertWidget"
:isDismissible="false" />
</div> </div>
</div> </div>
<div v-for="(item, i) in PartsOrQuestions" :key="i"> </div>
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) --> <div v-for="(item, i) in PartsOrQuestions" :key="i">
<hr v-if="i > 0" /> <!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<glassPartQuestion <hr v-if="i > 0" />
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`" <glassPartQuestion
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]" :ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
:glassLocation="item.glassLocation" v-model="
:glassName="item.glassName" selectedGlassParts[item.glassLocation + '-' + item.glassName]
:colorAnswers="item.colorAnswers" "
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" /> :glassLocation="item.glassLocation"
</div> :glassName="item.glassName"
<navbar :colorAnswers="item.colorAnswers"
cmsWidgetName="FunnelFooterWidget" :alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
ref="navbar" </div>
:isForwardActionDisabled="isForwardActionDisabled" <navbar
@back-clicked="navigateBack" cmsWidgetName="FunnelFooterWidget"
@ForwardClicked="forwardButtonAction" /> ref="navbar"
:isForwardActionDisabled="isForwardActionDisabled"
@back-clicked="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>

View file

@ -7,7 +7,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-3 col-lg-4">&nbsp;</div> <div class="d-none d-md-block col-md-3 col-lg-4">&nbsp;</div>
<div class="col-md-6 col-lg-4"> <div class="col-md-6 col-lg-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" />
<vehicleQuestion <vehicleQuestion
@ -65,7 +65,7 @@
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
ref="navbar" /> ref="navbar" />
</div> </div>
<div class="col-md-3 col-lg-4">&nbsp;</div> <div class="d-none d-md-block col-md-3 col-lg-4">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>

View file

@ -8,126 +8,122 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
<div class="col-md-8 col-lg-6"> <div class="col-md-8 col-lg-6">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<textboxQuestion <textboxQuestion
cmsWidgetName="VinNumberQuestionWidget" cmsWidgetName="VinNumberQuestionWidget"
v-model="vin" v-model="vin"
customInputId="vin" customInputId="vin"
isRequired isRequired
:validationRules=" :validationRules="!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : ''"
!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : '' :isDisabled="vinPopulatedOnPageLoad"
" maxLength="17"
:isDisabled="vinPopulatedOnPageLoad" :mask="vinMask"
maxLength="17" includeImageQuestion
:mask="vinMask" :imageQuestionSubmitHandler="getVinFromImage"
includeImageQuestion :maxFileSize="imageUploadMaxFileSize"
:imageQuestionSubmitHandler="getVinFromImage" @image-lookup-error="displayVinScanAlert"
:maxFileSize="imageUploadMaxFileSize" @image-validity-error="displayVinScanAlert"
@image-lookup-error="displayVinScanAlert" data-test="vin-lookup-field"
@image-validity-error="displayVinScanAlert" ref="vinLookupQuestion" />
data-test="vin-lookup-field"
ref="vinLookupQuestion" />
<alert <alert
cmsWidgetName="AlertVinScanFailed" cmsWidgetName="AlertVinScanFailed"
v-if="displayVinScanFailedAlert" v-if="displayVinScanFailedAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
<vinInformation /> <vinInformation />
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
customInputId="serviceZipCode" customInputId="serviceZipCode"
mask="#####" mask="#####"
isRequired isRequired
validationRules="zip-required|zip-format" /> validationRules="zip-required|zip-format" />
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
customInputId="emailAddress" customInputId="emailAddress"
isRequired isRequired
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" /> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
<alert <alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="my-4" class="my-4"
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader" :manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader"
:manualCopy="AlertPerfectMatchInsuranceVerifiedBody" :manualCopy="AlertPerfectMatchInsuranceVerifiedBody"
v-model="customAlertData" v-model="customAlertData"
v-if=" v-if="
vinPopulatedOnPageLoad && vinPopulatedOnPageLoad &&
isInsuranceVerified && isInsuranceVerified &&
!displayInvalidZipAlert && !displayInvalidZipAlert &&
!displayNonServiceableZipAlert !displayNonServiceableZipAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertMatchedDifferentVehicleHeader" :manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody" :manualCopy="AlertMatchedDifferentVehicleBody"
v-model="customAlertData" v-model="customAlertData"
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
v-model="customAlertData" v-model="customAlertData"
v-if="displayNonServiceableZipAlert" 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="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
alertClass="alert-danger" alertClass="alert-danger"
cmsWidgetName="AlertVinNotFoundWidget" /> cmsWidgetName="AlertVinNotFoundWidget" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader" :manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader"
:manualCopy="AlertPerfectMatchInsuranceNotVerifiedBody" :manualCopy="AlertPerfectMatchInsuranceNotVerifiedBody"
v-model="customAlertData" v-model="customAlertData"
v-if=" v-if="
vinPopulatedOnPageLoad && vinPopulatedOnPageLoad &&
!isInsuranceVerified && !isInsuranceVerified &&
!displayInvalidZipAlert && !displayInvalidZipAlert &&
!displayNonServiceableZipAlert !displayNonServiceableZipAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
<div class="col-md-2 col-lg-3">&nbsp;</div> <div class="d-none d-md-block col-md-2 col-lg-3">&nbsp;</div>
</div> </div>
</div> </div>
</Form> </Form>
</template> </template>
@ -300,7 +296,7 @@ export default {
// 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 = this.isCarIdDifferent =
resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId; resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId;
if ( if (
this.isCarIdDifferent && this.isCarIdDifferent &&
@ -400,16 +396,16 @@ export default {
getVinFromImage(image) { getVinFromImage(image) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, image) this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, image)
.then((response) => { .then((response) => {
if (response.data.length > 0) { if (response.data.length > 0) {
resolve(response.data[0]); resolve(response.data[0]);
} else { } else {
reject("No VINs detected."); reject("No VINs detected.");
} }
}) })
.catch(() => { .catch(() => {
reject("An error occurred during the lookup."); reject("An error occurred during the lookup.");
}); });
}); });
}, },
resetAlerts() { resetAlerts() {
@ -432,10 +428,10 @@ export default {
}, },
AlertMatchedDifferentVehicleBody() { AlertMatchedDifferentVehicleBody() {
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText") return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString()) .replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinlookupYear}", this.customAlertData?.vehicleInfo?.year) .replaceAll("{custom:vinlookupYear}", this.customAlertData?.vehicleInfo?.year)
.replaceAll("{custom:vinlookupMake}", this.customAlertData?.vehicleInfo?.make) .replaceAll("{custom:vinlookupMake}", this.customAlertData?.vehicleInfo?.make)
.replaceAll("{custom:vinlookupModel}", this.customAlertData?.vehicleInfo?.model); .replaceAll("{custom:vinlookupModel}", this.customAlertData?.vehicleInfo?.model);
}, },
AlertNonServiceableZipHeader() { AlertNonServiceableZipHeader() {
return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll( return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll(