From bba2631ec5722a8dc54b53f8862bf8882a10cad0 Mon Sep 17 00:00:00 2001 From: Chris Redelinghuys Date: Mon, 13 Jan 2025 09:36:16 -0500 Subject: [PATCH 01/65] CASH-69 --- src/constants/store-mutations.js | 2 ++ .../service-location/service-location.vue | 11 +++++++- src/layouts/vehicle/vehicle.vue | 8 ++++++ src/store/index.js | 25 ++++++++++++++++++- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 740c5a47e..f625e27cf 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -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", diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 4017088c4..70991f0f5 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -188,6 +188,8 @@ export default { isRecalibrationServiceableInshop: null, isGlassServiceableMobile: null, isRecalibrationServiceableMobile: null, + isVehicleMobileStaticRecalibrationApplicable: + this.getIsVehicleMobileStaticRecalibrationApplicableFromStore(), selectedAppointmentType: this.getSelectedAppointmentType(), selectedProvider: this.getSelectedProvider(), mobileFeePart: null, @@ -306,7 +308,11 @@ export default { }, isServiceableMobile() { if (this.isRecalibrationServiceableMobile !== null) { - return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile; + return ( + this.isGlassServiceableMobile && + this.isRecalibrationServiceableMobile && + this.isVehicleMobileStaticRecalibrationApplicable + ); } else { return this.isGlassServiceableMobile; } @@ -485,6 +491,9 @@ export default { getSelectedProvider() { return store.getters.order.serviceLocation.provider; }, + getIsVehicleMobileStaticRecalibrationApplicableFromStore() { + return store.getters.order.vehicle.isMobileStaticRecalibrationApplicable; + }, resetMobileLocation() { this.streetAddress = ""; this.apartmentNumberOrBusinessName = ""; diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index 18eee6988..6a634d826 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -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: { diff --git a/src/store/index.js b/src/store/index.js index d964a48d5..d7f7dcb06 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -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; @@ -2221,7 +2229,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 || @@ -2242,6 +2261,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 + ); } }, From 32fc82176b7c6292aeb2cfaeea5386a88c32e44b Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Mon, 13 Jan 2025 13:57:06 -0500 Subject: [PATCH 02/65] CASH-69 fix unit test --- src/layouts/service-location/service-location.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layouts/service-location/service-location.spec.js b/src/layouts/service-location/service-location.spec.js index eea946b89..6333082ec 100644 --- a/src/layouts/service-location/service-location.spec.js +++ b/src/layouts/service-location/service-location.spec.js @@ -181,6 +181,9 @@ beforeEach(() => { zipCode: "43235", state: "OH", }, + vehicle: { + isMobileStaticRecalibrationApplicable: true, + }, }, damage: { isRepair: false, From 6ec8709aa42fff3d545961bfed477849b37566bb Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Tue, 14 Jan 2025 11:47:14 -0500 Subject: [PATCH 03/65] CASH-61: add logging to GoToFunnelStartOn404 --- src/mixins/analytics-mixin.js | 13 +++++++ src/router/index.js | 68 +++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index e970e94a8..30f8328f0 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -650,6 +650,19 @@ export default { }); }, + pushPageErrorToDataLayer(error) { + + pushToDataLayerIfDefined({ + event: "page-error", + error: { + type: error.type || "", + cause: error.cause || "", + currentPage: error.currentPage || "", + nextPage: error.nextPage || "", + }, + }); + }, + prependActionToMethod(object, method, actionToPrepend) { const baseMethodName = method.name.startsWith("bound ") ? method.name.substring(6) diff --git a/src/router/index.js b/src/router/index.js index da3c1914c..028a6d85f 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -65,9 +65,17 @@ 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; } // Intercept all navigation if a submitted order exists in storage @@ -206,7 +214,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,9 +229,15 @@ 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. @@ -237,9 +258,18 @@ const routes = [ .components.default(); 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 +291,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; } }, }, @@ -399,6 +438,7 @@ router.navigateToExternalUrl = (url, optionalQuery = {}) => { router.navigateError = () => { DisplayPageError(); + /// TODO - Add error logging for dataLayer here? }; //Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example. @@ -588,7 +628,19 @@ 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, @@ -608,6 +660,8 @@ function GoToFunnelStartOn404(next) { } async function DisplayPageError() { + console.log("%c running DisplayPageError()... ", "font-size: 20px; color: purple;"); + // Put item on the bus eventBus.addEventToBus( globalEvents.Categories.GLOBAL_ALERT, From fc834f9d1211658c6389f995a86442e3edad3083 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Jan 2025 10:31:06 -0500 Subject: [PATCH 04/65] Additional error logging --- src/global-methods.js | 8 +++++++- src/mixins/analytics-mixin.js | 7 +------ src/router/index.js | 20 ++++++++++++++++---- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 22512fe41..96c5e21fc 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -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 diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 30f8328f0..d534a7200 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -654,12 +654,7 @@ export default { pushToDataLayerIfDefined({ event: "page-error", - error: { - type: error.type || "", - cause: error.cause || "", - currentPage: error.currentPage || "", - nextPage: error.nextPage || "", - }, + error: error, }); }, diff --git a/src/router/index.js b/src/router/index.js index 028a6d85f..d92f213bc 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -436,9 +436,8 @@ router.navigateToExternalUrl = (url, optionalQuery = {}) => { navigateToUrl(url, optionalQuery); }; -router.navigateError = () => { - DisplayPageError(); - /// TODO - Add error logging for dataLayer here? +router.navigateError = (errorPayload = null) => { + DisplayPageError(errorPayload); }; //Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example. @@ -659,9 +658,22 @@ function GoToFunnelStartOn404(next, errorPayload = null) { }); } -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 { + errorPayload = { + type: "DisplayPageError", + cause: "Unknown page error", + currentPage: getQuerystringParameter(queryStrings.FMG_PAGE), + nextPage: null, + }; + analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); + } + // Put item on the bus eventBus.addEventToBus( globalEvents.Categories.GLOBAL_ALERT, From 7af0c3f0a1da276f10ae5f44f189c65df8e27e66 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Jan 2025 10:50:14 -0500 Subject: [PATCH 05/65] Defensive coding in error handling --- src/router/index.js | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index d92f213bc..0da560c84 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -68,8 +68,8 @@ const routes = [ const errorPayload = { cause: "expired session", - currentPage: from.query.fmgPage, - nextPage: to.query.fmgPage, + currentPage: from?.query?.fmgPage, + nextPage: to?.query?.fmgPage, }; await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE); @@ -216,8 +216,8 @@ const routes = [ const errorPayload = { cause: "invalid page prerequisites for page", - currentPage: from.query.fmgPage, - nextPage: to.query.fmgPage, + currentPage: from?.query?.fmgPage, + nextPage: to?.query?.fmgPage, }; GoToFunnelStartOn404(next, errorPayload); @@ -231,8 +231,8 @@ const routes = [ if (!isExistingFmgPageName(to.query.fmgPage)) { const errorPayload = { cause: "invalid page name", - currentPage: from.query.fmgPage, - nextPage: to.query.fmgPage, + currentPage: from?.query?.fmgPage, + nextPage: to?.query?.fmgPage, }; GoToFunnelStartOn404(next, errorPayload); @@ -264,8 +264,8 @@ const routes = [ const errorPayload = { cause: "invalid page prerequisites for page", - currentPage: from.query.fmgPage, - nextPage: to.query.fmgPage, + currentPage: from?.query?.fmgPage, + nextPage: to?.query?.fmgPage, }; GoToFunnelStartOn404(next, errorPayload); @@ -293,10 +293,10 @@ const routes = [ // If we don't have a route, go to our 404 page. const errorPayload = { cause: "uncaught error in beforeEnter", - currentPage: from.query.fmgPage, - nextPage: to.query.fmgPage, + currentPage: from?.query?.fmgPage, + nextPage: to?.query?.fmgPage, fullError: error, - errorStack: error.stack, + errorStack: error?.stack, }; GoToFunnelStartOn404(next, errorPayload); @@ -665,11 +665,17 @@ async function DisplayPageError(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: getQuerystringParameter(queryStrings.FMG_PAGE), - nextPage: null, + currentPage: currentPage, }; analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); } From 341d1b3ed36827ca2b30b75046564c0c23a10451 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 15 Jan 2025 11:54:08 -0500 Subject: [PATCH 06/65] Revert "Merge pull request #2198 from Safelite/feature/CASH-77" This reverts commit 4d462fdb0af8e4a7f4cfe7e10bafc1dae94b5115, reversing changes made to 94504194ea846c3b6313840daad7b2461b943cf6. --- src/digital-components/modal/modal.vue | 49 +--- .../save-progress-modal-question.vue | 73 +++--- .../save-progress-popup-question.spec.js | 51 ---- .../save-progress-popup-question.vue | 227 ------------------ .../capability-questions.vue | 4 +- .../molding-questions/molding-questions.vue | 4 +- src/layouts/part-questions/part-questions.vue | 4 +- src/layouts/quote/quote.spec.js | 4 +- src/layouts/quote/quote.vue | 49 +--- 9 files changed, 67 insertions(+), 398 deletions(-) delete mode 100644 src/fmg-components/save-progress-popup-question/save-progress-popup-question.spec.js delete mode 100644 src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 2f9534750..e412678ff 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -2,9 +2,7 @@ -
-
- -
-
@@ -139,7 +134,6 @@ import { packageNames } from "@/constants/package-names"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { containsRecalParts } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; -import { saveQuote } from "@/helpers/heritage-integration/order-helper.js"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); @@ -461,9 +455,6 @@ export default { }, }, methods: { - async handleClick() { - await saveQuote({ pageNameToLog: "quote" }); - }, openModalAction(modalName) { this.$refs[modalName].openModal(); }, diff --git a/src/store/index.js b/src/store/index.js index 18c2834a4..4f9bf61e3 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1931,49 +1931,6 @@ export const actions = { }, // Session API Actions - saveQuote(context, { pageNameToLog, payload }) { - const vehicle = context.getters.vehicle; - const damage = context.getters.damage; - const order = context.state.order; - const applicationUser = context.getters.applicationUser; - const lineItems = context.state.order.lineItems; - const excludeRecalInquote = context.getters.shouldHideRecalibration; - - return globalMethods.callHttpClient({ - method: endpoints.SaveQuote.method, - endpoint: endpoints.SaveQuote.url, - payload: { - referralCorrelationId: order.referralCorrelationId, - referralNumber: order.referralNumber?.toString(), - referralSequenceNumber: order.referralSequenceNumber, - emailAddress: "cn@gm.com", //order.customer.emailAddress, - lastPage: pageNameToLog, - isRepair: damage.isRepair, - firstName: order.customer.firstName, - lastName: order.customer.lastName, - savedSessionId: applicationUser.savedSessionId, - serviceState: order.serviceLocation.state, - serviceZipCode: order.serviceLocation.zipCode, - parentAccountNumber: order.payment.parentAccountNumber, - excludeRecalInquote: excludeRecalInquote, - year: vehicle.year, - make: vehicle.make, - model: vehicle.model, - isInsurance: order.payment.isInsurance ?? false, - isVerified: order.payment.insuranceCoverage.isVerified ?? false, - lineItems: { - glassParts: lineItems.glassParts, - supportingItems: lineItems.supportingItems, - vaps: lineItems.vaps, - serverData: lineItems.serverData, - promos: lineItems.promos, - }, - }, - logApiCall: true, - pageNameToLog: pageNameToLog, - }); - }, - saveSession(context, { pageNameToLog, payload }) { const vehicle = context.getters.vehicle; const damage = context.getters.damage; @@ -2051,7 +2008,8 @@ export const actions = { order.payment.insuranceCoverage.coverageStatus?.toString(), coverageVerificationType: order.payment.insuranceCoverage.coverageVerificationType, - coverageSubStatus: order.payment.insuranceCoverage.coverageSubStatus, + coverageSubStatus: + order.payment.insuranceCoverage.coverageSubStatus, }, isInsurance: order.payment.isInsurance, parentAccountNumber: order.payment.parentAccountNumber, From 9791542dc0883a7aac557a5922dc897e312b91d7 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 15 Jan 2025 13:08:41 -0500 Subject: [PATCH 17/65] Revert "Revert "Merge pull request #2199 from Safelite/feature/CASH-79-BE"" This reverts commit a90b330d466396c85eb682dc1c5c3fe6f38b15b3. --- src/helpers/logger.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/helpers/logger.js b/src/helpers/logger.js index 53c2cb808..8af062c3b 100644 --- a/src/helpers/logger.js +++ b/src/helpers/logger.js @@ -32,7 +32,12 @@ export class Logger { } formatLogEntry(message, details) { - return `Application: ${applicationConfig.APPLICATION_NAME}\n${message}\n${ + const refSeqNumber = store.getters.order.referralSequenceNumber ?? ""; + const year = store.getters.vehicle.year ?? ""; + const make = store.getters.vehicle.make ?? ""; + const model = store.getters.vehicle.model ?? ""; + const vehicle = `${year} ${make} ${model}`; + return `${new Date()} ReferralSequenceNumber: ${refSeqNumber}\nVehicle: ${vehicle}\nApplication: ${applicationConfig.APPLICATION_NAME}\n${message}\n${ details ? JSON.stringify(details, undefined, 2) : "" }`; } From 9e24c0d45b1e57ee2f708bb57c718499464dd20f Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Thu, 16 Jan 2025 06:50:04 -0500 Subject: [PATCH 18/65] Revert "Merge pull request #2204 from Safelite/release/revert-syp-from-2025.01.16" This reverts commit 38e81949b3077f33e65c0d122c74cdde9c7d0e05, reversing changes made to 4d462fdb0af8e4a7f4cfe7e10bafc1dae94b5115. --- src/constants/endpoints.js | 4 + src/constants/store-actions.js | 1 + src/digital-components/modal/modal.vue | 83 ++++++- .../questions-page-layout.vue | 12 +- .../save-progress-modal-question.spec.js | 51 ++++ .../save-progress-modal-question.vue | 186 ++++++++++++++ .../save-progress-question.spec.js | 40 +++ .../save-progress-question.vue | 62 +++++ .../save-progress-popup-question.spec.js | 51 ++++ .../save-progress-popup-question.vue | 227 ++++++++++++++++++ .../heritage-integration/order-helper.js | 19 ++ .../capability-questions.vue | 18 +- .../molding-questions/molding-questions.vue | 18 +- src/layouts/part-questions/part-questions.vue | 18 +- src/layouts/quote/quote.spec.js | 36 +++ src/layouts/quote/quote.vue | 55 ++++- src/layouts/vehicle-parts/vehicle-parts.vue | 15 +- src/store/index.js | 46 +++- src/styles/common-styles.scss | 2 +- src/ux-components/button-main/button-main.vue | 4 +- 20 files changed, 924 insertions(+), 24 deletions(-) create mode 100644 src/fmg-components/save-progress-modal-question/save-progress-modal-question.spec.js create mode 100644 src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue create mode 100644 src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.spec.js create mode 100644 src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.vue create mode 100644 src/fmg-components/save-progress-popup-question/save-progress-popup-question.spec.js create mode 100644 src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 16e0803e6..c972d8118 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -124,6 +124,10 @@ const endpoints = { url: "/order/api/v1/order/load-session", method: "POST", }, + SaveQuote: { + url: "/order/api/v1/order/initiate-saved-progress-email", + method: "POST", + }, GetSignature: { url: "/order/api/v1/order/sign", method: "POST", diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 41e5896bd..45a18bace 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -37,6 +37,7 @@ const storeActions = { GET_MOBILE_PREMIUM_FEE: "getMobilePremiumFee", SAVE_SESSION: "saveSession", LOAD_SESSION: "loadSession", + SAVE_QUOTE: "saveQuote", UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse", VALIDATE_ZIP: "validateZip", PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "priceOrderItemsAndSaveServerData", diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 37ebee18e..2f9534750 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -2,7 +2,9 @@ @@ -53,6 +55,8 @@ export default { props: { headerText: String, footerButtonText: String, + suppressPageScroll: Boolean, + staticBackdrop: Boolean, onModalOpenedCallback: { type: Function, }, @@ -91,7 +95,7 @@ export default { e.preventDefault(); if (this.isEnterClicked) return; this.isEnterClicked = true; - document.getElementById("modalbtn")?.focus(); + document.getElementById(this.modalId + "-modalbtn")?.focus(); this.$refs.modalButtonMain.clicked(); document.getElementById(this.modalId)?.focus(); setTimeout(() => { @@ -107,8 +111,12 @@ export default { onModalClosed() { this.resetButtonStyle(); this.onModalClosedCallback?.(); + if (this.suppressPageScroll) + document.querySelector("body").classList.remove("prevent-modal-scroll"); }, openModal() { + if (this.suppressPageScroll) + document.querySelector("body").classList.add("prevent-modal-scroll"); const modal = Modal.getOrCreateInstance(document.getElementById(this.modalId)); modal.show(); this.$emit("isModalOpened", true); @@ -126,6 +134,9 @@ export default { } return !this.meta.dirty || !this.meta.valid; }, + backdropSetting() { + return this.staticBackdrop ? "static" : "true"; + }, }, components: { modalButtonMain, @@ -231,6 +242,54 @@ export default { } } } +.save-progress-modal-question { + p.modal-body { + padding: 0; + } + .modal-body { + display: flex; + flex-direction: column; + + .textbox-question { + padding: 0; + + margin: 0 0 1.5rem 0; + } + } +} + +.save-progress-modal-question, +.save-progress-popup-question { + p.modal-body { + padding: 0; + } + .modal-body { + display: flex; + flex-direction: column; + + .textbox-question { + padding: 0; + + label { + text-align: left; + font-weight: 900; + } + } + } + .modal-body-inner { + text-align: center; + margin-bottom: 1.5rem; + } + .modal-disclaimer { + font-size: 0.75rem; + order: 2; + } + .modal-footer { + margin: 0 0 1.5rem 0; + padding-top: 0; + padding-bottom: 0; + } +} body { .modal-backdrop { height: 100%; diff --git a/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue b/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue index 982738394..2c4d71803 100644 --- a/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue +++ b/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue @@ -25,7 +25,7 @@
-
+
+ + diff --git a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.spec.js b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.spec.js new file mode 100644 index 000000000..15fb1481d --- /dev/null +++ b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.spec.js @@ -0,0 +1,51 @@ +import { mount, shallowMount } from "@vue/test-utils"; +import saveProgressModalQuestion from "./save-progress-modal-question"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +jest.mock("@/digital-components/modal/modal", () => ({ + methods: { + openModal: jest.fn(), + resetButtonStyle: jest.fn(), + }, +})); + +describe("save-progress-modal-question ", () => { + describe("when openModal is run ", () => { + test("the modal should open ", () => { + // Arrange + const { wrapper } = setupMocks({ + props: { + modelValue: "", + modalWidgetName: "testModal", + }, + }); + + // Act + wrapper.vm.openModal(); + + // Assert + expect(wrapper.vm.modal).not.toBeNull(); + }); + }); +}); + +function setupMocks({ options, props }) { + const mountOptions = getMountOptions({ + ...options, + }); + + const mockBaseMixin = { + methods: { + getCmsContent: jest.fn(), + dispatchStoreAction: jest.fn(), + }, + }; + + if (props) mountOptions.propsData = props; + + mountOptions.global.mixins = [mockBaseMixin]; + + const wrapper = mount(saveProgressModalQuestion, mountOptions); + + return { wrapper }; +} diff --git a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue new file mode 100644 index 000000000..c8465fef7 --- /dev/null +++ b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.spec.js b/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.spec.js new file mode 100644 index 000000000..7cc3d100c --- /dev/null +++ b/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.spec.js @@ -0,0 +1,40 @@ +import { shallowMount } from "@vue/test-utils"; +import saveProgressQuestion from "./save-progress-question"; + +describe("save-progress-question.vue", () => { + it("Should get the modelValue", async () => { + // Arrange + const text = "test"; + const wrapper = shallowMount(saveProgressQuestion, { + props: { + modelValue: text, + }, + attachTo: document.body, + }); + + // Act + const modelValueText = wrapper.vm.value; + wrapper.vm.value = "test also"; + + // Assert + expect(modelValueText).toEqual("test"); + }); + + it("Should emit to set value", async () => { + // Arrange + const text = "test"; + const wrapper = shallowMount(saveProgressQuestion, { + props: { + modelValue: text, + }, + attachTo: document.body, + }); + + // Act + const modelValueText = wrapper.vm.value; + wrapper.vm.value = "test also"; + + // Assert + expect(wrapper.emitted("update:modelValue")).toEqual([["test also"]]); + }); +}); diff --git a/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.vue b/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.vue new file mode 100644 index 000000000..221aa3415 --- /dev/null +++ b/src/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question.vue @@ -0,0 +1,62 @@ + + + diff --git a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.spec.js b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.spec.js new file mode 100644 index 000000000..e2ca84f1d --- /dev/null +++ b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.spec.js @@ -0,0 +1,51 @@ +import { mount, shallowMount } from "@vue/test-utils"; +import saveProgressPopupQuestion from "./save-progress-popup-question"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +jest.mock("@/digital-components/modal/modal", () => ({ + methods: { + closeModal: jest.fn(), + resetButtonStyle: jest.fn(), + }, +})); + +describe("save-progress-popup-question ", () => { + describe("when closeModal is run ", () => { + test("the modal should close ", () => { + // Arrange + const { wrapper } = setupMocks({ + props: { + modelValue: "", + modalWidgetName: "testModal", + }, + }); + + // Act + wrapper.vm.closeModal(); + + // Assert + expect(wrapper.vm.modal).not.toBeNull(); + }); + }); +}); + +function setupMocks({ options, props }) { + const mountOptions = getMountOptions({ + ...options, + }); + + const mockBaseMixin = { + methods: { + getCmsContent: jest.fn(), + dispatchStoreAction: jest.fn(), + }, + }; + + if (props) mountOptions.propsData = props; + + mountOptions.global.mixins = [mockBaseMixin]; + + const wrapper = mount(saveProgressPopupQuestion, mountOptions); + + return { wrapper }; +} diff --git a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue new file mode 100644 index 000000000..740385dac --- /dev/null +++ b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 555c41325..76729e49f 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -98,6 +98,25 @@ export async function submitWorkOrder({ }); } +export async function saveQuote({ pageNameToLog }) { + await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.SAVE_QUOTE, + {}, + pageNameToLog, + false + ); + + // save session back to sv2 so the email gets saved just in case they refresh or step away and come back later + await saveSession({ + pageNameToLog: pageNameToLog, + shouldAwaitSaveSessionQueue: true, + submitAfterSave: false, + createUnscheduledStatusWorkOrderForPIA: false, + }); + + return; +} + // PRIVATE FUNCTIONS // /* diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 4d637c978..9d51ec2f7 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -12,13 +12,20 @@ @forwardButtonAction="forwardButtonAction" @back-click="navigateBack" :key="currentGlassIndex" - :index="currentGlassIndex" /> + :index="currentGlassIndex"> + + + diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 00df8c04b..2f2cc346c 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -12,13 +12,20 @@ @forwardButtonAction="forwardButtonAction" @back-click="navigateBack" :key="currentGlassIndex" - :index="currentGlassIndex" /> + :index="currentGlassIndex"> + + + diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index bc1ec308e..a5441acd6 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -12,13 +12,20 @@ @forwardButtonAction="forwardButtonAction" @back-click="navigateBack" :key="currentGlassIndex" - :index="currentGlassIndex" /> + :index="currentGlassIndex"> + + + diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index 778ce0ce8..deca0d6d1 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -121,6 +121,9 @@ store.getters = { isInsurance: false, parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, }, + customer: { + emailAddress: "test@test.com", + }, }, }; @@ -136,6 +139,9 @@ afterEach(() => { insuranceCoverage: {}, isInsurance: false, }, + customer: { + emailAddress: "test@test.com", + }, }; }); @@ -263,6 +269,9 @@ describe("quote.vue", () => { glassParts: ["item", "item2"], }, payment: {}, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { zipCode: "12345", zipCodeCtu: "value", @@ -309,6 +318,9 @@ describe("quote.vue", () => { glassParts: ["item", "item2"], }, payment: {}, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { zipCode: "12345", zipCodeCtu: "value", @@ -355,6 +367,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -396,6 +411,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -438,6 +456,9 @@ describe("quote.vue", () => { payment: { isInsurance: true, }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -480,6 +501,9 @@ describe("quote.vue", () => { payment: { isInsurance: false, }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -523,6 +547,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, // Ensure that previous selection isn't overriding selection }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -568,6 +595,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, // Ensure that previous selection isn't overriding selection }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: null, }, @@ -612,6 +642,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, }, + customer: { + emailAddress: "test@test.com", + }, serviceLocation: { state: "AZ", }, @@ -717,6 +750,9 @@ describe("quote.vue", () => { isInsurance: true, inactivePromos: [], }, + customer: { + emailAddress: "test@test.com", + }, }, externalParameterState: { isExternalParameter: 1 }, externalParameterQuote: { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 6f3809304..366a9d2cc 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -1,8 +1,10 @@ @@ -100,6 +120,8 @@ import contentGroupModal from "@/fmg-components/content-group-modal/content-grou import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner"; import recalDisclaimer from "@/layouts/quote/recal-disclaimer/recal-disclaimer.vue"; +import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question"; +import saveProgressPopupQuestion from "@/fmg-components/save-progress-popup-question/save-progress-popup-question"; // Supporting files import baseMixin from "@/mixins/base-mixin.js"; @@ -134,6 +156,7 @@ import { packageNames } from "@/constants/package-names"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { containsRecalParts } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; +import { saveQuote } from "@/helpers/heritage-integration/order-helper.js"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); @@ -183,6 +206,10 @@ export default { ]; const resultMap = await settleAllPromises(promiseResultMap); + const emailFromStore = store.getters.order.customer.emailAddress; + const isEmailInStoreOnPageLoad = emailFromStore?.length > 0; + const showSaveProgressPopup = isEmailInStoreOnPageLoad ? false : true; + const lineItems = deepClone(store.getters.order.lineItems); lineItems.vaps = lineItems.vaps ?? []; const nullSafeGlassParts = lineItems.glassParts ?? []; @@ -263,6 +290,8 @@ 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; vm.addableVaps = addableVaps; vm.lineItems = lineItems; vm.availableLineItems = pricingResults; @@ -409,6 +438,8 @@ export default { servicePackage: null, holdParentAccountNumber: null, holdBillToAccountNumber: null, + isEmailInStoreOnPageLoad: null, + showSaveProgressPopup: null, }; }, computed: { @@ -495,6 +526,14 @@ export default { backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); }, + saveProgress() { + this.isEmailInStoreOnPageLoad = true; + this.showSaveProgressPopup = false; + saveQuote({ pageNameToLog: "quote" }); + }, + closeSaveProgressPopup() { + this.showSaveProgressPopup = false; + }, forwardButtonAction() { this.dispatchStoreAction( this.storeActions.SAVE_PAYMENT_TYPE, @@ -680,10 +719,22 @@ export default { afterpayModalBanner, promoModalQuestion, recalDisclaimer, + saveProgressModalQuestion, + saveProgressPopupQuestion, }, }; + diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index d534a7200..5a2da603d 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -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(); } diff --git a/src/router/router-constants/fmgPage-values.js b/src/router/router-constants/fmgPage-values.js index 6b4ec77ea..5fade6506 100644 --- a/src/router/router-constants/fmgPage-values.js +++ b/src/router/router-constants/fmgPage-values.js @@ -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 }; diff --git a/vue.config.js b/vue.config.js index 28d20e406..d8cb42355 100644 --- a/vue.config.js +++ b/vue.config.js @@ -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 = From 47586b581619273210dd859bec66f2b5bb5aef85 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 17 Jan 2025 16:50:25 -0500 Subject: [PATCH 34/65] CASH-124: fix bug with unmounted hook --- .../save-progress-modal-question.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue index 510f7bc3e..e1fc3e180 100644 --- a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue +++ b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue @@ -53,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"); From 29ed44c68b022d5cabf682f0c7ff5bfb087e0331 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 17 Jan 2025 16:52:39 -0500 Subject: [PATCH 35/65] CASH-122: fix bug with edge case of styling of skip button --- .../modal-button-main/modal-button-main.vue | 2 +- .../save-progress-popup-question.vue | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue index 687ae6858..41f9d2d8a 100644 --- a/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue +++ b/src/digital-components/modal/ux-components/modal-button-main/modal-button-main.vue @@ -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: diff --git a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue index e23266a51..4ab1213c4 100644 --- a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue +++ b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue @@ -143,11 +143,12 @@ export default { } } - .skip-button { + .btn.btn-secondary.skip-button { order: 4; position: relative; color: $black; border: none; + border-radius: .25rem; font-weight: 900; font-size: 0.875rem; text-align: center; @@ -164,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 From 5360783093aacef1b0b25a474ea4f8e895d717c0 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Sat, 18 Jan 2025 07:53:42 -0500 Subject: [PATCH 36/65] CASH-109 CASH-109 will follow up later with tests for return-user --- jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.js b/jest.config.js index ce4aa3ad6..052e1c47b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -27,6 +27,7 @@ module.exports = { "!src/layouts/insurance/*.vue", // Temp test exclusion while in development "!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development "!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development + "!src/layouts/return-user/*.vue", // Temp test exclusion while in development // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], From 6a9585b661403ccfafd8be58d675af0dd2941363 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Sat, 18 Jan 2025 08:37:20 -0500 Subject: [PATCH 37/65] CASH-109 CASH-109 new variable --- azure-pipelines.yml | 4 ++++ vue.release.config.js | 1 + 2 files changed, 5 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3ac871d20..23d5e6806 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -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__) diff --git a/vue.release.config.js b/vue.release.config.js index 2c215c8ad..350a78ce3 100644 --- a/vue.release.config.js +++ b/vue.release.config.js @@ -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__"; From 32a73e25f43572a0e1a772c72c7c1d4da4cee3cb Mon Sep 17 00:00:00 2001 From: CarlNation Date: Sun, 19 Jan 2025 12:22:51 -0500 Subject: [PATCH 38/65] CASH-109 add logic to direct to return user page when navigating from external site excluding heritage CASH-109 add logic to direct to return user page when navigating from external site excluding heritage --- src/constants/query-strings.js | 1 + src/layouts/return-user/return-user.vue | 11 ++- src/mixins/analytics-mixin.js | 6 +- src/router/index.js | 72 ++++++++++++++++++-- src/router/router-constants/routing-table.js | 10 +++ 5 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 3cdfd655f..210ac28f0 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -45,6 +45,7 @@ const queryStrings = { ORGANIC: "organic", ORGANIC_SOCIAL: "organic_social", EXPERIMENTS: "experiments", + FROM_HERITAGE: "fromheritage", }; export { queryStrings }; diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index 189d6592f..3e72c91a9 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -82,8 +82,10 @@ export default { }, async forwardButtonAction() { - // clicking continue and use no page name to trigger the implicit navigation in router - window.location.href = "/fmg/"; + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.$route + ); }, async startOver() { @@ -95,7 +97,10 @@ export default { ); deleteFunnelCookie(); await this.dispatchStoreAction(storeActions.RESET_STATE); - window.location.href = "/fmg/"; + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_FORWARD, + this.$route + ); }, }, components: { diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 5a2da603d..136c0ef14 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -715,7 +715,11 @@ export default { // 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) { + if ( + this.noSession() && + funnelCookieLastTouched !== null && + funnelCookieLastTouched !== undefined + ) { await this.initSession(); window.location.href = applicationConfig.RETURN_USER_PAGE; return; diff --git a/src/router/index.js b/src/router/index.js index f6950b624..f04c0613d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -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,6 +54,7 @@ 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(); @@ -78,6 +80,9 @@ const routes = [ return; } + const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true"; + const fromReturnUser = from?.name === fmgPageValues.RETURN_USER; + // Intercept all navigation if a submitted order exists in storage if (window.sessionStorage.getItem("submittedOrder") !== null) { if (to.query.fmgPage !== funnelStartPageName) { @@ -86,7 +91,21 @@ 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 non-funnel check and see if there is already a funnel cookie. + // if so, send them to return-user page + const funnelCookieLastTouched = getFunnelCookie()?.LastTouched; + if ( + to?.query?.fmgPage !== fmgPageValues.RETURN_USER && + !fromReturnUser && + !fromHeritage && + funnelCookieLastTouched !== null && + funnelCookieLastTouched !== undefined + ) { + log(" --navigate to return user"); + NavigateToReturnUser(next, to); + } + // 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"); @@ -145,6 +164,11 @@ const routes = [ store.commit(storeMutations.RESET_GLASS_PARTS_STATE); } + // if coming from the return user page, clear the destination page so implicit navigation runs + if (fromReturnUser && to.query) { + to.query[queryStrings.FMG_PAGE] = ""; + } + const pageToRedirectTo = await getPageToRouteExistingOrderTo(to); log(" --pageToRedirectTo ", JSON.stringify(pageToRedirectTo)); @@ -237,11 +261,11 @@ const routes = [ 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({ @@ -258,7 +282,6 @@ const routes = [ .components.default(); if (!arePagePrerequisitesValid(nextComponent)) { - // prettier-ignore console.log("Page Prereqs not valid for next component: " + nextComponent.default.name); @@ -319,6 +342,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; @@ -370,6 +394,7 @@ router.beforeEach(async (to, from, next) => { } else { next(); } + log("------------- router index.js beforeEach end -----------------"); }); router.afterEach(async (to, from) => { @@ -626,6 +651,42 @@ function GetRouteInfoFromPageName(pageName) { return routeData; } +async function NavigateToReturnUser(next, to) { + const returnRoute = GetRouteInfoFromPageName(fmgPageValues.RETURN_USER); + log("--returnRoute:", returnRoute); + + if (router.hasRoute(to.query.fmgPage)) { + // Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function. + let component = router + .getRoutes() + .filter((x) => x.name === fmgPageValues.RETURN_USER)[0].components; + + log("--return-user component:", component); + + // If the component hasn't been loaded fully, load it before we check prerequisites. + if (component.default.methods === undefined) { + component = await component.default(); + } + + log(" --has route for return-user:", fmgPageValues.RETURN_USER); + return next({ name: fmgPageValues.RETURN_USER, query: to.query, params: to.params }); + } else { + log(" --add route for return-user:", fmgPageValues.RETURN_USER); + router.addRoute({ + path: returnRoute[0].path, // Always the same path, because we control it with query strings. + name: returnRoute[0].name, + component: returnRoute[0].component, + }); + + next({ + name: returnRoute[0].name, + query: Object.assign(to.query, { fmgPage: returnRoute[0].name }), + params: to.params, + }); + return; + } +} + // Go to our start page on a 404. function GoToFunnelStartOn404(next, errorPayload = null) { if (errorPayload !== null) { @@ -637,7 +698,6 @@ function GoToFunnelStartOn404(next, errorPayload = null) { "color: white; background-color: blue; padding: 5px;", errorPayload ); - } // Put item on the bus @@ -661,7 +721,7 @@ function GoToFunnelStartOn404(next, errorPayload = null) { async function DisplayPageError(errorPayload = null) { console.log("%c running DisplayPageError()... ", "font-size: 20px; color: purple;"); - if(errorPayload !== null) { + if (errorPayload !== null) { errorPayload.type = "DisplayPageError"; analyticsMixin.methods.pushPageErrorToDataLayer(errorPayload); } else { @@ -670,7 +730,7 @@ async function DisplayPageError(errorPayload = null) { try { currentPage = getQuerystringParameter(queryStrings.FMG_PAGE); } catch (e) { - // pass + // pass } errorPayload = { type: "DisplayPageError", diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 3e3dbd4bf..8891e7cff 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -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, + }, + ], + }, ]; }; From bfc0eda484bd37332f1b5f81ccc3999390886fc7 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 20 Jan 2025 06:27:26 -0500 Subject: [PATCH 39/65] CASH-109 style CASH-109 style --- src/layouts/return-user/return-user.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index 3e72c91a9..5facfde0a 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -118,6 +118,7 @@ export default { font-weight: 600; color: $black; cursor: pointer; + text-decoration: underline; } } From 5d014a22627791fc235cca40bdeeeb3dd4adcbee Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 20 Jan 2025 10:59:03 -0500 Subject: [PATCH 40/65] CASH-109 tech review recommendations Use router.push to navigate to return-user page --- .../save-progress-popup-question.vue | 2 +- src/mixins/analytics-mixin.js | 7 +++- src/router/index.js | 42 +++---------------- src/ux-components/button-main/button-main.vue | 2 +- 4 files changed, 13 insertions(+), 40 deletions(-) diff --git a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue index 4ab1213c4..808163fe6 100644 --- a/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue +++ b/src/fmg-components/save-progress-popup-question/save-progress-popup-question.vue @@ -148,7 +148,7 @@ export default { position: relative; color: $black; border: none; - border-radius: .25rem; + border-radius: 0.25rem; font-weight: 900; font-size: 0.875rem; text-align: center; diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 136c0ef14..114cacbfb 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -27,6 +27,8 @@ 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"; export default { methods: { @@ -721,7 +723,10 @@ export default { funnelCookieLastTouched !== undefined ) { await this.initSession(); - window.location.href = applicationConfig.RETURN_USER_PAGE; + router.push({ + path: "/", + query: { fmgPage: fmgPageValues.RETURN_USER }, + }); return; } diff --git a/src/router/index.js b/src/router/index.js index f04c0613d..594630221 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -103,7 +103,11 @@ const routes = [ funnelCookieLastTouched !== undefined ) { log(" --navigate to return user"); - NavigateToReturnUser(next, to); + router.push({ + path: "/", + query: { fmgPage: fmgPageValues.RETURN_USER }, + }); + return; } // clear the saveSessionPromise - if it exists in the vuex store but a new instance was created @@ -651,42 +655,6 @@ function GetRouteInfoFromPageName(pageName) { return routeData; } -async function NavigateToReturnUser(next, to) { - const returnRoute = GetRouteInfoFromPageName(fmgPageValues.RETURN_USER); - log("--returnRoute:", returnRoute); - - if (router.hasRoute(to.query.fmgPage)) { - // Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function. - let component = router - .getRoutes() - .filter((x) => x.name === fmgPageValues.RETURN_USER)[0].components; - - log("--return-user component:", component); - - // If the component hasn't been loaded fully, load it before we check prerequisites. - if (component.default.methods === undefined) { - component = await component.default(); - } - - log(" --has route for return-user:", fmgPageValues.RETURN_USER); - return next({ name: fmgPageValues.RETURN_USER, query: to.query, params: to.params }); - } else { - log(" --add route for return-user:", fmgPageValues.RETURN_USER); - router.addRoute({ - path: returnRoute[0].path, // Always the same path, because we control it with query strings. - name: returnRoute[0].name, - component: returnRoute[0].component, - }); - - next({ - name: returnRoute[0].name, - query: Object.assign(to.query, { fmgPage: returnRoute[0].name }), - params: to.params, - }); - return; - } -} - // Go to our start page on a 404. function GoToFunnelStartOn404(next, errorPayload = null) { if (errorPayload !== null) { diff --git a/src/ux-components/button-main/button-main.vue b/src/ux-components/button-main/button-main.vue index 848cf3866..7980adf99 100644 --- a/src/ux-components/button-main/button-main.vue +++ b/src/ux-components/button-main/button-main.vue @@ -5,7 +5,7 @@ :class="[ isPrimary ? 'btn-primary' : 'btn-secondary', isFloat ? 'float-end' : '', - (isLoaderDisplayed && !suppressLoader) ? 'has-loader' : '', + isLoaderDisplayed && !suppressLoader ? 'has-loader' : '', ]" @click="clicked"> {{ this.buttonText }} From 12bf9c03ae9cf8150d30ac1cee67338c6cb0bbc7 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 20 Jan 2025 11:01:18 -0500 Subject: [PATCH 41/65] CASH-125: remove unneeded action --- .../save-progress-modal-question.vue | 3 --- src/layouts/quote/quote.vue | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue index a25224f69..48973c2e5 100644 --- a/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue +++ b/src/fmg-components/save-progress-modal-question/save-progress-modal-question.vue @@ -99,9 +99,6 @@ 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(); }, }, diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 221eae723..fd32ccca9 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -83,8 +83,7 @@ modalWidgetName="SaveProgressModalWidget" modalName="SaveProgressModal" v-if="showSaveProgressModal" - pageName="quote" - @save-progress-saved="updateSaveProgressAsSaved" /> + pageName="quote" /> Date: Mon, 20 Jan 2025 11:45:23 -0500 Subject: [PATCH 42/65] CASH-109 exclude timeout check for SQ return CASH-109 exclude timeout check for savequote return from heritage --- src/mixins/analytics-mixin.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 114cacbfb..6f7f67c6f 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -29,6 +29,7 @@ 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: { @@ -716,9 +717,11 @@ export default { // 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 fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true"; const funnelCookieLastTouched = getFunnelCookie()?.LastTouched; if ( this.noSession() && + !fromHeritage && funnelCookieLastTouched !== null && funnelCookieLastTouched !== undefined ) { From a200ec8ad1f2ca2b250ecb9badef0b3aefdd67d3 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Mon, 20 Jan 2025 16:43:52 -0500 Subject: [PATCH 43/65] CASH-41 fix width of alerts and banners on quote page. --- .../button-question/button-question.vue | 2 +- src/layouts/quote/quote.vue | 16 ++++++++++++++-- .../service-package-question.vue | 1 + .../service-package-radio.vue | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue index b060167cb..f9c1b6279 100644 --- a/src/digital-components/button-question/button-question.vue +++ b/src/digital-components/button-question/button-question.vue @@ -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) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index fd32ccca9..d4a45969a 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -20,7 +20,7 @@
-
+
-
+
2) { + return "col-xl-8"; + } else { + return "col-xl-6"; + } + }, + currentNumberOfPackagesAction(packageNumber) { + this.packageNumber = packageNumber; + }, openModalAction(modalName) { this.$refs[modalName].openModal(); }, diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 7df8dab5f..b39213267 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -150,6 +150,7 @@ export default { : "Special: Save $" + this.getServicePackageDiscountPrice(), }, })); + this.$emit("currentNumberOfPackages", modifiedAnswers.length); return modifiedAnswers; }, isServicePackageDiscountOnOrder() { diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index 1ad393650..fa905c975 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -141,6 +141,9 @@ export default { .package-main { .package-wrapper { margin: 1rem 0; + &:first-child { + margin: 1rem 0 0 0; + } &:last-child { margin: 1rem 0 0 0; } @@ -148,6 +151,12 @@ export default { margin: 1rem 0.5rem 0 0.5rem; display: flex; flex-direction: column; + &:first-child { + margin: 1rem .5rem 0 0; + } + &:last-child { + margin: 1rem 0 0 .5rem; + } } label { From a8e6dfa9c30439ec1801c223bc1f79a628eb9c21 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 21 Jan 2025 06:29:02 -0500 Subject: [PATCH 44/65] CASH-126 CASH-126 prevent back from safeliteHop pages from navigating to return-user. also turn prettier back on for pipeline --- azure-pipelines.yml | 18 +++++++++--------- src/layouts/quote/quote.vue | 2 +- .../service-package-radio.vue | 4 ++-- src/router/index.js | 7 +++++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 23d5e6806..c47e1a8fb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,15 +37,15 @@ variables: stages: # PR's - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - # - stage: TestFormat - # displayName: Test Code Format - # jobs: - # - job: checkFormatting - # displayName: Check formatting - # container: prettier-node - # steps: - # - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)" - # displayName: Run Prettier check + - stage: TestFormat + displayName: Test Code Format + jobs: + - job: checkFormatting + displayName: Check formatting + container: prettier-node + steps: + - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)" + displayName: Run Prettier check - stage: TestPr displayName: Run Unit Tests For PullRequest diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index d4a45969a..7256acc69 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -495,7 +495,7 @@ export default { }, methods: { getColCount() { - if(this.packageNumber > 2) { + if (this.packageNumber > 2) { return "col-xl-8"; } else { return "col-xl-6"; diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index fa905c975..f16ff4821 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -152,10 +152,10 @@ export default { display: flex; flex-direction: column; &:first-child { - margin: 1rem .5rem 0 0; + margin: 1rem 0.5rem 0 0; } &:last-child { - margin: 1rem 0 0 .5rem; + margin: 1rem 0 0 0.5rem; } } diff --git a/src/router/index.js b/src/router/index.js index 594630221..ac1269eed 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -82,6 +82,7 @@ const routes = [ const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true"; const fromReturnUser = from?.name === fmgPageValues.RETURN_USER; + const toPaymentPage = to.query.fmgPage?.startsWith("payment"); // Intercept all navigation if a submitted order exists in storage if (window.sessionStorage.getItem("submittedOrder") !== null) { @@ -93,12 +94,14 @@ const routes = [ // On entering the funnel "fresh", read cookie information, decide what to do next. else if (from.redirectedFrom === undefined || fromReturnUser) { // if entering the funnel from non-funnel check and see if there is already a funnel cookie. - // if so, send them to return-user page + // if so, send them to return-user page. this is catching navigation from an external page. + // safeliteHop(payment) cancel or clicking back also trigger it so exclude payment. const funnelCookieLastTouched = getFunnelCookie()?.LastTouched; if ( to?.query?.fmgPage !== fmgPageValues.RETURN_USER && !fromReturnUser && !fromHeritage && + !toPaymentPage && funnelCookieLastTouched !== null && funnelCookieLastTouched !== undefined ) { @@ -115,7 +118,7 @@ const routes = [ log(" --clear promise"); baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - if (!to.query.fmgPage?.startsWith("payment")) { + if (!toPaymentPage) { //payment pages used to return from safelitehop so exclude here // Remove the parameter after quote release From fd98ed884cfbb765838504e88048520bdf7cccd9 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 21 Jan 2025 06:36:41 -0500 Subject: [PATCH 45/65] CASH-126 comment out prettier. not sure why it's breaking pipeline. --- azure-pipelines.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c47e1a8fb..23d5e6806 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,15 +37,15 @@ variables: stages: # PR's - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - - stage: TestFormat - displayName: Test Code Format - jobs: - - job: checkFormatting - displayName: Check formatting - container: prettier-node - steps: - - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)" - displayName: Run Prettier check + # - stage: TestFormat + # displayName: Test Code Format + # jobs: + # - job: checkFormatting + # displayName: Check formatting + # container: prettier-node + # steps: + # - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)" + # displayName: Run Prettier check - stage: TestPr displayName: Run Unit Tests For PullRequest From e409ae43a236bd8b51f7dcdf4f12604e088d060d Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 21 Jan 2025 09:21:11 -0500 Subject: [PATCH 46/65] CASH-126 CASH-126 we are only going to check the content site as an external site that triggers the return user page --- src/router/index.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index ac1269eed..118e39cd1 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -80,9 +80,9 @@ const routes = [ return; } - const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true"; const fromReturnUser = from?.name === fmgPageValues.RETURN_USER; - const toPaymentPage = to.query.fmgPage?.startsWith("payment"); + const fromContentSite = getQuerystringParameter(queryStrings.START_TYPE) === "fmg"; + const toReturnUserPage = to.query?.fmgPage === fmgPageValues.RETURN_USER; // Intercept all navigation if a submitted order exists in storage if (window.sessionStorage.getItem("submittedOrder") !== null) { @@ -93,19 +93,15 @@ const routes = [ } // On entering the funnel "fresh", read cookie information, decide what to do next. else if (from.redirectedFrom === undefined || fromReturnUser) { - // if entering the funnel from non-funnel check and see if there is already a funnel cookie. - // if so, send them to return-user page. this is catching navigation from an external page. - // safeliteHop(payment) cancel or clicking back also trigger it so exclude payment. + // if entering the funnel from the content site, check and see if there is already a funnel cookie. + // if so, send them to return-user page. const funnelCookieLastTouched = getFunnelCookie()?.LastTouched; - if ( - to?.query?.fmgPage !== fmgPageValues.RETURN_USER && - !fromReturnUser && - !fromHeritage && - !toPaymentPage && + if (fromContentSite && funnelCookieLastTouched !== null && - funnelCookieLastTouched !== undefined + funnelCookieLastTouched !== undefined && + !toReturnUserPage ) { - log(" --navigate to return user"); + log(" --from content site navigate to return user"); router.push({ path: "/", query: { fmgPage: fmgPageValues.RETURN_USER }, @@ -118,7 +114,7 @@ const routes = [ log(" --clear promise"); baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - if (!toPaymentPage) { + if (!to.query.fmgPage?.startsWith("payment")) { //payment pages used to return from safelitehop so exclude here // Remove the parameter after quote release From e92fa4b119e14ee1275a430fa07372173953535b Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Tue, 21 Jan 2025 14:14:12 -0500 Subject: [PATCH 47/65] CASH-54 update hover state for list-button-horizontal buttons --- .../list-button-horizontal.vue | 122 +++++++++++++++++- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/src/ux-components/list-button-horizontal/list-button-horizontal.vue b/src/ux-components/list-button-horizontal/list-button-horizontal.vue index 8bcd7bd3a..85a7c679a 100644 --- a/src/ux-components/list-button-horizontal/list-button-horizontal.vue +++ b/src/ux-components/list-button-horizontal/list-button-horizontal.vue @@ -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: .5rem; + border-bottom-left-radius: .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: .5rem; + border-bottom-right-radius: .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: .5rem; + border-bottom-left-radius: .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: .5rem; + border-bottom-right-radius: .5rem; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + } + } + } + } +} From 9edfa4163a38da87eb3d6713c9c631db5fe36d95 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Tue, 21 Jan 2025 14:16:05 -0500 Subject: [PATCH 48/65] Formate code. --- src/router/index.js | 3 ++- .../list-button-horizontal.vue | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index 118e39cd1..ed35f6808 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -96,7 +96,8 @@ const routes = [ // if entering the funnel from the content site, check and see if there is already a funnel cookie. // if so, send them to return-user page. const funnelCookieLastTouched = getFunnelCookie()?.LastTouched; - if (fromContentSite && + if ( + fromContentSite && funnelCookieLastTouched !== null && funnelCookieLastTouched !== undefined && !toReturnUserPage diff --git a/src/ux-components/list-button-horizontal/list-button-horizontal.vue b/src/ux-components/list-button-horizontal/list-button-horizontal.vue index 85a7c679a..4b66023e0 100644 --- a/src/ux-components/list-button-horizontal/list-button-horizontal.vue +++ b/src/ux-components/list-button-horizontal/list-button-horizontal.vue @@ -231,8 +231,8 @@ export default { z-index: 2; &:hover { background-color: $white; - border-top-left-radius: .5rem; - border-bottom-left-radius: .5rem; + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; border-top-right-radius: 0; border-bottom-right-radius: 0; } @@ -267,8 +267,8 @@ export default { z-index: 2; &:hover { background-color: $white; - border-top-right-radius: .5rem; - border-bottom-right-radius: .5rem; + border-top-right-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; border-top-left-radius: 0; border-bottom-left-radius: 0; } @@ -289,8 +289,8 @@ fieldset { z-index: 6; &:hover { background-color: $white; - border-top-left-radius: .5rem; - border-bottom-left-radius: .5rem; + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; border-top-right-radius: 0; border-bottom-right-radius: 0; } @@ -325,8 +325,8 @@ fieldset { z-index: 6; &:hover { background-color: $white; - border-top-right-radius: .5rem; - border-bottom-right-radius: .5rem; + border-top-right-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; border-top-left-radius: 0; border-bottom-left-radius: 0; } From d3d3320d6dcf891b718fa279e163f92799f90974 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 22 Jan 2025 09:57:35 -0500 Subject: [PATCH 49/65] CASH-136 reapply modal sticky footer. --- src/digital-components/modal/modal.vue | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 461d144ae..58260e831 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -27,17 +27,17 @@
+
@@ -173,7 +173,7 @@ export default { } } .modal-footer { - padding: 1rem 0; + padding: 1rem 1.5rem; position: sticky; width: 100%; bottom: 0; From 16cb4fc6b4b557ae08b98c081cd518e5b633ea47 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 22 Jan 2025 10:13:45 -0500 Subject: [PATCH 50/65] CASH-143: turn off SYP for time being --- src/layouts/capability-questions/capability-questions.vue | 4 +++- src/layouts/molding-questions/molding-questions.vue | 4 +++- src/layouts/part-questions/part-questions.vue | 4 +++- src/layouts/quote/quote.vue | 8 ++++++-- src/layouts/vehicle-parts/vehicle-parts.vue | 5 ++++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 1896513a1..57567e128 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -64,7 +64,9 @@ export default { // Call the "next" function to complete the transition to this page. next(async (vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.showSaveProgressModal = !(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( diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 1bcc3d7a8..4da3588d7 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -64,7 +64,9 @@ export default { // Call the "next" function to complete the transition to this page. next(async (vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.showSaveProgressModal = !(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( diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index f905e86c7..37f005d48 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -64,7 +64,9 @@ export default { // Call the "next" function to complete the transition to this page. next(async (vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.showSaveProgressModal = !(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; diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 7256acc69..f3590cbc3 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -293,8 +293,12 @@ export default { // Call the "next" function to complete the transition to this page. next(async (vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.showSaveProgressPopup = showSaveProgressPopup; - vm.showSaveProgressModal = showSaveProgressModal; + + // 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; diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue index fd9b90b79..43f66c376 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.vue +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -94,7 +94,10 @@ export default { // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.showSaveProgressModal = !(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) From 7ff2c1b38f4c9efa8907f4e8179988895a6c7483 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Wed, 22 Jan 2025 10:44:12 -0500 Subject: [PATCH 51/65] CASH-109 CASH-109 the implicit navigation won't work for verified insurance because the quote prereqs always returns false because verified insurance is not permitted on quote page. Also prevent glassparts from being removed for return-users. --- .../heritage-integration/navigation-helper.js | 4 +++ src/router/index.js | 28 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 4afc7e115..2fc557a16 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -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) { diff --git a/src/router/index.js b/src/router/index.js index ed35f6808..d956af773 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -83,6 +83,8 @@ const routes = [ 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) { @@ -103,9 +105,17 @@ const routes = [ !toReturnUserPage ) { log(" --from content site navigate to return user"); + var qso = { + fmgPage: fmgPageValues.RETURN_USER, + }; + const lg = getQuerystringParameter(queryStrings.LOG); + if (lg) { + qso[queryStrings.LOG] = true; + } + router.push({ path: "/", - query: { fmgPage: fmgPageValues.RETURN_USER }, + query: Object.assign({}, qso), }); return; } @@ -156,21 +166,27 @@ 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) { - to.query[queryStrings.FMG_PAGE] = ""; + 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); @@ -550,7 +566,7 @@ async function navigate( const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR); const logQs = getQuerystringParameter(queryStrings.LOG); baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false); - + log("------------- router index.js navigate start -----------------"); log(" --scenario: ", scenario); log(" --isSavingNavigation: ", isSavingNavigation); @@ -614,6 +630,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; From 1240ef92c0de2529712532bb9f3d1d60ae39c1da Mon Sep 17 00:00:00 2001 From: CarlNation Date: Wed, 22 Jan 2025 15:11:52 -0500 Subject: [PATCH 52/65] CASH-139 CASH-139 remove fromHeritage querystring once validation is checked so expiration works on service location --- src/router/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/router/index.js b/src/router/index.js index d956af773..963a0b552 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -58,6 +58,11 @@ const routes = [ 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 }); @@ -185,7 +190,6 @@ const routes = [ log( " --clear to.query"); delete to.query[queryStrings.FMG_PAGE]; - //to.query[queryStrings.FMG_PAGE] = ""; log(" --to.query cleared ", JSON.stringify(to.query)); } From fc87763e5dd98fc230df50587177208b7d0fea25 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 22 Jan 2025 15:26:30 -0500 Subject: [PATCH 53/65] Parse string -> bool without eval. --- src/layouts/payment-method/payment-method.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index c45a5c98c..38fa19611 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -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); From 3d7e8b00e23b14402cc12b28ca69cb97c235a1bf Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 22 Jan 2025 15:34:01 -0500 Subject: [PATCH 54/65] CASH-147 move contine scheduling/start over block lower in page. --- src/layouts/return-user/return-user.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index 5facfde0a..69b389026 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -8,7 +8,7 @@
-
+
From dc5a1ac6215c5780d00aac2e02fa4e7869ad27f7 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 22 Jan 2025 15:37:10 -0500 Subject: [PATCH 55/65] Change px to rem. --- src/layouts/return-user/return-user.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index 69b389026..adf55ce2b 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -123,7 +123,7 @@ export default { } .return-user { .return-user-spacing { - margin-top: 225px; + margin-top: 14rem; } } From e7fee443985e3a4f7ddb64f9b25aca7c743e3cc3 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Thu, 23 Jan 2025 07:14:57 -0500 Subject: [PATCH 56/65] CASH-144 CASH-144 checking expired session and routing to return user from the validateSession function in analytics does not prevent the forward click. So move the expiration check and routing to the forward and back buttons and skip the emit click when expired. --- src/fmg-components/nav-bar/nav-bar.vue | 15 ++++++++++++- src/mixins/analytics-mixin.js | 21 +++++++++--------- src/ux-components/button-main/button-main.vue | 22 +++++++++++++++++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/fmg-components/nav-bar/nav-bar.vue b/src/fmg-components/nav-bar/nav-bar.vue index 631e5c0e5..95100c639 100644 --- a/src/fmg-components/nav-bar/nav-bar.vue +++ b/src/fmg-components/nav-bar/nav-bar.vue @@ -45,6 +45,9 @@