CASH-2037 change the products logged in the session name to use the part number and part type. Also add the service package selected for the data analytics team.
1006 lines
41 KiB
JavaScript
1006 lines
41 KiB
JavaScript
import { storeActions } from "@/constants/store-actions";
|
||
import {
|
||
getDeviceIdValue,
|
||
getSessionIdValue,
|
||
getSessionKeyValue,
|
||
getUserIdValue,
|
||
regenerateDeviceId,
|
||
regenerateUserId,
|
||
refreshSessionExpiration,
|
||
areAllSessionCookiesSet,
|
||
setSessionIdIfUnset,
|
||
setSessionKeyIfUnset,
|
||
getskeyValue,
|
||
} from "@/helpers/heritage-integration/cookie-helper";
|
||
import { queryStrings } from "@/constants/query-strings";
|
||
import { experimentSettings, experimentUniverses } from "@/constants/experiments";
|
||
import experimentMixin from "@/mixins/experiment-mixin";
|
||
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";
|
||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||
import { routeData } from "@/router/constants/routes";
|
||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||
import { Variables } from "../constants/analytics";
|
||
import { containsRecalParts, getRecalPartNumbers } from "@/helpers/recal-helper";
|
||
import { getAmountDue, getSubTotal, getSalesTax } from "@/helpers/pricing-helper.js";
|
||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||
import router from "@/router";
|
||
|
||
export default {
|
||
methods: {
|
||
getPageName() {
|
||
return getPageNameFromRouter();
|
||
},
|
||
|
||
async logPageView(pageEvent) {
|
||
const currentPageName = getPageNameFromRouter();
|
||
await this.validateSession();
|
||
|
||
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;
|
||
|
||
const parentAccountNum = hasSubmittedOrderAtConfirmationPage
|
||
? submittedOrder.payment.parentAccountNumber
|
||
: store.getters.order.payment.parentAccountNumber;
|
||
|
||
var payload = {
|
||
userId: getUserIdValue(),
|
||
sessionKey: getSessionKeyValue(),
|
||
pageName: currentPageName,
|
||
sessionId: getSessionIdValue(),
|
||
action: "",
|
||
event: pageEvent,
|
||
shouldUseSessionId: false,
|
||
experimentsForUser: store.getters.applicationUser.experiments,
|
||
referralSequenceNumber: refSequenceNum,
|
||
parentAccountNumber: parentAccountNum,
|
||
};
|
||
|
||
await baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
|
||
},
|
||
|
||
async logCustomEvent(category, action, label, value) {
|
||
const currentPageName = getPageNameFromRouter();
|
||
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,
|
||
value = null
|
||
) {
|
||
const currentPageName = getPageNameFromRouter();
|
||
const labelToLog = getValueToLog(label, valueToLogType);
|
||
|
||
const eventToBePushed = {
|
||
event: GaEvents.GENERIC_EVENT,
|
||
category: category,
|
||
action: action,
|
||
label: labelToLog,
|
||
value: value ?? undefined,
|
||
path: `/fmg/${currentPageName}`,
|
||
};
|
||
|
||
pushToDataLayerIfDefined(eventToBePushed);
|
||
|
||
if (pushToLogApp) {
|
||
await this.logCustomEvent(category, action, labelToLog, undefined);
|
||
}
|
||
},
|
||
|
||
async logDigitalConsumer() {
|
||
const currentPageName = getPageNameFromRouter();
|
||
const universes = store.getters.applicationUser.experiments;
|
||
|
||
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 isConceptExposed = universes.find(
|
||
(item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL
|
||
)?.isExposed;
|
||
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
|
||
const hasSubmittedOrderAtConfirmationPage =
|
||
hasSubmittedOrder && currentPageName?.toLowerCase() == routeData.CONFIRMATION.name;
|
||
|
||
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,
|
||
isConceptExposed: isConceptExposed,
|
||
};
|
||
|
||
await baseMixin.methods.dispatchStoreAction(
|
||
storeActions.LOG_DIGITALCONSUMER,
|
||
payload,
|
||
false
|
||
);
|
||
},
|
||
|
||
async pushEventForChatsToGA(category, action, label, pushToLogApp = false) {
|
||
const currentPageName = getPageNameFromRouter();
|
||
const value = `2.0_${currentPageName}`;
|
||
await this.pushEventToGA(category, action, label, pushToLogApp, null, value);
|
||
},
|
||
|
||
async pushVariableToDataLayer(data) {
|
||
pushToDataLayerIfDefined(data);
|
||
},
|
||
|
||
async pushPageViewToGA() {
|
||
const currentPageName = getPageNameFromRouter();
|
||
const pageViewEvent = {
|
||
event: GaEvents.PAGE_VIEW_EVENT,
|
||
pagePath: `/fmg/${currentPageName}`,
|
||
pageTitle: currentPageName,
|
||
};
|
||
|
||
pushToDataLayerIfDefined(pageViewEvent);
|
||
|
||
await this.logPageView(analyticsPageEvents.ENTRY);
|
||
},
|
||
|
||
// This sends session data to the session logging endpoint on the analytics service.
|
||
// From there, it uses aws kinesis data stream, DigitalConsumer-Session-Data-Stream,
|
||
// and aws FireHose stream, DigitalConsumer-Session-Firehose, to push data to an
|
||
// S3 bucket, safelite-dev-digitalconsumer-session-data-us-east-2/1.
|
||
// This bucket data is then picked up by snowflake for analytics use.
|
||
async pushFmgSessionData() {
|
||
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
const order = hasSubmittedOrder ? submittedOrder : store.getters.order;
|
||
|
||
const hasSubmittedApplicationUser = baseMixin.methods.hasSubmittedApplicationUser();
|
||
const submittedApplicationUser = baseMixin.methods.getSubmittedApplicationUser();
|
||
const applicationUser = hasSubmittedApplicationUser
|
||
? submittedApplicationUser
|
||
: store.getters.applicationUser;
|
||
|
||
const isEarlyBird = order?.lineItems?.supportingItems?.find(
|
||
(lineItem) => lineItem.partType == partTypeStrings.EARLY_BIRD
|
||
);
|
||
|
||
const promoCodes = Array.isArray(order?.lineItems?.promos)
|
||
? order?.lineItems?.promos
|
||
.map((item) => item.promoCode)
|
||
.filter((code) => code)
|
||
.join(", ")
|
||
: null;
|
||
|
||
const glassProducts = order?.damage?.glassToReplace?.map(
|
||
(part) => `${part.glassLocation}-${part.glassName}`
|
||
);
|
||
|
||
const format = (part) => `${part?.partNumber}-${part?.partType ? part.partType : ""}`;
|
||
const mapParts = (arr) => (arr ?? []).map(format);
|
||
|
||
const glassParts = mapParts(order?.lineItems?.glassParts);
|
||
const supportingItems = mapParts(order?.lineItems?.supportingItems);
|
||
const vaps = mapParts(order?.lineItems?.vaps);
|
||
const childParts = [].concat(
|
||
...(order?.lineItems?.glassParts ?? []).map((gp) => mapParts(gp?.childParts))
|
||
);
|
||
const allParts = [...glassParts, ...supportingItems, ...vaps, ...childParts];
|
||
|
||
if (applicationUser?.pageData?.quote?.servicePackageSelected) {
|
||
allParts.push(applicationUser.pageData.quote.servicePackageSelected);
|
||
}
|
||
|
||
var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`;
|
||
|
||
var sessionData = {};
|
||
sessionData.currentPage = getPageNameFromRouter();
|
||
sessionData.sid = getSessionIdValue();
|
||
sessionData.deviceId = getDeviceIdValue();
|
||
sessionData.fmgSessionId = applicationUser?.savedSessionId;
|
||
sessionData.skey = getskeyValue().toString();
|
||
sessionData.userId = getUserIdValue();
|
||
sessionData.carId = order?.vehicle?.carId;
|
||
sessionData.vehicleYear = order?.vehicle?.year;
|
||
sessionData.vehicleMake = order?.vehicle?.make;
|
||
sessionData.vehicleModel = order?.vehicle?.model;
|
||
sessionData.vehicleStyle = order?.vehicle?.style;
|
||
sessionData.hasVin = order?.vehicle?.vin ? true : false;
|
||
sessionData.cashOrInsuranceAccountType = order?.payment?.isInsurance
|
||
? "Insurance"
|
||
: "Cash";
|
||
sessionData.damageType = order?.damage?.isRepair ? "Repair" : "Replace";
|
||
sessionData.productType = allParts;
|
||
sessionData.eon = order?.eon;
|
||
sessionData.referralNumber = order?.referralNumber;
|
||
sessionData.referralSequenceNumber = order?.referralSequenceNumber;
|
||
sessionData.referralDate = order?.referralDate;
|
||
sessionData.workOrderNumber = order?.workOrderNumber;
|
||
sessionData.workOrderId = order?.workOrderId;
|
||
sessionData.isPia = order?.payment?.isPia ?? false;
|
||
sessionData.piaType = order?.payment?.piaType;
|
||
sessionData.parentAccountNumber = order?.payment?.parentAccountNumber;
|
||
sessionData.settledTenderAmount = order?.settledTenderAmount;
|
||
sessionData.recalRequired = containsRecalParts(order?.lineItems);
|
||
sessionData.recalType = getRecalPartNumbers(order?.lineItems?.glassParts);
|
||
sessionData.serviceZipCode = order?.serviceLocation?.provider?.address?.zipCode
|
||
? order?.serviceLocation?.provider?.address?.zipCode
|
||
: order?.serviceLocation?.zipCode;
|
||
sessionData.providerCtu = order?.serviceLocation?.provider?.address?.zipCodeCtu
|
||
? order?.serviceLocation?.provider?.address?.zipCodeCtu
|
||
: order?.serviceLocation?.zipCodeCtu;
|
||
sessionData.appointmentDate = appointment;
|
||
sessionData.serviceType = order?.serviceLocation?.appointmentType;
|
||
sessionData.promoCodes = promoCodes;
|
||
sessionData.hasTechnicianNotes = order?.serviceLocation?.techNotes ? true : false;
|
||
sessionData.paymentMethod = order?.payment?.piaType;
|
||
sessionData.isTextingOptedIn = order?.customer?.isSmsOptIn ? true : false;
|
||
sessionData.isEarlyBird = isEarlyBird ? true : false;
|
||
sessionData.insuranceCo = order?.policy?.insuranceCompanyName;
|
||
sessionData.deductible = order?.policy?.currentDeductible;
|
||
sessionData.isVerified = order?.payment?.insuranceCoverage?.isVerified ?? false;
|
||
sessionData.coverageStatus = order?.payment?.insuranceCoverage?.coverageStatus;
|
||
sessionData.coverageSubStatus = order?.payment?.insuranceCoverage?.coverageSubStatus;
|
||
sessionData.isNoComp = order?.policy?.isNoComp;
|
||
sessionData.isItac = order?.policy?.isItac;
|
||
sessionData.subTotalPrice = getSubTotal(order?.lineItems);
|
||
sessionData.totalPrice = getAmountDue(order?.lineItems, true);
|
||
sessionData.userAgent = navigator.userAgent;
|
||
sessionData.cashPriceSubTotal = order?.cashPriceSubTotal;
|
||
|
||
await baseMixin.methods.dispatchStoreAction(
|
||
storeActions.LOG_FMG_SESSION_DATA,
|
||
sessionData,
|
||
false
|
||
);
|
||
},
|
||
|
||
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 = baseMixin.methods.hasSubmittedOrder();
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
const order = hasSubmittedOrder ? 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;
|
||
}
|
||
|
||
//EON
|
||
if (order.eon) {
|
||
payload.eon = order.eon;
|
||
} else {
|
||
payload.eon = "";
|
||
}
|
||
|
||
// 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)) {
|
||
payload.providerCtu = order.serviceLocation.zipCodeCtu;
|
||
} 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));
|
||
|
||
//unverified (in scenarios we don’t display the price)
|
||
if (
|
||
order.payment.isInsurance &&
|
||
isDefined(order.payment.insuranceCoverage.isVerified) &&
|
||
!order.payment.insuranceCoverage.isVerified
|
||
) {
|
||
payload.priceSubTotal = "";
|
||
}
|
||
//deductible (in scenarios we don’t display the price)
|
||
else if (
|
||
order.payment.isInsurance &&
|
||
isDefined(order.payment.insuranceCoverage.isVerified) &&
|
||
order.payment.insuranceCoverage.isVerified &&
|
||
isDefined(order.policy.currentDeductible) &&
|
||
order.policy.currentDeductible >= 0 &&
|
||
!order.policy.isItac &&
|
||
!order.policy.isNoComp
|
||
) {
|
||
payload.priceSubTotal = "";
|
||
} else if (isPricingAvailable) {
|
||
const subtotal = baseMixin.methods
|
||
.getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false)
|
||
.toFixed(2);
|
||
|
||
payload.priceSubTotal = parseFloat(subtotal);
|
||
} else {
|
||
payload.priceSubTotal = "";
|
||
}
|
||
|
||
// Cash Quote or Cash Price Sub Total
|
||
payload.cashPriceSubTotal = order?.cashPriceSubTotal ?? "";
|
||
|
||
//unverified (in scenarios we don’t display the price)
|
||
if (
|
||
order.payment.isInsurance &&
|
||
isDefined(order.payment.insuranceCoverage.isVerified) &&
|
||
!order.payment.insuranceCoverage.isVerified
|
||
) {
|
||
payload.priceTotal = "";
|
||
}
|
||
//deductible (in scenarios we don’t display the price)
|
||
else if (
|
||
order.payment.isInsurance &&
|
||
isDefined(order.payment.insuranceCoverage.isVerified) &&
|
||
order.payment.insuranceCoverage.isVerified &&
|
||
isDefined(order.policy.currentDeductible) &&
|
||
order.policy.currentDeductible >= 0 &&
|
||
!order.policy.isItac &&
|
||
!order.policy.isNoComp
|
||
) {
|
||
payload.priceTotal = "";
|
||
} else 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.isRecalibrationOnSubmittedState;
|
||
} else {
|
||
payload.isRecalibrationOnOrder = store.getters.isRecalibrationOnOrder;
|
||
}
|
||
|
||
// Appointment Type
|
||
if (isDefined(order.serviceLocation.appointmentType)) {
|
||
payload.appointmentType = order.serviceLocation.appointmentType;
|
||
} else {
|
||
payload.appointmentType = "";
|
||
}
|
||
//Insurance
|
||
if (order.payment.isInsurance) {
|
||
payload.isInsuranceVerified = order.payment.insuranceCoverage.isVerified ?? "";
|
||
payload.insuranceCompanyName = order.policy.insuranceCompanyName ?? "";
|
||
if (!order.payment.insuranceCoverage.isVerified) {
|
||
payload.isInsuranceItac = "";
|
||
payload.isInsuranceNoComp = "";
|
||
} else {
|
||
payload.isInsuranceItac = order.policy.isItac ?? "";
|
||
payload.isInsuranceNoComp = order.policy.isNoComp ?? "";
|
||
}
|
||
if (
|
||
order.policy.isItac ||
|
||
order.policy.isNoComp ||
|
||
!order.payment.insuranceCoverage.isVerified
|
||
) {
|
||
payload.insuranceDeductible = "";
|
||
} else {
|
||
payload.insuranceDeductible = order.policy.currentDeductible ?? "";
|
||
}
|
||
} else {
|
||
payload.isInsuranceVerified = "";
|
||
payload.insuranceDeductible = "";
|
||
payload.isInsuranceItac = "";
|
||
payload.isInsuranceNoComp = "";
|
||
payload.insuranceCompanyName = "";
|
||
}
|
||
|
||
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);
|
||
});
|
||
},
|
||
|
||
pushProductArrayToDataLayer() {
|
||
// Get correct order object
|
||
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
|
||
if (hasSubmittedOrder) {
|
||
var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};
|
||
|
||
// combine all line items
|
||
var combinedLineItems = [
|
||
...(lineItems.glassParts ?? []),
|
||
...(lineItems.supportingItems ?? []),
|
||
...(lineItems.vaps ?? []),
|
||
...(lineItems.promos ?? []),
|
||
];
|
||
|
||
//Get child parts
|
||
combinedLineItems = flattenArray(combinedLineItems);
|
||
|
||
var products = [];
|
||
var discount = 0;
|
||
var coupon = "";
|
||
var subTotal = 0;
|
||
for (var i = 0; i < combinedLineItems.length; i++) {
|
||
let part = combinedLineItems[i];
|
||
let productSku = part.partNumber;
|
||
let productType = part.partType;
|
||
let promoCode = part.promoCode;
|
||
let productPrice = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||
[part],
|
||
false
|
||
);
|
||
|
||
if (productSku == "DISCOUNT" || productType == "SERVICE PACKAGE DISCOUNT") {
|
||
if (coupon) {
|
||
coupon += ",";
|
||
}
|
||
if (productSku == "DISCOUNT") {
|
||
coupon += promoCode;
|
||
} else {
|
||
coupon += productSku;
|
||
}
|
||
|
||
discount += productPrice * -1;
|
||
} else {
|
||
products.push({
|
||
productType: productType,
|
||
productSku: productSku,
|
||
productPrice: productPrice.toFixed(2),
|
||
productQuantity: "1",
|
||
});
|
||
subTotal += productPrice;
|
||
}
|
||
}
|
||
pushToDataLayerIfDefined({
|
||
event: "productArray",
|
||
productArray: {
|
||
coupon: coupon,
|
||
discount: discount.toFixed(2),
|
||
subTotal: subTotal.toFixed(2),
|
||
products: products,
|
||
},
|
||
});
|
||
}
|
||
},
|
||
|
||
pushECommerceCartToDataLayer() {
|
||
const isDefined = (x) => x !== null && x !== undefined;
|
||
// Get correct order object
|
||
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
if (hasSubmittedOrder) {
|
||
var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};
|
||
var supportingItems =
|
||
submittedOrder.lineItems && submittedOrder.lineItems.supportingItems
|
||
? submittedOrder.lineItems.supportingItems
|
||
: [];
|
||
var insurance = submittedOrder.payment && submittedOrder.payment.isInsurance;
|
||
var itac = submittedOrder.policy && submittedOrder.policy.isItac;
|
||
var nocomp = submittedOrder.policy && submittedOrder.policy.isNoComp;
|
||
|
||
var recalLineItem = supportingItems.filter(function (lineItem) {
|
||
return lineItem.partType.indexOf("RECALIBRATION") !== -1;
|
||
});
|
||
var disposalFee = supportingItems.filter(function (lineItem) {
|
||
return lineItem.partType.indexOf("DISPOSAL FEE") !== -1;
|
||
});
|
||
var mobileFee = supportingItems.filter(function (lineItem) {
|
||
return lineItem.partType.indexOf("MOBILE FEE") !== -1;
|
||
});
|
||
var repairFee = supportingItems.filter(function (lineItem) {
|
||
return lineItem.partType.indexOf("REPAIR FEE") !== -1;
|
||
});
|
||
|
||
var vaps =
|
||
submittedOrder.lineItems && submittedOrder.lineItems.vaps
|
||
? submittedOrder.lineItems.vaps
|
||
: [];
|
||
var wipers = vaps.filter(function (lineItem) {
|
||
return (
|
||
lineItem.partType.indexOf("FRONT WIPER") !== -1 ||
|
||
lineItem.partType.indexOf("REAR WIPER") !== -1
|
||
);
|
||
});
|
||
var rainRepel = vaps.filter(function (lineItem) {
|
||
return lineItem.partType.indexOf("RAIN REPEL") !== -1;
|
||
});
|
||
|
||
// Combine line items
|
||
var combinedLineItems = [];
|
||
if (lineItems.glassParts) {
|
||
combinedLineItems = combinedLineItems.concat(lineItems.glassParts);
|
||
}
|
||
if (recalLineItem) {
|
||
combinedLineItems = combinedLineItems.concat(recalLineItem);
|
||
}
|
||
if (disposalFee) {
|
||
combinedLineItems = combinedLineItems.concat(disposalFee);
|
||
}
|
||
if (mobileFee && !(insurance && !itac && !nocomp)) {
|
||
combinedLineItems = combinedLineItems.concat(mobileFee);
|
||
}
|
||
if (repairFee) {
|
||
combinedLineItems = combinedLineItems.concat(repairFee);
|
||
}
|
||
if (wipers) {
|
||
combinedLineItems = combinedLineItems.concat(wipers);
|
||
}
|
||
if (rainRepel) {
|
||
combinedLineItems = combinedLineItems.concat(rainRepel);
|
||
}
|
||
|
||
//Remove child Parts if any
|
||
combinedLineItems.forEach((lineItem) => {
|
||
lineItem.childParts = [];
|
||
});
|
||
|
||
var isPricingAvailable =
|
||
combinedLineItems.length > 0 &&
|
||
combinedLineItems.every(function (lineItem) {
|
||
return (
|
||
isDefined(lineItem.kitPrice) &&
|
||
isDefined(lineItem.laborAmount) &&
|
||
isDefined(lineItem.sellingPrice)
|
||
);
|
||
});
|
||
let subtotal = 0;
|
||
if (isPricingAvailable) {
|
||
subtotal = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||
combinedLineItems,
|
||
false
|
||
);
|
||
}
|
||
pushToDataLayerIfDefined({
|
||
event: "eCommerceCart",
|
||
eCommerceCart: {
|
||
products: combinedLineItems,
|
||
subTotal: parseInt(subtotal),
|
||
},
|
||
});
|
||
}
|
||
},
|
||
|
||
pushCommissionJunctionGtmDataToDataLayer() {
|
||
// helper check for if an object is defined (but maybe falsey)
|
||
const isDefined = (x) => x !== null && x !== undefined;
|
||
let repairReplace = "";
|
||
let coupons = "";
|
||
let refSequenceNum = "";
|
||
let accountType = "";
|
||
let amount = 0;
|
||
let cjEvent = "";
|
||
if (store.getters.applicationUser.affiliateCookies?.length > 0) {
|
||
const affiliateCookies = store.getters.applicationUser.affiliateCookies;
|
||
var cookieArray = [];
|
||
affiliateCookies.forEach((item) => {
|
||
let cookieObject = convertCookieStringToObject(item.CookieValue);
|
||
cookieArray.push(cookieObject);
|
||
});
|
||
const sortedCookies = cookieArray.sort(
|
||
(a, b) =>
|
||
new Date(b.timestamp.replace("/", "T")) -
|
||
new Date(a.timestamp.replace("/", "T"))
|
||
);
|
||
const filteredCookie = sortedCookies?.find(
|
||
(x) => x.tagEvent?.length > 0 && x.batchEvent?.length > 0
|
||
);
|
||
if (isDefined(filteredCookie)) {
|
||
cjEvent = filteredCookie.tagEvent;
|
||
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
|
||
const submittedOrder = baseMixin.methods.getSubmittedOrder();
|
||
|
||
if (hasSubmittedOrder) {
|
||
repairReplace = submittedOrder.damage.isRepair ? "Repair" : "Replace";
|
||
const promos = submittedOrder.lineItems.promos ?? [];
|
||
if (promos.length === 0) {
|
||
coupons = "";
|
||
} else {
|
||
const promoCodes = promos.map((promo) => promo.promoCode);
|
||
const promoString = promoCodes.reduce(
|
||
(prev, next) => `${prev}_${next}`
|
||
);
|
||
coupons = promoString;
|
||
}
|
||
const serviceZipPackage = submittedOrder.lineItems?.supportingItems?.find(
|
||
(x) => x.partType == "SERVICE PACKAGE DISCOUNT"
|
||
);
|
||
if (isDefined(serviceZipPackage)) {
|
||
if (coupons) {
|
||
coupons += ",";
|
||
}
|
||
coupons += serviceZipPackage.partNumber;
|
||
}
|
||
refSequenceNum = submittedOrder.referralSequenceNumber;
|
||
|
||
if (isDefined(submittedOrder.payment.isInsurance)) {
|
||
accountType = submittedOrder.payment.isInsurance ? "insurance" : "cash";
|
||
} else {
|
||
accountType = "";
|
||
}
|
||
const lineItems = submittedOrder.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)
|
||
);
|
||
if (accountType == "cash" && isPricingAvailable) {
|
||
amount = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||
combinedLineItems,
|
||
false
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
pushToDataLayerIfDefined({
|
||
event: "commissionJunctionGtmData",
|
||
commissionJunctionGtmData: {
|
||
cj_commission_junction_event: cjEvent,
|
||
cj_referral_sequence_number: refSequenceNum,
|
||
cj_amount: amount.toFixed(2),
|
||
cj_repair_replace: repairReplace,
|
||
cj_coupon: coupons,
|
||
},
|
||
});
|
||
},
|
||
|
||
pushPageErrorToDataLayer(error) {
|
||
pushToDataLayerIfDefined({
|
||
event: "page-error",
|
||
error: error,
|
||
});
|
||
},
|
||
|
||
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();
|
||
},
|
||
|
||
// sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the vehicle year in vuex
|
||
sessionExpired() {
|
||
const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true";
|
||
if (this.noSession() && !fromHeritage && store.getters.order.vehicle?.year > 0) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
},
|
||
|
||
async validateSession() {
|
||
// do not init session if it is expired. let the click event on nav-bar handle session expired logic
|
||
if (this.sessionExpired()) {
|
||
return;
|
||
}
|
||
|
||
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;
|
||
},
|
||
Variables() {
|
||
return Variables;
|
||
},
|
||
},
|
||
};
|
||
|
||
function pushToDataLayerIfDefined(data) {
|
||
if (window.dataLayer !== undefined) {
|
||
window.dataLayer.push(data);
|
||
}
|
||
}
|
||
|
||
function getPageNameFromRouter() {
|
||
if (
|
||
router &&
|
||
router.currentRoute &&
|
||
router.currentRoute.value &&
|
||
router.currentRoute.value.name
|
||
) {
|
||
return router.currentRoute.value.name;
|
||
}
|
||
|
||
return window.location.href.replace(/\/$/, "").split("/").pop();
|
||
}
|
||
|
||
function getValueToLog(value, valueToLogType) {
|
||
if (valueToLogType != null && valueToLogType === ValueToLogTypes.LAST_5) {
|
||
return value.slice(-5);
|
||
}
|
||
return value;
|
||
}
|
||
|
||
function flattenArray(arr) {
|
||
let result = [];
|
||
arr.forEach((item) => {
|
||
result.push(item);
|
||
if (item.childParts) {
|
||
result = result.concat(item.childParts);
|
||
delete item.childParts; // Remove childParts after flattening
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
function convertCookieStringToObject(cookieValue) {
|
||
const cookieObject = cookieValue.split("&").reduce((acc, pair) => {
|
||
const [key, value] = pair.split("=");
|
||
acc[key] = value;
|
||
return acc;
|
||
}, {});
|
||
return cookieObject;
|
||
}
|