438 lines
15 KiB
JavaScript
438 lines
15 KiB
JavaScript
import { storeActions } from "@/constants/store-actions";
|
|
import {
|
|
getDeviceIdValue,
|
|
getSessionIdValue,
|
|
getSessionKeyValue,
|
|
getUserIdValue,
|
|
regenerateDeviceId,
|
|
regenerateUserId,
|
|
refreshSessionExpiration,
|
|
areAllSessionCookiesSet,
|
|
setSessionIdIfUnset,
|
|
setSessionKeyIfUnset,
|
|
} from "@/helpers/heritage-integration/cookie-helper";
|
|
import { queryStrings } from "@/constants/query-strings";
|
|
import { experimentSettings } from "@/constants/experiments";
|
|
import {
|
|
analyticsPageEvents,
|
|
GaCategories,
|
|
GaActions,
|
|
GaLabels,
|
|
GaEvents,
|
|
ValueToLogTypes,
|
|
} from "@/constants/analytics";
|
|
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
|
import store from "@/store";
|
|
|
|
import baseMixin from "@/mixins/base-mixin";
|
|
import { applicationConfig } from "../constants/application-config";
|
|
|
|
export default {
|
|
methods: {
|
|
getPageName() {
|
|
return getPageNameByQueryString();
|
|
},
|
|
|
|
async logPageView(pageEvent) {
|
|
const currentPageName = getPageNameByQueryString();
|
|
await this.validateSession();
|
|
|
|
const refSequenceNum =
|
|
store.getters.order.referralSequenceNumber ||
|
|
store.getters.submittedOrder?.referralSequenceNumber;
|
|
|
|
var payload = {
|
|
userId: getUserIdValue(),
|
|
sessionKey: getSessionKeyValue(),
|
|
pageName: currentPageName,
|
|
sessionId: getSessionIdValue(),
|
|
action: "",
|
|
event: pageEvent,
|
|
shouldUseSessionId: false,
|
|
experimentsForUser: store.getters.applicationUser.experiments,
|
|
referralSequenceNumber: refSequenceNum,
|
|
parentAccountNumber: store.getters.order.payment.parentAccountNumber,
|
|
};
|
|
|
|
await baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
|
|
},
|
|
|
|
async logCustomEvent(category, action, label, value) {
|
|
const currentPageName = getPageNameByQueryString();
|
|
await this.validateSession();
|
|
|
|
const refSequenceNum =
|
|
store.getters.order.referralSequenceNumber ||
|
|
store.getters.submittedOrder?.referralSequenceNumber;
|
|
|
|
var payload = {
|
|
userId: getUserIdValue(),
|
|
sessionKey: getSessionKeyValue(),
|
|
pageName: currentPageName,
|
|
sessionId: getSessionIdValue(),
|
|
category: category,
|
|
action: action,
|
|
label: label,
|
|
value: value,
|
|
shouldUseSessionId: false,
|
|
experimentsForUser: store.getters.applicationUser.experiments,
|
|
referralSequenceNumber: refSequenceNum,
|
|
parentAccountNumber: store.getters.order.payment.parentAccountNumber,
|
|
};
|
|
|
|
await baseMixin.methods.dispatchStoreAction(
|
|
storeActions.LOG_CUSTOM_EVENT,
|
|
payload,
|
|
false
|
|
);
|
|
},
|
|
|
|
async pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
|
|
const currentPageName = getPageNameByQueryString();
|
|
const labelToLog = getValueToLog(label, valueToLogType);
|
|
|
|
const eventToBePushed = {
|
|
event: GaEvents.GENERIC_EVENT,
|
|
category: category,
|
|
action: action,
|
|
label: labelToLog,
|
|
value: undefined,
|
|
path: `/fmg/?${queryStrings.FMG_PAGE}=${currentPageName}`,
|
|
};
|
|
|
|
pushToDataLayerIfDefined(eventToBePushed);
|
|
|
|
if (pushToLogApp) {
|
|
await this.logCustomEvent(category, action, labelToLog, undefined);
|
|
}
|
|
},
|
|
|
|
async pushPageViewToGA() {
|
|
const currentPageName = getPageNameByQueryString();
|
|
const pageViewEvent = {
|
|
event: GaEvents.PAGE_VIEW_EVENT,
|
|
pagePath: `/fmg/?${queryStrings.FMG_PAGE}=${currentPageName}`,
|
|
pageTitle: currentPageName,
|
|
};
|
|
|
|
pushToDataLayerIfDefined(pageViewEvent);
|
|
|
|
await this.logPageView(analyticsPageEvents.ENTRY);
|
|
},
|
|
|
|
pushOrderToDataLayer() {
|
|
// helper check for if an object is defined (but maybe falsey)
|
|
const isDefined = (x) => x !== null && x !== undefined;
|
|
|
|
// Get correct order object
|
|
const hasSubmittedOrder = store.getters.hasSubmittedOrder;
|
|
const order = hasSubmittedOrder ? store.getters.submittedOrder : store.getters.order;
|
|
|
|
// Begin assembling payload for data layer
|
|
const payload = {};
|
|
|
|
// Service Zip
|
|
if (
|
|
order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE &&
|
|
isDefined(order.serviceLocation.zipCode)
|
|
) {
|
|
payload.serviceZipCode = order.serviceLocation.zipCode;
|
|
} else if (
|
|
isDefined(order.serviceLocation.appointmentType) &&
|
|
order.serviceLocation.appointmentType !== AppointmentTypeStrings.MOBILE &&
|
|
isDefined(order.serviceLocation.provider.address.zipCode)
|
|
) {
|
|
payload.serviceZipCode = order.serviceLocation.provider.address.zipCode;
|
|
} else {
|
|
payload.serviceZipCode = "";
|
|
}
|
|
|
|
// Damage Type
|
|
if (isDefined(order.damage.isRepair)) {
|
|
payload.damageType = order.damage.isRepair ? "repair" : "replace";
|
|
} else {
|
|
payload.damageType = "";
|
|
}
|
|
|
|
// Account Type
|
|
if (isDefined(order.payment.isInsurance)) {
|
|
payload.accountType = order.payment.isInsurance ? "insurance" : "cash";
|
|
} else {
|
|
payload.accountType = "";
|
|
}
|
|
|
|
// Promo Codes
|
|
const promos = order.lineItems.promos ?? [];
|
|
if (promos.length === 0) {
|
|
payload.promoCodes = "";
|
|
} else {
|
|
const promoCodes = promos.map((promo) => promo.promoCode);
|
|
const promoString = promoCodes.reduce((prev, next) => `${prev},${next}`);
|
|
payload.promoCodes = promoString;
|
|
}
|
|
|
|
// Vehicle info
|
|
if (isDefined(order.vehicle.year)) {
|
|
// Ensure cast to string.
|
|
payload.vehicleYear = `${order.vehicle.year}`;
|
|
} else {
|
|
payload.vehicleYear = "";
|
|
}
|
|
|
|
if (isDefined(order.vehicle.make)) {
|
|
payload.vehicleMake = order.vehicle.make;
|
|
} else {
|
|
payload.vehicleMake = "";
|
|
}
|
|
|
|
if (isDefined(order.vehicle.model)) {
|
|
payload.vehicleModel = order.vehicle.model;
|
|
} else {
|
|
payload.vehicleModel = "";
|
|
}
|
|
|
|
if (isDefined(order.vehicle.style)) {
|
|
payload.vehicleStyle = order.vehicle.style;
|
|
} else {
|
|
payload.vehicleStyle = "";
|
|
}
|
|
|
|
// Glass pieces
|
|
const glass = order.damage.glassToReplace ?? [];
|
|
if (glass.length === 0) {
|
|
payload.glassToReplace = "";
|
|
} else {
|
|
const glassNames = glass.map((g) => `${g.glassLocation}/${g.glassName}`);
|
|
const glassString = glassNames.reduce((prev, next) => `${prev},${next}`);
|
|
|
|
payload.glassToReplace = glassString;
|
|
}
|
|
|
|
// Work Order Id
|
|
if (order.workOrderId) {
|
|
const parsedId = parseInt(order.workOrderId);
|
|
if (!isNaN(parsedId)) {
|
|
payload.workOrderId = parsedId;
|
|
} else {
|
|
payload.workOrderId = "";
|
|
}
|
|
} else {
|
|
payload.workOrderId = "";
|
|
}
|
|
|
|
// Provider Ctu
|
|
if (isDefined(order.serviceLocation.zipCodeCtu)) {
|
|
const parsedCtu = parseInt(order.serviceLocation.zipCodeCtu);
|
|
if (!isNaN(parsedCtu)) {
|
|
payload.providerCtu = parseInt(order.serviceLocation.zipCodeCtu);
|
|
} else {
|
|
payload.providerCtu = "";
|
|
}
|
|
} else {
|
|
payload.providerCtu = "";
|
|
}
|
|
|
|
// Work Order Number
|
|
if (order.workOrderNumber) {
|
|
payload.orderNumber = order.workOrderNumber;
|
|
} else {
|
|
payload.orderNumber = "";
|
|
}
|
|
|
|
// Pricing
|
|
// Only fire for completed orders?
|
|
|
|
const lineItems = order.lineItems ?? {};
|
|
const combinedLineItems = [
|
|
...(lineItems.glassParts ?? []),
|
|
...(lineItems.supportingItems ?? []),
|
|
...(lineItems.vaps ?? []),
|
|
...(lineItems.promos ?? []),
|
|
];
|
|
|
|
const isPricingAvailable =
|
|
combinedLineItems.length > 0 &&
|
|
combinedLineItems.every(
|
|
(lineItem) =>
|
|
isDefined(lineItem.kitPrice) &&
|
|
isDefined(lineItem.laborAmount) &&
|
|
isDefined(lineItem.sellingPrice)
|
|
);
|
|
const isTaxAvailable =
|
|
isPricingAvailable &&
|
|
combinedLineItems.every((lineItem) => isDefined(lineItem.salesTax));
|
|
|
|
if (isPricingAvailable) {
|
|
const subtotal = baseMixin.methods
|
|
.getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false)
|
|
.toFixed(2);
|
|
|
|
payload.priceSubTotal = parseFloat(subtotal);
|
|
} else {
|
|
payload.priceSubTotal = "";
|
|
}
|
|
|
|
if (isTaxAvailable) {
|
|
const total = baseMixin.methods
|
|
.getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, true)
|
|
.toFixed(2);
|
|
|
|
payload.priceTotal = parseFloat(total);
|
|
} else {
|
|
payload.priceTotal = "";
|
|
}
|
|
|
|
// Recalibration
|
|
if (hasSubmittedOrder) {
|
|
payload.isRecalibrationOnOrder = store.getters.isRecalibrationOnSubmittedOrder;
|
|
} else {
|
|
payload.isRecalibrationOnOrder = store.getters.isRecalibrationOnOrder;
|
|
}
|
|
|
|
// Appointment Type
|
|
if (isDefined(order.serviceLocation.appointmentType)) {
|
|
payload.appointmentType = order.serviceLocation.appointmentType;
|
|
} else {
|
|
payload.appointmentType = "";
|
|
}
|
|
|
|
pushToDataLayerIfDefined(payload);
|
|
},
|
|
|
|
pushExperimentsToDataLayer() {
|
|
const experiments = store.getters.applicationUser.experiments;
|
|
experiments?.forEach((exp) => {
|
|
// Set Google Dimension Index based on experiment settings.
|
|
let googleDimensionIndex = 99;
|
|
|
|
if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) {
|
|
googleDimensionIndex =
|
|
exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX];
|
|
}
|
|
|
|
// Create object with dimension index and value.
|
|
const experimentWithDimension = {
|
|
[`experimentId_${googleDimensionIndex}`]: exp.universeId,
|
|
[`variationId_${googleDimensionIndex}`]: exp.variationId,
|
|
[`experimentName_${googleDimensionIndex}`]: exp.universeName,
|
|
[`variationName_${googleDimensionIndex}`]: exp.variationName,
|
|
[`customDimension_${googleDimensionIndex}`]: `${exp.universeId}_${exp.variationId}_${exp.universeName}_${exp.variationName}`,
|
|
};
|
|
|
|
// Push to the data layer with the Google Custom Dimension Index.
|
|
pushToDataLayerIfDefined(experimentWithDimension);
|
|
});
|
|
},
|
|
|
|
prependActionToMethod(object, method, actionToPrepend) {
|
|
const baseMethodName = method.name.startsWith("bound ")
|
|
? method.name.substring(6)
|
|
: method.name;
|
|
const baseMethod = object[baseMethodName];
|
|
object[baseMethodName] = function () {
|
|
actionToPrepend.apply(this, arguments);
|
|
return baseMethod.apply(object, arguments);
|
|
};
|
|
},
|
|
|
|
async initSession() {
|
|
regenerateDeviceId();
|
|
regenerateUserId();
|
|
|
|
const userId = getUserIdValue(); // cookieNames.FUNNEL_USER_ID
|
|
const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
|
|
const sessionId = getSessionIdValue(); // cookieNames.SESSION_ID
|
|
const userAgent = navigator.userAgent; // navigator.userAgent
|
|
const referrer =
|
|
applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above
|
|
|
|
const payload = {
|
|
userId: userId,
|
|
deviceId: deviceId,
|
|
sessionId: sessionId,
|
|
userAgent: userAgent,
|
|
referrer: referrer,
|
|
};
|
|
|
|
const response = await baseMixin.methods.dispatchStoreAction(
|
|
storeActions.INITIALIZE_SESSION,
|
|
payload,
|
|
false
|
|
);
|
|
|
|
if (response?.data) {
|
|
if (response.data.sessionKey) {
|
|
setSessionKeyIfUnset(response.data.sessionKey);
|
|
}
|
|
|
|
if (response.data.sessionId) {
|
|
setSessionIdIfUnset(response.data.sessionId);
|
|
}
|
|
}
|
|
},
|
|
|
|
noSession() {
|
|
return !areAllSessionCookiesSet();
|
|
},
|
|
|
|
async validateSession() {
|
|
if (this.noSession()) {
|
|
await this.initSession();
|
|
}
|
|
|
|
refreshSessionExpiration();
|
|
},
|
|
|
|
removeParamsFromEndpoint(endpoint) {
|
|
const endpointWithoutParams = endpoint.split("?")[0];
|
|
const numSlashesBeforeParams = 6;
|
|
let splitString = endpointWithoutParams.split("/");
|
|
if (splitString.length > numSlashesBeforeParams) {
|
|
splitString = splitString.slice(0, numSlashesBeforeParams);
|
|
return splitString.join("/");
|
|
} else {
|
|
return endpointWithoutParams;
|
|
}
|
|
},
|
|
},
|
|
computed: {
|
|
analyticsPageEvents() {
|
|
return analyticsPageEvents;
|
|
},
|
|
GaCategories() {
|
|
return GaCategories;
|
|
},
|
|
GaActions() {
|
|
return GaActions;
|
|
},
|
|
GaLabels() {
|
|
return GaLabels;
|
|
},
|
|
ValueToLogTypes() {
|
|
return ValueToLogTypes;
|
|
},
|
|
},
|
|
};
|
|
|
|
function pushToDataLayerIfDefined(data) {
|
|
if (window.dataLayer !== undefined) {
|
|
window.dataLayer.push(data);
|
|
}
|
|
}
|
|
|
|
function getPageNameByQueryString() {
|
|
const params = new URLSearchParams(location.search);
|
|
|
|
if (params.has(queryStrings.FMG_PAGE)) {
|
|
return params.get(queryStrings.FMG_PAGE);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function getValueToLog(value, valueToLogType) {
|
|
if (valueToLogType != null && valueToLogType === ValueToLogTypes.LAST_5) {
|
|
return value.slice(-5);
|
|
}
|
|
return value;
|
|
}
|