diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index b619b6b4..ec213fbc 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -24,6 +24,7 @@ import { getCartTotal, getSubtotal } from '@/helpers/cart-helper'; import { getRecalPartNumbers } from "@/helpers/recal-helper"; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import issPageValues from '@/router/router-constants/issPage-values'; import { useMainStore } from '@/store'; @@ -140,6 +141,256 @@ export default { this.pushGenericObjectToGA(gaServiceType); } }, + + pushOrderToDataLayer() { + // helper check for if an object is defined (but maybe falsey) + const isDefined = (x) => x !== null && x !== undefined; + const store = useMainStore(); + + // Get correct order object + const hasSubmittedOrder = store.hasSubmittedOrder(); + const submittedOrder = store.getSubmittedOrder(); + const order = hasSubmittedOrder ? submittedOrder : store.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) + // TODO: Need to redo this for ISS 2.0 + 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 = getSubtotal(order).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 = getCartTotal(order).toFixed(2); + + payload.priceTotal = parseFloat(total); + } else { + payload.priceTotal = ""; + } + + // Recalibration + // TODO: Find equivalent ISS methods. + 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 + // TODO: Find equivalent ISS methods. + 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 } = useMainStore().applicationUser; diff --git a/src/router/index.js b/src/router/index.js index eeca615e..4fd5306e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -192,6 +192,9 @@ router.afterEach(async (to, from) => { // Push values to GA analyticsMixin.methods.pushValueToGA(); + + // Push current order status to Data Layer + analyticsMixin.methods.pushOrderToDataLayer(); } });