Auto stash before merge of "feature/Digital/SSR-51" and "develop"

This commit is contained in:
Jeremy Zimmerman 2022-11-01 13:36:44 -04:00
parent d772b06b68
commit 0d981dde56
17 changed files with 426 additions and 39 deletions

View file

@ -15,6 +15,35 @@ const endpoints = {
url: "/vehicle/api/v1/vehicle/years",
method: "GET",
},
GetPageData: {
url: (applicationAbbreviation, pageName) =>
`/content/api/v1/content/${applicationAbbreviation}/${pageName}`,
method: "GET",
},
LogExperimentExposureIfAssigned: {
url: "/experiments/api/v1/experiments/log-exposure",
method: "POST",
},
LogPageView: {
url: "/analytics/api/v1/analytics/log-page-view",
method: "POST",
},
LogCustomEvent: {
url: "/analytics/api/v1/analytics/log-custom-event",
method: "POST",
},
InitializeSession: {
url: "/analytics/api/v1/analytics/initialize",
method: "POST",
},
GetExperimentsByUser: {
url: "/analytics/api/v1/analytics/get-experiments",
method: "GET",
},
RunExperimentsForTrigger: {
url: "/experiments/api/v1/experiments/run",
method: "POST",
},
};
export { endpoints };

View file

@ -3,6 +3,15 @@ const storeActions = {
GET_ROUTE_INFO_ACTION: "getRouteInfo",
GET_HOMEPAGE_NAME: "getHomepageName",
GET_PAGE_DATA: "getPageData",
// Lookup Actions
LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
LOG_PAGE_VIEW: "logPageView",
LOG_CUSTOM_EVENT: "logCustomEvent",
INITIALIZE_SESSION: "initializeSession",
GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser",
RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger",
};
export { storeActions };

View file

@ -0,0 +1,71 @@
const storeMutations = {
// VEHICLE MUTATIONS
UPDATE_YEAR: "updateYear",
UPDATE_MAKE: "updateMake",
UPDATE_MODEL: "updateModel",
UPDATE_STYLE: "updateStyle",
UPDATE_CAR_ID: "updateCarId",
UPDATE_VEHICLE_CATEGORY: "updateVehicleCategory",
UPDATE_VEHICLE_IMAGE_URL: "updateVehicleImageUrl",
UPDATE_VEHICLE_IMAGE_VIF_NUMBER: "updateVehicleImageVifNumber",
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
UPDATE_VEHICLE_VIN: "updateVehicleVin",
UPDATE_VEHICLE: "updateVehicle",
UPDATE_IS_REPAIR: "updateIsRepair",
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers",
UPDATE_MOLDING_QUESTION_ANSWERS: "updateMoldingQuestionAnswers",
UPDATE_CAPABILITY_QUESTION_ANSWERS: "updateCapabilityQuestionAnswers",
UPDATE_GLASS_PARTS: "updateGlassParts",
UPDATE_OTHER_PARTS: "updateOtherParts",
UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate",
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
UPDATE_REGISTRATION_CITY: "updateRegistrationCity",
UPDATE_REGISTRATION_STATE: "updateRegistrationState",
UPDATE_REGISTRATION_ZIP_CODE: "updateRegistrationZipCode",
UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName",
UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName",
UPDATE_REGISTRATION: "updateRegistration",
UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode",
UPDATE_SERVICE_LOCATION_STATE: "updateServiceLocationState",
UPDATE_SERVICE_LOCATION: "updateServiceLocation",
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",
// ORDER MUTATIONS
UPDATE_REFERRAL_NUMBER: "updateReferralNumber",
UPDATE_REFERRAL_DATE: "updateReferralDate",
UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId",
UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber",
UPDATE_EON: "updateEON",
UPDATE_SAVED_SESSION_ID: "updateSavedSessionId",
UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId",
// EVENT BUS MUTATIONS
ADD_EVENT_TO_BUS: "addEventToBus",
REMOVE_EVENT_FROM_BUS: "removeEventFromBus",
// DEPENDENCY MUTATIONS
RESET_VEHICLE_STATE: "resetVehicleState",
RESET_DAMAGE_STATE: "resetDamageState",
RESET_REGISTRATION_STATE: "resetRegistrationState",
RESET_GLASS_PARTS_STATE: "resetGlassPartsState",
RESET_STATE: "resetState",
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
// OTHER MUTATIONS
UPDATE_PAGE_DATA: "updatePageData",
UPDATE_STATE_WITH_ORDER_INFORMATION: "updateStateWithOrderInformation",
UPDATE_SAVE_SESSION_PROMISE: "updateSaveSessionPromise",
UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited",
// EXPERIMENT MUTATIONS
UPDATE_EXPERIMENTS: "updateExperiments",
UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry",
};
export { storeMutations };

