Merge pull request #1182 from Safelite/feature/jzimmerman/INSR-9224
INSR-9224: Updated the datalayer to populate common page properties on each page load.
This commit is contained in:
commit
58e4741796
5 changed files with 240 additions and 43 deletions
|
|
@ -86,3 +86,17 @@ export function getPropertyCaseInsensitive(obj, property) {
|
||||||
while (prop = props.pop()) if (prop.toLowerCase() === property.toLowerCase()) return prop;
|
while (prop = props.pop()) if (prop.toLowerCase() === property.toLowerCase()) return prop;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||||
|
return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||||
|
if (!arrayOfObjects) return null;
|
||||||
|
|
||||||
|
return arrayOfObjects.sort((a, b) => {
|
||||||
|
if (a[propertyName] < b[propertyName]) return -1;
|
||||||
|
if (a[propertyName] > b[propertyName]) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import partTypeStrings from '@/constants/part-type-strings';
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
import { deepClone } from '@/helpers/object-helper';
|
import { deepClone, getNonFalseValuesOfPropertyInArrayOfObjects } from '@/helpers/object-helper';
|
||||||
|
|
||||||
const recalPartTypes = [partTypeStrings.RECALIBRATION, partTypeStrings.ADAS_RECALIBRATION];
|
const recalPartTypes = [partTypeStrings.RECALIBRATION, partTypeStrings.ADAS_RECALIBRATION];
|
||||||
|
|
||||||
|
|
@ -73,6 +73,31 @@ export function containsRecalParts(lineItems) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRecalOrder(lineItems) {
|
||||||
|
return (containsRecalParts(lineItems) && getHasRecalibrationPart(lineItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHasRecalibrationPart(lineItems) {
|
||||||
|
const hasRequiresRecalibration = getNonFalseValuesOfPropertyInArrayOfObjects(lineItems.glassParts, 'requiresRecalibration')?.length > 0;
|
||||||
|
const hasRecalibrationType = getNonFalseValuesOfPropertyInArrayOfObjects(lineItems.glassParts, 'recalibrationType')?.length > 0;
|
||||||
|
|
||||||
|
if (hasRequiresRecalibration) {
|
||||||
|
if (hasRecalibrationType) {
|
||||||
|
// Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
|
||||||
|
return (
|
||||||
|
getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||||
|
lineItems.glassParts,
|
||||||
|
'recalibrationType'
|
||||||
|
)[0].toLowerCase() !== 'unknown'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Has 'requiresRecalibration' but no 'recalibrationType' at all
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Does not have 'requiresRecalibration'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export function anyPartWithRequiresRecalFlag(lineItems) {
|
export function anyPartWithRequiresRecalFlag(lineItems) {
|
||||||
if (!lineItems) {
|
if (!lineItems) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,10 @@ import {
|
||||||
ValueToLogTypes
|
ValueToLogTypes
|
||||||
} from '@/constants/analytics';
|
} from '@/constants/analytics';
|
||||||
import { getCartTotal, getSubtotal } from '@/helpers/cart-helper';
|
import { getCartTotal, getSubtotal } from '@/helpers/cart-helper';
|
||||||
import { getRecalPartNumbers } from "@/helpers/recal-helper";
|
import { getRecalPartNumbers, isRecalOrder } from "@/helpers/recal-helper";
|
||||||
import coverageStatuses from '@/constants/coverage-statuses';
|
import coverageStatuses from '@/constants/coverage-statuses';
|
||||||
import coverageType from '@/constants/coverage-type';
|
import coverageType from '@/constants/coverage-type';
|
||||||
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
import issPageValues from '@/router/router-constants/issPage-values';
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
|
|
@ -128,11 +129,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
pushValueToGA() {
|
pushValueToGA() {
|
||||||
const gaSiteType = {
|
|
||||||
['siteType']: useMainStore().issConfig.siteType
|
|
||||||
};
|
|
||||||
this.pushGenericObjectToGA(gaSiteType);
|
|
||||||
|
|
||||||
const gaServiceType = {
|
const gaServiceType = {
|
||||||
['service_type']: useMainStore().order?.serviceLocation?.appointmentType?.toLowerCase()
|
['service_type']: useMainStore().order?.serviceLocation?.appointmentType?.toLowerCase()
|
||||||
};
|
};
|
||||||
|
|
@ -140,6 +136,195 @@ export default {
|
||||||
this.pushGenericObjectToGA(gaServiceType);
|
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;
|
||||||
|
const deviceId = getDeviceIdValue();
|
||||||
|
const sid = getSessionIdValue();
|
||||||
|
|
||||||
|
// Begin assembling payload for data layer
|
||||||
|
const payload = {};
|
||||||
|
|
||||||
|
payload.appName = "ISS";
|
||||||
|
payload.siteType = store.issConfig.siteType;
|
||||||
|
payload.pageName = this.getPageNameByQueryString();
|
||||||
|
payload.deviceId = deviceId;
|
||||||
|
payload.sessionId = sid;
|
||||||
|
payload.clientName = store.issConfig.clientName;
|
||||||
|
payload.lossCause = order.policy?.damageCause ?? "";
|
||||||
|
|
||||||
|
// 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 - always insurance for ISS
|
||||||
|
payload.accountType = "insurance";
|
||||||
|
|
||||||
|
// 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 = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unverified (no price or deductible displayed)
|
||||||
|
if (!store.isVerified) {
|
||||||
|
payload.priceSubTotal = "";
|
||||||
|
payload.priceTotal = "";
|
||||||
|
}
|
||||||
|
// Deductible case (no price is displayed, only deductible)
|
||||||
|
else if (
|
||||||
|
store.isVerified &&
|
||||||
|
(typeof store.currentDeductible === 'number' && store.currentDeductible >= 0) &&
|
||||||
|
!store.isITAC &&
|
||||||
|
!store.isNoComp
|
||||||
|
) {
|
||||||
|
payload.priceSubTotal = "";
|
||||||
|
payload.priceTotal = "";
|
||||||
|
// ITAC or NoComp (where cash price is shown)
|
||||||
|
} else if (store.isVerified && (store.isITAC || store.isNoComp)) {
|
||||||
|
const subtotal = getSubtotal(order).toFixed(2);
|
||||||
|
payload.priceSubTotal = parseFloat(subtotal);
|
||||||
|
const total = getCartTotal(order).toFixed(2);
|
||||||
|
payload.priceTotal = parseFloat(total);
|
||||||
|
} else {
|
||||||
|
payload.priceSubTotal = "";
|
||||||
|
payload.priceTotal = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cash Quote or Cash Price Sub Total
|
||||||
|
payload.cashPriceSubTotal = getSubtotal(order).toString();
|
||||||
|
|
||||||
|
// Recalibration
|
||||||
|
payload.isRecalibrationOnOrder = isRecalOrder(order.lineItems);
|
||||||
|
|
||||||
|
// Appointment Type
|
||||||
|
if (isDefined(order.serviceLocation.appointmentType)) {
|
||||||
|
payload.appointmentType = order.serviceLocation.appointmentType;
|
||||||
|
} else {
|
||||||
|
payload.appointmentType = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
payload.isInsuranceVerified = store.isVerified;
|
||||||
|
payload.insuranceCompanyName = store.issConfig.clientName ?? "";
|
||||||
|
if (!store.isVerified) {
|
||||||
|
payload.isInsuranceItac = "";
|
||||||
|
payload.isInsuranceNoComp = "";
|
||||||
|
} else {
|
||||||
|
payload.isInsuranceItac = store.isITAC ?? "";
|
||||||
|
payload.isInsuranceNoComp = store.isNoComp ?? "";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
store.isITAC ||
|
||||||
|
store.isNoComp ||
|
||||||
|
!store.isVerified
|
||||||
|
) {
|
||||||
|
payload.insuranceDeductible = "";
|
||||||
|
} else {
|
||||||
|
payload.insuranceDeductible = store.currentDeductible ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pushToDataLayerIfDefined(payload);
|
||||||
|
},
|
||||||
|
|
||||||
pushExperimentsToDataLayer() {
|
pushExperimentsToDataLayer() {
|
||||||
const { experiments } = useMainStore().applicationUser;
|
const { experiments } = useMainStore().applicationUser;
|
||||||
|
|
@ -345,7 +530,7 @@ export default {
|
||||||
sessionData.coverageSubStatus = coverageType.mapToApi(order?.insuranceCoverage.coverageType);
|
sessionData.coverageSubStatus = coverageType.mapToApi(order?.insuranceCoverage.coverageType);
|
||||||
|
|
||||||
sessionData.isNoComp = store.isNoComp;
|
sessionData.isNoComp = store.isNoComp;
|
||||||
sessionData.isItac = store.isITAC;
|
sessionData.isItac = store.isITAC;
|
||||||
sessionData.subTotalPrice = getSubtotal(order).toString();
|
sessionData.subTotalPrice = getSubtotal(order).toString();
|
||||||
sessionData.totalPrice = getCartTotal(order).toString();
|
sessionData.totalPrice = getCartTotal(order).toString();
|
||||||
sessionData.cashPriceSubTotal = getSubtotal(order).toString();
|
sessionData.cashPriceSubTotal = getSubtotal(order).toString();
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,9 @@ router.afterEach(async (to, from) => {
|
||||||
|
|
||||||
// Push values to GA
|
// Push values to GA
|
||||||
analyticsMixin.methods.pushValueToGA();
|
analyticsMixin.methods.pushValueToGA();
|
||||||
|
|
||||||
|
// Push current order status to Data Layer
|
||||||
|
analyticsMixin.methods.pushOrderToDataLayer();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,12 @@ import {
|
||||||
repairWaivedForSelectedVehicle
|
repairWaivedForSelectedVehicle
|
||||||
} from '@/helpers/policy-vehicle-helper';
|
} from '@/helpers/policy-vehicle-helper';
|
||||||
import { buildURLSearchParams, getPartNumbersListForQueryString } from '@/helpers/querystring-helper';
|
import { buildURLSearchParams, getPartNumbersListForQueryString } from '@/helpers/querystring-helper';
|
||||||
import { getRecalPartNumbers, getTopLevelGlassPartsWithRecal } from '@/helpers/recal-helper';
|
import { getRecalPartNumbers, getTopLevelGlassPartsWithRecal, getHasRecalibrationPart } from '@/helpers/recal-helper';
|
||||||
import { getDateForSavedSessionTimeout } from '@/helpers/session-helper';
|
import { getDateForSavedSessionTimeout } from '@/helpers/session-helper';
|
||||||
import { isMobileDevice } from '@/helpers/useragent-helper';
|
import { isMobileDevice } from '@/helpers/useragent-helper';
|
||||||
import issPageValues from '@/router/router-constants/issPage-values';
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
import CoverageStatuses from '@/constants/coverage-statuses';
|
import CoverageStatuses from '@/constants/coverage-statuses';
|
||||||
|
import { getNonFalseValuesOfPropertyInArrayOfObjects, sortArrayOfObjectsByPropertyValue } from '@/helpers/object-helper';
|
||||||
|
|
||||||
const storeId = 'main';
|
const storeId = 'main';
|
||||||
|
|
||||||
|
|
@ -276,7 +277,7 @@ export const useMainStore = defineStore({
|
||||||
state: () => state,
|
state: () => state,
|
||||||
getters: {
|
getters: {
|
||||||
billToAccountNumber: (storeState) => storeState.issConfig.billToAccountNumber,
|
billToAccountNumber: (storeState) => storeState.issConfig.billToAccountNumber,
|
||||||
hasRecalibrationPart: (storeState) => getHasRecalibrationPart(storeState),
|
hasRecalibrationPart: (storeState) => getHasRecalibrationPartOnOrder(storeState),
|
||||||
vehicle: (storeState) => storeState.order.vehicle,
|
vehicle: (storeState) => storeState.order.vehicle,
|
||||||
damage: (storeState) => storeState.order.damage,
|
damage: (storeState) => storeState.order.damage,
|
||||||
lineItems: (state) => state.order.lineItems,
|
lineItems: (state) => state.order.lineItems,
|
||||||
|
|
@ -3179,39 +3180,8 @@ export const useMainStore = defineStore({
|
||||||
|
|
||||||
// Private Functions
|
// Private Functions
|
||||||
|
|
||||||
function getHasRecalibrationPart(state) {
|
function getHasRecalibrationPartOnOrder(state) {
|
||||||
const hasRequiresRecalibration = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'requiresRecalibration')?.length > 0;
|
return getHasRecalibrationPart(state.order.lineItems);
|
||||||
const hasRecalibrationType = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'recalibrationType')?.length > 0;
|
|
||||||
|
|
||||||
if (hasRequiresRecalibration) {
|
|
||||||
if (hasRecalibrationType) {
|
|
||||||
// Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
|
|
||||||
return (
|
|
||||||
getNonFalseValuesOfPropertyInArrayOfObjects(
|
|
||||||
state.order.lineItems.glassParts,
|
|
||||||
'recalibrationType'
|
|
||||||
)[0].toLowerCase() !== 'unknown'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Has 'requiresRecalibration' but no 'recalibrationType' at all
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Does not have 'requiresRecalibration'
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
|
||||||
return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
|
||||||
if (!arrayOfObjects) return null;
|
|
||||||
|
|
||||||
return arrayOfObjects.sort((a, b) => {
|
|
||||||
if (a[propertyName] < b[propertyName]) return -1;
|
|
||||||
if (a[propertyName] > b[propertyName]) return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertGlassPieceNamingForApi(glassArray) {
|
function convertGlassPieceNamingForApi(glassArray) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue