From 2b5dc365d054291855b9b8f18e5fe6458f24d029 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Thu, 20 Apr 2023 09:00:16 -0400 Subject: [PATCH 1/7] CSR-1337 Address look up option restrict to only zips that are able to look up address --- src/layouts/estimate/estimate.vue | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index cfec5923d..b9929813a 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -149,11 +149,17 @@ export default { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); - const hasZip = urlParams.has(queryStrings.ZIP_CODE); - const zip = urlParams.get(queryStrings.ZIP_CODE); + const lowerCaseParams = new URLSearchParams(); + for (const [name, value] of urlParams) { + lowerCaseParams.append(name.toLowerCase(), value); + } + + const zip = lowerCaseParams.get(queryStrings.ZIP_CODE) + ? lowerCaseParams.get(queryStrings.ZIP_CODE) + : store.getters.order.serviceLocation.zipCode; var vinByAddressPromise; - if (hasZip) { + if (zip) { vinByAddressPromise = baseMixin.methods.dispatchStoreAction( storeActions.IS_VIN_BY_ADDRESS_PERMISSIBLE, zip, @@ -193,7 +199,7 @@ export default { } } - if (zip && resultMap.vinByAddress === false) { + if (!zip || resultMap.vinByAddress === false) { var indexToRemove = resultMap.cmsContent.VinLookupMethod.Answers.findIndex( (answer) => answer.Name === "HomeAddress" ); @@ -201,6 +207,7 @@ export default { resultMap.cmsContent.VinLookupMethod.Answers.splice(indexToRemove, 1); } } + vm.setCmsContent(resultMap.cmsContent); }); }, From 0a4645c605a0b4d606f254e696fab5e3df8c1b4f Mon Sep 17 00:00:00 2001 From: CarlNation Date: Thu, 20 Apr 2023 10:16:51 -0400 Subject: [PATCH 2/7] CSR-1337 --- src/layouts/estimate/estimate.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index 4a0a3f434..462287851 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -101,6 +101,9 @@ describe("estimate.vue", () => { //Arrange const { wrapper } = setupMocks({}); + delete window.location; + window.location = { search: "?fmgPage=estimate&zipcode=43015" }; + //Act estimate.beforeRouteEnter.call( wrapper.vm, From e316378d2c972ae6df97854f3be2e340eda7a4e0 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Fri, 21 Apr 2023 10:14:35 -0400 Subject: [PATCH 3/7] CSR-1338 If there is no windshield selected then do not require a vin lookup --- src/helpers/damage-helper.js | 6 ++++++ src/helpers/heritage-integration/navigation-helper.js | 7 ++++--- src/helpers/heritage-integration/navigation-helper.spec.js | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 22e312939..91546c3e2 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -1,6 +1,7 @@ import store from "@/store"; import baseMixin from "@/mixins/base-mixin.js"; import { storeActions } from "@/constants/store-actions"; +import { damageLocationsSelected as glassLocations } from "@/constants/damage-locations-selected"; export function getDamageString() { // If it's a repair it's always a windshield. @@ -45,6 +46,11 @@ export function getIsWindshieldOnly() { return returnString; } +export function hasWindshield() { + const windshieldMatches = store.getters.order.damage.glassToReplace?.filter((glassToReplace) => glassToReplace.glassLocation === glassLocations.WINDSHIELD) ?? []; + return windshieldMatches.length > 0; +} + export async function isGlassAvailableForCarId(carId) { const newGlassOptions = await baseMixin.methods.dispatchStoreAction( storeActions.GET_DAMAGE_OPTIONS, diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 0e756a8a4..6cbed862b 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -7,6 +7,7 @@ import { storeActions } from "@/constants/store-actions.js"; import { settleAllPromises } from "@/helpers/layout-helper"; import experimentMixin from "@/mixins/experiment-mixin"; import { experimentSettings } from "@/constants/experiments"; +import { hasWindshield } from "@/helpers/damage-helper"; import store from "@/store"; import router from "@/router"; @@ -72,7 +73,7 @@ export async function skipVinLookup() { return ( store.getters.damage.isRepair || - isVinOptionalVehicle || + isVinOptionalVehicle || !hasWindshield() || experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, "true") ); } @@ -83,8 +84,8 @@ export async function skipVinLookupNotRepair() { : false; return ( - !store.getters.damage.isRepair && - (isVinOptionalVehicle || + !store.getters.damage.isRepair && + (isVinOptionalVehicle || !hasWindshield() || experimentMixin.methods.hasSettingEqualTo( experimentSettings.SUPPRESS_VIN_CAPTURE, "true" diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index f9b3b1017..0322631f3 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -135,7 +135,7 @@ describe("getPageToRouteExistingOrderTo", () => { expect(result).toBe(fmgPageValues.VEHICLE_DAMAGE); }); - test("user has YMMS and no vehicle questions > should return vin-lookup", async () => { + test("user has YMMS and no vehicle questions > should return estimate", async () => { // Arrange const toRoute = { query: {}, @@ -172,7 +172,7 @@ describe("getPageToRouteExistingOrderTo", () => { const result = await getPageToRouteExistingOrderTo(toRoute, false); //Assert - expect(result).toBe(fmgPageValues.VIN_LOOKUP); + expect(result).toBe(fmgPageValues.ESTIMATE); }); test("user has YMMS but no questions or carId > should return estimate", async () => { From 553338e56f674948bd7a5872bb5bc76290d4fa6c Mon Sep 17 00:00:00 2001 From: CarlNation Date: Fri, 21 Apr 2023 10:30:58 -0400 Subject: [PATCH 4/7] CSR-1338 prettier --- src/helpers/damage-helper.js | 5 ++++- src/helpers/heritage-integration/navigation-helper.js | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 91546c3e2..0c4735b6c 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -47,7 +47,10 @@ export function getIsWindshieldOnly() { } export function hasWindshield() { - const windshieldMatches = store.getters.order.damage.glassToReplace?.filter((glassToReplace) => glassToReplace.glassLocation === glassLocations.WINDSHIELD) ?? []; + const windshieldMatches = + store.getters.order.damage.glassToReplace?.filter( + (glassToReplace) => glassToReplace.glassLocation === glassLocations.WINDSHIELD + ) ?? []; return windshieldMatches.length > 0; } diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 6cbed862b..e7010cfa9 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -73,7 +73,8 @@ export async function skipVinLookup() { return ( store.getters.damage.isRepair || - isVinOptionalVehicle || !hasWindshield() || + isVinOptionalVehicle || + !hasWindshield() || experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, "true") ); } @@ -84,8 +85,9 @@ export async function skipVinLookupNotRepair() { : false; return ( - !store.getters.damage.isRepair && - (isVinOptionalVehicle || !hasWindshield() || + !store.getters.damage.isRepair && + (isVinOptionalVehicle || + !hasWindshield() || experimentMixin.methods.hasSettingEqualTo( experimentSettings.SUPPRESS_VIN_CAPTURE, "true" From 8b824d9ec137395e2db291e758b09a93dd3d73ae Mon Sep 17 00:00:00 2001 From: CarlNation Date: Fri, 21 Apr 2023 13:42:32 -0400 Subject: [PATCH 5/7] CSR-1338 rename hasWindshield to includesWindshieldReplacement --- src/helpers/damage-helper.js | 2 +- src/helpers/heritage-integration/navigation-helper.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 0c4735b6c..727825d9d 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -46,7 +46,7 @@ export function getIsWindshieldOnly() { return returnString; } -export function hasWindshield() { +export function includesWindshieldReplacement() { const windshieldMatches = store.getters.order.damage.glassToReplace?.filter( (glassToReplace) => glassToReplace.glassLocation === glassLocations.WINDSHIELD diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index e7010cfa9..913fbcb1b 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -7,7 +7,7 @@ import { storeActions } from "@/constants/store-actions.js"; import { settleAllPromises } from "@/helpers/layout-helper"; import experimentMixin from "@/mixins/experiment-mixin"; import { experimentSettings } from "@/constants/experiments"; -import { hasWindshield } from "@/helpers/damage-helper"; +import { includesWindshieldReplacement } from "@/helpers/damage-helper"; import store from "@/store"; import router from "@/router"; @@ -74,7 +74,7 @@ export async function skipVinLookup() { return ( store.getters.damage.isRepair || isVinOptionalVehicle || - !hasWindshield() || + !includesWindshieldReplacement() || experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, "true") ); } @@ -87,7 +87,7 @@ export async function skipVinLookupNotRepair() { return ( !store.getters.damage.isRepair && (isVinOptionalVehicle || - !hasWindshield() || + !includesWindshieldReplacement() || experimentMixin.methods.hasSettingEqualTo( experimentSettings.SUPPRESS_VIN_CAPTURE, "true" From 43954352a0b757ba1e6a3896e2fc648b471797ff Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 25 Apr 2023 09:18:56 -0400 Subject: [PATCH 6/7] CSR-1339 Allow site to function when analytic service calls fail --- src/mixins/analytics-mixin.js | 10 +++++----- src/store/index.js | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 3fbc9501d..29eb76c3d 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -146,18 +146,18 @@ export default { false ); - if (response.data) { - if (response.data.sessionKey && skey === 0) { + if (response?.data) { + if (response?.data.sessionKey && skey === 0) { setCookieProperties( - { [cookieNames.SESSION_KEY]: response.data.sessionKey }, + { [cookieNames.SESSION_KEY]: response?.data.sessionKey }, { useDefaultFunnelCookieAttributes: false, } ); } - if (response.data.sessionId && sid === "00000000-0000-0000-0000-000000000000") { + if (response?.data.sessionId && sid === "00000000-0000-0000-0000-000000000000") { setCookieProperties( - { [cookieNames.SESSION_ID]: response.data.sessionId }, + { [cookieNames.SESSION_ID]: response?.data.sessionId }, { maxAge: 60 * 30, // 30 minutes } diff --git a/src/store/index.js b/src/store/index.js index f42a950ea..70f6cf3a2 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -720,7 +720,13 @@ export const actions = { endpoint: endpoints.LogPageView.url, payload: payload, logApiCall: false, - }); + }).then((response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, logCustomEvent( context, @@ -756,7 +762,13 @@ export const actions = { endpoint: endpoints.LogCustomEvent.url, payload: payload, logApiCall: false, - }); + }).then((response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, initializeSession(context, { userId, sessionId, userAgent, referrer }) { var payload = { @@ -775,7 +787,13 @@ export const actions = { endpoint: endpoints.InitializeSession.url, payload: payload, logApiCall: false, - }); + }).then((response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, // Misc Actions From f18e00caedbda0ff9319882fc8668cb3af08aa20 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 25 Apr 2023 09:26:41 -0400 Subject: [PATCH 7/7] CSR-1339 Add GA event to show what button options displayed --- .../button-question/button-question.vue | 25 ++++++ src/constants/analytics.js | 1 + src/layouts/estimate/estimate.vue | 3 +- src/store/index.js | 81 ++++++++++--------- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/common-components/button-question/button-question.vue b/src/common-components/button-question/button-question.vue index 646b244be..b96b99bb4 100644 --- a/src/common-components/button-question/button-question.vue +++ b/src/common-components/button-question/button-question.vue @@ -79,6 +79,7 @@ import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-bu import listCard from "@/ux-components/list-card/list-card"; import radio from "@/ux-components/radio/radio"; import { ErrorMessage } from "vee-validate"; +import { queryStrings } from "@/constants/query-strings"; export default { name: "buttonQuestion", @@ -119,6 +120,10 @@ export default { useTextForValue: Boolean, valueToLogType: String, additionalButtonStyling: String, + logDisplayedValuesEvent: { + type: Boolean, + default: false, + }, }, beforeMount() { if (this.buttonTypeObject) { @@ -130,6 +135,26 @@ export default { lastValuePushedToGa: null, }; }, + watch: { + answers() { + //once we get the answers to display from parent, see if we need a GA event to log what we showed + if (this.logDisplayedValuesEvent && this.answers.length > 0) { + var eventLabel = ""; + //build comma separated list of all items in button list that we are going to display on page + this.answers.forEach((item) => { + eventLabel += item.Name + ","; + }); + + eventLabel = eventLabel.slice(0, -1); //remove the last comma + this.pushEventToGA( + this.$route.query[queryStrings.FMG_PAGE], + this.GaActions.DISPLAYED, + eventLabel, + true + ); + } + }, + }, computed: { getFieldSetClasses() { if (this.isOverflowScrollable) { diff --git a/src/constants/analytics.js b/src/constants/analytics.js index eed7da2fe..b5b24660d 100644 --- a/src/constants/analytics.js +++ b/src/constants/analytics.js @@ -19,6 +19,7 @@ const GaActions = { CLICKED: "Clicked", VIF: "vif", SUBMITTED: "Submitted", + DISPLAYED: "Displayed", }; const GaLabels = { diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index b9929813a..17135b1aa 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -18,7 +18,8 @@ buttonTypeString="listButton" v-model="selectedVinLookupMethod" isRequired - validationRules="option-required" /> + validationRules="option-required" + :logDisplayedValuesEvent="true" />
{ - return response; - }, - (error) => { - console.log("Analytics Service Error: " + error.data); - } - ); + return globalMethods + .callHttpClient({ + method: endpoints.LogPageView.method, + endpoint: endpoints.LogPageView.url, + payload: payload, + logApiCall: false, + }) + .then( + (response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, logCustomEvent( context, @@ -757,18 +760,21 @@ export const actions = { experimentsForUser: experimentsForUser, }; - return globalMethods.callHttpClient({ - method: endpoints.LogCustomEvent.method, - endpoint: endpoints.LogCustomEvent.url, - payload: payload, - logApiCall: false, - }).then((response) => { - return response; - }, - (error) => { - console.log("Analytics Service Error: " + error.data); - } - ); + return globalMethods + .callHttpClient({ + method: endpoints.LogCustomEvent.method, + endpoint: endpoints.LogCustomEvent.url, + payload: payload, + logApiCall: false, + }) + .then( + (response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, initializeSession(context, { userId, sessionId, userAgent, referrer }) { var payload = { @@ -782,18 +788,21 @@ export const actions = { referrer: referrer, }; - return globalMethods.callHttpClient({ - method: endpoints.InitializeSession.method, - endpoint: endpoints.InitializeSession.url, - payload: payload, - logApiCall: false, - }).then((response) => { - return response; - }, - (error) => { - console.log("Analytics Service Error: " + error.data); - } - ); + return globalMethods + .callHttpClient({ + method: endpoints.InitializeSession.method, + endpoint: endpoints.InitializeSession.url, + payload: payload, + logApiCall: false, + }) + .then( + (response) => { + return response; + }, + (error) => { + console.log("Analytics Service Error: " + error.data); + } + ); }, // Misc Actions