From eabc10454ca0e5142f608e761e88c6faaaff187c Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Wed, 10 Jun 2026 14:57:52 -0400 Subject: [PATCH 01/15] Added initial code to display a build version string on the index.html page. --- public/index.html | 3 ++- vue.config.js | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/public/index.html b/public/index.html index 5e2434b9..bd345695 100644 --- a/public/index.html +++ b/public/index.html @@ -46,6 +46,7 @@
+ + - \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index d9d97c60..07ff90bd 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,3 +1,30 @@ +const { execSync } = require('child_process'); +const pkg = require('./package.json'); + +function safeExec(cmd, fallback = 'unknown') { + try { + return execSync(cmd).toString().trim(); + } catch { + return fallback; + } +} + +const buildTime = new Date().toISOString(); +const buildTimeStamp = Math.floor(Date.now() / 1000); + +const gitInfo = { + commit: safeExec('git rev-parse --short HEAD', 'dev'), + branch: safeExec('git rev-parse --abbrev-ref HEAD', 'unknown') +}; + +const buildInfo = { + version: pkg.version, + buildTime: buildTime, + buildTimeStamp: buildTimeStamp, + ...gitInfo, + versionString: `${pkg.version}-${gitInfo.branch}-${gitInfo.commit}-${buildTimeStamp}` +}; + process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/'; @@ -32,7 +59,12 @@ module.exports = { } } }, - configureWebpack: { - devtool: 'source-map' + configureWebpack: { + devtool: 'source-map', + plugins: [ + new (require('webpack')).DefinePlugin({ + __BUILD_INFO__: JSON.stringify(buildInfo) + }) + ] } -}; +}; \ No newline at end of file From cf693023d76ba0e62044aec4c76d80e6a09b017f Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 10 Jun 2026 16:47:56 -0400 Subject: [PATCH 02/15] INSR-9940: Improve logic for showing/hiding MSR related copy Includes text on contact-details page and showing/hiding the relevant line item in the cart. Also includes some fixes to clear some warning related to the cart dropdown component. --- src/constants/experiments.js | 3 +- .../cart-dropdown/cart-dropdown.vue | 39 ++++++++++++++++++- .../contact-details/contact-details.vue | 6 ++- .../order-confirmation/order-confirmation.vue | 2 - src/layouts/payment-method/payment-method.vue | 2 - .../payment-page-adyen/payment-page-adyen.vue | 4 +- src/layouts/payment-page/payment-page.vue | 4 +- src/store/index.js | 6 ++- 8 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 1c0edd15..41a51f84 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -16,7 +16,8 @@ const experimentSettings = Object.freeze({ ISS_MOBILE_FIRST_MAX_MOBILE_DAYS: 'MaxMobileDays', ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS: 'MaxPmMobileDays', ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT: 'ShowMobileFirstAppointment', - ISS_ENABLE_ADYEN_V1: 'ISS_Enable_Adyen_V1' + ISS_ENABLE_ADYEN_V1: 'ISS_Enable_Adyen_V1', + MSR_SPLIT_PAY_ENABLED: 'EnableMSRSplitPay' }); const experimentTest = Object.freeze({ diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 19a7fe71..e7e4d923 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -146,6 +146,7 @@ import { } from '@/helpers/cart-helper'; import { getPriceOfLineItem, getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator'; import { processIfStatements } from '@/helpers/cms-content-helper'; +import partNumberStrings from '@/constants/part-number-strings'; const VERIFYING_COVERAGE = 'Verifying coverage'; const ADVANCED_MOBILE_MODAL_REF_NAME = 'advancedMobileModal'; @@ -229,7 +230,8 @@ export default { servicePrice() { const price = getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0; const recycleFee = this.recycleFeeLineItem ? getPriceOfLineItem(this.recycleFeeLineItem) : 0; - return price - this.recalibrationPrice - recycleFee; + const mobileFee = this.mobileFeeCartItem ? this.mobileFeeCartItem.subTotal : 0; + return price - this.recalibrationPrice - recycleFee - mobileFee; }, isUnverified() { return isOrderUnverified(this.cartOrder); @@ -242,6 +244,7 @@ export default { }, // TODO fix rounding subTotal() { + const subtotal = getSubtotal(this.cartOrder); return getSubtotal(this.cartOrder); }, salesTax() { @@ -291,7 +294,7 @@ export default { } }); items.push(...vapsCartItems.filter((item) => item != null)); - if (this.mobileFeeCartItem && !isMobileFeeHidden && !this.mobileFeeCartItem.isInsurable) { + if (this.includeMobileFeeInCart) { items.push(this.mobileFeeCartItem); } return items; @@ -380,6 +383,38 @@ export default { return { feeAmount: this.mobileFeeCartItem ? formatAmountInDollars(this.mobileFeeCartItem.subTotal) : '' } + }, + hasMSRPart() { + return this.cartOrder.lineItems?.feeItems?.some((item) => item.partNumber === partNumberStrings.RECAL_MOBILEDUAL || item.partNumber === partNumberStrings.RECAL_MOBILE) ?? false; + }, + includeMobileFeeInCart() { + if (!this.mobileFeeCartItem || this.mobileFeeCartItem.subTotal === 0) { + return false; + } + + const isMobileFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true'; + if (isMobileFeeHidden) { + return false; + } + + if (this.isITAC || this.isNoComp) { + return true; + } + + if (!this.hasMSRPart) { + return false; + } + + const isSplitPayEnabled = this.getSettingValue(experimentSettings.MSR_SPLIT_PAY_ENABLED) === 'true'; + if (!isSplitPayEnabled) { + return false; + } + + if (!this.mobileFeeCartItem.isInsurable) { + return true; + } + + return false; } }, methods: { diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue index 2af0960d..778c1daf 100644 --- a/src/layouts/contact-details/contact-details.vue +++ b/src/layouts/contact-details/contact-details.vue @@ -17,12 +17,11 @@ ref="siteSubHeader" class="subheader" :cmsWidgetName="widget.siteSubHeader" /> - + :cmsWidgetName="appointmentInformationWidget" /> diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 31b09b27..1f68e584 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -33,8 +33,6 @@ + :showAsPaid="false" /> diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index d116b502..9f936bb8 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -45,9 +45,7 @@ ref="cart" class="cart-dropdown-component" :readOnly="true" - :showAsPaid="false" - recyclingModalCmsWidgetName="RecycleModal" - servicePackageTitleWidgetName="ServicePackageTitle" /> + :showAsPaid="false" />
Object.assign(r, c), {}) ?? {}, originalDeductible: (state) => (state.order.damage.isRepair ? state.order.originalDeductible.repair : state.order.originalDeductible.replace), currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace), - accountNameForEvents: (state) => state.issConfig.clientName + accountNameForEvents: (state) => state.issConfig.clientName, + hasMSRPart: (state) => state.order.lineItems?.feeItems?.some((item) => item.partNumber === partNumberStrings.RECAL_MOBILEDUAL || item.partNumber === partNumberStrings.RECAL_MOBILE) ?? false }, actions: { @@ -572,7 +573,8 @@ export const useMainStore = defineStore({ policyNumber: policy.policyNumber, dateOfLoss: policy.dateOfLoss, zipCode: policy.policyZipCode, - referralCorrelationId: order.referralCorrelationId + referralCorrelationId: order.referralCorrelationId, + referralNumber: order.referralNumber }, bailoutOnError: false }); From eeff370d425da48649ae8de5c18a95e597b1761e Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 10 Jun 2026 16:55:05 -0400 Subject: [PATCH 03/15] INSR-9940: Remove unused variables --- src/iss-components/cart-dropdown/cart-dropdown.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index e7e4d923..f4b28f53 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -244,7 +244,6 @@ export default { }, // TODO fix rounding subTotal() { - const subtotal = getSubtotal(this.cartOrder); return getSubtotal(this.cartOrder); }, salesTax() { @@ -273,7 +272,6 @@ export default { cartItems() { const items = []; const isRecycleFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true'; - const isMobileFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true'; if (this.isITAC || this.isNoComp) { items.push(this.warrantyCartItem); } From 19b870dc7ce751281f3b9761589522cf0605e52c Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 11 Jun 2026 09:25:46 -0400 Subject: [PATCH 04/15] INSR-9940: Add/fix tests for cart-dropdown --- .../cart-dropdown/cart-dropdown.spec.js | 160 +++++++++++++++++- .../cart-dropdown/cart-dropdown.vue | 4 - 2 files changed, 156 insertions(+), 8 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.spec.js b/src/iss-components/cart-dropdown/cart-dropdown.spec.js index 16692604..1efd6907 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.spec.js +++ b/src/iss-components/cart-dropdown/cart-dropdown.spec.js @@ -13,6 +13,7 @@ import { getPriceOfLineItems } from '@/helpers/price-calculator.js'; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; import * as cartHelper from '@/helpers/cart-helper'; +import { experimentSettings } from '@/constants/experiments'; const VERIFYING_COVERAGE = 'Verifying coverage'; @@ -30,7 +31,7 @@ jest.mock('@/helpers/service-package-helper', () => ({ getPackageContents: jest.fn() })); -function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}) { +function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}, experimentMockFunction = jest.fn(() => 'false')) { const mountOptions = getMountOptions({ router: { navigate: jest.fn() @@ -44,7 +45,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, propsData }); useMainStore(testingPinia); - mountOptions.global.mixins[0].methods.getSettingValue = jest.fn(() => 'false'); + mountOptions.global.mixins[0].methods.getSettingValue = experimentMockFunction; mountOptions.global.plugins = [testingPinia]; mountOptions.data = () => (initialData); mountOptions.propsData = propsData; @@ -804,12 +805,16 @@ describe('cart-dropdown component', () => { partType: partTypeStrings.REPLACE_FEE })); }); - test('when mobileFee, includes mobile fee', () => { + test('when mobile fee should be included, includes mobile fee', () => { // Arrange const storeData = { order: { lineItems: { - feeItems: [{ partType: partTypeStrings.MOBILE_FEE }] + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, sellingPrice: 123}] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.NO_COMP } } }; @@ -977,6 +982,153 @@ describe('cart-dropdown component', () => { expect(result.name).toBe(expectedName); }); }); + describe('includeMobileFeeInCart', () => { + test('returns false with no mobile fee', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [] + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(false); + }); + + test('returns false with a mobile fee with no price', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 0 }] + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(false); + }); + + test('returns true for priced mobile fee for No Comp', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 100 }] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.NO_COMP + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(true); + }); + + test('returns true for priced mobile fee for ITAC', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 100 }] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.ITAC + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(true); + }); + + test('returns false for priced mobile fee for Deductible without Split Pay', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 100 }] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.Deductible + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(false); + }); + + test('returns false for priced mobile fee for Deductible with Split Pay and isInsurable=true', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 100, isInsurable: true }] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.Deductible + } + } + }; + const { wrapper } = getMountedComponent(storeData, {}, {}, (settingName) => (settingName === experimentSettings.MSR_SPLIT_PAY_ENABLED).toString()); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(false); + }); + + test('returns true for priced mobile fee for Deductible with Split Pay and isInsurable=false', () => { + // Arrange + const storeData = { + order: { + lineItems: { + feeItems: [{ partType: partTypeStrings.MOBILE_FEE, price: 100, isInsurable: false }] + }, + insuranceCoverage: { + coverageStatus: coverageStatuses.VERIFIED, + coverageType: coverageType.Deductible + } + } + }; + const { wrapper } = getMountedComponent(storeData, {}, {}, (settingName) => (settingName === experimentSettings.MSR_SPLIT_PAY_ENABLED).toString()); + + // Act + const result = wrapper.vm.includeMobileFeeInCart; + + // Assert + expect(result).toBe(true); + }); + }); }); describe('method', () => { const dollarAmount = '$84.00'; diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index f4b28f53..2cd0fb94 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -399,10 +399,6 @@ export default { return true; } - if (!this.hasMSRPart) { - return false; - } - const isSplitPayEnabled = this.getSettingValue(experimentSettings.MSR_SPLIT_PAY_ENABLED) === 'true'; if (!isSplitPayEnabled) { return false; From cb811c804c698701dd584760a5a4fcdf7928b822 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 11 Jun 2026 11:09:49 -0400 Subject: [PATCH 05/15] Updates to build info. --- package.json | 2 +- public/index.html | 4 ++-- vue.config.js | 52 +++++++++++++++++++++++++---------------------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 04a0f3a4..2d57cec7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digitalconsumer.iss", - "version": "0.1.0", + "version": "1.1.0", "private": true, "eslintConfig": { "env": { diff --git a/public/index.html b/public/index.html index bd345695..6fe17575 100644 --- a/public/index.html +++ b/public/index.html @@ -46,7 +46,7 @@
- - + + \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index 07ff90bd..bd31d343 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,30 +1,6 @@ const { execSync } = require('child_process'); const pkg = require('./package.json'); -function safeExec(cmd, fallback = 'unknown') { - try { - return execSync(cmd).toString().trim(); - } catch { - return fallback; - } -} - -const buildTime = new Date().toISOString(); -const buildTimeStamp = Math.floor(Date.now() / 1000); - -const gitInfo = { - commit: safeExec('git rev-parse --short HEAD', 'dev'), - branch: safeExec('git rev-parse --abbrev-ref HEAD', 'unknown') -}; - -const buildInfo = { - version: pkg.version, - buildTime: buildTime, - buildTimeStamp: buildTimeStamp, - ...gitInfo, - versionString: `${pkg.version}-${gitInfo.branch}-${gitInfo.commit}-${buildTimeStamp}` -}; - process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/'; @@ -42,6 +18,34 @@ process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC = process.env.VUE_APP_GOOGLE_MAPS_API_SCRIPT = "(g=>{var h,a,k,p='The Google Maps JavaScript API',c='google',l='importLibrary',q='__ib__',m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement('script'));e.set('libraries',[...r]+'');for(k in g)e.set(k.replace(/[A-Z]/g,t=>'_'+t[0].toLowerCase()),g[k]);e.set('callback',c+'.maps.'+q);a.src=`https://maps.googleapis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+' could not load.'));a.nonce=m.querySelector('script[nonce]')?.nonce||'';m.head.append(a)}));d[l]?console.warn(p+' only loads once. Ignoring:',g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({key: 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0', v: 'weekly'});"; +function safeExec(cmd, fallback = 'unknown') { + try { + return execSync(cmd).toString().trim(); + } catch { + return fallback; + } +} + +const gitInfo = { + commit: safeExec('git rev-parse --short HEAD', 'dev'), + branch: safeExec('git rev-parse --abbrev-ref HEAD', 'unknown') +}; + +const buildTimes = { + buildTime: new Date().toISOString(), + buildTimeLocal: new Date().toLocaleString(), + buildTimeStamp: Math.floor(Date.now() / 1000) +} + +const buildInfo = { + version: pkg.version, + buildTime: buildTimes.buildTime, + buildTimeLocal: buildTimes.buildTimeLocal, + buildTimeStamp: buildTimes.buildTimeStamp, + ...gitInfo, + versionString: `${pkg.version}-${gitInfo.commit}-${buildTimes.buildTimeStamp}-${gitInfo.branch}` +}; + module.exports = { publicPath: '/', css: { From b1b1bdfad37ea55aa3179b60dac24b5a9e8f667c Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 11 Jun 2026 11:26:45 -0400 Subject: [PATCH 06/15] INSR-9835: Only offer wipers on payment-method if available --- src/layouts/payment-method/payment-method.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 31b09b27..792592a9 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -303,7 +303,9 @@ export default { return MaskaFormattedMasks.PHONE_NUMBER; }, offerWipers() { - return !this.mainStore.lineItems.vaps?.some((part) => part.partType.toLowerCase().includes('wiper')); + const orderHasWipers = this.mainStore.lineItems.vaps?.some((part) => part.partType.toLowerCase().includes('wiper')); + const wipersAvailable = this.mainStore.availableVaps?.some((part) => part.partType.toLowerCase().includes('wiper')); + return !orderHasWipers && wipersAvailable; }, wiperOfferPanel() { const wiperImage = this.getCmsContent(this.widget.wiperOffer, widgetFields.CONTENT_GROUP_WIDGET.IMAGE); From 6fe9213486aed01872c83cfaf5c8130c8450cc99 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 11 Jun 2026 11:33:45 -0400 Subject: [PATCH 07/15] INSR-9835: Get availableVaps from the right place --- src/layouts/payment-method/payment-method.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 792592a9..b98c7ded 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -304,7 +304,7 @@ export default { }, offerWipers() { const orderHasWipers = this.mainStore.lineItems.vaps?.some((part) => part.partType.toLowerCase().includes('wiper')); - const wipersAvailable = this.mainStore.availableVaps?.some((part) => part.partType.toLowerCase().includes('wiper')); + const wipersAvailable = this.mainStore.order.availableVaps?.some((part) => part.partType.toLowerCase().includes('wiper')); return !orderHasWipers && wipersAvailable; }, wiperOfferPanel() { From cb76253882273161bb783f1f73c3026bb08dca99 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 11 Jun 2026 11:50:11 -0400 Subject: [PATCH 08/15] Updates for build info. Added it to the error logger. --- src/helpers/logger.js | 2 ++ src/store/index.js | 3 +++ vue.config.js | 3 +++ 3 files changed, 8 insertions(+) diff --git a/src/helpers/logger.js b/src/helpers/logger.js index e583f7c1..b07013f9 100644 --- a/src/helpers/logger.js +++ b/src/helpers/logger.js @@ -51,6 +51,8 @@ export class Logger { return [ `Application: ${applicationConfig.APPLICATION_NAME}`, + `Build Version: ${store.issConfig?.buildInfo?.versionString}`, + `Build Time: ${store.issConfig?.buildInfo?.buildTimeLocal}`, `ClientTag: ${store.issConfig?.clientTag}`, `ParentAccountNumber: ${store.issConfig?.parentAccountNumber}`, `ClientName: ${store.issConfig?.clientName}`, diff --git a/src/store/index.js b/src/store/index.js index 0dbf8c29..5be85c4b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -269,6 +269,7 @@ export const getDefaultState = () => ({ policyZipCode: null, dateOfLoss: null }, + buildInfo: (typeof __BUILD_INFO__ !== 'undefined') ? __BUILD_INFO__ : null, // Contains the build info for the website, set during the build process. Version, Time, Git info etc.... siteType: null, // SiteType / SubType the site is set to (Essential/Advanced). enableNoCompQuote: false } @@ -2258,6 +2259,8 @@ export const useMainStore = defineStore({ this.issConfig.siteType = null; this.issConfig.enableNoCompQuote = false; this.issConfig.billToAccountNumber = null; + + // NOTE: Do not wipe out build info. }, disableKeyFields() { diff --git a/vue.config.js b/vue.config.js index bd31d343..41fd8c5d 100644 --- a/vue.config.js +++ b/vue.config.js @@ -46,6 +46,9 @@ const buildInfo = { versionString: `${pkg.version}-${gitInfo.commit}-${buildTimes.buildTimeStamp}-${gitInfo.branch}` }; +// This will be replaced by the actual build info during the build process via webpack.DefinePlugin in this config file. +__BUILD_INFO__ = buildInfo; + module.exports = { publicPath: '/', css: { From 0e0e1305f046a77f6530a7d2313cc6370d479f55 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 11 Jun 2026 12:02:30 -0400 Subject: [PATCH 09/15] Updates. --- vue.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue.config.js b/vue.config.js index 41fd8c5d..4d556775 100644 --- a/vue.config.js +++ b/vue.config.js @@ -74,4 +74,4 @@ module.exports = { }) ] } -}; \ No newline at end of file +}; From ada9e54d098ffe2c1022d3d77a6106dfe8967787 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 11 Jun 2026 12:08:00 -0400 Subject: [PATCH 10/15] INSR-9940: hasMSRPart as helper function instead of store getter --- src/helpers/recal-helper.js | 5 +++++ src/iss-components/cart-dropdown/cart-dropdown.vue | 3 ++- src/layouts/contact-details/contact-details.vue | 3 ++- src/store/index.js | 3 +-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/helpers/recal-helper.js b/src/helpers/recal-helper.js index 029aee25..0bb650ff 100644 --- a/src/helpers/recal-helper.js +++ b/src/helpers/recal-helper.js @@ -1,3 +1,4 @@ +import partNumberStrings from '@/constants/part-number-strings'; import partTypeStrings from '@/constants/part-type-strings'; import { deepClone, getNonFalseValuesOfPropertyInArrayOfObjects } from '@/helpers/object-helper'; @@ -117,3 +118,7 @@ export function anyPartWithRequiresRecalFlag(lineItems) { return flattened.some((li) => li.requiresRecalibration === true); } + +export function hasMSRPart(lineItems) { + return lineItems?.feeItems?.some((item) => item.partNumber === partNumberStrings.RECAL_MOBILEDUAL || item.partNumber === partNumberStrings.RECAL_MOBILE) ?? false +} diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 2cd0fb94..9572f9af 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -147,6 +147,7 @@ import { import { getPriceOfLineItem, getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator'; import { processIfStatements } from '@/helpers/cms-content-helper'; import partNumberStrings from '@/constants/part-number-strings'; +import { hasMSRPart } from '@/helpers/recal-helper'; const VERIFYING_COVERAGE = 'Verifying coverage'; const ADVANCED_MOBILE_MODAL_REF_NAME = 'advancedMobileModal'; @@ -383,7 +384,7 @@ export default { } }, hasMSRPart() { - return this.cartOrder.lineItems?.feeItems?.some((item) => item.partNumber === partNumberStrings.RECAL_MOBILEDUAL || item.partNumber === partNumberStrings.RECAL_MOBILE) ?? false; + return hasMSRPart(this.cartOrder.lineItems); }, includeMobileFeeInCart() { if (!this.mobileFeeCartItem || this.mobileFeeCartItem.subTotal === 0) { diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue index 778c1daf..65c348d5 100644 --- a/src/layouts/contact-details/contact-details.vue +++ b/src/layouts/contact-details/contact-details.vue @@ -134,6 +134,7 @@ import widgetFields from '@/constants/cms-widget-fields'; import states from '@/constants/states'; import applicationConfig from '@/constants/application-config'; import { vehicleProtectedAnswers } from '@/constants/contact-details'; +import { hasMSRPart } from '@/helpers/recal-helper'; // DEFINE VALIDATION RULES defineRule('street-address-required', required(errorMessages.SERVICE_ADDRESS_REQUIRED)); @@ -228,7 +229,7 @@ export default { }, {}); }, appointmentInformationWidget() { - return this.mainStore.hasMSRPart ? this.widget.MSRAppointmentInformation : this.widget.appointmentInformation; + return hasMSRPart(this.mainStore.lineItems) ? this.widget.MSRAppointmentInformation : this.widget.appointmentInformation; } }, watch: { diff --git a/src/store/index.js b/src/store/index.js index 6e4b4d07..e43f60d3 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -454,8 +454,7 @@ export const useMainStore = defineStore({ .reduce((r, c) => Object.assign(r, c), {}) ?? {}, originalDeductible: (state) => (state.order.damage.isRepair ? state.order.originalDeductible.repair : state.order.originalDeductible.replace), currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace), - accountNameForEvents: (state) => state.issConfig.clientName, - hasMSRPart: (state) => state.order.lineItems?.feeItems?.some((item) => item.partNumber === partNumberStrings.RECAL_MOBILEDUAL || item.partNumber === partNumberStrings.RECAL_MOBILE) ?? false + accountNameForEvents: (state) => state.issConfig.clientName }, actions: { From 4415a21e9c720f63d6b677b71fae87eee4ed12b2 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 11 Jun 2026 12:11:10 -0400 Subject: [PATCH 11/15] Adding updates for release vue config file. --- vue.release.config.js | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/vue.release.config.js b/vue.release.config.js index 43abce0e..18cc1771 100644 --- a/vue.release.config.js +++ b/vue.release.config.js @@ -1,3 +1,6 @@ +const { execSync } = require('child_process'); +const pkg = require('./package.json'); + process.env.VUE_APP_CONSUMER_CF_DISTRO = "__VUE_APP_CONSUMER_CF_DISTRO__"; process.env.VUE_APP_CURRENT_ENVIRONMENT = "__VUE_APP_CURRENT_ENVIRONMENT__"; process.env.VUE_APP_CUSTOMER_PORTAL_URL = '__VUE_APP_CUSTOMER_PORTAL_URL__'; @@ -11,6 +14,37 @@ process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = "__VUE_APP_GOOGLE_TAG_MANAG process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC = "__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__" process.env.VUE_APP_GOOGLE_MAPS_API_SCRIPT = "__VUE_APP_GOOGLE_MAPS_API_SCRIPT__"; +function safeExec(cmd, fallback = 'unknown') { + try { + return execSync(cmd).toString().trim(); + } catch { + return fallback; + } +} + +const gitInfo = { + commit: safeExec('git rev-parse --short HEAD', 'dev'), + branch: safeExec('git rev-parse --abbrev-ref HEAD', 'unknown') +}; + +const buildTimes = { + buildTime: new Date().toISOString(), + buildTimeLocal: new Date().toLocaleString(), + buildTimeStamp: Math.floor(Date.now() / 1000) +} + +const buildInfo = { + version: pkg.version, + buildTime: buildTimes.buildTime, + buildTimeLocal: buildTimes.buildTimeLocal, + buildTimeStamp: buildTimes.buildTimeStamp, + ...gitInfo, + versionString: `${pkg.version}-${gitInfo.commit}-${buildTimes.buildTimeStamp}-${gitInfo.branch}` +}; + +// This will be replaced by the actual build info during the build process via webpack.DefinePlugin in this config file. +__BUILD_INFO__ = buildInfo; + module.exports = { publicPath: "/", css: { @@ -29,6 +63,11 @@ module.exports = { }, }, configureWebpack: { - devtool: 'source-map' + devtool: 'source-map', + plugins: [ + new (require('webpack')).DefinePlugin({ + __BUILD_INFO__: JSON.stringify(buildInfo) + }) + ] }, }; From ed188f329108acafb645fb7a5f2239bc86a22b71 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 11 Jun 2026 12:30:43 -0400 Subject: [PATCH 12/15] Changed build info to be in JS instead of comments so it is not stripped during release build. --- public/index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index 6fe17575..c344f758 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,9 @@ -