View file

@ -1,5 +1,4 @@
import { cookieNames } from "@/constants/cookie-names";
import store from "@/store";
import { applicationConfig } from "@/constants/application-config";
/*
@ -12,13 +11,13 @@ export function updateOrCreateFunnelCookie() {
// Set up cookie with all the props.
setFunnelCookieProperties({
LastTouched: new Date().toUTCString(),
SavedSessionTimeoutDate: store.getters.applicationUser.savedSessionTimeout,
SavedSessionTimeoutDate: useMainStore().getters.applicationUser.savedSessionTimeout,
DidHeritageFunnelUpdateLast: false,
ShouldResetState: false,
ReferralNumber: store.getters.order.referralNumber,
ReferralDate: store.getters.order.referralDate,
ReferralCorrelationId: store.getters.order.referralCorrelationId,
ReferralParentAccountNumber: store.getters.order.accountNumber,
ReferralNumber: useMainStore().getters.order.referralNumber,
ReferralDate: useMainStore().getters.order.referralDate,
ReferralCorrelationId: useMainStore().getters.order.referralCorrelationId,
ReferralParentAccountNumber: useMainStore().getters.order.accountNumber,
HasDelayedClaimRegistration: wasClaimRegistrationDelayed,
SuppressConceptFunnel: shouldSuppressConceptFunnel,
});

View file

@ -2,8 +2,8 @@ import { queryStrings } from "@/constants/query-strings";
import { externalUrls } from "@/router/router-constants/externalUrl-values";
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import store from "@/store";
import { fmgPageValues } from "@/router/router-constants/issPage-values";
import { useMainStore } from "@/store";
import router from "@/router";
/*
@ -46,9 +46,9 @@ export async function navigateToHeritageFunnel(shouldSaveSession = true) {
}
router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, {
corid: store.getters.order.referralCorrelationId,
corid: useMainStore.getters.order.referralCorrelationId,
src: "concept-funnel",
conceptsqid: store.getters.applicationUser.savedSessionId,
conceptsqid: useMainStore.getters.applicationUser.savedSessionId,
});
}
@ -93,7 +93,7 @@ async function getLatestPageForRedirection() {
return fmgPageValues.PART_QUESTIONS;
} else if (
vinLookupComponent.methods.arePagePrerequisitesValid() &&
!store.getters.damage.isRepair
!useMainStore.getters.damage.isRepair
) {
return fmgPageValues.VIN_LOOKUP;
} else {
@ -111,7 +111,7 @@ async function getLatestPageForRedirection() {
function overrideYmmsDirectionIfNeeded(toRoute) {
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
if (store.getters.payment.insuranceCoverage.isVerified) {
if (useMainStore.getters.payment.insuranceCoverage.isVerified) {
switch (fmgPageValue) {
case fmgPageValues.VEHICLE_YEAR:
case fmgPageValues.VEHICLE_MAKE:

View file

@ -10,7 +10,7 @@ import { externalUrls } from "@/router/router-constants/externalUrl-values";
import { queryStrings } from "@/constants/query-strings";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import store from "@/store";
import { useMainStore } from "@/store";
import router from "@/router";
// Mock Lazy Load
@ -372,7 +372,7 @@ describe("navigateToHeritageFunnel", () => {
setupMocksForJsFiles(mockData);
store.getters.order.referralCorrelationId = mockCorrelationId;
useMainStore.getters.order.referralCorrelationId = mockCorrelationId;
router.navigateToExternalUrl = jest.fn();

View file

@ -5,11 +5,12 @@ import "../node_modules/bootstrap/dist/js/bootstrap.js";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import { useMainStore } from '@/store';
import baseMixin from "@/mixins/base-mixin.js";
import analyticsMixin from "@/mixins/analytics-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js";
import { createPinia } from 'pinia';
import Maska from "maska";
import analyticsMixin from "@/mixins/analytics-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js";
// Vue App Setup
const vueApp = createApp(App);
@ -20,10 +21,10 @@ pinia.use(piniaPluginPersistedstate);
useMainStore().populateInitialState();
// Additional Vue items to setup
vueApp.mixin(baseMixin);
vueApp.use(Maska);
vueApp.use(router);
vueApp.mixin(baseMixin);
vueApp.mixin(analyticsMixin);
vueApp.mixin(experimentMixin);
vueApp.use(Maska);
vueApp.mount("#app");

View file

@ -16,13 +16,15 @@ import {
ValueToLogTypes,
} from "@/constants/analytics";
import { cookieNames } from "@/constants/cookie-names";
import store from "@/store";
import { useMainStore } from "@/store";
import baseMixin from "@/mixins/base-mixin";
export default {
methods: {
logPageView(pageEvent) {
logPageView(pageEvent) {
const currentPageName = getPageNameByQueryString();
var payload = {
userId: getDeviceIdValue(),
@ -32,7 +34,7 @@ export default {
action: "",
event: pageEvent,
shouldUseSessionId: false,
experimentsForUser: store.getters.applicationUser.experiments,
experimentsForUser: useMainStore.getters.applicationUser.experiments,
};
baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
@ -51,7 +53,7 @@ export default {
label: label,
value: value,
shouldUseSessionId: false,
experimentsForUser: store.getters.applicationUser.experiments,
experimentsForUser: useMainStore.getters.applicationUser.experiments,
};
baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false);
@ -91,7 +93,7 @@ export default {
},
pushExperimentsToDataLayer() {
const experiments = store.getters.applicationUser.experiments;
const experiments = useMainStore.getters.applicationUser.experiments;
experiments?.forEach((exp) => {
// Set Google Dimension Index based on experiment settings.
let googleDimensionIndex = 99;

View file

@ -9,7 +9,7 @@ import {
GaEvents,
ValueToLogTypes,
} from "@/constants/analytics";
import store from "@/store";
import { useMainStore } from "@/store";
describe("analyticsMixin.js", () => {
test("logPageView: calls dispatch with type and payload", () => {
@ -153,7 +153,7 @@ describe("analyticsMixin.js", () => {
{ virtual: true }
);
store.getters = {
useMainStore.getters = {
applicationUser: {
experiments: [
{
@ -201,7 +201,7 @@ describe("analyticsMixin.js", () => {
{ virtual: true }
);
store.getters = {
useMainStore.getters = {
applicationUser: {
experiments: [
{

View file

@ -21,7 +21,7 @@ export default {
},
},
computed: {
// store will be accessible globally as its id + 'Store'
// store will be accessible globally as its id + 'Store'
...mapStores(useMainStore),
storeActions() {
return storeActions;

View file

@ -1,16 +1,16 @@
import store from "@/store";
import { useMainStore } from "@/store";
export default {
methods: {
hasSettingEqualTo(settingName, settingValue) {
return store.getters.experimentSettings[settingName] == settingValue;
return useMainStore.getters.experimentSettings[settingName] == settingValue;
},
hasSetting(settingName) {
return Object.hasOwn(store.getters.experimentSettings, settingName);
return Object.hasOwn( useMainStore.getters.experimentSettings, settingName);
},
getSettingValue(settingName) {
return this.hasSetting(settingName)
? store.getters.experimentSettings[settingName]
? useMainStore.getters.experimentSettings[settingName]
: null;
},
},

View file

@ -1,7 +1,6 @@
import experimentMixin from "@/mixins/experiment-mixin";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
describe("experiment-mixin", () => {
describe("hasSettingEqualTo", () => {

View file

@ -50,6 +50,28 @@ const router = createRouter({
routes,
});
router.afterEach((to, from) => {
// Update lastPageVisited in the store
store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);
// If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate
if (eval(to.params.isSavingNavigation)) {
if (
store.getters.applicationUser.savedSessionId ||
store.getters.order.customer?.emailAddress
) {
saveSession();
}
}
// Push page view to GA
analyticsMixin.methods.pushPageViewToGA();
// Push experiments to Data Layer
analyticsMixin.methods.pushExperimentsToDataLayer();
});
// Get route information by page name.
// This will reach out to the Cms and there is a 1:1 relationship between page names and route names.

View file

@ -0,0 +1,5 @@
const externalUrls = {
HERITAGE_FUNNEL: process.env.VUE_APP_HERITAGE_FUNNEL,
};
export { externalUrls };

View file

@ -0,0 +1,21 @@
const fmgPageValues = {
VEHICLE_YEAR: "vehicle-year",
VEHICLE_MAKE: "vehicle-make",
VEHICLE_MODEL: "vehicle-model",
VEHICLE_STYLE: "vehicle-style",
VEHICLE_DAMAGE: "vehicle-damage",
ADDRESS_LOOKUP: "address-lookup",
VIN_LOOKUP: "vin-lookup",
VEHICLE_PARTS: "vehicle-parts",
PART_QUESTIONS: "part-questions",
MOLDING_QUESTIONS: "molding-questions",
CAPABILITY_QUESTIONS: "capability-questions",
LICENSE_PLATE_LOOKUP: "license-plate-lookup",
REVEAL: "reveal",
ESTIMATE: "estimate",
ADDRESS_VEHICLES: "address-vehicles",
QUOTE: "quote",
HERITAGE: "heritage",
};
export { fmgPageValues };

View file

@ -0,0 +1,5 @@
const routerParams = {
DISPLAY_VEHICLE_CHANGE_ALERT: "displayVehicleChangeAlert",
};
export { routerParams };

View file

@ -1,7 +1,9 @@
import { defineStore, createPinia } from "pinia";
import { endpoints } from "@/constants/endpoints.js";
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
import globalMethods from "@/global-methods";
import { applicationConfig } from "@/constants/application-config";
import { experimentTriggers } from "@/constants/experiments";
const storeId = 'main';
@ -34,10 +36,18 @@ const getDefaultState = () => {
accountNumber: 0,
},
applicationUser: {
lastPageVisited: null,
experiments: [],
triggeredSiteEntry: false,
eventBus: [],
pageData: {},
savedSessionTimeout: getDateForSavedSessionTimeout(),
saveSessionPromise: null,
savedSessionId: null,
crmCustomerId: null,
lastPageVisited: null,
experiments: [],
triggeredSiteEntry: false
triggeredSiteEntry: false,
},
};
};
@ -47,7 +57,74 @@ export const state = getDefaultState();
export const useMainStore = defineStore({
id: storeId,
state: () => state,
getters: {},
getters: {
applicationUser: (state) => state.applicationUser,
pageData: (state) => (page) => {
return state.applicationUser.pageData[page];
},
experimentOrder: (state) => {
return {
funnelVehicleYear: state.order.vehicle.year,
funnelVehicleMake: state.order.vehicle.make,
funnelVehicleModel: state.order.vehicle.model,
funnelVehicleStyle: state.order.vehicle.style,
funnelIsRepair: state.order.damage.isRepair,
funnelNumberOfChips: state.order.damage.numberOfChips,
funnelCarId: state.order.vehicle.carId,
funnelServiceCity: state.order.serviceLocation.city,
funnelServiceState: state.order.serviceLocation.state,
funnelServiceZipCode: state.order.serviceLocation.zipCode,
funnelParentAccountNumber: state.order.accountNumber,
funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified,
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.WINDSHIELD),
funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.REAR),
funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.DRIVER),
funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.PASSENGER),
funnelOrderPartNumbers: [
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.glassParts,
"partNumber"
),
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.otherParts,
"partNumber"
),
],
funnelOrderPartTypes: [
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.glassParts,
"recalibrationType"
),
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.otherParts,
"recalibrationType"
),
],
};
},
experimentSettings: (state) =>
state.applicationUser.experiments
.map((x) => x.settings)
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
},
actions:
{
// Content API Actions
@ -66,11 +143,14 @@ export const useMainStore = defineStore({
endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION),
});
},
getPageData(pageName) {
getPageData(context, { pageName }) {
return globalMethods.callHttpClient({
method: endpoints.GetPageData.method,
endpoint: endpoints.GetPageData.url(applicationConfig.APPLICATION_ABBREVIATION, pageName),
payload: {},
method: endpoints.GetPageData.method,
endpoint: endpoints.GetPageData.url(
applicationConfig.APPLICATION_ABBREVIATION,
pageName
),
payload: {},
});
},
@ -97,7 +177,151 @@ export const useMainStore = defineStore({
if(!localStorage.getItem(storeId)) {
this.$state = state;
}
}
},
// Analytics Actions
logExperimentExposure(context, { userId, sessionKey, pageName, experiment }) {
return globalMethods.callHttpClient({
method: endpoints.LogExperimentExposureIfAssigned.method,
endpoint: endpoints.LogExperimentExposureIfAssigned.url,
payload: {
experimentForLogging: {
userId: userId,
experimentUniverseId: experiment.universeId,
experimentUniverseName: experiment.universeName,
experimentTestId: experiment.testId,
experimentTestName: experiment.testName,
experimentVariationId: experiment.variationId,
experimentVariationName: experiment.variationName,
enabled: experiment.isActive,
isExposed: experiment.isExposed,
userPartitionNumber: experiment.userPartitionNumber,
assignmentId: experiment.assignmentId,
sessionKey: sessionKey,
pageName: pageName,
},
},
});
},
logPageView(
context,
{
userId,
sessionKey,
pageName,
sessionId,
action,
event,
shouldUseSessionId,
experimentsForUser,
}
) {
var payload = {
userId: userId,
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
applicationName: applicationConfig.APPLICATION_NAME,
action: action,
event: event,
shouldUseSessionId: shouldUseSessionId,
experimentsForUser: experimentsForUser,
};
return globalMethods.callHttpClient({
method: endpoints.LogPageView.method,
endpoint: endpoints.LogPageView.url,
payload: payload,
logApiCall: false,
});
},
logCustomEvent(
context,
{
userId,
sessionKey,
pageName,
sessionId,
category,
action,
label,
value,
shouldUseSessionId,
experimentsForUser,
}
) {
var payload = {
userId: userId,
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
applicationName: applicationConfig.APPLICATION_NAME,
category: category,
action: action,
label: label,
value: value,
shouldUseSessionId: shouldUseSessionId,
experimentsForUser: experimentsForUser,
};
return globalMethods.callHttpClient({
method: endpoints.LogCustomEvent.method,
endpoint: endpoints.LogCustomEvent.url,
payload: payload,
logApiCall: false,
});
},
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
userId: userId,
deviceId: userId,
sessionId: sessionId,
userAgent: userAgent,
operatorId: "WEB",
userName: "SafeliteISS",
referrer: referrer,
};
return globalMethods.callHttpClient({
method: endpoints.InitializeSession.method,
endpoint: endpoints.InitializeSession.url,
payload: payload,
logApiCall: false,
});
},
GetExperimentsByUser(context, { userId }) {
return globalMethods.callHttpClient({
method: endpoints.GetExperimentsByUser.method,
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
payload: {},
});
},
async runExperimentsForTrigger(context, { userId, triggerEvent, triggerValue }) {
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
}
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
userId: userId,
triggerEvent: triggerEvent,
triggerValue: triggerValue,
experimentOrder: context.getters.experimentOrder,
};
const response = await globalMethods.callHttpClient({
method: endpoints.RunExperimentsForTrigger.method,
endpoint: endpoints.RunExperimentsForTrigger.url,
payload: payload,
});
context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments);
},
},
persist: true
});