From a0a922b302a4904d947f56a3757cbbf8003fa25a Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 24 Jun 2025 14:43:54 -0400 Subject: [PATCH] CASH-1029 Dynamo Logging CASH-1029 Dynamo Logging --- src/constants/endpoints.js | 4 +++ src/constants/experiments.js | 1 + src/constants/store-actions.js | 1 + src/fmg-components/cart/cart.vue | 3 +- src/global-methods.js | 58 +++++++++++++++++--------------- src/mixins/analytics-mixin.js | 57 ++++++++++++++++++++++++++++++- src/mixins/base-mixin.js | 12 +++++++ src/router/methods/after-each.js | 3 ++ src/store/index.js | 36 +++++++++++++++++++- src/styles/ux-variables.scss | 4 +-- 10 files changed, 146 insertions(+), 33 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index aa0643821..085651f20 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -176,6 +176,10 @@ const endpoints = { url: "/analytics/api/v1/analytics/log-part-questions", method: "POST", }, + LogDigitalConsumer: { + url: "/analytics/api/v1/analytics/digitalconsumer-log", + method: "POST", + }, GetExperimentsByUser: { url: "/analytics/api/v1/analytics/get-experiments", method: "GET", diff --git a/src/constants/experiments.js b/src/constants/experiments.js index c5c24536d..871c6fd24 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -26,6 +26,7 @@ const experimentSettings = { FOSTER_LOVE: "DisplayFosterLove", SKIP_TO_INSURANCE: "SkipToInsurance", DISPLAY_AFTERPAY_BREAKOUT_DISPLAY: "Display_AfterpayBreakoutDisplay", + DYNAMO_LOGGING: "DynamoLogging", }; const experimentTriggers = { diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 9f0965480..cb2c84940 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -63,6 +63,7 @@ const storeActions = { LOG_CUSTOM_EVENT: "logCustomEvent", INITIALIZE_SESSION: "initializeSession", LOG_PART_QUESTIONS: "logPartQuestions", + LOG_DIGITALCONSUMER: "logDigitalConsumer", // DEPENDENCY MUTATIONS RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleStateAndDependencies", diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 55e062e24..433dfb3e4 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -1311,8 +1311,7 @@ export default { .amount-due, .amount-paid, .donation-amount { - font-family: - UrbanistSemibold, AvertaSemibold; /* Okay to remove AvertaSemibold after 2025.06.19 merge/release */ + font-family: UrbanistSemibold, AvertaSemibold; /* Okay to remove AvertaSemibold after 2025.06.19 merge/release */ color: $black; } .sub-total { diff --git a/src/global-methods.js b/src/global-methods.js index e90843bdc..75fabb356 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -100,34 +100,38 @@ export default { return resolve(response); }, (error) => { - if (logApiCall) { - analyticsMixIn.methods.pushEventToGA( - GaCategories.API_RESPONSE, - GaActions.RESULT, - `${GaLabels.ERROR}_${endpoint}`, - true - ); + if (endpoint.toLowerCase().includes("/digitalconsumer-log")) { + return resolve({ data: null, error: "Ignore errors when logging" }); + } else { + if (logApiCall) { + analyticsMixIn.methods.pushEventToGA( + GaCategories.API_RESPONSE, + GaActions.RESULT, + `${GaLabels.ERROR}_${endpoint}`, + true + ); + } + + if (error.response.status && error.response.status != "404") { + // Do not route to error logic when no wipers found or no promo found (404s) + const errorPayload = { + cause: `Response error ${error.response.status}`, + currentPage: pageNameToLog, + endpoint: endpoint, + }; + + router.bailout(errorPayload); + + // do not log 404 errors from services because we return NotFound + // when a service doesn't return an object + global.$logger.logError( + `${method}: ${endpoint}: ${error.message}`, + error.response + ); + } + + return reject(error.response); } - - if (error.response.status && error.response.status != "404") { - // Do not route to error logic when no wipers found or no promo found (404s) - const errorPayload = { - cause: `Response error ${error.response.status}`, - currentPage: pageNameToLog, - endpoint: endpoint, - }; - - router.bailout(errorPayload); - - // do not log 404 errors from services because we return NotFound - // when a service doesn't return an object - global.$logger.logError( - `${method}: ${endpoint}: ${error.message}`, - error.response - ); - } - - return reject(error.response); } ); }); diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 298a3af8f..90513e764 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -12,7 +12,8 @@ import { setSessionKeyIfUnset, } from "@/helpers/heritage-integration/cookie-helper"; import { queryStrings } from "@/constants/query-strings"; -import { experimentSettings } from "@/constants/experiments"; +import { experimentSettings, experimentUniverses } from "@/constants/experiments"; +import experimentMixin from "@/mixins/experiment-mixin"; import { analyticsPageEvents, GaCategories, @@ -128,6 +129,60 @@ export default { } }, + async logDigitalConsumer() { + const currentPageName = getPageNameFromRouter(); + const universes = store.getters.applicationUser.experiments; + console.log(JSON.stringify(universes)); + + let hasDynamoLogging = experimentMixin.methods.hasSettingEqualTo( + experimentSettings.DYNAMO_LOGGING, + "true", + universes + ); + if (!hasDynamoLogging) { + return; + } + + const variationNames = universes + .filter((item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL) + .map((item) => item.variationName) + .filter(Boolean); // removes undefined/null + + const conceptVariation = variationNames.length > 0 ? variationNames[0] : ""; + + const submittedOrder = baseMixin.methods.getSubmittedOrder(); + const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder(); + const hasSubmittedOrderAtConfirmationPage = + hasSubmittedOrder && currentPageName?.toLowerCase() == routeData.CONFIRMATION.name; + + const refSequenceNum = hasSubmittedOrderAtConfirmationPage + ? submittedOrder.referralSequenceNumber + : store.getters.order.referralSequenceNumber; + + var payload = { + actionName: `Browser page:${currentPageName}`, + referralSequenceNumber: hasSubmittedOrderAtConfirmationPage + ? submittedOrder.referralSequenceNumber + : store.getters.order.referralSequenceNumber, + referralNumber: hasSubmittedOrderAtConfirmationPage + ? submittedOrder.referralNumber + : store.getters.order.referralNumber, + workOrderId: hasSubmittedOrderAtConfirmationPage + ? submittedOrder.workOrderId + : store.getters.order.workOrderId, + workOrderNumber: hasSubmittedOrderAtConfirmationPage + ? submittedOrder.workOrderNumber + : store.getters.order.workOrderNumber, + conceptVariation: conceptVariation, + }; + + await baseMixin.methods.dispatchStoreAction( + storeActions.LOG_DIGITALCONSUMER, + payload, + false + ); + }, + async pushEventForChatsToGA(category, action, label, pushToLogApp = false) { const currentPageName = getPageNameFromRouter(); const value = `2.0_${currentPageName}`; diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index ecce2632d..4046fa477 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -197,6 +197,18 @@ export default { return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)]; } }, + isMobileDevice() { + const userAgent = navigator.userAgent; + return ( + userAgent.includes("Android") || + userAgent.includes("Mobile") || + userAgent.includes("iPod") || + userAgent.includes("iPhone") || + userAgent.includes("IEMobile") || + userAgent.includes("BlackBerry") || + userAgent.includes("webOS") + ); + }, getSubmittedOrder() { return JSON.parse( window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) diff --git a/src/router/methods/after-each.js b/src/router/methods/after-each.js index ef3dc0d93..27cecffde 100644 --- a/src/router/methods/after-each.js +++ b/src/router/methods/after-each.js @@ -1,6 +1,9 @@ import analyticsMixin from "@/mixins/analytics-mixin"; export async function afterEach(to, from) { + // digital consumer logging + analyticsMixin.methods.logDigitalConsumer(); + // Push page view to GA analyticsMixin.methods.pushPageViewToGA(); diff --git a/src/store/index.js b/src/store/index.js index 073a50e23..2cfe39ead 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -11,7 +11,11 @@ import { experimentTriggers } from "@/constants/experiments"; import { damageLocationsSelected } from "@/constants/damage-locations-selected"; import { singleWindshieldCarIds } from "@/constants/single-windshield-carids"; import { routeData } from "@/router/constants/routes"; -import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; +import { + deleteFunnelCookie, + getSessionIdValue, + getDeviceIdValue, +} from "@/helpers/heritage-integration/cookie-helper.js"; import { deepEqual } from "@/helpers/object-helper"; import baseMixin from "@/mixins/base-mixin.js"; import { @@ -1551,6 +1555,36 @@ export const actions = { }); }, + logDigitalConsumer( + context, + { + actionName, + referralSequenceNumber, + referralNumber, + workOrderId, + workOrderNumber, + conceptVariation, + } + ) { + var payload = { + sessionId: getSessionIdValue(), + deviceId: getDeviceIdValue(), + actionName: actionName ?? "", + referralSequenceNumber: referralSequenceNumber ?? "", + referralNumber: referralNumber ?? "", + applicationName: baseMixin.methods.isMobileDevice() ? "2.0 Mobile" : "2.0", + workOrderId: workOrderId ?? "", + workOrderNumber: workOrderNumber ?? "", + conceptVariation: conceptVariation, + }; + + return globalMethods.callHttpClient({ + method: endpoints.LogDigitalConsumer.method, + endpoint: endpoints.LogDigitalConsumer.url, + payload: payload, + }); + }, + // Misc Actions setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) { context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber); diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 01b122b31..69ba0d7ac 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -121,8 +121,8 @@ $body-color: $gray-600; //Fonts $font-family-sans-serif: UrbanistRegular, Arial, Helvetica, sans-serif; -$font-family-monospace: - UrbanistRegular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +$font-family-monospace: UrbanistRegular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", + monospace; // stylelint-enable value-keyword-case $font-family-base: $font-family-sans-serif; $font-family-code: $font-family-monospace;