diff --git a/src/helpers/recal-helper.js b/src/helpers/recal-helper.js index e72c2d63..c6cce97e 100644 --- a/src/helpers/recal-helper.js +++ b/src/helpers/recal-helper.js @@ -11,7 +11,7 @@ export function isRecalPartOrHasChildRecalPart(glassPart) { const isGlassPartRecalPart = isRecalPart(glassPart); if (!isGlassPartRecalPart && glassPart.childParts && glassPart.childParts.length > 0) { - return glassPart.childParts.filter((cp) => isRecalPartOrHasChildRecalPart(cp)); + return glassPart.childParts.some((cp) => isRecalPartOrHasChildRecalPart(cp)); } return isGlassPartRecalPart; @@ -52,3 +52,24 @@ export function getRecalPartNumbers(glassPartsArray) { } } +export function containsRecalParts(lineItems) { + if (!lineItems) { + return false; + } + + if (Array.isArray(lineItems)) { + return lineItems.some((li) => isRecalPartOrHasChildRecalPart(li)); + } else { + // complex object form -- flatten and re-call. + const flattened = [ + ...(lineItems.glassParts ?? []), + ...(lineItems.supportingItems ?? []), + ...(lineItems.otherParts ?? []), + ...(lineItems.feeItems ?? []), + ...(lineItems.vaps ?? []), + ]; + + return flattened.some((li) => isRecalPartOrHasChildRecalPart(li)); + } +} + diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index a8b77aa5..dcccbed6 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -32,6 +32,12 @@ jest.mock('@/helpers/text-helper', () => ({ formatAmountInDollars: jest.fn() })); +jest.mock('@/helpers/recal-helper.js', () => ({ + containsRecalParts: jest.fn() +})); + +import { containsRecalParts } from '@/helpers/recal-helper.js'; + const SAFELITE_PROVIDER = 'Safelite'; const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal'; @@ -337,15 +343,17 @@ describe('coverageStatement.vue', () => { // Assert expect(result).toBeFalsy(); }); - test('returns true when a part in glassParts require recalibration', () => { + test('returns true when a part in glassParts require recalibration and recalibration has been added to order', () => { // Arrange + containsRecalParts.mockReturnValue(true); const mainInitialState = { order: { lineItems: { glassParts: [ { partNumber: 123, - requiresRecalibration: true + requiresRecalibration: true, + partType: 'RECALIBRATION' }, { partNumber: 111, diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 4cc38651..0e2dadc4 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -147,6 +147,7 @@ import { getPriceOfLineItems } from '@/helpers/price-calculator'; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; import oemEndorsementModal from '@/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue'; +import { containsRecalParts } from '@/helpers/recal-helper'; const RECAL_MODAL_REF_NAME = 'RecalModal'; const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal'; @@ -305,9 +306,11 @@ export default { }, isADAS() { const { glassParts } = useMainStore().order.lineItems; + const orderContainsRecalPart = containsRecalParts(glassParts); return ( glassParts !== null && !!glassParts.find((part) => part.requiresRecalibration) + && orderContainsRecalPart ); }, totalServicePrice() { @@ -410,7 +413,8 @@ export default { } }, async navigateForward() { - if (this.isUnverifiedVisible || this.isDeductibleVisible) { + showIssLoadingModal(true); + if (this.isUnverifiedVisible || this.isDeductibleVisible) { this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD); } else if (this.isITACQuoteVisible || this.isNoCompQuoteVisible) { this.mainStore.updateIsSafeliteProvider(true); diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 32203b5c..aeb58dcb 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -3,7 +3,7 @@ ref="theForm" v-slot="{ meta }" @submit="onSubmit" - @invalidSubmit="onInvalidSubmit"> + @invalidSubmit="customInvalidSubmit">
@@ -251,12 +251,15 @@ export default { if (vinLookupResponse.error) { this.displayVinNotFoundAlert = true; this.previouslyEnteredCarId = null; + this.pushEventToGA("VehicleDamage", "LicensePlate_NoMatch", "Trouble_Finding", true, null, '0'); showIssLoadingModal(false); return this.$refs.siteFooter.disableForwardButton(); } // Vehicle found from VIN lookup const vehicleFromLookup = vinLookupResponse.data.vehicle; + const vehicleString = vehicleFromLookup.year + '_' + vehicleFromLookup.make + '_' + vehicleFromLookup.model + '_' + vehicleFromLookup.style; + this.pushEventToGA("VehicleDamage", "LicensePlate_Vin_Match", vehicleString, true, null, '1'); if (!vehicleFromLookup.canSafeliteService) { this.mainStore.setBailout({ type: 'HeavyTruckVehicle', @@ -321,6 +324,12 @@ export default { resetWarningsAndErrors() { this.displayVinNotFoundAlert = false; this.displayMatchedDifferentVehicleAlert = false; + }, + customInvalidSubmit({ errors }) { + if (errors['license-plate-question']) { + this.pushEventToGA("VehicleDamage", "LicensePlate_NoMatch", "Plate_Required", true, null, '0'); + } + this.onInvalidSubmit({ errors }); } } }; diff --git a/src/layouts/service-packages/service-package-question/service-package-question.vue b/src/layouts/service-packages/service-package-question/service-package-question.vue index 73e29932..63bac64f 100644 --- a/src/layouts/service-packages/service-package-question/service-package-question.vue +++ b/src/layouts/service-packages/service-package-question/service-package-question.vue @@ -23,6 +23,7 @@ import partTypeStrings from '@/constants/part-type-strings'; import { useMainStore } from '@/store'; import { getPriceOfLineItem } from '@/helpers/price-calculator'; import { shallowRef } from 'vue'; +import { containsRecalParts } from '@/helpers/recal-helper'; const glassLocations = damageLocationsSelected; @@ -100,7 +101,7 @@ export default { return modifiedAnswers; }, isRecalibrationOnOrder() { - return this.mainStore.hasRecalibrationPart; + return this.mainStore.hasRecalibrationPart && containsRecalParts(this.mainStore.order.lineItems); }, frontWipersApplicableForTierTwo() { const frontWipersAreAvailable = this.lineItemsContainsPartType(partTypeStrings.FRONT_WIPER); diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js index 8bc26edb..e4911f36 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.spec.js +++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js @@ -41,7 +41,8 @@ const mountOptions = { methods: { getCmsContent: jest.fn(), getFooterInfoBoxHeight: jest.fn(() => 80), - getPageNameByQueryString: jest.fn(() => '') + getPageNameByQueryString: jest.fn(() => ''), + pushEventToGA: jest.fn() } } ], diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 47f7463d..9833cdcd 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -412,6 +412,8 @@ export default { this.selectedWindshieldOptions.selectedWindshieldChipCount ); + this.logEvents(); + if (this.isWindshieldRepair) { const results = await Promise.allSettled([useMainStore().getSupportingItems(), useMainStore().getRecalParts()]); const supportingItems = results[0].value; @@ -481,6 +483,76 @@ export default { } return selectedGlassToReplace; + }, + logEvents() { + const vehicleString = this.mainStore.order.vehicle.make + '_' + this.mainStore.order.vehicle.model + '_' + this.mainStore.order.vehicle.style; + this.pushEventToGA("CAR SUBMISSION", this.mainStore.order.vehicle.year?.toString(), vehicleString, true, null, 0); + + if (this.isWindshieldRepair) { + this.pushEventToGA("damage", "selected", "repair", true, null, null); + this.pushEventToGA("VehicleDamage", "Repair", this.mainStore.damage.numberOfChips?.toString(), true, null, this.mainStore.damage.numberOfChips); + } else { + this.pushEventToGA("damage", "selected", "replace", true, null, null); + this.selectedGlassToReplace().forEach((glass) => { + this.logEventForPart(glass); + }); + } + }, + logEventForPart(glass) { + let eventGlassLocation = ''; + let eventGlassName = ''; + switch (glass.glassLocation) { + case damageLocationsSelected.WINDSHIELD: + eventGlassLocation = 'Windshield Replace'; + break; + case damageLocationsSelected.DRIVER: + eventGlassLocation = "Driver's Side"; + break; + case damageLocationsSelected.PASSENGER: + eventGlassLocation = "Passenger's Side"; + break; + case damageLocationsSelected.REAR: + eventGlassLocation = 'Back Glass'; + break; + default: + eventGlassLocation = glass.glassLocation; + } + + switch (glass.glassName) { + // Windshield options + case damageLocationsSelected.DRIVER: + eventGlassName = "Left piece"; + break; + case damageLocationsSelected.PASSENGER: + eventGlassName = "Right piece"; + break; + // Bottom two cases here are for rear options, but they are handled the same as single windshield + case damageLocationsSelected.SINGLE: + case damageLocationsSelected.STATIONARY: + case damageLocationsSelected.SLIDER: + eventGlassName = ''; + break; + // Side door options + case damageLocationsSelected.FRONT: + eventGlassName = "Front door"; + break; + case damageLocationsSelected.BACK: + eventGlassName = "Rear door"; + break; + case damageLocationsSelected.QUARTER: + eventGlassName = "Quarter"; + break; + case damageLocationsSelected.VENT: + eventGlassName = "Vent"; + break; + case damageLocationsSelected.SIDEDOOR: + eventGlassName = "Sliding door"; + break; + default: + eventGlassName = glass.glassName; + } + const label = eventGlassName ? `${eventGlassLocation} - ${eventGlassName}` : eventGlassLocation; + this.pushEventToGA("VehicleDamage", "Replacement", label, true, null, 1); } } }; diff --git a/src/layouts/vin-lookup/vin-location-information/vin-location-information.vue b/src/layouts/vin-lookup/vin-location-information/vin-location-information.vue index 7bc12729..b462e860 100644 --- a/src/layouts/vin-lookup/vin-location-information/vin-location-information.vue +++ b/src/layouts/vin-lookup/vin-location-information/vin-location-information.vue @@ -38,6 +38,7 @@ export default { isVinLocationDetailVisible: false }; }, + emits: ['vin-location-detail-shown'], computed: { textForToggle() { return this.getCmsContent('WhereCanIFindMyVINToggle', 'HeaderText'); @@ -52,6 +53,9 @@ export default { methods: { handleClickToggle() { this.isVinLocationDetailVisible = !this.isVinLocationDetailVisible; + if (this.isVinLocationDetailVisible) { + this.$emit('vin-location-detail-shown'); + } } } }; diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index a2efafc8..af598359 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -16,11 +16,12 @@ class="mt-4" /> - +