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_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||
indexDeployVariables:
|
||||
__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__)
|
||||
|
|
@ -160,6 +161,7 @@ stages:
|
|||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||
indexDeployVariables:
|
||||
__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__)
|
||||
|
|
@ -220,6 +222,7 @@ stages:
|
|||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||
indexDeployVariables:
|
||||
__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__)
|
||||
|
|
@ -280,6 +283,7 @@ stages:
|
|||
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
||||
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
||||
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
||||
indexDeployVariables:
|
||||
__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__)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ const applicationConfig = {
|
|||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
|
||||
AFFILIATE_COOKIE_CONTAINING_NAME: "_Track",
|
||||
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 };
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const cookieNames = {
|
|||
};
|
||||
|
||||
const cookieExpirations = {
|
||||
SESSION_ID: convertToSeconds({ minutes: 30 }),
|
||||
SESSION_ID: convertToSeconds({ minutes: applicationConfig.SESSION_TIMEOUT_MINUTES }),
|
||||
DXDEV: convertToSeconds({ years: 1 }),
|
||||
FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
|
||||
FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ const queryStrings = {
|
|||
ORGANIC: "organic",
|
||||
ORGANIC_SOCIAL: "organic_social",
|
||||
EXPERIMENTS: "experiments",
|
||||
FROM_HERITAGE: "fromheritage",
|
||||
};
|
||||
|
||||
export { queryStrings };
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ const storeMutations = {
|
|||
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
|
||||
UPDATE_VEHICLE_VIN: "updateVehicleVin",
|
||||
UPDATE_VEHICLE: "updateVehicle",
|
||||
UPDATE_VEHICLE_MOBILE_STATIC_RECALIBRATION_APPLICABLE:
|
||||
"updateIsMobileStaticRecalibrationApplicable",
|
||||
|
||||
UPDATE_IS_REPAIR: "updateIsRepair",
|
||||
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export default {
|
|||
if (this.buttonTypeString == "radio") {
|
||||
classes += " radio-button-container";
|
||||
} else if (this.buttonTypeString == "servicePackageRadio") {
|
||||
classes = "package-wrapper col-md-4";
|
||||
classes = "package-wrapper col";
|
||||
}
|
||||
|
||||
if (this.buttonTypeString == "listCard" && this.buttonsInfo.length > 2) {
|
||||
|
|
|
|||
|
|
@ -27,17 +27,17 @@
|
|||
</div>
|
||||
<div class="modal-body ps-5 pe-5 pb-4 pt-1">
|
||||
<slot></slot>
|
||||
<div class="modal-footer">
|
||||
<modalButtonMain
|
||||
isPrimary
|
||||
class="w-100"
|
||||
:id="modalId + '-modalbtn'"
|
||||
ref="modalButtonMain"
|
||||
loaderColor="white"
|
||||
:buttonText="footerButtonText"
|
||||
@click-event="validateAndEmit"
|
||||
:class="isFooterButtonDisabled && 'form-test-invalid'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<modalButtonMain
|
||||
isPrimary
|
||||
class="w-100"
|
||||
:id="modalId + '-modalbtn'"
|
||||
ref="modalButtonMain"
|
||||
loaderColor="white"
|
||||
:buttonText="footerButtonText"
|
||||
@click-event="validateAndEmit"
|
||||
:class="isFooterButtonDisabled && 'form-test-invalid'" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -173,7 +173,7 @@ export default {
|
|||
}
|
||||
}
|
||||
.modal-footer {
|
||||
padding: 1rem 0;
|
||||
padding: 1rem 1.5rem;
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
|
|
@ -216,8 +216,12 @@ export default {
|
|||
overflow: auto;
|
||||
flex: none;
|
||||
}
|
||||
.textbox-question {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.modal-dialog-centered {
|
||||
align-items: flex-end;
|
||||
min-height: 100%;
|
||||
|
|
@ -269,8 +273,6 @@ export default {
|
|||
flex-direction: column;
|
||||
|
||||
.textbox-question {
|
||||
padding: 0;
|
||||
|
||||
label {
|
||||
text-align: left;
|
||||
font-weight: 900;
|
||||
|
|
@ -284,6 +286,10 @@ export default {
|
|||
.modal-disclaimer {
|
||||
font-size: 0.75rem;
|
||||
order: 2;
|
||||
text-align: left;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
margin: 0 0 1.5rem 0;
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export default {
|
|||
@include blue-gradient;
|
||||
}
|
||||
&:focus, // Mouse, touch, stylus focus
|
||||
&:focus-visible {
|
||||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@
|
|||
<script>
|
||||
import textLink from "@/ux-components/text-link/text-link";
|
||||
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 {
|
||||
name: "navbar",
|
||||
|
|
@ -94,10 +97,28 @@ export default {
|
|||
document.onkeydown = function (e) {
|
||||
return false;
|
||||
};
|
||||
this.$emit("ForwardClicked");
|
||||
// check session expired and initSession to recreate cookies
|
||||
if (analyticsMixin.methods.sessionExpired()) {
|
||||
this.routeReturnUser();
|
||||
} else {
|
||||
this.$emit("ForwardClicked");
|
||||
}
|
||||
},
|
||||
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>
|
||||
<div class="save-progress-modal-question">
|
||||
<div class="save-progress-modal-question" :class="isProgressSaved ? 'progress-saved' : ''">
|
||||
<buttonMain
|
||||
ref="buttonMain"
|
||||
type="button"
|
||||
v-if="!isProgressSaved"
|
||||
:buttonText="buttonText"
|
||||
loaderColor="white"
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
:ref="modalName"
|
||||
:headerText="modalHeaderText"
|
||||
suppressPageScroll
|
||||
:onModalClosedCallback="onModalClosed"
|
||||
:footerButtonText="modalButtonText"
|
||||
@footer-button-event="saveProgress">
|
||||
<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 buttonMain from "@/ux-components/button-main/button-main";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
export default {
|
||||
name: "save-progress-modal-question",
|
||||
|
|
@ -50,6 +53,10 @@ export default {
|
|||
modalWidgetName: String,
|
||||
pageName: String,
|
||||
},
|
||||
unmounted() {
|
||||
// remove any modal effects before leaving page (e.g. user hits browser back button)
|
||||
this.modal.closeModal();
|
||||
},
|
||||
computed: {
|
||||
buttonText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "SubheaderText");
|
||||
|
|
@ -78,17 +85,21 @@ export default {
|
|||
this.modal.openModal();
|
||||
this.modal.resetButtonStyle();
|
||||
},
|
||||
onModalClosed() {
|
||||
this.userInput = "";
|
||||
this.modal.resetForm();
|
||||
},
|
||||
async saveProgress() {
|
||||
// save email address to store
|
||||
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
|
||||
this.isProgressSaved = true;
|
||||
|
||||
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;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
&.progress-saved {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.save-progress-button {
|
||||
order: 4;
|
||||
position: relative;
|
||||
|
|
@ -125,7 +140,7 @@ export default {
|
|||
width: auto;
|
||||
height: auto;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.375rem;
|
||||
text-underline-offset: 0.25rem;
|
||||
line-height: 1rem;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
|
|
@ -148,6 +163,7 @@ export default {
|
|||
:deep(.alert) {
|
||||
border-radius: $border-radius-lg;
|
||||
border: 1px solid $green;
|
||||
margin-top: 0;
|
||||
}
|
||||
:deep(.alert-heading) {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
class="save-progress-popup-question" />
|
||||
<buttonMain
|
||||
ref="skipButton"
|
||||
type="button"
|
||||
:buttonText="buttonText"
|
||||
loaderColor="white"
|
||||
:suppressLoader="true"
|
||||
|
|
@ -37,6 +38,7 @@ import modal from "@/digital-components/modal/modal";
|
|||
import { storeActions } from "@/constants/store-actions.js";
|
||||
import buttonMain from "@/ux-components/button-main/button-main";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
export default {
|
||||
name: "save-progress-popup-question",
|
||||
|
|
@ -50,6 +52,10 @@ export default {
|
|||
mounted() {
|
||||
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
|
||||
props: {
|
||||
modelValue: Object,
|
||||
|
|
@ -94,15 +100,14 @@ export default {
|
|||
// save email address to store
|
||||
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
|
||||
this.isProgressSaved = true;
|
||||
|
||||
// send store call to send to new API (that triggers an email send)
|
||||
this.$emit("save-progress");
|
||||
|
||||
// send call to close popup
|
||||
this.closeModal();
|
||||
this.$emit("close-save-progress-popup");
|
||||
// communicate to parent the new status
|
||||
this.$emit("save-progress-saved");
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -138,11 +143,12 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.skip-button {
|
||||
.btn.btn-secondary.skip-button {
|
||||
order: 4;
|
||||
position: relative;
|
||||
color: $black;
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
font-weight: 900;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
|
|
@ -150,7 +156,7 @@ export default {
|
|||
width: auto;
|
||||
height: auto;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.375rem;
|
||||
text-underline-offset: 0.25rem;
|
||||
line-height: 1rem;
|
||||
padding: 0 0 4px 0;
|
||||
margin: 0 auto 1.5rem auto;
|
||||
|
|
@ -159,12 +165,17 @@ export default {
|
|||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
&:focus {
|
||||
color: $blue-700;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
box-shadow:
|
||||
0 0 0 3px $white,
|
||||
0 0 0 5.5px $blue-300;
|
||||
}
|
||||
|
||||
&.delay {
|
||||
// fixes flicker while transitioning between states
|
||||
|
|
@ -200,9 +211,6 @@ export default {
|
|||
}
|
||||
.modal-disclaimer {
|
||||
order: 4;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.progress-saved {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,13 @@ export default {
|
|||
|
||||
if (error.response.status && error.response.status != "404") {
|
||||
// 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
|
||||
// when a service doesn't return an object
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ export async function getImplicitNavigation(toRoute) {
|
|||
|
||||
const skipVin = await skipVinLookup();
|
||||
|
||||
if (store.getters.order.payment.insuranceCoverage?.isVerified) {
|
||||
return fmgPageValues.HERITAGE;
|
||||
}
|
||||
|
||||
if (quoteComponent.methods.arePagePrerequisitesValid()) {
|
||||
// Do not send to quote if verified insurance user.
|
||||
if (store.getters.requiresVerifiedRedirecting) {
|
||||
|
|
|
|||
|
|
@ -8,3 +8,17 @@ export function getQuerystringParameter(key) {
|
|||
|
||||
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 -->
|
||||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
v-if="!isEmailInStoreOnPageLoad"
|
||||
@save-progress="saveProgress" />
|
||||
pageName="capability-questions"
|
||||
v-if="showSaveProgressModal" />
|
||||
</questions-page-layout>
|
||||
</Form>
|
||||
</template>
|
||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
|||
import { errorMessages } from "@/constants/error-messages";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
|
@ -65,7 +64,9 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next(async (vm) => {
|
||||
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.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
|
|
@ -87,7 +88,7 @@ export default {
|
|||
questionsData: null,
|
||||
selectedAnswers: {},
|
||||
currentGlassIndex: 0,
|
||||
isEmailInStoreOnPageLoad: null,
|
||||
showSaveProgressModal: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -157,9 +158,6 @@ export default {
|
|||
this.questionsData
|
||||
);
|
||||
},
|
||||
saveProgress() {
|
||||
saveQuote({ pageNameToLog: "capability-questions" });
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
// get answerResult2 of returned answer
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
<!-- save progress goes into <slot> on questions-page-layout -->
|
||||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
v-if="!isEmailInStoreOnPageLoad"
|
||||
@save-progress="saveProgress" />
|
||||
pageName="molding-questions"
|
||||
v-if="showSaveProgressModal" />
|
||||
</questions-page-layout>
|
||||
</Form>
|
||||
</template>
|
||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
|||
import { errorMessages } from "@/constants/error-messages";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
|
@ -65,7 +64,9 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next(async (vm) => {
|
||||
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.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
|
|
@ -88,7 +89,7 @@ export default {
|
|||
questionsData: null,
|
||||
selectedAnswers: {},
|
||||
currentGlassIndex: 0,
|
||||
isEmailInStoreOnPageLoad: null,
|
||||
showSaveProgressModal: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -157,9 +158,6 @@ export default {
|
|||
this.questionsData
|
||||
);
|
||||
},
|
||||
saveProgress() {
|
||||
saveQuote({ pageNameToLog: "molding-questions" });
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
<!-- save progress goes into <slot> on questions-page-layout -->
|
||||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
v-if="!isEmailInStoreOnPageLoad"
|
||||
@save-progress="saveProgress" />
|
||||
pageName="part-questions"
|
||||
v-if="showSaveProgressModal" />
|
||||
</questions-page-layout>
|
||||
</Form>
|
||||
</template>
|
||||
|
|
@ -38,7 +38,6 @@ import { required } from "@/helpers/validation-rules";
|
|||
import { errorMessages } from "@/constants/error-messages";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
|
@ -65,7 +64,9 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next(async (vm) => {
|
||||
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.externalParameterServiceZip.zipCode) {
|
||||
const serviceState = store.getters.order.serviceLocation.state;
|
||||
|
|
@ -89,7 +90,7 @@ export default {
|
|||
questionsData: null,
|
||||
selectedAnswers: {},
|
||||
currentGlassIndex: 0,
|
||||
isEmailInStoreOnPageLoad: null,
|
||||
showSaveProgressModal: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -156,9 +157,6 @@ export default {
|
|||
this.questionsData
|
||||
);
|
||||
},
|
||||
saveProgress() {
|
||||
saveQuote({ pageNameToLog: "part-questions" });
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -429,7 +429,8 @@ export default {
|
|||
// prettier-ignore
|
||||
{
|
||||
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(new Date() + " serviceLocationReqs::isMobile: " + isMobile);
|
||||
console.log(new Date() + " serviceLocationReqs::mobileReqs: " + mobileReqs);
|
||||
|
|
@ -621,7 +622,7 @@ export default {
|
|||
: this.$store.getters.order.serviceLocation?.appointmentType;
|
||||
},
|
||||
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() {
|
||||
if (this.AppointmentType === AppointmentTypeStrings.MOBILE) {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default {
|
|||
computed: {
|
||||
displayContent() {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-12 col-xl-8">
|
||||
<div class="col-md-12 mb-5" :class="getColCount()">
|
||||
<servicePackageQuestion
|
||||
ref="servicePackage"
|
||||
cashCmsWidgetName="CashServicePackageQuestionWidget"
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
:shouldHideRecalibration="shouldHideRecalibration"
|
||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||
@servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
|
||||
@currentNumberOfPackages="currentNumberOfPackagesAction"
|
||||
:servicePackage="servicePackage"
|
||||
:activePromos="lineItems.promos"
|
||||
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
||||
|
|
@ -40,7 +41,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<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 -->
|
||||
<afterpayModalBanner
|
||||
v-if="showAfterpayBanner"
|
||||
|
|
@ -82,8 +83,8 @@
|
|||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
modalName="SaveProgressModal"
|
||||
v-if="!isEmailInStoreOnPageLoad"
|
||||
@save-progress="saveProgress" />
|
||||
v-if="showSaveProgressModal"
|
||||
pageName="quote" />
|
||||
|
||||
<textBlock
|
||||
cmsWidgetName="quoteDisclaimer"
|
||||
|
|
@ -98,9 +99,10 @@
|
|||
<saveProgressPopupQuestion
|
||||
modalWidgetName="SaveProgressPopupWidget"
|
||||
modalName="SaveProgressPopup"
|
||||
v-if="!isEmailInStoreOnPageLoad && showSaveProgressPopup"
|
||||
pageName="quote"
|
||||
v-if="showSaveProgressPopup"
|
||||
:showSaveProgressPopup="showSaveProgressPopup"
|
||||
@save-progress="saveProgress"
|
||||
@save-progress-saved="updateSaveProgressAsSaved"
|
||||
@close-save-progress-popup="closeSaveProgressPopup" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -209,6 +211,7 @@ export default {
|
|||
const emailFromStore = store.getters.order.customer.emailAddress;
|
||||
const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
||||
const showSaveProgressPopup = isEmailInStoreOnPageLoad ? false : true;
|
||||
const showSaveProgressModal = isEmailInStoreOnPageLoad ? false : true;
|
||||
|
||||
const lineItems = deepClone(store.getters.order.lineItems);
|
||||
lineItems.vaps = lineItems.vaps ?? [];
|
||||
|
|
@ -290,8 +293,12 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next(async (vm) => {
|
||||
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.lineItems = lineItems;
|
||||
vm.availableLineItems = pricingResults;
|
||||
|
|
@ -438,10 +445,15 @@ export default {
|
|||
servicePackage: null,
|
||||
holdParentAccountNumber: null,
|
||||
holdBillToAccountNumber: null,
|
||||
isEmailInStoreOnPageLoad: null,
|
||||
showSaveProgressPopup: null,
|
||||
showSaveProgressModal: null,
|
||||
isSaveProgressComplete: null,
|
||||
packageNumber: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.attachCustomEvents();
|
||||
},
|
||||
computed: {
|
||||
lineItemsCloneForWatcher() {
|
||||
return Object.assign({}, this.lineItems);
|
||||
|
|
@ -486,6 +498,16 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getColCount() {
|
||||
if (this.packageNumber > 2) {
|
||||
return "col-xl-8";
|
||||
} else {
|
||||
return "col-xl-6";
|
||||
}
|
||||
},
|
||||
currentNumberOfPackagesAction(packageNumber) {
|
||||
this.packageNumber = packageNumber;
|
||||
},
|
||||
openModalAction(modalName) {
|
||||
this.$refs[modalName].openModal();
|
||||
},
|
||||
|
|
@ -526,10 +548,8 @@ export default {
|
|||
backButtonAction() {
|
||||
vehicleQuestionsMixin.methods.navigateBack(this);
|
||||
},
|
||||
saveProgress() {
|
||||
this.isEmailInStoreOnPageLoad = true;
|
||||
this.showSaveProgressPopup = false;
|
||||
saveQuote({ pageNameToLog: "quote" });
|
||||
updateSaveProgressAsSaved() {
|
||||
this.showSaveProgressModal = false;
|
||||
},
|
||||
closeSaveProgressPopup() {
|
||||
this.showSaveProgressPopup = false;
|
||||
|
|
@ -677,9 +697,6 @@ export default {
|
|||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.attachCustomEvents();
|
||||
},
|
||||
watch: {
|
||||
lineItemsCloneForWatcher: {
|
||||
handler(newValue, oldValue) {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ export default {
|
|||
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
||||
},
|
||||
}));
|
||||
this.$emit("currentNumberOfPackages", modifiedAnswers.length);
|
||||
return modifiedAnswers;
|
||||
},
|
||||
isServicePackageDiscountOnOrder() {
|
||||
|
|
|
|||
|
|
@ -141,10 +141,22 @@ export default {
|
|||
.package-main {
|
||||
.package-wrapper {
|
||||
margin: 1rem 0;
|
||||
&:first-child {
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
margin: 1rem 0.5rem;
|
||||
margin: 1rem 0.5rem 0 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&:first-child {
|
||||
margin: 1rem 0.5rem 0 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin: 1rem 0 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
|
|
@ -322,6 +334,7 @@ export default {
|
|||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
div.strikethrough-discount-price {
|
||||
text-decoration: line-through;
|
||||
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
|
||||
const mobileFeePart = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_MOBILE_FEE_PART,
|
||||
null,
|
||||
{
|
||||
serviceZipCode: serviceZipCode,
|
||||
serviceZipCodeCtu: zipCodeData.zipCodeCtu,
|
||||
},
|
||||
pageNameToLog,
|
||||
false
|
||||
);
|
||||
|
|
|
|||
|
|
@ -241,57 +241,46 @@ export default {
|
|||
this.displayMismatchStateAndZipAlert = false;
|
||||
},
|
||||
async setMobileLocation() {
|
||||
if (
|
||||
this.internalModel.addressQuestions.zipCode !==
|
||||
this.modelValue.addressQuestions.zipCode
|
||||
) {
|
||||
this.resetAlerts();
|
||||
// Validate the Zip Code
|
||||
const zipCodeData = await this.getZipCodeData(
|
||||
this.internalModel.addressQuestions.zipCode,
|
||||
this.resetAlerts();
|
||||
// Validate the Zip Code
|
||||
const zipCodeData = await this.getZipCodeData(
|
||||
this.internalModel.addressQuestions.zipCode,
|
||||
"service-location"
|
||||
);
|
||||
|
||||
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"
|
||||
);
|
||||
|
||||
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"
|
||||
);
|
||||
// retrieve serviceability details
|
||||
const serviceabilityDetails = await getServiceabilityDetails(
|
||||
serviceZipCode,
|
||||
null,
|
||||
"service-location"
|
||||
);
|
||||
|
||||
// retrieve serviceability details
|
||||
const serviceabilityDetails = await getServiceabilityDetails(
|
||||
serviceZipCode,
|
||||
null,
|
||||
"service-location"
|
||||
);
|
||||
const billToAccountNumber = await getBillToAccountNumber(
|
||||
this.internalModel.zipCodeCtu
|
||||
);
|
||||
|
||||
const billToAccountNumber = await getBillToAccountNumber(
|
||||
this.internalModel.zipCodeCtu
|
||||
);
|
||||
// update content related to service zip code
|
||||
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
|
||||
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
|
||||
// update the page level model
|
||||
this.$emit("update:modelValue", this.internalModel);
|
||||
|
||||
//Page advance to Schedule page
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ beforeEach(() => {
|
|||
zipCode: "43235",
|
||||
state: "OH",
|
||||
},
|
||||
vehicle: {
|
||||
isMobileStaticRecalibrationApplicable: true,
|
||||
},
|
||||
},
|
||||
damage: {
|
||||
isRepair: false,
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ import { defineRule } from "vee-validate";
|
|||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
|
||||
const MOBILE_STATIC_RECAL_FEE_PART_NUMBER = "RECAL MOBILE";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("mobile-location-required", (value) => {
|
||||
|
|
@ -188,6 +189,8 @@ export default {
|
|||
isRecalibrationServiceableInshop: null,
|
||||
isGlassServiceableMobile: null,
|
||||
isRecalibrationServiceableMobile: null,
|
||||
isVehicleMobileStaticRecalibrationApplicable:
|
||||
this.getIsVehicleMobileStaticRecalibrationApplicableFromStore(),
|
||||
selectedAppointmentType: this.getSelectedAppointmentType(),
|
||||
selectedProvider: this.getSelectedProvider(),
|
||||
mobileFeePart: null,
|
||||
|
|
@ -306,11 +309,21 @@ export default {
|
|||
},
|
||||
isServiceableMobile() {
|
||||
if (this.isRecalibrationServiceableMobile !== null) {
|
||||
return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile;
|
||||
return (
|
||||
(this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile) ||
|
||||
this.isMobileStaticRecalibrationApplicable
|
||||
);
|
||||
} else {
|
||||
return this.isGlassServiceableMobile;
|
||||
}
|
||||
},
|
||||
isMobileStaticRecalibrationApplicable() {
|
||||
return (
|
||||
this.isVehicleMobileStaticRecalibrationApplicable &&
|
||||
this.mobileFeePart?.partNumber == MOBILE_STATIC_RECAL_FEE_PART_NUMBER &&
|
||||
(this.isInsurance ? this.mobileFeePart?.isInsurable : true)
|
||||
);
|
||||
},
|
||||
mobileFeeApplies() {
|
||||
if (
|
||||
this.mobileFeePart?.laborAmount > 0 ||
|
||||
|
|
@ -349,7 +362,8 @@ export default {
|
|||
return (
|
||||
this.isServiceableInshop &&
|
||||
this.isGlassServiceableMobile &&
|
||||
this.isRecalibrationServiceableMobile === false
|
||||
this.isRecalibrationServiceableMobile === false &&
|
||||
!this.isMobileStaticRecalibrationApplicable
|
||||
);
|
||||
},
|
||||
displayRecalibrationWarning() {
|
||||
|
|
@ -485,6 +499,9 @@ export default {
|
|||
getSelectedProvider() {
|
||||
return store.getters.order.serviceLocation.provider;
|
||||
},
|
||||
getIsVehicleMobileStaticRecalibrationApplicableFromStore() {
|
||||
return store.getters.order.vehicle.isMobileStaticRecalibrationApplicable;
|
||||
},
|
||||
resetMobileLocation() {
|
||||
this.streetAddress = "";
|
||||
this.apartmentNumberOrBusinessName = "";
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@
|
|||
|
||||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
v-if="!isEmailInStoreOnPageLoad"
|
||||
@save-progress="saveProgress" />
|
||||
pageName="vehicle-parts"
|
||||
v-if="showSaveProgressModal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -75,7 +75,6 @@ import store from "@/store";
|
|||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
export default {
|
||||
name: "vehicle-parts",
|
||||
|
|
@ -95,7 +94,10 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
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
|
||||
Object.keys(vm.$refs)
|
||||
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
||||
|
|
@ -115,7 +117,7 @@ export default {
|
|||
selectedGlassParts: {},
|
||||
alertWidgetData: Object,
|
||||
alreadyPopulatedPartsData: [],
|
||||
isEmailInStoreOnPageLoad: null,
|
||||
showSaveProgressModal: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -234,9 +236,6 @@ export default {
|
|||
});
|
||||
});
|
||||
},
|
||||
saveProgress() {
|
||||
saveQuote({ pageNameToLog: "vehicle-parts" });
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.LoadInitialPartsData();
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ export default {
|
|||
modelOptions: [],
|
||||
styleOptions: [],
|
||||
displayNoServiceAlert: false,
|
||||
isMobileStaticRecalibrationApplicable: this.getIsMobileStaticRecalibrationApplicable(),
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -438,6 +439,8 @@ export default {
|
|||
this.imageVifNumber = result?.data.imageVifNumber;
|
||||
this.imageVifColor = result?.data.imageVifColor;
|
||||
this.displayNoServiceAlert = !result?.data.canSafeliteService;
|
||||
this.isMobileStaticRecalibrationApplicable =
|
||||
result?.data.isMobileStaticRecalibrationApplicable;
|
||||
},
|
||||
resetAlert() {
|
||||
this.displayNoServiceAlert = false;
|
||||
|
|
@ -456,6 +459,8 @@ export default {
|
|||
imageUrl: this.imageUrl,
|
||||
imageVifNumber: this.imageVifNumber,
|
||||
imageVifColor: this.imageVifColor,
|
||||
isMobileStaticRecalibrationApplicable:
|
||||
this.isMobileStaticRecalibrationApplicable,
|
||||
},
|
||||
false
|
||||
);
|
||||
|
|
@ -531,6 +536,9 @@ export default {
|
|||
getImageVifColorfromStore() {
|
||||
return store.getters.vehicle.imageVifColor;
|
||||
},
|
||||
getIsMobileStaticRecalibrationApplicable() {
|
||||
return store.getters.vehicle.isMobileStaticRecalibrationApplicable;
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ import store from "@/store";
|
|||
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
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 {
|
||||
methods: {
|
||||
|
|
@ -650,6 +654,13 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
pushPageErrorToDataLayer(error) {
|
||||
pushToDataLayerIfDefined({
|
||||
event: "page-error",
|
||||
error: error,
|
||||
});
|
||||
},
|
||||
|
||||
prependActionToMethod(object, method, actionToPrepend) {
|
||||
const baseMethodName = method.name.startsWith("bound ")
|
||||
? method.name.substring(6)
|
||||
|
|
@ -701,7 +712,22 @@ export default {
|
|||
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() {
|
||||
// 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()) {
|
||||
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 { globalEvents, globalEventTypes } from "@/constants/events";
|
||||
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 { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
|
||||
|
|
@ -26,6 +26,7 @@ import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integratio
|
|||
import {
|
||||
getPageToRouteExistingOrderTo,
|
||||
navigateToHeritageFunnel,
|
||||
getImplicitNavigation,
|
||||
} from "@/helpers/heritage-integration/navigation-helper";
|
||||
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
|
|
@ -53,9 +54,15 @@ const routes = [
|
|||
log("------------- router index.js beforeEnter start -----------------");
|
||||
log(" --to: ", to);
|
||||
log(" --cookie: ", getFunnelCookie());
|
||||
log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, "");
|
||||
|
||||
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) {
|
||||
log(" --go to heritage suppressConceptFunnel: ");
|
||||
await navigateToHeritageFunnel({ shouldSaveSession: false });
|
||||
|
|
@ -65,11 +72,25 @@ const routes = [
|
|||
// If the saved session has timed out, clear the session, execute 404 logic.
|
||||
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
||||
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);
|
||||
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
|
||||
if (window.sessionStorage.getItem("submittedOrder") !== null) {
|
||||
if (to.query.fmgPage !== funnelStartPageName) {
|
||||
|
|
@ -78,7 +99,29 @@ const routes = [
|
|||
}
|
||||
}
|
||||
// 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
|
||||
// the saveSessionPromise will no longer point to a valid promise
|
||||
log(" --clear promise");
|
||||
|
|
@ -125,18 +168,28 @@ const routes = [
|
|||
log(" --load session end");
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
// clear part related state because heritage selected a new vehicle
|
||||
if (
|
||||
to.query.fmgPage === fmgPageValues.VEHICLE &&
|
||||
eval(getFunnelCookie()?.HasDelayedClaimRegistration)
|
||||
eval(getFunnelCookie()?.HasDelayedClaimRegistration && !fromReturnUser)
|
||||
) {
|
||||
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);
|
||||
log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo));
|
||||
|
||||
|
|
@ -206,7 +259,14 @@ const routes = [
|
|||
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);
|
||||
|
|
@ -214,13 +274,19 @@ const routes = [
|
|||
}
|
||||
|
||||
if (!isExistingFmgPageName(to.query.fmgPage)) {
|
||||
console.log("Not an existing fmg page name:" + to.query.fmgPage);
|
||||
GoToFunnelStartOn404(next);
|
||||
const errorPayload = {
|
||||
cause: "invalid page name",
|
||||
currentPage: from?.query?.fmgPage,
|
||||
nextPage: to?.query?.fmgPage,
|
||||
};
|
||||
|
||||
GoToFunnelStartOn404(next, errorPayload);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
log("--routeData:", routeData);
|
||||
|
||||
// Add our dynamic route.
|
||||
router.addRoute({
|
||||
|
|
@ -239,7 +305,15 @@ const routes = [
|
|||
if (!arePagePrerequisitesValid(nextComponent)) {
|
||||
// prettier-ignore
|
||||
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 -----------------");
|
||||
|
|
@ -261,7 +335,16 @@ const routes = [
|
|||
console.log(new Date() + " Exception in beforeEnter:" + JSON.stringify(error));
|
||||
|
||||
// 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.beforeEach(async (to, from, next) => {
|
||||
log("------------- router index.js beforeEach start -----------------");
|
||||
// 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)
|
||||
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
||||
|
|
@ -331,6 +415,7 @@ router.beforeEach(async (to, from, next) => {
|
|||
} else {
|
||||
next();
|
||||
}
|
||||
log("------------- router index.js beforeEach end -----------------");
|
||||
});
|
||||
|
||||
router.afterEach(async (to, from) => {
|
||||
|
|
@ -397,8 +482,8 @@ router.navigateToExternalUrl = (url, optionalQuery = {}) => {
|
|||
navigateToUrl(url, optionalQuery);
|
||||
};
|
||||
|
||||
router.navigateError = () => {
|
||||
DisplayPageError();
|
||||
router.navigateError = (errorPayload = null) => {
|
||||
DisplayPageError(errorPayload);
|
||||
};
|
||||
|
||||
//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) {
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);
|
||||
|
||||
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.
|
||||
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
|
||||
eventBus.addEventToBus(
|
||||
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
|
||||
eventBus.addEventToBus(
|
||||
globalEvents.Categories.GLOBAL_ALERT,
|
||||
|
|
@ -619,7 +738,11 @@ async function DisplayPageError() {
|
|||
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);
|
||||
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
||||
|
||||
|
|
@ -700,22 +823,6 @@ function getRedirectedStartPage() {
|
|||
}
|
||||
|
||||
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 externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
||||
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
||||
|
|
@ -734,6 +841,7 @@ function updateExternalParameterState() {
|
|||
externalParameterModel &&
|
||||
externalParameterStyle
|
||||
) {
|
||||
resetStoreForExternalParameter();
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE);
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ const fmgPageValues = {
|
|||
PAYMENT: "payment",
|
||||
PAYMENT_PIA_RETURN: "payment-pia-return",
|
||||
CONFIRMATION: "confirmation",
|
||||
RETURN_USER: "return-user",
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
// 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: {
|
||||
licensePlate: null,
|
||||
},
|
||||
isMobileStaticRecalibrationApplicable: false,
|
||||
},
|
||||
serviceLocation: {
|
||||
address: null,
|
||||
|
|
@ -225,6 +226,10 @@ export const mutations = {
|
|||
updateVehicleVin(state, vin) {
|
||||
state.order.vehicle.vin = vin;
|
||||
},
|
||||
updateIsMobileStaticRecalibrationApplicable(state, isMobileStaticRecalibrationApplicable) {
|
||||
state.order.vehicle.isMobileStaticRecalibrationApplicable =
|
||||
isMobileStaticRecalibrationApplicable;
|
||||
},
|
||||
updateIsRepair(state, isRepair) {
|
||||
state.order.damage.isRepair = isRepair;
|
||||
},
|
||||
|
|
@ -350,6 +355,8 @@ export const mutations = {
|
|||
state.order.vehicle.imageUrl = vehicleInfo.imageUrl;
|
||||
state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber;
|
||||
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
||||
state.order.vehicle.isMobileStaticRecalibrationApplicable =
|
||||
vehicleInfo.isMobileStaticRecalibrationApplicable;
|
||||
},
|
||||
updateRegistration(state, registrationInfo) {
|
||||
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
|
||||
|
|
@ -534,6 +541,7 @@ export const mutations = {
|
|||
state.order.vehicle.imageUrl = null;
|
||||
state.order.vehicle.imageVifNumber = null;
|
||||
state.order.vehicle.imageColor = null;
|
||||
state.order.vehicle.isMobileStaticRecalibrationApplicable = false;
|
||||
},
|
||||
resetDamageState(state) {
|
||||
state.order.damage.isRepair = null;
|
||||
|
|
@ -1600,7 +1608,7 @@ export const actions = {
|
|||
return response;
|
||||
},
|
||||
|
||||
getMobileFeePart(context, { pageNameToLog }) {
|
||||
getMobileFeePart(context, { payload: { serviceZipCode, serviceZipCodeCtu }, pageNameToLog }) {
|
||||
const serviceType = context.getters.damage.isRepair ? "Repair" : "Install";
|
||||
const facilityType = "Mobile";
|
||||
const parentAccountNumber = context.getters.payment.parentAccountNumber;
|
||||
|
|
@ -1612,16 +1620,31 @@ export const actions = {
|
|||
const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus);
|
||||
const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType);
|
||||
const isItacOptimized = order.policy?.isItac ?? false;
|
||||
const isMobileStaticRecalibrationApplicable =
|
||||
order.vehicle?.isMobileStaticRecalibrationApplicable;
|
||||
const zipCode =
|
||||
order.serviceLocation?.provider?.address?.zipCode ?? order.serviceLocation?.zipCode;
|
||||
serviceZipCode ??
|
||||
order.serviceLocation?.provider?.address?.zipCode ??
|
||||
order.serviceLocation?.zipCode;
|
||||
|
||||
var providerNumber =
|
||||
order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu;
|
||||
serviceZipCodeCtu ??
|
||||
order.serviceLocation?.provider?.providerNumber ??
|
||||
order.serviceLocation?.zipCodeCtu;
|
||||
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
|
||||
providerNumber = providerNumber.substring(1);
|
||||
}
|
||||
|
||||
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) {
|
||||
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
|
||||
}
|
||||
|
|
@ -2222,7 +2245,18 @@ export const actions = {
|
|||
// Vehicle
|
||||
saveVehicle(
|
||||
context,
|
||||
{ year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor }
|
||||
{
|
||||
year,
|
||||
make,
|
||||
model,
|
||||
style,
|
||||
carId,
|
||||
category,
|
||||
imageUrl,
|
||||
imageVifNumber,
|
||||
imageVifColor,
|
||||
isMobileStaticRecalibrationApplicable,
|
||||
}
|
||||
) {
|
||||
if (
|
||||
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_VIF_NUMBER, imageVifNumber);
|
||||
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) {
|
||||
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="[
|
||||
isPrimary ? 'btn-primary' : 'btn-secondary',
|
||||
isFloat ? 'float-end' : '',
|
||||
(isLoaderDisplayed && !suppressLoader) ? 'has-loader' : '',
|
||||
isLoaderDisplayed && !suppressLoader ? 'has-loader' : '',
|
||||
]"
|
||||
@click="clicked">
|
||||
<span class="m-0">{{ this.buttonText }}</span>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ export default {
|
|||
.list-button-horizontal-content {
|
||||
outline: none;
|
||||
position: relative;
|
||||
background: $white;
|
||||
transition: all 150ms linear;
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 0;
|
||||
|
|
@ -110,8 +109,8 @@ export default {
|
|||
}
|
||||
|
||||
.list-button-horizontal-content:hover {
|
||||
background-color: $blue-700;
|
||||
color: $white;
|
||||
background-color: transparent;
|
||||
color: $blue;
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -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 = "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx";
|
||||
process.env.VUE_APP_SOLARWINDS_MONITORING = "";
|
||||
process.env.VUE_APP_SESSION_TIMEOUT_MINUTES = 30;
|
||||
|
||||
// GA & GTM
|
||||
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_SAFELITE_HOP = "__VUE_APP_SAFELITE_HOP__";
|
||||
process.env.VUE_APP_SOLARWINDS_MONITORING_SCRIPT = "__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__";
|
||||
process.env.VUE_APP_SESSION_TIMEOUT_MINUTES = 30;
|
||||
|
||||
// GA & GTM
|
||||
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = "__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__";
|
||||
|
|
|
|||
Loading…
Reference in a new issue