CASH-109 return user page

CASH-109 return user page for when a session times out
This commit is contained in:
CarlNation 2025-01-17 15:34:05 -05:00
parent 66da230cc9
commit 9822cdfedf
11 changed files with 144 additions and 10 deletions

View file

@ -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 };

View file

@ -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 }),

View file

@ -217,11 +217,11 @@ export default {
flex: none;
}
.textbox-question {
padding: .25rem 0;
padding: 0.25rem 0;
}
}
}
&.modal-dialog-centered {
align-items: flex-end;
min-height: 100%;

View file

@ -94,10 +94,10 @@ export default {
// hide save progress button; show success message alert
this.isProgressSaved = true;
// communicate to parent the new status
this.$emit("save-progress-saved");
this.modal.closeModal();
},
},

View file

@ -115,7 +115,7 @@ export default {
currentPage: pageNameToLog,
endpoint: endpoint,
};
router.navigateError(errorPayload);
// do not log 404 errors from services because we return NotFound

View file

@ -621,7 +621,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) {

View file

@ -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() {

View file

@ -0,0 +1,118 @@
<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">
<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() {
// clicking continue and use no page name to trigger the implicit navigation in router
window.location.href = "/fmg/";
},
async startOver() {
this.pushEventToGA(
this.$route.query[this.queryStrings.FMG_PAGE],
this.GaActions.CLICKED,
"Start over",
true
);
deleteFunnelCookie();
await this.dispatchStoreAction(storeActions.RESET_STATE);
window.location.href = "/fmg/";
},
},
components: {
Form,
funnelHeader,
funnelSubHeader,
navbar,
},
};
</script>
<style lang="scss" scoped>
.start-over {
text-align: center;
a {
font-weight: 600;
color: $black;
cursor: pointer;
}
}
</style>

View file

@ -26,6 +26,7 @@ import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { applicationConfig } from "../constants/application-config";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
export default {
methods: {
@ -651,7 +652,6 @@ export default {
},
pushPageErrorToDataLayer(error) {
pushToDataLayerIfDefined({
event: "page-error",
error: error,
@ -710,6 +710,17 @@ export default {
},
async validateSession() {
// The noSession function checks the cookies related to analytics logging(sid). it is not the funnel info cookie.
// The sid cookie for analytics will expire every 30 minutes and get recreated in initSession. If this happens
// and we also have the funnel cookie present, that indicates they have an existing session that is now expired
// so route them to the return user page.
const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
if (this.noSession() && funnelCookieLastTouched !== null && funnelCookieLastTouched !== undefined) {
await this.initSession();
window.location.href = applicationConfig.RETURN_USER_PAGE;
return;
}
if (this.noSession()) {
await this.initSession();
}

View file

@ -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 };

View file

@ -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 =