From 29f727a342f1619c02182e26165e1a5c69cf9fb8 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 24 Mar 2026 15:18:24 -0400 Subject: [PATCH 01/22] recalAckModal WIP --- src/helpers/recal-helper.js | 28 +++++++ src/layouts/schedule-page/schedule-page.vue | 41 +++++++++- src/store/index.js | 84 ++++++++++++++++----- 3 files changed, 131 insertions(+), 22 deletions(-) diff --git a/src/helpers/recal-helper.js b/src/helpers/recal-helper.js index e72c2d63..8387dbc8 100644 --- a/src/helpers/recal-helper.js +++ b/src/helpers/recal-helper.js @@ -52,3 +52,31 @@ 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.vaps ?? []), + ...(lineItems.promos ?? []), + ]; + + return flattened.some((li) => isRecalPartOrHasChildRecalPart(li)); + } +} + +export function anyPartWithRequiresRecalFlag(lineItems) { + if (!lineItems) { + return false; + } + + return lineItems.glassParts?.some((li) => li.requiresRecalibration === true); +} + diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index b4a68eb0..3e33861d 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -46,6 +46,19 @@ :customSelectableDatesCallback="getAvailableDatesMethod" @dateSelected="dateSelectedFromPicker" @timeSlotSelected="timeSlotSelectedFromPicker" /> + +
+ {{ recalModalContent.subHeaderText }} +
+
+
- + --> + \ No newline at end of file diff --git a/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue b/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue index 59880d1c..238de834 100644 --- a/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue +++ b/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue @@ -1,5 +1,5 @@ @@ -374,6 +376,71 @@ export default { setupModalLinks(this); }, methods: { + logEventsToGA() { + const clientName = this.mainStore.accountNameForEvents; + + if (this.isDeductibleVisible || this.isITACQuoteVisible) { + this.pushEventToGA('coverage', 'Yes', clientName, true, null, '1'); + if (this.isITACQuoteVisible) { + this.pushEventToGA('Coverage', 'ITAC', `${this.deductibleValue}_${this.totalServicePrice}`, true); + } + else { + this.pushEventToGA('coverage', 'full_comprehensive', clientName, true); + this.pushEventToGA('coverage', 'deductible', this.deductibleValue.toString(), true); + } + } + else { + this.pushEventToGA('coverage', 'No', clientName, true, null, '0'); + if (this.isNoCompQuoteVisible) { + this.pushEventToGA('coverage', 'no_comprehensive', `${this.totalServicePrice}`, true); + this.pushEventToGA('coverage', 'deductible', '9999', true); + } + else { + this.pushEventToGA('coverage', 'deductible', '7777', true); + } + } + + if (this.mainStore.hasOemEndorsement) { + this.pushEventToGA('oem_endorsement', 'displayed', 'Yes', true, null, '1'); + } + else { + this.pushEventToGA('oem_endorsement', 'displayed', 'No', true, null, '0'); + } + + if (this.isADAS) { + if (this.mainStore.vehicle.canSafeliteService) { + this.pushEventToGA('ADAS_self_service', 'ADAS_servicable_status', 'yes', true); + if (this.mainStore.hasRecalibrationPart) { + if (this.isDeductibleVisible) { + const recalibrationType = this.mainStore.lineItems.glassParts.find((part) => part.requiresRecalibration).recalibrationType; + if (this.deductibleValue <= 0) { + this.pushEventToGA('recalibration_opportunity_verified_0_deductible', this.mainStore.vehicle.carId, `recal_type_${recalibrationType}`, true); + } + else { + this.pushEventToGA('recalibration_opportunity_verified_over_0_deductible', this.mainStore.vehicle.carId, `recal_type_${recalibrationType}`, true); + } + } + else { + let appointmentType = ''; + if (this.isITACQuoteVisible) { + appointmentType = 'ITAC'; + } + else if (this.isNoCompQuoteVisible) { + appointmentType = 'no_comp'; + } + else { + appointmentType = 'unverified'; + } + this.pushEventToGA(`recalibration_opportunity_${appointmentType}`, this.mainStore.vehicle.carId, `recal_type_${this.mainStore.lineItems.glassParts.find((part) => part.requiresRecalibration).recalibrationType}`, true); + } + } + } + else { + this.pushEventToGA('ADAS_self_service', 'ADAS_servicable_status', 'no', true); + } + } + }, + arePagePrerequisitesValid() { return !!useMainStore().vehicle.carId; }, @@ -393,6 +460,8 @@ export default { } } + this.logEventsToGA(); + showIssLoadingModal(false); this.isPageLoading = false; }, @@ -410,8 +479,13 @@ export default { } }, async navigateForward() { - showIssLoadingModal(true); - if (this.isUnverifiedVisible || this.isDeductibleVisible) { + if (this.isUnverifiedVisible || this.isDeductibleVisible) { + if (this.isRepair) { + this.pushEventToGA('RepairDamage', 'Repair', this.mainStore.damage.numberOfChips.toString(), true, null, '1'); + } + else { + this.pushEventToGA('RepairDamage', 'Replacement', 'Replacement', true, null, '1'); + } this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD); } else if (this.isITACQuoteVisible || this.isNoCompQuoteVisible) { this.mainStore.updateIsSafeliteProvider(true); @@ -475,7 +549,13 @@ export default { cancelClaim() { this.mainStore.updateIsSafeliteProvider(false); this.$router.navigateBailout(bailoutMessage.CoverageCancelledByUser()); - } + }, + handleRecalModalOpened() { + this.pushEventToGA('recalibration_modal', 'learn_more_clicked', this.mainStore.vehicle.carId, true); + }, + handleOemEndorsementModalOpened() { + this.pushEventToGA('oem_endorsement_modal', 'clicked', 'Yes', true, null, '1'); + }, } }; diff --git a/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue b/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue index 85ee726b..6daff222 100644 --- a/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue +++ b/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue @@ -26,6 +26,7 @@ export default { default: 'OEMEndorsementModal' } }, + emits: ['oem-endorsement-modal-opened'], computed: { modalBodyText() { return this.getCmsContent(this.cmsWidgetName, 'BodyText'); @@ -40,6 +41,7 @@ export default { methods: { openModal() { this.$refs.oemEndorsementModal.openModal(); + this.$emit('oem-endorsement-modal-opened'); }, footerButtonClick() { this.$refs.oemEndorsementModal.closeModal(); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index d533f276..21ce4fc7 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -193,7 +193,7 @@ export default { appointmentType: serviceLocation.appointmentType, providerAddress: serviceLocation?.provider?.address, customerPortalLoginToken, - carrierName: issConfig.clientName, + carrierName: issConfig.clientDisplayName, carrierUrl: issConfig.successReturnURL, isRepair: damage.isRepair, hasRecalibrationPart, diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index cfe48753..74bf65c1 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -96,6 +96,8 @@ export default { const currentPageName = this.getPageNameByQueryString(); const labelToLog = getValueToLog(label, valueToLogType); + console.log(`Pushing event to GA: category=${category}, action=${action}, label=${labelToLog}, value=${value}, page=${currentPageName}`); + const eventToBePushed = { event: GaEvents.GENERIC_EVENT, category, From 7a3068580da8eb7e7bd7823972253854c137ca13 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Fri, 3 Apr 2026 11:05:07 -0400 Subject: [PATCH 19/22] INSR-8881: Remove console.log, restore loading modal change --- src/layouts/coverage-statement/coverage-statement.vue | 1 + src/mixins/analytics-mixin.js | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index d70dca87..c6ceeb04 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -479,6 +479,7 @@ export default { } }, async navigateForward() { + showIssLoadingModal(true); if (this.isUnverifiedVisible || this.isDeductibleVisible) { if (this.isRepair) { this.pushEventToGA('RepairDamage', 'Repair', this.mainStore.damage.numberOfChips.toString(), true, null, '1'); diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 74bf65c1..cfe48753 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -96,8 +96,6 @@ export default { const currentPageName = this.getPageNameByQueryString(); const labelToLog = getValueToLog(label, valueToLogType); - console.log(`Pushing event to GA: category=${category}, action=${action}, label=${labelToLog}, value=${value}, page=${currentPageName}`); - const eventToBePushed = { event: GaEvents.GENERIC_EVENT, category, From 19bf2d0faf98dc6025fe64ecc7e11a77dd2d114f Mon Sep 17 00:00:00 2001 From: katiekroell <100247286+katiekroell@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:23:21 -0400 Subject: [PATCH 20/22] Update src/helpers/recal-helper.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/helpers/recal-helper.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/helpers/recal-helper.js b/src/helpers/recal-helper.js index 5ad9c390..f364bf68 100644 --- a/src/helpers/recal-helper.js +++ b/src/helpers/recal-helper.js @@ -78,5 +78,17 @@ export function anyPartWithRequiresRecalFlag(lineItems) { return false; } - return lineItems.some((li) => li.requiresRecalibration === true); + if (Array.isArray(lineItems)) { + return lineItems.some((li) => li.requiresRecalibration === true); + } + + const flattened = [ + ...(lineItems.glassParts ?? []), + ...(lineItems.supportingItems ?? []), + ...(lineItems.otherParts ?? []), + ...(lineItems.feeItems ?? []), + ...(lineItems.vaps ?? []), + ]; + + return flattened.some((li) => li.requiresRecalibration === true); } From abf8b13a997ea8397ab9a789d49a7d2a40d2f8ce Mon Sep 17 00:00:00 2001 From: scottkiener-at-safelite Date: Fri, 3 Apr 2026 13:23:28 -0400 Subject: [PATCH 21/22] Fix pipeline error --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9f677925..8c04697c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -342,6 +342,7 @@ stages: - template: templates/digital/auto-tag.yml@AzureDevOps parameters: dependsOn: prodBuildDeployment + environment: digitalCloud-prod userName: SafeliteAzureDevops userEmail: githubazuredevops@safelite.com From 116ca1192dc948c09172810a937a130fda046ae1 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Fri, 3 Apr 2026 14:53:23 -0400 Subject: [PATCH 22/22] refactor --- src/layouts/schedule-page/schedule-page.vue | 4 ++-- src/store/index.js | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 257995c1..904329f3 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -467,7 +467,7 @@ export default { this.mql = window.matchMedia('(min-width: 1200px)'); this.isMobileView = !this.mql.matches; this.mql.addEventListener('change', this.handleMqlChange); - this.mainStore.updateIsRecalAcknowledgedForScheduling(false); + this.mainStore.order.isRecalAcknowledgedForScheduling = false; this.isRecalAcknowledged = false; }, unmounted() { @@ -985,7 +985,7 @@ export default { }, updateIsRecalAcknowledged(isAcknowledged) { this.isRecalAcknowledged = isAcknowledged; - this.mainStore.saveIsRecalAcknowledgedForScheduling(this.isRecalAcknowledged); + this.mainStore.order.isRecalAcknowledgedForScheduling = isAcknowledged; }, getIsRecalAcknowledgedForScheduling() { return this.mainStore.order.isRecalAcknowledgedForScheduling; diff --git a/src/store/index.js b/src/store/index.js index c1f79f0d..06c0b505 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3160,13 +3160,6 @@ export const useMainStore = defineStore({ // clear from sessionStorage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); }, - - saveIsRecalAcknowledgedForScheduling(isRecalAcknowledged) { - this.updateIsRecalAcknowledgedForScheduling(isRecalAcknowledged); - }, - updateIsRecalAcknowledgedForScheduling(isRecalAcknowledged) { - this.order.isRecalAcknowledgedForScheduling = isRecalAcknowledged; - } }, persist: { // Default is localStorage, but sessionStorage is used here to ensure state is cleared when the browser tab is closed, preventing potential issues with stale data on return visits.