Merge branch 'develop' into feature/CASH-93
This commit is contained in:
commit
089529757b
39 changed files with 1078 additions and 178 deletions
|
|
@ -100,6 +100,7 @@ stages:
|
||||||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||||
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||||
indexDeployVariables:
|
indexDeployVariables:
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
|
|
@ -160,6 +161,7 @@ stages:
|
||||||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||||
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||||
indexDeployVariables:
|
indexDeployVariables:
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
|
|
@ -220,6 +222,7 @@ stages:
|
||||||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||||
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||||
indexDeployVariables:
|
indexDeployVariables:
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
|
|
@ -280,6 +283,7 @@ stages:
|
||||||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||||
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||||
indexDeployVariables:
|
indexDeployVariables:
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ const applicationConfig = {
|
||||||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
|
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
|
||||||
AFFILIATE_COOKIE_CONTAINING_NAME: "_Track",
|
AFFILIATE_COOKIE_CONTAINING_NAME: "_Track",
|
||||||
COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
|
COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
|
||||||
|
SESSION_TIMEOUT_MINUTES: process.env.VUE_APP_SESSION_TIMEOUT_MINUTES,
|
||||||
|
RETURN_USER_PAGE: "/fmg/?fmgPage=return-user",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { applicationConfig };
|
export { applicationConfig };
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const cookieNames = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const cookieExpirations = {
|
const cookieExpirations = {
|
||||||
SESSION_ID: convertToSeconds({ minutes: 30 }),
|
SESSION_ID: convertToSeconds({ minutes: applicationConfig.SESSION_TIMEOUT_MINUTES }),
|
||||||
DXDEV: convertToSeconds({ years: 1 }),
|
DXDEV: convertToSeconds({ years: 1 }),
|
||||||
FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
|
FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
|
||||||
FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
|
FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ const queryStrings = {
|
||||||
ORGANIC: "organic",
|
ORGANIC: "organic",
|
||||||
ORGANIC_SOCIAL: "organic_social",
|
ORGANIC_SOCIAL: "organic_social",
|
||||||
EXPERIMENTS: "experiments",
|
EXPERIMENTS: "experiments",
|
||||||
|
FROM_HERITAGE: "fromheritage",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { queryStrings };
|
export { queryStrings };
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ const storeMutations = {
|
||||||
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
|
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
|
||||||
UPDATE_VEHICLE_VIN: "updateVehicleVin",
|
UPDATE_VEHICLE_VIN: "updateVehicleVin",
|
||||||
UPDATE_VEHICLE: "updateVehicle",
|
UPDATE_VEHICLE: "updateVehicle",
|
||||||
|
UPDATE_VEHICLE_MOBILE_STATIC_RECALIBRATION_APPLICABLE:
|
||||||
|
"updateIsMobileStaticRecalibrationApplicable",
|
||||||
|
|
||||||
UPDATE_IS_REPAIR: "updateIsRepair",
|
UPDATE_IS_REPAIR: "updateIsRepair",
|
||||||
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ export default {
|
||||||
if (this.buttonTypeString == "radio") {
|
if (this.buttonTypeString == "radio") {
|
||||||
classes += " radio-button-container";
|
classes += " radio-button-container";
|
||||||
} else if (this.buttonTypeString == "servicePackageRadio") {
|
} else if (this.buttonTypeString == "servicePackageRadio") {
|
||||||
classes = "package-wrapper col-md-4";
|
classes = "package-wrapper col";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.buttonTypeString == "listCard" && this.buttonsInfo.length > 2) {
|
if (this.buttonTypeString == "listCard" && this.buttonsInfo.length > 2) {
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,17 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body ps-5 pe-5 pb-4 pt-1">
|
<div class="modal-body ps-5 pe-5 pb-4 pt-1">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<modalButtonMain
|
<div class="modal-footer">
|
||||||
isPrimary
|
<modalButtonMain
|
||||||
class="w-100"
|
isPrimary
|
||||||
:id="modalId + '-modalbtn'"
|
class="w-100"
|
||||||
ref="modalButtonMain"
|
:id="modalId + '-modalbtn'"
|
||||||
loaderColor="white"
|
ref="modalButtonMain"
|
||||||
:buttonText="footerButtonText"
|
loaderColor="white"
|
||||||
@click-event="validateAndEmit"
|
:buttonText="footerButtonText"
|
||||||
:class="isFooterButtonDisabled && 'form-test-invalid'" />
|
@click-event="validateAndEmit"
|
||||||
</div>
|
:class="isFooterButtonDisabled && 'form-test-invalid'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -173,7 +173,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
padding: 1rem 0;
|
padding: 1rem 1.5rem;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
@ -216,8 +216,12 @@ export default {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
flex: none;
|
flex: none;
|
||||||
}
|
}
|
||||||
|
.textbox-question {
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modal-dialog-centered {
|
&.modal-dialog-centered {
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
@ -269,8 +273,6 @@ export default {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.textbox-question {
|
.textbox-question {
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
label {
|
label {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
|
|
@ -284,6 +286,10 @@ export default {
|
||||||
.modal-disclaimer {
|
.modal-disclaimer {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
order: 2;
|
order: 2;
|
||||||
|
text-align: left;
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
margin: 0 0 1.5rem 0;
|
margin: 0 0 1.5rem 0;
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ export default {
|
||||||
@include blue-gradient;
|
@include blue-gradient;
|
||||||
}
|
}
|
||||||
&:focus, // Mouse, touch, stylus focus
|
&:focus, // Mouse, touch, stylus focus
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
// Keyboard focus for accessibility
|
// Keyboard focus for accessibility
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@
|
||||||
<script>
|
<script>
|
||||||
import textLink from "@/ux-components/text-link/text-link";
|
import textLink from "@/ux-components/text-link/text-link";
|
||||||
import buttonMain from "@/ux-components/button-main/button-main";
|
import buttonMain from "@/ux-components/button-main/button-main";
|
||||||
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
|
import router from "@/router/index.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "navbar",
|
name: "navbar",
|
||||||
|
|
@ -94,10 +97,28 @@ export default {
|
||||||
document.onkeydown = function (e) {
|
document.onkeydown = function (e) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
this.$emit("ForwardClicked");
|
// check session expired and initSession to recreate cookies
|
||||||
|
if (analyticsMixin.methods.sessionExpired()) {
|
||||||
|
this.routeReturnUser();
|
||||||
|
} else {
|
||||||
|
this.$emit("ForwardClicked");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
linkClick() {
|
linkClick() {
|
||||||
this.$emit("BackClicked");
|
// check session expired and initSession to recreate cookies
|
||||||
|
if (analyticsMixin.methods.sessionExpired()) {
|
||||||
|
this.routeReturnUser();
|
||||||
|
} else {
|
||||||
|
this.$emit("BackClicked");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
routeReturnUser() {
|
||||||
|
analyticsMixin.methods.initSession();
|
||||||
|
|
||||||
|
router.push({
|
||||||
|
path: "/",
|
||||||
|
query: { fmgPage: fmgPageValues.RETURN_USER },
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="save-progress-modal-question">
|
<div class="save-progress-modal-question" :class="isProgressSaved ? 'progress-saved' : ''">
|
||||||
<buttonMain
|
<buttonMain
|
||||||
ref="buttonMain"
|
ref="buttonMain"
|
||||||
|
type="button"
|
||||||
v-if="!isProgressSaved"
|
v-if="!isProgressSaved"
|
||||||
:buttonText="buttonText"
|
:buttonText="buttonText"
|
||||||
loaderColor="white"
|
loaderColor="white"
|
||||||
|
|
@ -17,6 +18,7 @@
|
||||||
:ref="modalName"
|
:ref="modalName"
|
||||||
:headerText="modalHeaderText"
|
:headerText="modalHeaderText"
|
||||||
suppressPageScroll
|
suppressPageScroll
|
||||||
|
:onModalClosedCallback="onModalClosed"
|
||||||
:footerButtonText="modalButtonText"
|
:footerButtonText="modalButtonText"
|
||||||
@footer-button-event="saveProgress">
|
@footer-button-event="saveProgress">
|
||||||
<p class="modal-body-inner">{{ modalBodyText }}</p>
|
<p class="modal-body-inner">{{ modalBodyText }}</p>
|
||||||
|
|
@ -35,6 +37,7 @@ import modal from "@/digital-components/modal/modal";
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import buttonMain from "@/ux-components/button-main/button-main";
|
import buttonMain from "@/ux-components/button-main/button-main";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
|
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "save-progress-modal-question",
|
name: "save-progress-modal-question",
|
||||||
|
|
@ -50,6 +53,10 @@ export default {
|
||||||
modalWidgetName: String,
|
modalWidgetName: String,
|
||||||
pageName: String,
|
pageName: String,
|
||||||
},
|
},
|
||||||
|
unmounted() {
|
||||||
|
// remove any modal effects before leaving page (e.g. user hits browser back button)
|
||||||
|
this.modal.closeModal();
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
buttonText() {
|
buttonText() {
|
||||||
return this.getCmsContent(this.modalWidgetName, "SubheaderText");
|
return this.getCmsContent(this.modalWidgetName, "SubheaderText");
|
||||||
|
|
@ -78,17 +85,21 @@ export default {
|
||||||
this.modal.openModal();
|
this.modal.openModal();
|
||||||
this.modal.resetButtonStyle();
|
this.modal.resetButtonStyle();
|
||||||
},
|
},
|
||||||
|
onModalClosed() {
|
||||||
|
this.userInput = "";
|
||||||
|
this.modal.resetForm();
|
||||||
|
},
|
||||||
async saveProgress() {
|
async saveProgress() {
|
||||||
// save email address to store
|
// save email address to store
|
||||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.userInput, false);
|
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.userInput, false);
|
||||||
|
|
||||||
|
// send store call to send to new API (that triggers an email send)
|
||||||
|
await saveQuote({ pageNameToLog: this.pageName });
|
||||||
|
|
||||||
// hide save progress button; show success message alert
|
// hide save progress button; show success message alert
|
||||||
this.isProgressSaved = true;
|
this.isProgressSaved = true;
|
||||||
|
|
||||||
this.modal.closeModal();
|
this.modal.closeModal();
|
||||||
|
|
||||||
// send store call to send to new API (that triggers an email send)
|
|
||||||
this.$emit("save-progress");
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -113,6 +124,10 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
&.progress-saved {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
.save-progress-button {
|
.save-progress-button {
|
||||||
order: 4;
|
order: 4;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -125,7 +140,7 @@ export default {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 0.375rem;
|
text-underline-offset: 0.25rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
@ -148,6 +163,7 @@ export default {
|
||||||
:deep(.alert) {
|
:deep(.alert) {
|
||||||
border-radius: $border-radius-lg;
|
border-radius: $border-radius-lg;
|
||||||
border: 1px solid $green;
|
border: 1px solid $green;
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
:deep(.alert-heading) {
|
:deep(.alert-heading) {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
class="save-progress-popup-question" />
|
class="save-progress-popup-question" />
|
||||||
<buttonMain
|
<buttonMain
|
||||||
ref="skipButton"
|
ref="skipButton"
|
||||||
|
type="button"
|
||||||
:buttonText="buttonText"
|
:buttonText="buttonText"
|
||||||
loaderColor="white"
|
loaderColor="white"
|
||||||
:suppressLoader="true"
|
:suppressLoader="true"
|
||||||
|
|
@ -37,6 +38,7 @@ import modal from "@/digital-components/modal/modal";
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import buttonMain from "@/ux-components/button-main/button-main";
|
import buttonMain from "@/ux-components/button-main/button-main";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
|
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "save-progress-popup-question",
|
name: "save-progress-popup-question",
|
||||||
|
|
@ -50,6 +52,10 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.showSaveProgressPopup) this.modal.openModal();
|
if (this.showSaveProgressPopup) this.modal.openModal();
|
||||||
},
|
},
|
||||||
|
unmounted() {
|
||||||
|
// remove any modal effects before leaving page (e.g. user hits browser back button)
|
||||||
|
this.modal.closeModal();
|
||||||
|
},
|
||||||
emits: ["close-save-progress-popup", "save-progress"], // <--- should remove oodles of warnings in dev tools
|
emits: ["close-save-progress-popup", "save-progress"], // <--- should remove oodles of warnings in dev tools
|
||||||
props: {
|
props: {
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
|
|
@ -94,15 +100,14 @@ export default {
|
||||||
// save email address to store
|
// save email address to store
|
||||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.userInput, false);
|
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.userInput, false);
|
||||||
|
|
||||||
|
// send store call to send to new API (that triggers an email send)
|
||||||
|
await saveQuote({ pageNameToLog: this.pageName });
|
||||||
|
|
||||||
// hide save progress button; show success message alert
|
// hide save progress button; show success message alert
|
||||||
this.isProgressSaved = true;
|
this.isProgressSaved = true;
|
||||||
|
|
||||||
// send store call to send to new API (that triggers an email send)
|
// communicate to parent the new status
|
||||||
this.$emit("save-progress");
|
this.$emit("save-progress-saved");
|
||||||
|
|
||||||
// send call to close popup
|
|
||||||
this.closeModal();
|
|
||||||
this.$emit("close-save-progress-popup");
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -138,11 +143,12 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.skip-button {
|
.btn.btn-secondary.skip-button {
|
||||||
order: 4;
|
order: 4;
|
||||||
position: relative;
|
position: relative;
|
||||||
color: $black;
|
color: $black;
|
||||||
border: none;
|
border: none;
|
||||||
|
border-radius: 0.25rem;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -150,7 +156,7 @@ export default {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 0.375rem;
|
text-underline-offset: 0.25rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
padding: 0 0 4px 0;
|
padding: 0 0 4px 0;
|
||||||
margin: 0 auto 1.5rem auto;
|
margin: 0 auto 1.5rem auto;
|
||||||
|
|
@ -159,12 +165,17 @@ export default {
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus {
|
||||||
&:focus-visible {
|
|
||||||
color: $blue-700;
|
color: $blue-700;
|
||||||
background: none;
|
background: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 3px $white,
|
||||||
|
0 0 0 5.5px $blue-300;
|
||||||
|
}
|
||||||
|
|
||||||
&.delay {
|
&.delay {
|
||||||
// fixes flicker while transitioning between states
|
// fixes flicker while transitioning between states
|
||||||
|
|
@ -200,9 +211,6 @@ export default {
|
||||||
}
|
}
|
||||||
.modal-disclaimer {
|
.modal-disclaimer {
|
||||||
order: 4;
|
order: 4;
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.progress-saved {
|
&.progress-saved {
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,13 @@ export default {
|
||||||
|
|
||||||
if (error.response.status && error.response.status != "404") {
|
if (error.response.status && error.response.status != "404") {
|
||||||
// Do not route to error logic when no wipers found or no promo found (404s)
|
// Do not route to error logic when no wipers found or no promo found (404s)
|
||||||
router.navigateError();
|
const errorPayload = {
|
||||||
|
cause: `Response error ${error.response.status}`,
|
||||||
|
currentPage: pageNameToLog,
|
||||||
|
endpoint: endpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
router.navigateError(errorPayload);
|
||||||
|
|
||||||
// do not log 404 errors from services because we return NotFound
|
// do not log 404 errors from services because we return NotFound
|
||||||
// when a service doesn't return an object
|
// when a service doesn't return an object
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,10 @@ export async function getImplicitNavigation(toRoute) {
|
||||||
|
|
||||||
const skipVin = await skipVinLookup();
|
const skipVin = await skipVinLookup();
|
||||||
|
|
||||||
|
if (store.getters.order.payment.insuranceCoverage?.isVerified) {
|
||||||
|
return fmgPageValues.HERITAGE;
|
||||||
|
}
|
||||||
|
|
||||||
if (quoteComponent.methods.arePagePrerequisitesValid()) {
|
if (quoteComponent.methods.arePagePrerequisitesValid()) {
|
||||||
// Do not send to quote if verified insurance user.
|
// Do not send to quote if verified insurance user.
|
||||||
if (store.getters.requiresVerifiedRedirecting) {
|
if (store.getters.requiresVerifiedRedirecting) {
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,17 @@ export function getQuerystringParameter(key) {
|
||||||
|
|
||||||
return lowerCaseParams.get(key) ? lowerCaseParams.get(key) : null;
|
return lowerCaseParams.get(key) ? lowerCaseParams.get(key) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if you add the fmgPage to the querystringobject before calling, then pass true for skipFmgPageName
|
||||||
|
export function buildQuerystringObject(qso, skipFmgPageName=false) {
|
||||||
|
const queryString = window.location.search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
|
||||||
|
for (const [name, value] of urlParams) {
|
||||||
|
if (name.toLowerCase() === "fmgpage" && skipFmgPageName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qso[name] = value;
|
||||||
|
}
|
||||||
|
return qso;
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
<!-- save progress goes into <slot> on questions-page-layout -->
|
<!-- save progress goes into <slot> on questions-page-layout -->
|
||||||
<saveProgressModalQuestion
|
<saveProgressModalQuestion
|
||||||
modalWidgetName="SaveProgressModalWidget"
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
v-if="!isEmailInStoreOnPageLoad"
|
pageName="capability-questions"
|
||||||
@save-progress="saveProgress" />
|
v-if="showSaveProgressModal" />
|
||||||
</questions-page-layout>
|
</questions-page-layout>
|
||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
@ -65,7 +64,9 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next(async (vm) => {
|
next(async (vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
// turned off Save Your Progress for 1/23/25 release
|
||||||
|
// to restore, uncomment line below
|
||||||
|
// vm.showSaveProgressModal = !(emailFromStore?.length > 0);
|
||||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||||
await baseMixin.methods.dispatchStoreAction(
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
|
@ -87,7 +88,7 @@ export default {
|
||||||
questionsData: null,
|
questionsData: null,
|
||||||
selectedAnswers: {},
|
selectedAnswers: {},
|
||||||
currentGlassIndex: 0,
|
currentGlassIndex: 0,
|
||||||
isEmailInStoreOnPageLoad: null,
|
showSaveProgressModal: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -157,9 +158,6 @@ export default {
|
||||||
this.questionsData
|
this.questionsData
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
saveProgress() {
|
|
||||||
saveQuote({ pageNameToLog: "capability-questions" });
|
|
||||||
},
|
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||||
// get answerResult2 of returned answer
|
// get answerResult2 of returned answer
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
<!-- save progress goes into <slot> on questions-page-layout -->
|
<!-- save progress goes into <slot> on questions-page-layout -->
|
||||||
<saveProgressModalQuestion
|
<saveProgressModalQuestion
|
||||||
modalWidgetName="SaveProgressModalWidget"
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
v-if="!isEmailInStoreOnPageLoad"
|
pageName="molding-questions"
|
||||||
@save-progress="saveProgress" />
|
v-if="showSaveProgressModal" />
|
||||||
</questions-page-layout>
|
</questions-page-layout>
|
||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
@ -65,7 +64,9 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next(async (vm) => {
|
next(async (vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
// turned off Save Your Progress for 1/23/25 release
|
||||||
|
// to restore, uncomment line below
|
||||||
|
// vm.showSaveProgressModal = !(emailFromStore?.length > 0);
|
||||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||||
await baseMixin.methods.dispatchStoreAction(
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
|
@ -88,7 +89,7 @@ export default {
|
||||||
questionsData: null,
|
questionsData: null,
|
||||||
selectedAnswers: {},
|
selectedAnswers: {},
|
||||||
currentGlassIndex: 0,
|
currentGlassIndex: 0,
|
||||||
isEmailInStoreOnPageLoad: null,
|
showSaveProgressModal: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -157,9 +158,6 @@ export default {
|
||||||
this.questionsData
|
this.questionsData
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
saveProgress() {
|
|
||||||
saveQuote({ pageNameToLog: "molding-questions" });
|
|
||||||
},
|
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
<!-- save progress goes into <slot> on questions-page-layout -->
|
<!-- save progress goes into <slot> on questions-page-layout -->
|
||||||
<saveProgressModalQuestion
|
<saveProgressModalQuestion
|
||||||
modalWidgetName="SaveProgressModalWidget"
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
v-if="!isEmailInStoreOnPageLoad"
|
pageName="part-questions"
|
||||||
@save-progress="saveProgress" />
|
v-if="showSaveProgressModal" />
|
||||||
</questions-page-layout>
|
</questions-page-layout>
|
||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
@ -65,7 +64,9 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next(async (vm) => {
|
next(async (vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
// turned off Save Your Progress for 1/23/25 release
|
||||||
|
// to restore, uncomment line below
|
||||||
|
// vm.showSaveProgressModal = !(emailFromStore?.length > 0);
|
||||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||||
const serviceState = store.getters.order.serviceLocation.state;
|
const serviceState = store.getters.order.serviceLocation.state;
|
||||||
|
|
@ -89,7 +90,7 @@ export default {
|
||||||
questionsData: null,
|
questionsData: null,
|
||||||
selectedAnswers: {},
|
selectedAnswers: {},
|
||||||
currentGlassIndex: 0,
|
currentGlassIndex: 0,
|
||||||
isEmailInStoreOnPageLoad: null,
|
showSaveProgressModal: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -156,9 +157,6 @@ export default {
|
||||||
this.questionsData
|
this.questionsData
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
saveProgress() {
|
|
||||||
saveQuote({ pageNameToLog: "part-questions" });
|
|
||||||
},
|
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -429,7 +429,8 @@ export default {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
{
|
{
|
||||||
const log = getQuerystringParameter(queryStrings.LOG);
|
const log = getQuerystringParameter(queryStrings.LOG);
|
||||||
if (eval(log) || !preReqResult) {
|
const logAsBool = (log?.toLowerCase() === "true");
|
||||||
|
if (logAsBool || !preReqResult) {
|
||||||
console.log("------------- payment-method.vue pagePrereqs start -----------------");
|
console.log("------------- payment-method.vue pagePrereqs start -----------------");
|
||||||
console.log(new Date() + " serviceLocationReqs::isMobile: " + isMobile);
|
console.log(new Date() + " serviceLocationReqs::isMobile: " + isMobile);
|
||||||
console.log(new Date() + " serviceLocationReqs::mobileReqs: " + mobileReqs);
|
console.log(new Date() + " serviceLocationReqs::mobileReqs: " + mobileReqs);
|
||||||
|
|
@ -621,7 +622,7 @@ export default {
|
||||||
: this.$store.getters.order.serviceLocation?.appointmentType;
|
: this.$store.getters.order.serviceLocation?.appointmentType;
|
||||||
},
|
},
|
||||||
ServiceLocationFullAddressText() {
|
ServiceLocationFullAddressText() {
|
||||||
return `${this.ServiceLocationAddress.toLowerCase()}${this.ServiceLocationAddress2 ? ", " + this.ServiceLocationAddress2 : ""}, ${this.ServiceLocationCity.toLowerCase()}, ${this.ServiceLocationState} ${this.ServiceLocationZipCode}`;
|
return `${this.ServiceLocationAddress?.toLowerCase()}${this.ServiceLocationAddress2 ? ", " + this.ServiceLocationAddress2 : ""}, ${this.ServiceLocationCity?.toLowerCase()}, ${this.ServiceLocationState} ${this.ServiceLocationZipCode}`;
|
||||||
},
|
},
|
||||||
ServiceLocationFullAddress() {
|
ServiceLocationFullAddress() {
|
||||||
if (this.AppointmentType === AppointmentTypeStrings.MOBILE) {
|
if (this.AppointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
displayContent() {
|
displayContent() {
|
||||||
return [
|
return [
|
||||||
`${this.addressInfo.address.toLowerCase()}${this.addressInfo.address2 ? ", " : ""}${this.addressInfo.address2.toLowerCase()}, ${this.addressInfo.city.toLowerCase()}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`,
|
`${this.addressInfo?.address?.toLowerCase()}${this.addressInfo?.address2 ? ", " : ""}${this.addressInfo?.address2?.toLowerCase()}, ${this.addressInfo?.city?.toLowerCase()}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
addressInfo() {
|
addressInfo() {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-12 col-xl-8">
|
<div class="col-md-12 mb-5" :class="getColCount()">
|
||||||
<servicePackageQuestion
|
<servicePackageQuestion
|
||||||
ref="servicePackage"
|
ref="servicePackage"
|
||||||
cashCmsWidgetName="CashServicePackageQuestionWidget"
|
cashCmsWidgetName="CashServicePackageQuestionWidget"
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
:shouldHideRecalibration="shouldHideRecalibration"
|
:shouldHideRecalibration="shouldHideRecalibration"
|
||||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||||
@servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
|
@servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
|
||||||
|
@currentNumberOfPackages="currentNumberOfPackagesAction"
|
||||||
:servicePackage="servicePackage"
|
:servicePackage="servicePackage"
|
||||||
:activePromos="lineItems.promos"
|
:activePromos="lineItems.promos"
|
||||||
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
||||||
|
|
@ -40,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-12 col-xl-8 p-md-0">
|
<div class="col-md-12" :class="getColCount()">
|
||||||
<!-- If Cash AND vehicle does not require recal OR if Cash AND State requires showing recal, then show Afterpay banner -->
|
<!-- If Cash AND vehicle does not require recal OR if Cash AND State requires showing recal, then show Afterpay banner -->
|
||||||
<afterpayModalBanner
|
<afterpayModalBanner
|
||||||
v-if="showAfterpayBanner"
|
v-if="showAfterpayBanner"
|
||||||
|
|
@ -82,8 +83,8 @@
|
||||||
<saveProgressModalQuestion
|
<saveProgressModalQuestion
|
||||||
modalWidgetName="SaveProgressModalWidget"
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
modalName="SaveProgressModal"
|
modalName="SaveProgressModal"
|
||||||
v-if="!isEmailInStoreOnPageLoad"
|
v-if="showSaveProgressModal"
|
||||||
@save-progress="saveProgress" />
|
pageName="quote" />
|
||||||
|
|
||||||
<textBlock
|
<textBlock
|
||||||
cmsWidgetName="quoteDisclaimer"
|
cmsWidgetName="quoteDisclaimer"
|
||||||
|
|
@ -98,9 +99,10 @@
|
||||||
<saveProgressPopupQuestion
|
<saveProgressPopupQuestion
|
||||||
modalWidgetName="SaveProgressPopupWidget"
|
modalWidgetName="SaveProgressPopupWidget"
|
||||||
modalName="SaveProgressPopup"
|
modalName="SaveProgressPopup"
|
||||||
v-if="!isEmailInStoreOnPageLoad && showSaveProgressPopup"
|
pageName="quote"
|
||||||
|
v-if="showSaveProgressPopup"
|
||||||
:showSaveProgressPopup="showSaveProgressPopup"
|
:showSaveProgressPopup="showSaveProgressPopup"
|
||||||
@save-progress="saveProgress"
|
@save-progress-saved="updateSaveProgressAsSaved"
|
||||||
@close-save-progress-popup="closeSaveProgressPopup" />
|
@close-save-progress-popup="closeSaveProgressPopup" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -209,6 +211,7 @@ export default {
|
||||||
const emailFromStore = store.getters.order.customer.emailAddress;
|
const emailFromStore = store.getters.order.customer.emailAddress;
|
||||||
const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
||||||
const showSaveProgressPopup = isEmailInStoreOnPageLoad ? false : true;
|
const showSaveProgressPopup = isEmailInStoreOnPageLoad ? false : true;
|
||||||
|
const showSaveProgressModal = isEmailInStoreOnPageLoad ? false : true;
|
||||||
|
|
||||||
const lineItems = deepClone(store.getters.order.lineItems);
|
const lineItems = deepClone(store.getters.order.lineItems);
|
||||||
lineItems.vaps = lineItems.vaps ?? [];
|
lineItems.vaps = lineItems.vaps ?? [];
|
||||||
|
|
@ -290,8 +293,12 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next(async (vm) => {
|
next(async (vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.isEmailInStoreOnPageLoad = isEmailInStoreOnPageLoad;
|
|
||||||
vm.showSaveProgressPopup = showSaveProgressPopup;
|
// turned off Save Your Progress for 1/23/25 release
|
||||||
|
// to restore, uncomment the 2 lines below
|
||||||
|
// vm.showSaveProgressPopup = showSaveProgressPopup;
|
||||||
|
// vm.showSaveProgressModal = showSaveProgressModal;
|
||||||
|
|
||||||
vm.addableVaps = addableVaps;
|
vm.addableVaps = addableVaps;
|
||||||
vm.lineItems = lineItems;
|
vm.lineItems = lineItems;
|
||||||
vm.availableLineItems = pricingResults;
|
vm.availableLineItems = pricingResults;
|
||||||
|
|
@ -438,10 +445,15 @@ export default {
|
||||||
servicePackage: null,
|
servicePackage: null,
|
||||||
holdParentAccountNumber: null,
|
holdParentAccountNumber: null,
|
||||||
holdBillToAccountNumber: null,
|
holdBillToAccountNumber: null,
|
||||||
isEmailInStoreOnPageLoad: null,
|
|
||||||
showSaveProgressPopup: null,
|
showSaveProgressPopup: null,
|
||||||
|
showSaveProgressModal: null,
|
||||||
|
isSaveProgressComplete: null,
|
||||||
|
packageNumber: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.attachCustomEvents();
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
lineItemsCloneForWatcher() {
|
lineItemsCloneForWatcher() {
|
||||||
return Object.assign({}, this.lineItems);
|
return Object.assign({}, this.lineItems);
|
||||||
|
|
@ -486,6 +498,16 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getColCount() {
|
||||||
|
if (this.packageNumber > 2) {
|
||||||
|
return "col-xl-8";
|
||||||
|
} else {
|
||||||
|
return "col-xl-6";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentNumberOfPackagesAction(packageNumber) {
|
||||||
|
this.packageNumber = packageNumber;
|
||||||
|
},
|
||||||
openModalAction(modalName) {
|
openModalAction(modalName) {
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
},
|
},
|
||||||
|
|
@ -526,10 +548,8 @@ export default {
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
vehicleQuestionsMixin.methods.navigateBack(this);
|
vehicleQuestionsMixin.methods.navigateBack(this);
|
||||||
},
|
},
|
||||||
saveProgress() {
|
updateSaveProgressAsSaved() {
|
||||||
this.isEmailInStoreOnPageLoad = true;
|
this.showSaveProgressModal = false;
|
||||||
this.showSaveProgressPopup = false;
|
|
||||||
saveQuote({ pageNameToLog: "quote" });
|
|
||||||
},
|
},
|
||||||
closeSaveProgressPopup() {
|
closeSaveProgressPopup() {
|
||||||
this.showSaveProgressPopup = false;
|
this.showSaveProgressPopup = false;
|
||||||
|
|
@ -677,9 +697,6 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.attachCustomEvents();
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
lineItemsCloneForWatcher: {
|
lineItemsCloneForWatcher: {
|
||||||
handler(newValue, oldValue) {
|
handler(newValue, oldValue) {
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ export default {
|
||||||
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
this.$emit("currentNumberOfPackages", modifiedAnswers.length);
|
||||||
return modifiedAnswers;
|
return modifiedAnswers;
|
||||||
},
|
},
|
||||||
isServicePackageDiscountOnOrder() {
|
isServicePackageDiscountOnOrder() {
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,22 @@ export default {
|
||||||
.package-main {
|
.package-main {
|
||||||
.package-wrapper {
|
.package-wrapper {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
|
&:first-child {
|
||||||
|
margin: 1rem 0 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin: 1rem 0 0 0;
|
||||||
|
}
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
margin: 1rem 0.5rem;
|
margin: 1rem 0.5rem 0 0.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
&:first-child {
|
||||||
|
margin: 1rem 0.5rem 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin: 1rem 0 0 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
|
@ -322,6 +334,7 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
align-self: flex-start;
|
||||||
div.strikethrough-discount-price {
|
div.strikethrough-discount-price {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
|
|
||||||
312
src/layouts/return-user/return-user.spec.js
Normal file
312
src/layouts/return-user/return-user.spec.js
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
// Components
|
||||||
|
import returnUser from "@/layouts/return-user/return-user.vue";
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||||
|
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import { dispatchStoreAction } from "@/mixins/base-mixin.js";
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
|
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
||||||
|
import { Form } from "vee-validate";
|
||||||
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
|
||||||
|
import { experimentSettings } from "../../constants/experiments";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import buttonMain from "@/ux-components/button-main/button-main";
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
|
||||||
|
// Setup global mocks
|
||||||
|
let mockStoreActionData = {};
|
||||||
|
|
||||||
|
let mockStoreData = {};
|
||||||
|
let mockExperimentSettings = {
|
||||||
|
experiments: [
|
||||||
|
{
|
||||||
|
universeName: "ConceptFunnel",
|
||||||
|
settings: {
|
||||||
|
SuppressVinCapture: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function resetMockStoreData() {
|
||||||
|
mockStoreData = {
|
||||||
|
vehicle: {
|
||||||
|
year: "2000",
|
||||||
|
make: "TestMake",
|
||||||
|
model: "TestModel",
|
||||||
|
style: "TestStyle",
|
||||||
|
carId: "TestID",
|
||||||
|
vin: null,
|
||||||
|
registration: {
|
||||||
|
licensePlate: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
address: null,
|
||||||
|
address2: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null,
|
||||||
|
appointmentType: null,
|
||||||
|
isVehicleProtected: null,
|
||||||
|
provider: {
|
||||||
|
providerNumber: null,
|
||||||
|
address: {
|
||||||
|
streetAddress: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
techNotes: null,
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
firstName: null,
|
||||||
|
lastName: null,
|
||||||
|
emailAddress: null,
|
||||||
|
phoneNumber: null,
|
||||||
|
isSmsOptIn: null,
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [{ glassLocation: "Windshield", glassName: "windshield" }],
|
||||||
|
partQuestionAnswers: null,
|
||||||
|
moldingQuestionAnswers: null,
|
||||||
|
capabilityQuestionAnswers: null,
|
||||||
|
dateOfLoss: null,
|
||||||
|
damageCause: null,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [
|
||||||
|
{
|
||||||
|
canSafeliteRecalibrate: true,
|
||||||
|
childParts: [
|
||||||
|
{
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 23.55,
|
||||||
|
partNumber: "GGG FW4896",
|
||||||
|
salesTax: 1.77,
|
||||||
|
sellingPrice: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
color: "Green Tint",
|
||||||
|
description:
|
||||||
|
"solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
|
||||||
|
id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 60,
|
||||||
|
partNumber: "FW04896GTYN",
|
||||||
|
partType: "WINDSHIELD",
|
||||||
|
recalibrationType: "STATIC",
|
||||||
|
requiresCapabilityQuestions: false,
|
||||||
|
requiresRecalibration: true,
|
||||||
|
salesTax: 63.86,
|
||||||
|
sellingPrice: 791.46,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
supportingItems: null,
|
||||||
|
vaps: null,
|
||||||
|
serverData: null,
|
||||||
|
promos: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: null,
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: null,
|
||||||
|
coverageStatus: null,
|
||||||
|
coverageType: null,
|
||||||
|
coverageVerificationType: null,
|
||||||
|
},
|
||||||
|
parentAccountNumber: 0,
|
||||||
|
billToAccountNumber: null,
|
||||||
|
isPia: null,
|
||||||
|
piaType: null,
|
||||||
|
inactivePromos: null,
|
||||||
|
paypalToken: null,
|
||||||
|
nextGenSettledAmount: 0,
|
||||||
|
ccToken: {
|
||||||
|
subscriptionId: null,
|
||||||
|
expMonth: null,
|
||||||
|
expYear: null,
|
||||||
|
cardType: null,
|
||||||
|
billToPostalCode: null,
|
||||||
|
billToFirstName: null,
|
||||||
|
billToLastName: null,
|
||||||
|
referenceNumber: null,
|
||||||
|
authCode: null,
|
||||||
|
transactionId: null,
|
||||||
|
transReferenceNumber: null,
|
||||||
|
lastFour: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
policy: {
|
||||||
|
currentDeductible: 0,
|
||||||
|
policyNumber: null,
|
||||||
|
isItac: false,
|
||||||
|
additionalAuthFlag: null,
|
||||||
|
isNoComp: false,
|
||||||
|
insuranceCompanyName: null,
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
routeCode: null,
|
||||||
|
jobMaxMinutes: null,
|
||||||
|
jobMinMinutes: null,
|
||||||
|
},
|
||||||
|
externalParameterServiceZip: {
|
||||||
|
zipCode: null,
|
||||||
|
emailAddress: null,
|
||||||
|
},
|
||||||
|
externalParameterState: { isExternalParameter: false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMockStoreDataToGetters() {
|
||||||
|
store.getters = {
|
||||||
|
vehicle: mockStoreData.vehicle,
|
||||||
|
};
|
||||||
|
store.state.order = mockStoreData;
|
||||||
|
store.state.applicationUser.experiments = mockExperimentSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mockDispatchStoreAction(actionName) {
|
||||||
|
return mockStoreActionData[actionName];
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
|
methods: {
|
||||||
|
dispatchStoreAction: jest.fn(),
|
||||||
|
dispatchStoreActionWithLogging: jest.fn().mockImplementation(mockDispatchStoreAction),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||||
|
fetchCmsContentForPage: () => Promise.resolve("content"),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
|
||||||
|
saveSession: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({
|
||||||
|
deleteFunnelCookie: jest.fn(),
|
||||||
|
getFunnelCookie: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
router.navigateWithoutSaving = jest.fn();
|
||||||
|
router.navigateWithSaving = jest.fn();
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
describe("return-user.vue", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resetMockStoreData();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test prerequisites are valid and child components are rendered", () => {
|
||||||
|
test("expect pagePrerequisites are valid to be called", () => {
|
||||||
|
// Arrange
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
|
||||||
|
applyMockStoreDataToGetters();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const pagePrerequisitesSpy = jest.spyOn(wrapper.vm, "arePagePrerequisitesValid");
|
||||||
|
|
||||||
|
wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(pagePrerequisitesSpy).toBeCalled();
|
||||||
|
expect(getFunnelCookie).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders child components", () => {
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
|
||||||
|
expect(wrapper.findComponent(funnelHeader).exists()).toBe(true);
|
||||||
|
expect(wrapper.findComponent(funnelSubHeader).exists()).toBe(true);
|
||||||
|
expect(wrapper.findComponent(navbar).exists()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Navigation", () => {
|
||||||
|
test("Check forwardButtonAction is working", async () => {
|
||||||
|
// Arrange
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
// Act
|
||||||
|
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
|
||||||
|
navigationScenarios.CLICKED_FORWARD,
|
||||||
|
wrapper.vm.$route
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("expect functions in startOver to be called", async () => {
|
||||||
|
//Arrange
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const dispatchStoreActionSpy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
await wrapper.vm.startOver();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
|
||||||
|
navigationScenarios.CLICKED_FORWARD,
|
||||||
|
wrapper.vm.$route
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(dispatchStoreActionSpy).toHaveBeenCalledWith(storeActions.RESET_STATE);
|
||||||
|
expect(deleteFunnelCookie).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks({ customMountOptions }) {
|
||||||
|
const route = { query: { fmgPage: "return-user" }, params: {} };
|
||||||
|
|
||||||
|
baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn();
|
||||||
|
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
...customMountOptions,
|
||||||
|
route: route,
|
||||||
|
});
|
||||||
|
|
||||||
|
mountOptions.global.mocks["$store"] = store;
|
||||||
|
mountOptions.global.mocks["$router"] = router;
|
||||||
|
baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true);
|
||||||
|
mountOptions["attachTo"] = document.body;
|
||||||
|
|
||||||
|
const wrapper = shallowMount(returnUser, mountOptions, {
|
||||||
|
stubs: {
|
||||||
|
Form,
|
||||||
|
funnelHeader,
|
||||||
|
funnelSubHeader,
|
||||||
|
navbar,
|
||||||
|
loadingModal: true,
|
||||||
|
buttonMain,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
129
src/layouts/return-user/return-user.vue
Normal file
129
src/layouts/return-user/return-user.vue
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
<template>
|
||||||
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||||
|
<div class="return-user small-question-text">
|
||||||
|
<loadingModal ref="loadingModal" />
|
||||||
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center return-user-spacing">
|
||||||
|
<div class="col-md-6 col-xl-4 mt-4">
|
||||||
|
<funnelSubHeader
|
||||||
|
ref="funnelSubHeader"
|
||||||
|
cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6 col-xl-4">
|
||||||
|
<navbar
|
||||||
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
ref="navbar"
|
||||||
|
buttonSize
|
||||||
|
:isBackButtonHidden="true"
|
||||||
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6 col-xl-4 start-over">
|
||||||
|
<a @click="startOver" alt="Start Over Button"
|
||||||
|
><img v-bind:src="startOverImage" />{{ startOverText }}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Components
|
||||||
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||||
|
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||||
|
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
||||||
|
// Supporting Files
|
||||||
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import { Form } from "vee-validate";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "return-user",
|
||||||
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
// Call APIs
|
||||||
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
// Settle promises and get results
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: "cmsContent",
|
||||||
|
promise: cmsContentPromise,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
// Call the "next" function to complete the transition to this page.
|
||||||
|
next((vm) => {
|
||||||
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
vm.startOverText = resultMap.cmsContent.StartOverWidget.HeaderText;
|
||||||
|
vm.startOverImage = resultMap.cmsContent.StartOverWidget.Image;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
startOverText: "",
|
||||||
|
startOverImage: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
arePagePrerequisitesValid() {
|
||||||
|
return getFunnelCookie() !== null;
|
||||||
|
},
|
||||||
|
|
||||||
|
async forwardButtonAction() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
this.navigationScenarios.CLICKED_FORWARD,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async startOver() {
|
||||||
|
this.pushEventToGA(
|
||||||
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
|
this.GaActions.CLICKED,
|
||||||
|
"Start over",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
deleteFunnelCookie();
|
||||||
|
await this.dispatchStoreAction(storeActions.RESET_STATE);
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
this.navigationScenarios.CLICKED_FORWARD,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Form,
|
||||||
|
funnelHeader,
|
||||||
|
funnelSubHeader,
|
||||||
|
navbar,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.start-over {
|
||||||
|
text-align: center;
|
||||||
|
a {
|
||||||
|
font-weight: 600;
|
||||||
|
color: $black;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.return-user {
|
||||||
|
.return-user-spacing {
|
||||||
|
margin-top: 14rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -11,7 +11,10 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
|
||||||
// Get the Mobile Fee Part
|
// Get the Mobile Fee Part
|
||||||
const mobileFeePart = await baseMixin.methods.dispatchStoreActionWithLogging(
|
const mobileFeePart = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
storeActions.GET_MOBILE_FEE_PART,
|
storeActions.GET_MOBILE_FEE_PART,
|
||||||
null,
|
{
|
||||||
|
serviceZipCode: serviceZipCode,
|
||||||
|
serviceZipCodeCtu: zipCodeData.zipCodeCtu,
|
||||||
|
},
|
||||||
pageNameToLog,
|
pageNameToLog,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -241,57 +241,46 @@ export default {
|
||||||
this.displayMismatchStateAndZipAlert = false;
|
this.displayMismatchStateAndZipAlert = false;
|
||||||
},
|
},
|
||||||
async setMobileLocation() {
|
async setMobileLocation() {
|
||||||
if (
|
this.resetAlerts();
|
||||||
this.internalModel.addressQuestions.zipCode !==
|
// Validate the Zip Code
|
||||||
this.modelValue.addressQuestions.zipCode
|
const zipCodeData = await this.getZipCodeData(
|
||||||
) {
|
this.internalModel.addressQuestions.zipCode,
|
||||||
this.resetAlerts();
|
"service-location"
|
||||||
// Validate the Zip Code
|
);
|
||||||
const zipCodeData = await this.getZipCodeData(
|
|
||||||
this.internalModel.addressQuestions.zipCode,
|
if (!zipCodeData.isValid) {
|
||||||
|
this.displayInvalidZipAlert = true;
|
||||||
|
this.resetModalButtonStyle();
|
||||||
|
} else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
|
||||||
|
this.displayMismatchStateAndZipAlert = true;
|
||||||
|
this.resetModalButtonStyle();
|
||||||
|
} else {
|
||||||
|
// retrieve mobile fee part
|
||||||
|
const serviceZipCode = this.internalModel.addressQuestions.zipCode;
|
||||||
|
const mobileFeePart = await getPricedMobileFeePart(
|
||||||
|
serviceZipCode,
|
||||||
"service-location"
|
"service-location"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!zipCodeData.isValid) {
|
// retrieve serviceability details
|
||||||
this.displayInvalidZipAlert = true;
|
const serviceabilityDetails = await getServiceabilityDetails(
|
||||||
this.resetModalButtonStyle();
|
serviceZipCode,
|
||||||
} else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
|
null,
|
||||||
this.displayMismatchStateAndZipAlert = true;
|
"service-location"
|
||||||
this.resetModalButtonStyle();
|
);
|
||||||
} else {
|
|
||||||
// retrieve mobile fee part
|
|
||||||
const serviceZipCode = this.internalModel.addressQuestions.zipCode;
|
|
||||||
const mobileFeePart = await getPricedMobileFeePart(
|
|
||||||
serviceZipCode,
|
|
||||||
"service-location"
|
|
||||||
);
|
|
||||||
|
|
||||||
// retrieve serviceability details
|
const billToAccountNumber = await getBillToAccountNumber(
|
||||||
const serviceabilityDetails = await getServiceabilityDetails(
|
this.internalModel.zipCodeCtu
|
||||||
serviceZipCode,
|
);
|
||||||
null,
|
|
||||||
"service-location"
|
|
||||||
);
|
|
||||||
|
|
||||||
const billToAccountNumber = await getBillToAccountNumber(
|
// update content related to service zip code
|
||||||
this.internalModel.zipCodeCtu
|
this.$emit("updated-mobile-fee-part", mobileFeePart);
|
||||||
);
|
this.$emit("updated-serviceability", serviceabilityDetails.data);
|
||||||
|
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
||||||
|
this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
|
||||||
|
this.$emit("updated-bill-to-account-number", billToAccountNumber);
|
||||||
|
|
||||||
// update content related to service zip code
|
// update the page level model
|
||||||
this.$emit("updated-mobile-fee-part", mobileFeePart);
|
|
||||||
this.$emit("updated-serviceability", serviceabilityDetails.data);
|
|
||||||
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
|
||||||
this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
|
|
||||||
this.$emit("updated-bill-to-account-number", billToAccountNumber);
|
|
||||||
|
|
||||||
// update the page level model
|
|
||||||
this.$emit("update:modelValue", this.internalModel);
|
|
||||||
|
|
||||||
//Page advance to Schedule page
|
|
||||||
this.$emit("mobileLocationSelected");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Update the page level model
|
|
||||||
this.$emit("update:modelValue", this.internalModel);
|
this.$emit("update:modelValue", this.internalModel);
|
||||||
|
|
||||||
//Page advance to Schedule page
|
//Page advance to Schedule page
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,9 @@ beforeEach(() => {
|
||||||
zipCode: "43235",
|
zipCode: "43235",
|
||||||
state: "OH",
|
state: "OH",
|
||||||
},
|
},
|
||||||
|
vehicle: {
|
||||||
|
isMobileStaticRecalibrationApplicable: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
damage: {
|
damage: {
|
||||||
isRepair: false,
|
isRepair: false,
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ import { defineRule } from "vee-validate";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
||||||
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
|
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
|
||||||
|
const MOBILE_STATIC_RECAL_FEE_PART_NUMBER = "RECAL MOBILE";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("mobile-location-required", (value) => {
|
defineRule("mobile-location-required", (value) => {
|
||||||
|
|
@ -188,6 +189,8 @@ export default {
|
||||||
isRecalibrationServiceableInshop: null,
|
isRecalibrationServiceableInshop: null,
|
||||||
isGlassServiceableMobile: null,
|
isGlassServiceableMobile: null,
|
||||||
isRecalibrationServiceableMobile: null,
|
isRecalibrationServiceableMobile: null,
|
||||||
|
isVehicleMobileStaticRecalibrationApplicable:
|
||||||
|
this.getIsVehicleMobileStaticRecalibrationApplicableFromStore(),
|
||||||
selectedAppointmentType: this.getSelectedAppointmentType(),
|
selectedAppointmentType: this.getSelectedAppointmentType(),
|
||||||
selectedProvider: this.getSelectedProvider(),
|
selectedProvider: this.getSelectedProvider(),
|
||||||
mobileFeePart: null,
|
mobileFeePart: null,
|
||||||
|
|
@ -306,11 +309,21 @@ export default {
|
||||||
},
|
},
|
||||||
isServiceableMobile() {
|
isServiceableMobile() {
|
||||||
if (this.isRecalibrationServiceableMobile !== null) {
|
if (this.isRecalibrationServiceableMobile !== null) {
|
||||||
return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile;
|
return (
|
||||||
|
(this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile) ||
|
||||||
|
this.isMobileStaticRecalibrationApplicable
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return this.isGlassServiceableMobile;
|
return this.isGlassServiceableMobile;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isMobileStaticRecalibrationApplicable() {
|
||||||
|
return (
|
||||||
|
this.isVehicleMobileStaticRecalibrationApplicable &&
|
||||||
|
this.mobileFeePart?.partNumber == MOBILE_STATIC_RECAL_FEE_PART_NUMBER &&
|
||||||
|
(this.isInsurance ? this.mobileFeePart?.isInsurable : true)
|
||||||
|
);
|
||||||
|
},
|
||||||
mobileFeeApplies() {
|
mobileFeeApplies() {
|
||||||
if (
|
if (
|
||||||
this.mobileFeePart?.laborAmount > 0 ||
|
this.mobileFeePart?.laborAmount > 0 ||
|
||||||
|
|
@ -349,7 +362,8 @@ export default {
|
||||||
return (
|
return (
|
||||||
this.isServiceableInshop &&
|
this.isServiceableInshop &&
|
||||||
this.isGlassServiceableMobile &&
|
this.isGlassServiceableMobile &&
|
||||||
this.isRecalibrationServiceableMobile === false
|
this.isRecalibrationServiceableMobile === false &&
|
||||||
|
!this.isMobileStaticRecalibrationApplicable
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
displayRecalibrationWarning() {
|
displayRecalibrationWarning() {
|
||||||
|
|
@ -485,6 +499,9 @@ export default {
|
||||||
getSelectedProvider() {
|
getSelectedProvider() {
|
||||||
return store.getters.order.serviceLocation.provider;
|
return store.getters.order.serviceLocation.provider;
|
||||||
},
|
},
|
||||||
|
getIsVehicleMobileStaticRecalibrationApplicableFromStore() {
|
||||||
|
return store.getters.order.vehicle.isMobileStaticRecalibrationApplicable;
|
||||||
|
},
|
||||||
resetMobileLocation() {
|
resetMobileLocation() {
|
||||||
this.streetAddress = "";
|
this.streetAddress = "";
|
||||||
this.apartmentNumberOrBusinessName = "";
|
this.apartmentNumberOrBusinessName = "";
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@
|
||||||
|
|
||||||
<saveProgressModalQuestion
|
<saveProgressModalQuestion
|
||||||
modalWidgetName="SaveProgressModalWidget"
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
v-if="!isEmailInStoreOnPageLoad"
|
pageName="vehicle-parts"
|
||||||
@save-progress="saveProgress" />
|
v-if="showSaveProgressModal" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -75,7 +75,6 @@ import store from "@/store";
|
||||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "vehicle-parts",
|
name: "vehicle-parts",
|
||||||
|
|
@ -95,7 +94,10 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
// turned off Save Your Progress for 1/23/25 release
|
||||||
|
// to restore, uncomment line below
|
||||||
|
// vm.showSaveProgressModal = !(emailFromStore?.length > 0);
|
||||||
|
|
||||||
// Glass Part Question dynamic component
|
// Glass Part Question dynamic component
|
||||||
Object.keys(vm.$refs)
|
Object.keys(vm.$refs)
|
||||||
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
||||||
|
|
@ -115,7 +117,7 @@ export default {
|
||||||
selectedGlassParts: {},
|
selectedGlassParts: {},
|
||||||
alertWidgetData: Object,
|
alertWidgetData: Object,
|
||||||
alreadyPopulatedPartsData: [],
|
alreadyPopulatedPartsData: [],
|
||||||
isEmailInStoreOnPageLoad: null,
|
showSaveProgressModal: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -234,9 +236,6 @@ export default {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
saveProgress() {
|
|
||||||
saveQuote({ pageNameToLog: "vehicle-parts" });
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.LoadInitialPartsData();
|
this.LoadInitialPartsData();
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ export default {
|
||||||
modelOptions: [],
|
modelOptions: [],
|
||||||
styleOptions: [],
|
styleOptions: [],
|
||||||
displayNoServiceAlert: false,
|
displayNoServiceAlert: false,
|
||||||
|
isMobileStaticRecalibrationApplicable: this.getIsMobileStaticRecalibrationApplicable(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -438,6 +439,8 @@ export default {
|
||||||
this.imageVifNumber = result?.data.imageVifNumber;
|
this.imageVifNumber = result?.data.imageVifNumber;
|
||||||
this.imageVifColor = result?.data.imageVifColor;
|
this.imageVifColor = result?.data.imageVifColor;
|
||||||
this.displayNoServiceAlert = !result?.data.canSafeliteService;
|
this.displayNoServiceAlert = !result?.data.canSafeliteService;
|
||||||
|
this.isMobileStaticRecalibrationApplicable =
|
||||||
|
result?.data.isMobileStaticRecalibrationApplicable;
|
||||||
},
|
},
|
||||||
resetAlert() {
|
resetAlert() {
|
||||||
this.displayNoServiceAlert = false;
|
this.displayNoServiceAlert = false;
|
||||||
|
|
@ -456,6 +459,8 @@ export default {
|
||||||
imageUrl: this.imageUrl,
|
imageUrl: this.imageUrl,
|
||||||
imageVifNumber: this.imageVifNumber,
|
imageVifNumber: this.imageVifNumber,
|
||||||
imageVifColor: this.imageVifColor,
|
imageVifColor: this.imageVifColor,
|
||||||
|
isMobileStaticRecalibrationApplicable:
|
||||||
|
this.isMobileStaticRecalibrationApplicable,
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
@ -531,6 +536,9 @@ export default {
|
||||||
getImageVifColorfromStore() {
|
getImageVifColorfromStore() {
|
||||||
return store.getters.vehicle.imageVifColor;
|
return store.getters.vehicle.imageVifColor;
|
||||||
},
|
},
|
||||||
|
getIsMobileStaticRecalibrationApplicable() {
|
||||||
|
return store.getters.vehicle.isMobileStaticRecalibrationApplicable;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@ import store from "@/store";
|
||||||
|
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
import { applicationConfig } from "../constants/application-config";
|
import { applicationConfig } from "../constants/application-config";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
import router from "@/router/index.js";
|
||||||
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -650,6 +654,13 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pushPageErrorToDataLayer(error) {
|
||||||
|
pushToDataLayerIfDefined({
|
||||||
|
event: "page-error",
|
||||||
|
error: error,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
prependActionToMethod(object, method, actionToPrepend) {
|
prependActionToMethod(object, method, actionToPrepend) {
|
||||||
const baseMethodName = method.name.startsWith("bound ")
|
const baseMethodName = method.name.startsWith("bound ")
|
||||||
? method.name.substring(6)
|
? method.name.substring(6)
|
||||||
|
|
@ -701,7 +712,22 @@ export default {
|
||||||
return !areAllSessionCookiesSet();
|
return !areAllSessionCookiesSet();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the vehicle year in vuex
|
||||||
|
sessionExpired() {
|
||||||
|
const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true";
|
||||||
|
if (this.noSession() && !fromHeritage && store.getters.order.vehicle?.year > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async validateSession() {
|
async validateSession() {
|
||||||
|
// do not init session if it is expired. let the click event on nav-bar handle session expired logic
|
||||||
|
if (this.sessionExpired()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.noSession()) {
|
if (this.noSession()) {
|
||||||
await this.initSession();
|
await this.initSession();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"
|
||||||
import { routingTable } from "@/router/router-constants/routing-table.js";
|
import { routingTable } from "@/router/router-constants/routing-table.js";
|
||||||
import { globalEvents, globalEventTypes } from "@/constants/events";
|
import { globalEvents, globalEventTypes } from "@/constants/events";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter, buildQuerystringObject } from "@/helpers/querystring-helper";
|
||||||
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||||
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
|
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
|
||||||
|
|
@ -26,6 +26,7 @@ import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integratio
|
||||||
import {
|
import {
|
||||||
getPageToRouteExistingOrderTo,
|
getPageToRouteExistingOrderTo,
|
||||||
navigateToHeritageFunnel,
|
navigateToHeritageFunnel,
|
||||||
|
getImplicitNavigation,
|
||||||
} from "@/helpers/heritage-integration/navigation-helper";
|
} from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
|
@ -53,9 +54,15 @@ const routes = [
|
||||||
log("------------- router index.js beforeEnter start -----------------");
|
log("------------- router index.js beforeEnter start -----------------");
|
||||||
log(" --to: ", to);
|
log(" --to: ", to);
|
||||||
log(" --cookie: ", getFunnelCookie());
|
log(" --cookie: ", getFunnelCookie());
|
||||||
|
log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, "");
|
||||||
|
|
||||||
await analyticsMixin.methods.validateSession();
|
await analyticsMixin.methods.validateSession();
|
||||||
|
|
||||||
|
// after session is validated, remove the fromHeritage querystring if it exists so session expiration works
|
||||||
|
if (to.query) {
|
||||||
|
delete to.query[queryStrings.FROM_HERITAGE];
|
||||||
|
}
|
||||||
|
|
||||||
if (getFunnelCookie()?.SuppressConceptFunnel) {
|
if (getFunnelCookie()?.SuppressConceptFunnel) {
|
||||||
log(" --go to heritage suppressConceptFunnel: ");
|
log(" --go to heritage suppressConceptFunnel: ");
|
||||||
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
||||||
|
|
@ -65,11 +72,25 @@ const routes = [
|
||||||
// If the saved session has timed out, clear the session, execute 404 logic.
|
// If the saved session has timed out, clear the session, execute 404 logic.
|
||||||
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
||||||
log(" --save session timeout go to start");
|
log(" --save session timeout go to start");
|
||||||
|
|
||||||
|
const errorPayload = {
|
||||||
|
cause: "expired session",
|
||||||
|
currentPage: from?.query?.fmgPage,
|
||||||
|
nextPage: to?.query?.fmgPage,
|
||||||
|
};
|
||||||
|
|
||||||
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
||||||
deleteFunnelCookie();
|
deleteFunnelCookie();
|
||||||
GoToFunnelStartOn404(next);
|
GoToFunnelStartOn404(next, errorPayload);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fromReturnUser = from?.name === fmgPageValues.RETURN_USER;
|
||||||
|
const fromContentSite = getQuerystringParameter(queryStrings.START_TYPE) === "fmg";
|
||||||
|
const toReturnUserPage = to.query?.fmgPage === fmgPageValues.RETURN_USER;
|
||||||
|
log(" --fromReturnUser ", fromReturnUser);
|
||||||
|
log(" --to.query.fmgPage ", to.query?.fmgPage);
|
||||||
|
|
||||||
// Intercept all navigation if a submitted order exists in storage
|
// Intercept all navigation if a submitted order exists in storage
|
||||||
if (window.sessionStorage.getItem("submittedOrder") !== null) {
|
if (window.sessionStorage.getItem("submittedOrder") !== null) {
|
||||||
if (to.query.fmgPage !== funnelStartPageName) {
|
if (to.query.fmgPage !== funnelStartPageName) {
|
||||||
|
|
@ -78,7 +99,29 @@ const routes = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// On entering the funnel "fresh", read cookie information, decide what to do next.
|
// On entering the funnel "fresh", read cookie information, decide what to do next.
|
||||||
else if (from.redirectedFrom === undefined) {
|
else if (from.redirectedFrom === undefined || fromReturnUser) {
|
||||||
|
// if entering the funnel from the content site, check and see if there is already a vehicle year in vuex.
|
||||||
|
// if so, send them to return-user page.
|
||||||
|
if (
|
||||||
|
fromContentSite &&
|
||||||
|
!toReturnUserPage &&
|
||||||
|
store.getters.order.vehicle?.year > 0
|
||||||
|
) {
|
||||||
|
log(" --from content site navigate to return user");
|
||||||
|
var qso = {
|
||||||
|
fmgPage: fmgPageValues.RETURN_USER,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newQueryString = buildQuerystringObject(qso, true);
|
||||||
|
log(" -- returnUser add querystring: " + JSON.stringify(newQueryString));
|
||||||
|
|
||||||
|
router.push({
|
||||||
|
path: "/",
|
||||||
|
query: Object.assign({}, newQueryString),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// clear the saveSessionPromise - if it exists in the vuex store but a new instance was created
|
// clear the saveSessionPromise - if it exists in the vuex store but a new instance was created
|
||||||
// the saveSessionPromise will no longer point to a valid promise
|
// the saveSessionPromise will no longer point to a valid promise
|
||||||
log(" --clear promise");
|
log(" --clear promise");
|
||||||
|
|
@ -125,18 +168,28 @@ const routes = [
|
||||||
log(" --load session end");
|
log(" --load session end");
|
||||||
|
|
||||||
//Update external parameter state but not when returning from heritage
|
//Update external parameter state but not when returning from heritage
|
||||||
if (!to.query.fmgPage?.startsWith("service-location")) {
|
if (!to.query.fmgPage?.startsWith("service-location") && !fromReturnUser) {
|
||||||
updateExternalParameterState();
|
updateExternalParameterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear part related state because heritage selected a new vehicle
|
// clear part related state because heritage selected a new vehicle
|
||||||
if (
|
if (
|
||||||
to.query.fmgPage === fmgPageValues.VEHICLE &&
|
to.query.fmgPage === fmgPageValues.VEHICLE &&
|
||||||
eval(getFunnelCookie()?.HasDelayedClaimRegistration)
|
eval(getFunnelCookie()?.HasDelayedClaimRegistration && !fromReturnUser)
|
||||||
) {
|
) {
|
||||||
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if coming from the return user page, clear the destination page so implicit navigation runs
|
||||||
|
log(" --to.query ", JSON.stringify(to.query));
|
||||||
|
if (fromReturnUser && to.query) {
|
||||||
|
log(" --clear to.query");
|
||||||
|
delete to.query[queryStrings.FMG_PAGE];
|
||||||
|
|
||||||
|
//to.query[queryStrings.FMG_PAGE] = "";
|
||||||
|
log(" --to.query cleared ", JSON.stringify(to.query));
|
||||||
|
}
|
||||||
|
|
||||||
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
|
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
|
||||||
log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
|
log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
|
||||||
|
|
||||||
|
|
@ -206,7 +259,14 @@ const routes = [
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GoToFunnelStartOn404(next);
|
const errorPayload = {
|
||||||
|
cause: "invalid page prerequisites for page",
|
||||||
|
currentPage: from?.query?.fmgPage,
|
||||||
|
nextPage: to?.query?.fmgPage,
|
||||||
|
};
|
||||||
|
|
||||||
|
GoToFunnelStartOn404(next, errorPayload);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(" --has route:", to.query.fmgPage);
|
log(" --has route:", to.query.fmgPage);
|
||||||
|
|
@ -214,13 +274,19 @@ const routes = [
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isExistingFmgPageName(to.query.fmgPage)) {
|
if (!isExistingFmgPageName(to.query.fmgPage)) {
|
||||||
console.log("Not an existing fmg page name:" + to.query.fmgPage);
|
const errorPayload = {
|
||||||
GoToFunnelStartOn404(next);
|
cause: "invalid page name",
|
||||||
|
currentPage: from?.query?.fmgPage,
|
||||||
|
nextPage: to?.query?.fmgPage,
|
||||||
|
};
|
||||||
|
|
||||||
|
GoToFunnelStartOn404(next, errorPayload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get route info for the given url. Names will have a 1:1 relationship with names in the Cms.
|
// Get route info for the given url. Names will have a 1:1 relationship with names in the Cms.
|
||||||
const routeData = GetRouteInfoFromPageName(to.query.fmgPage);
|
const routeData = GetRouteInfoFromPageName(to.query.fmgPage);
|
||||||
|
log("--routeData:", routeData);
|
||||||
|
|
||||||
// Add our dynamic route.
|
// Add our dynamic route.
|
||||||
router.addRoute({
|
router.addRoute({
|
||||||
|
|
@ -239,7 +305,15 @@ const routes = [
|
||||||
if (!arePagePrerequisitesValid(nextComponent)) {
|
if (!arePagePrerequisitesValid(nextComponent)) {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
console.log("Page Prereqs not valid for next component: " + nextComponent.default.name);
|
console.log("Page Prereqs not valid for next component: " + nextComponent.default.name);
|
||||||
GoToFunnelStartOn404(next);
|
|
||||||
|
const errorPayload = {
|
||||||
|
cause: "invalid page prerequisites for page",
|
||||||
|
currentPage: from?.query?.fmgPage,
|
||||||
|
nextPage: to?.query?.fmgPage,
|
||||||
|
};
|
||||||
|
|
||||||
|
GoToFunnelStartOn404(next, errorPayload);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("------------- router index.js beforeEnter end -----------------");
|
log("------------- router index.js beforeEnter end -----------------");
|
||||||
|
|
@ -261,7 +335,16 @@ const routes = [
|
||||||
console.log(new Date() + " Exception in beforeEnter:" + JSON.stringify(error));
|
console.log(new Date() + " Exception in beforeEnter:" + JSON.stringify(error));
|
||||||
|
|
||||||
// If we don't have a route, go to our 404 page.
|
// If we don't have a route, go to our 404 page.
|
||||||
GoToFunnelStartOn404(next);
|
const errorPayload = {
|
||||||
|
cause: "uncaught error in beforeEnter",
|
||||||
|
currentPage: from?.query?.fmgPage,
|
||||||
|
nextPage: to?.query?.fmgPage,
|
||||||
|
fullError: error,
|
||||||
|
errorStack: error?.stack,
|
||||||
|
};
|
||||||
|
|
||||||
|
GoToFunnelStartOn404(next, errorPayload);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -280,6 +363,7 @@ const router = createRouter({
|
||||||
//---------------------------------------------------------- Router Functions ----------------------------------------------------------
|
//---------------------------------------------------------- Router Functions ----------------------------------------------------------
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
log("------------- router index.js beforeEach start -----------------");
|
||||||
// set lastNavigationPage here to capture state before API calls for analytics.
|
// set lastNavigationPage here to capture state before API calls for analytics.
|
||||||
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
|
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
|
||||||
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
||||||
|
|
@ -331,6 +415,7 @@ router.beforeEach(async (to, from, next) => {
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
log("------------- router index.js beforeEach end -----------------");
|
||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach(async (to, from) => {
|
router.afterEach(async (to, from) => {
|
||||||
|
|
@ -397,8 +482,8 @@ router.navigateToExternalUrl = (url, optionalQuery = {}) => {
|
||||||
navigateToUrl(url, optionalQuery);
|
navigateToUrl(url, optionalQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
router.navigateError = () => {
|
router.navigateError = (errorPayload = null) => {
|
||||||
DisplayPageError();
|
DisplayPageError(errorPayload);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
|
//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
|
||||||
|
|
@ -546,6 +631,8 @@ function getNavigationMap(scenario, currentRoute) {
|
||||||
|
|
||||||
function log(message, data) {
|
function log(message, data) {
|
||||||
const log = getQuerystringParameter(queryStrings.LOG);
|
const log = getQuerystringParameter(queryStrings.LOG);
|
||||||
|
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);
|
||||||
|
|
||||||
data = data ?? "";
|
data = data ?? "";
|
||||||
const outData = typeof data === "object" ? JSON.stringify(data) : data;
|
const outData = typeof data === "object" ? JSON.stringify(data) : data;
|
||||||
|
|
||||||
|
|
@ -588,7 +675,18 @@ function GetRouteInfoFromPageName(pageName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go to our start page on a 404.
|
// Go to our start page on a 404.
|
||||||
function GoToFunnelStartOn404(next) {
|
function GoToFunnelStartOn404(next, errorPayload = null) {
|
||||||
|
if (errorPayload !== null) {
|
||||||
|
errorPayload.type = "GoToFunnelStartOn404";
|
||||||
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"%cGoToFunnelStartOn404()... errorPayload",
|
||||||
|
"color: white; background-color: blue; padding: 5px;",
|
||||||
|
errorPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Put item on the bus
|
// Put item on the bus
|
||||||
eventBus.addEventToBus(
|
eventBus.addEventToBus(
|
||||||
globalEvents.Categories.GLOBAL_ALERT,
|
globalEvents.Categories.GLOBAL_ALERT,
|
||||||
|
|
@ -607,7 +705,28 @@ function GoToFunnelStartOn404(next) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function DisplayPageError() {
|
async function DisplayPageError(errorPayload = null) {
|
||||||
|
console.log("%c running DisplayPageError()... ", "font-size: 20px; color: purple;");
|
||||||
|
|
||||||
|
if (errorPayload !== null) {
|
||||||
|
errorPayload.type = "DisplayPageError";
|
||||||
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
||||||
|
} else {
|
||||||
|
// very cautiously to avoid additional errors:
|
||||||
|
var currentPage = "";
|
||||||
|
try {
|
||||||
|
currentPage = getQuerystringParameter(queryStrings.FMG_PAGE);
|
||||||
|
} catch (e) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
errorPayload = {
|
||||||
|
type: "DisplayPageError",
|
||||||
|
cause: "Unknown page error",
|
||||||
|
currentPage: currentPage,
|
||||||
|
};
|
||||||
|
analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload);
|
||||||
|
}
|
||||||
|
|
||||||
// Put item on the bus
|
// Put item on the bus
|
||||||
eventBus.addEventToBus(
|
eventBus.addEventToBus(
|
||||||
globalEvents.Categories.GLOBAL_ALERT,
|
globalEvents.Categories.GLOBAL_ALERT,
|
||||||
|
|
@ -619,7 +738,11 @@ async function DisplayPageError() {
|
||||||
type: globalEventTypes.Danger,
|
type: globalEventTypes.Danger,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.INACTIVE);
|
if (
|
||||||
|
store.getters.externalParameterState?.isExternalParameter == externalParameterStatus.ACTIVE
|
||||||
|
) {
|
||||||
|
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.INACTIVE);
|
||||||
|
}
|
||||||
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||||
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
||||||
|
|
||||||
|
|
@ -700,22 +823,6 @@ function getRedirectedStartPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateExternalParameterState() {
|
function updateExternalParameterState() {
|
||||||
// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
|
|
||||||
// are returning. clear out prior related things that need to be selected again like parts and damage type.
|
|
||||||
if (
|
|
||||||
store.getters.externalParameterState?.isExternalParameter ==
|
|
||||||
externalParameterStatus.INACTIVE
|
|
||||||
) {
|
|
||||||
store.dispatch(storeActions.RESET_VEHICLE_STATE_AND_DEPENDENCIES);
|
|
||||||
store.dispatch(storeActions.SAVE_SERVICE_ZIP_CODE_INFO, {
|
|
||||||
state: null,
|
|
||||||
zipCode: null,
|
|
||||||
zipCodeCtu: null,
|
|
||||||
});
|
|
||||||
store.dispatch(storeActions.SAVE_EMAIL, null);
|
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
|
const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
|
||||||
const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
||||||
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
||||||
|
|
@ -734,6 +841,7 @@ function updateExternalParameterState() {
|
||||||
externalParameterModel &&
|
externalParameterModel &&
|
||||||
externalParameterStyle
|
externalParameterStyle
|
||||||
) {
|
) {
|
||||||
|
resetStoreForExternalParameter();
|
||||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE);
|
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE);
|
||||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear);
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear);
|
||||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
|
||||||
|
|
@ -784,4 +892,22 @@ function updateExternalParameterState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
|
||||||
|
// are returning. clear out prior related things that need to be selected again like parts and damage type.
|
||||||
|
function resetStoreForExternalParameter() {
|
||||||
|
if (
|
||||||
|
store.getters.externalParameterState?.isExternalParameter ==
|
||||||
|
externalParameterStatus.INACTIVE
|
||||||
|
) {
|
||||||
|
store.dispatch(storeActions.RESET_VEHICLE_STATE_AND_DEPENDENCIES);
|
||||||
|
store.dispatch(storeActions.SAVE_SERVICE_ZIP_CODE_INFO, {
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null,
|
||||||
|
});
|
||||||
|
store.dispatch(storeActions.SAVE_EMAIL, null);
|
||||||
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,10 @@ const fmgPageValues = {
|
||||||
PAYMENT: "payment",
|
PAYMENT: "payment",
|
||||||
PAYMENT_PIA_RETURN: "payment-pia-return",
|
PAYMENT_PIA_RETURN: "payment-pia-return",
|
||||||
CONFIRMATION: "confirmation",
|
CONFIRMATION: "confirmation",
|
||||||
|
RETURN_USER: "return-user",
|
||||||
};
|
};
|
||||||
|
|
||||||
const funnelStartPageName = fmgPageValues.VEHICLE;
|
const funnelStartPageName = fmgPageValues.VEHICLE;
|
||||||
|
const returnUserPageName = fmgPageValues.RETURN_USER;
|
||||||
|
|
||||||
export { fmgPageValues, funnelStartPageName };
|
export { fmgPageValues, funnelStartPageName, returnUserPageName };
|
||||||
|
|
|
||||||
|
|
@ -530,6 +530,16 @@ const routingTable = function (store) {
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.CONFIRMATION,
|
fmgPageValue: fmgPageValues.CONFIRMATION,
|
||||||
},
|
},
|
||||||
|
// The destination page for return user does not matter. the router will invoke implicit navigation
|
||||||
|
{
|
||||||
|
fmgPageValue: fmgPageValues.RETURN_USER,
|
||||||
|
maps: [
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VEHICLE,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ const getDefaultState = () => {
|
||||||
registration: {
|
registration: {
|
||||||
licensePlate: null,
|
licensePlate: null,
|
||||||
},
|
},
|
||||||
|
isMobileStaticRecalibrationApplicable: false,
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
address: null,
|
address: null,
|
||||||
|
|
@ -225,6 +226,10 @@ export const mutations = {
|
||||||
updateVehicleVin(state, vin) {
|
updateVehicleVin(state, vin) {
|
||||||
state.order.vehicle.vin = vin;
|
state.order.vehicle.vin = vin;
|
||||||
},
|
},
|
||||||
|
updateIsMobileStaticRecalibrationApplicable(state, isMobileStaticRecalibrationApplicable) {
|
||||||
|
state.order.vehicle.isMobileStaticRecalibrationApplicable =
|
||||||
|
isMobileStaticRecalibrationApplicable;
|
||||||
|
},
|
||||||
updateIsRepair(state, isRepair) {
|
updateIsRepair(state, isRepair) {
|
||||||
state.order.damage.isRepair = isRepair;
|
state.order.damage.isRepair = isRepair;
|
||||||
},
|
},
|
||||||
|
|
@ -350,6 +355,8 @@ export const mutations = {
|
||||||
state.order.vehicle.imageUrl = vehicleInfo.imageUrl;
|
state.order.vehicle.imageUrl = vehicleInfo.imageUrl;
|
||||||
state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber;
|
state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber;
|
||||||
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
||||||
|
state.order.vehicle.isMobileStaticRecalibrationApplicable =
|
||||||
|
vehicleInfo.isMobileStaticRecalibrationApplicable;
|
||||||
},
|
},
|
||||||
updateRegistration(state, registrationInfo) {
|
updateRegistration(state, registrationInfo) {
|
||||||
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
|
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
|
||||||
|
|
@ -534,6 +541,7 @@ export const mutations = {
|
||||||
state.order.vehicle.imageUrl = null;
|
state.order.vehicle.imageUrl = null;
|
||||||
state.order.vehicle.imageVifNumber = null;
|
state.order.vehicle.imageVifNumber = null;
|
||||||
state.order.vehicle.imageColor = null;
|
state.order.vehicle.imageColor = null;
|
||||||
|
state.order.vehicle.isMobileStaticRecalibrationApplicable = false;
|
||||||
},
|
},
|
||||||
resetDamageState(state) {
|
resetDamageState(state) {
|
||||||
state.order.damage.isRepair = null;
|
state.order.damage.isRepair = null;
|
||||||
|
|
@ -1600,7 +1608,7 @@ export const actions = {
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
getMobileFeePart(context, { pageNameToLog }) {
|
getMobileFeePart(context, { payload: { serviceZipCode, serviceZipCodeCtu }, pageNameToLog }) {
|
||||||
const serviceType = context.getters.damage.isRepair ? "Repair" : "Install";
|
const serviceType = context.getters.damage.isRepair ? "Repair" : "Install";
|
||||||
const facilityType = "Mobile";
|
const facilityType = "Mobile";
|
||||||
const parentAccountNumber = context.getters.payment.parentAccountNumber;
|
const parentAccountNumber = context.getters.payment.parentAccountNumber;
|
||||||
|
|
@ -1612,16 +1620,31 @@ export const actions = {
|
||||||
const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus);
|
const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus);
|
||||||
const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType);
|
const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType);
|
||||||
const isItacOptimized = order.policy?.isItac ?? false;
|
const isItacOptimized = order.policy?.isItac ?? false;
|
||||||
|
const isMobileStaticRecalibrationApplicable =
|
||||||
|
order.vehicle?.isMobileStaticRecalibrationApplicable;
|
||||||
const zipCode =
|
const zipCode =
|
||||||
order.serviceLocation?.provider?.address?.zipCode ?? order.serviceLocation?.zipCode;
|
serviceZipCode ??
|
||||||
|
order.serviceLocation?.provider?.address?.zipCode ??
|
||||||
|
order.serviceLocation?.zipCode;
|
||||||
|
|
||||||
var providerNumber =
|
var providerNumber =
|
||||||
order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu;
|
serviceZipCodeCtu ??
|
||||||
|
order.serviceLocation?.provider?.providerNumber ??
|
||||||
|
order.serviceLocation?.zipCodeCtu;
|
||||||
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
|
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
|
||||||
providerNumber = providerNumber.substring(1);
|
providerNumber = providerNumber.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
|
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
|
||||||
|
|
||||||
|
if (isMobileStaticRecalibrationApplicable) {
|
||||||
|
const staticRecalPartNumber = getStaticRecalPartNumber(order.lineItems?.glassParts[0]);
|
||||||
|
const carId = order.vehicle?.carId;
|
||||||
|
if (staticRecalPartNumber && carId) {
|
||||||
|
endPoint = `${endPoint}&partNumbers=${staticRecalPartNumber}&carId=${carId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (coverageStatus) {
|
if (coverageStatus) {
|
||||||
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
|
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
|
||||||
}
|
}
|
||||||
|
|
@ -2222,7 +2245,18 @@ export const actions = {
|
||||||
// Vehicle
|
// Vehicle
|
||||||
saveVehicle(
|
saveVehicle(
|
||||||
context,
|
context,
|
||||||
{ year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor }
|
{
|
||||||
|
year,
|
||||||
|
make,
|
||||||
|
model,
|
||||||
|
style,
|
||||||
|
carId,
|
||||||
|
category,
|
||||||
|
imageUrl,
|
||||||
|
imageVifNumber,
|
||||||
|
imageVifColor,
|
||||||
|
isMobileStaticRecalibrationApplicable,
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
context.state.order.vehicle.year != year ||
|
context.state.order.vehicle.year != year ||
|
||||||
|
|
@ -2243,6 +2277,10 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl);
|
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl);
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber);
|
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber);
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor);
|
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_MOBILE_STATIC_RECALIBRATION_APPLICABLE,
|
||||||
|
isMobileStaticRecalibrationApplicable
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -3646,3 +3684,13 @@ function getExternalParameterDefaultState() {
|
||||||
function saveExternalParameterState(externalParameterState) {
|
function saveExternalParameterState(externalParameterState) {
|
||||||
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
|
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//This function checks if static recalibration is available for the vehicle and returns the part number for it.
|
||||||
|
function getStaticRecalPartNumber(glassPartsArray) {
|
||||||
|
const recalPart = glassPartsArray.childParts.find((item) => item.partNumber === "RECAL STATIC");
|
||||||
|
if (recalPart) {
|
||||||
|
return recalPart.partNumber;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
:class="[
|
:class="[
|
||||||
isPrimary ? 'btn-primary' : 'btn-secondary',
|
isPrimary ? 'btn-primary' : 'btn-secondary',
|
||||||
isFloat ? 'float-end' : '',
|
isFloat ? 'float-end' : '',
|
||||||
(isLoaderDisplayed && !suppressLoader) ? 'has-loader' : '',
|
isLoaderDisplayed && !suppressLoader ? 'has-loader' : '',
|
||||||
]"
|
]"
|
||||||
@click="clicked">
|
@click="clicked">
|
||||||
<span class="m-0">{{ this.buttonText }}</span>
|
<span class="m-0">{{ this.buttonText }}</span>
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,6 @@ export default {
|
||||||
.list-button-horizontal-content {
|
.list-button-horizontal-content {
|
||||||
outline: none;
|
outline: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: $white;
|
|
||||||
transition: all 150ms linear;
|
transition: all 150ms linear;
|
||||||
border: 1px solid $gray-500;
|
border: 1px solid $gray-500;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
@ -110,8 +109,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-button-horizontal-content:hover {
|
.list-button-horizontal-content:hover {
|
||||||
background-color: $blue-700;
|
background-color: transparent;
|
||||||
color: $white;
|
color: $blue;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,4 +219,121 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Special styles when there are multiple list-button-horizontal buttons
|
||||||
|
// (number of chips, pay w/cash/insurance)
|
||||||
|
.windshield-chip-count-question {
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
&:first-child {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
z-index: 2;
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-top-left-radius: 0.5rem;
|
||||||
|
border-bottom-left-radius: 0.5rem;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
&:last-child {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
z-index: 2;
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-top-right-radius: 0.5rem;
|
||||||
|
border-bottom-right-radius: 0.5rem;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//NOT Windshiled Chip Count
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
&:first-child {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
z-index: 6;
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-top-left-radius: 0.5rem;
|
||||||
|
border-bottom-left-radius: 0.5rem;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
.d-flex {
|
||||||
|
.col {
|
||||||
|
&:last-child {
|
||||||
|
label {
|
||||||
|
&.list-group.list-button-horizontal {
|
||||||
|
z-index: 6;
|
||||||
|
&:hover {
|
||||||
|
background-color: $white;
|
||||||
|
border-top-right-radius: 0.5rem;
|
||||||
|
border-bottom-right-radius: 0.5rem;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ process.env.VUE_APP_MY_ACCOUNT = "https://myaccountdev.safelite.com/";
|
||||||
//process.env.VUE_APP_SAFELITE_HOP = "http://localhost:60966/fmgCheckoutShared.aspx";
|
//process.env.VUE_APP_SAFELITE_HOP = "http://localhost:60966/fmgCheckoutShared.aspx";
|
||||||
process.env.VUE_APP_SAFELITE_HOP = "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx";
|
process.env.VUE_APP_SAFELITE_HOP = "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx";
|
||||||
process.env.VUE_APP_SOLARWINDS_MONITORING = "";
|
process.env.VUE_APP_SOLARWINDS_MONITORING = "";
|
||||||
|
process.env.VUE_APP_SESSION_TIMEOUT_MINUTES = 30;
|
||||||
|
|
||||||
// GA & GTM
|
// GA & GTM
|
||||||
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY =
|
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY =
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ process.env.VUE_APP_CURRENT_ENVIRONMENT = "__VUE_APP_CURRENT_ENVIRONMENT__";
|
||||||
process.env.VUE_APP_MY_ACCOUNT = "__VUE_APP_MY_ACCOUNT__";
|
process.env.VUE_APP_MY_ACCOUNT = "__VUE_APP_MY_ACCOUNT__";
|
||||||
process.env.VUE_APP_SAFELITE_HOP = "__VUE_APP_SAFELITE_HOP__";
|
process.env.VUE_APP_SAFELITE_HOP = "__VUE_APP_SAFELITE_HOP__";
|
||||||
process.env.VUE_APP_SOLARWINDS_MONITORING_SCRIPT = "__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__";
|
process.env.VUE_APP_SOLARWINDS_MONITORING_SCRIPT = "__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__";
|
||||||
|
process.env.VUE_APP_SESSION_TIMEOUT_MINUTES = 30;
|
||||||
|
|
||||||
// GA & GTM
|
// GA & GTM
|
||||||
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = "__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__";
|
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = "__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue