From f7b452351dba0afc7d10a03a9d4faa107d32cbf7 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Mon, 10 Nov 2025 12:50:10 -0500 Subject: [PATCH 1/6] Organization + Delete Cookies + Send Pageview request --- public/static/error/index.html | 253 +++++++++++++++++++++++++-------- 1 file changed, 190 insertions(+), 63 deletions(-) diff --git a/public/static/error/index.html b/public/static/error/index.html index a4c141f85..53bb9fc08 100644 --- a/public/static/error/index.html +++ b/public/static/error/index.html @@ -114,7 +114,7 @@ body { debug: true, }, { - name: 'Test', + name: 'SysTest', hostName: 'www-test2.safelite.com', apiHostname: 'digitalapi.test.safelite.io', debug: true, @@ -142,83 +142,178 @@ body { return match; } + function getExperimentSettingsFromVuex(vuexData) { + const experiments = vuexData?.applicationUser?.experiments; + + if(experiments) { + return experiments + .filter((e) => !!e.isActive) + .map((e) => e.settings) + .reduce((prev, next) => Object.assign(prev, next), {}) ?? {}; + } + + return {}; + } + + function extractDataFromVuex(existingVuexData) { + let bailoutInfo = []; + let headerInfo = []; + + try { + // =============== Collect diagnostic data: + bailoutInfo = []; + + // App & Site Name + bailoutInfo.push({ name: 'App Name', value: 'FixMyGlass' }); + bailoutInfo.push({ name: 'Site Name', value: 'SafeliteDotcom' }); + + // Not included (yet) from heritage: + // - Site ID + // - Code + // - Module + // - Page + + bailoutInfo.push({ name: 'Timestamp', value: `${new Date()}` }); + + // - URL + // - Server + + const sessionId = getCookieValueByName('sid'); + bailoutInfo.push({ name: 'Session Id', value: sessionId }); + + const userAgent = window.navigator.userAgent; + bailoutInfo.push({ name: 'User Agent', value: userAgent }); + + // - IP + // - Session Log Sequence Number + + bailoutInfo.push({ name: 'Referral Seq Number', value: existingVuexData.order?.referralSequenceNumber }); + bailoutInfo.push({ name: 'Referral Number', value: existingVuexData.order?.referralNumber }); + bailoutInfo.push({ name: 'Referral Date', value: existingVuexData.order?.referralDate }); + bailoutInfo.push({ name: 'Referral Provider Number', value: existingVuexData.order?.serviceLocation?.provider?.providerNumber }); + bailoutInfo.push({ name: 'Referral CTU', value: existingVuexData.order?.serviceLocation?.provider?.address?.zipCodeCtu }); + + // - Referral Insured Zip + // - Referral Insured Service Zip + + bailoutInfo.push({ name: 'Referral CarID', value: existingVuexData.order?.vehicle?.carId }); + + const vehicle = existingVuexData.order?.vehicle; + const vehicleString = vehicle?.year + ? `${vehicle.year} ${vehicle.make} ${vehicle.model} - ${vehicle.style}` + : null; + bailoutInfo.push({ name: 'Referral Vehicle', value: vehicleString }); + bailoutInfo.push({ name: 'Work Order Number', value: existingVuexData.order?.workOrderNumber }); + bailoutInfo.push({ name: 'Work Order ID', value: existingVuexData.order?.workOrderId }); + bailoutInfo.push({ name: 'Parent Account Number', value: existingVuexData.order?.payment?.parentAccountNumber }); + + const environmentData = getCurrentEnvironmentData(); + const userIdCookieName = `FunnelUserId-${environmentData?.name}`; + bailoutInfo.push({ name: 'User Id', value: getCookieValueByName(userIdCookieName) }); + + // - Parent Account Name + // - Client GUID + + // =============== Collect header data: + headerInfo = []; + + headerInfo.push({ name: 'X-Experiment-Data', value: JSON.stringify(getExperimentSettingsFromVuex(existingVuexData)) }); + headerInfo.push({ name: 'X-Application-Name', value: 'FixMyGlass' }); + + const sessionKeyCookieName = `FunnelSessionKey-${environmentData?.name}`; + + headerInfo.push({ name: 'X-Session-Sequence-Number', value: getCookieValueByName(sessionKeyCookieName) }); + headerInfo.push({ name: 'X-Referral-Sequence-Number', value: existingVuexData?.order?.referralSequenceNumber }); + headerInfo.push({ name: 'X-Enterprise-Order-Number', value: existingVuexData?.order?.eon }); + headerInfo.push({ name: 'log-enabled', value: existingVuexData?.applicationUser?.loggingOption ?? false }); + } finally { + return { + headerInfo: headerInfo, + bailoutInfo: bailoutInfo + }; + } + } + + function generateRequestHeader(headerInfo) { + let headers = {}; + + headerInfo.forEach( + keyPair => { + headers[keyPair.name] = keyPair.value; + } + ); + + headers['X-Transaction-Id'] = crypto.randomUUID(); + + headers['Content-Type'] = 'application/json'; + + return headers; + } + + function getFieldWithName(info, name) { + const match = info?.find( + (row) => row.name === name + ); + + return match?.value; + } + + function clearApplicationData() { + window.localStorage.removeItem('vuex'); + + const environmentData = getCurrentEnvironmentData(); + const cookieNames = [ + `FunnelUserId-${environmentData?.name}`, + `FunnelSessionKey-${environmentData?.name}`, + `FunnelSessionInfo-${environmentData?.name}`, + `sid`, + `dxdev`, + ]; + + cookieNames.forEach( + (cookieName) => { + let cookieToAdd = `${cookieName}=undefined; path=/; domain=${environmentData.hostName}; max-age=0`; + document.cookie = cookieToAdd; + } + ) + } + window.onload = async () => { // =============== Check for session info: const existingVuexDataJSON = window.localStorage.getItem('vuex'); const existingVuexData = existingVuexDataJSON ? JSON.parse(existingVuexDataJSON) : null; const existingBailoutInfoJSON = window.sessionStorage.getItem('bailoutInfo'); const existingBailoutInfo = existingBailoutInfoJSON ? JSON.parse(existingBailoutInfoJSON) : null; + const existingHeaderInfoJSON = window.sessionStorage.getItem('headerInfo'); + const existingHeaderInfo = existingHeaderInfoJSON ? JSON.parse(existingHeaderInfoJSON) : null; console.log(`================ VUEX DATA`); console.log(existingVuexData); console.log(`================ PRIOR BAILOUT DATA`); console.log(existingBailoutInfo); + console.log(`================ PRIOR HEADER DATA`); + console.log(existingHeaderInfo); let bailoutInfo = null; + let headerInfo = null; if(existingVuexData) { - try { - // =============== Collect diagnostic data: - bailoutInfo = []; + const results = extractDataFromVuex(existingVuexData); + bailoutInfo = results.bailoutInfo; + headerInfo = results.headerInfo; - // App & Site Name - bailoutInfo.push({ name: 'App Name', value: 'FixMyGlass' }); - bailoutInfo.push({ name: 'Site Name', value: 'SafeliteDotcom' }); + clearApplicationData(); - // Not included (yet) from heritage: - // - Site ID - // - Code - // - Module - // - Page - - bailoutInfo.push({ name: 'Timestamp', value: `${new Date()}` }); - - // - URL - // - Server - - const sessionId = getCookieValueByName('sid'); - bailoutInfo.push({ name: 'Session Id', value: sessionId }); - - const userAgent = window.navigator.userAgent; - bailoutInfo.push({ name: 'User Agent', value: userAgent }); - - // - IP - // - Session Log Sequence Number - - bailoutInfo.push({ name: 'Referral Seq Number', value: existingVuexData.order?.referralSequenceNumber }); - bailoutInfo.push({ name: 'Referral Number', value: existingVuexData.order?.referralNumber }); - bailoutInfo.push({ name: 'Referral Date', value: existingVuexData.order?.referralDate }); - bailoutInfo.push({ name: 'Referral Provider Number', value: existingVuexData.order?.serviceLocation?.provider?.providerNumber }); - bailoutInfo.push({ name: 'Referral CTU', value: existingVuexData.order?.serviceLocation?.provider?.address?.zipCodeCtu }); - - // - Referral Insured Zip - // - Referral Insured Service Zip - - bailoutInfo.push({ name: 'Referral CarID', value: existingVuexData.order?.vehicle?.carId }); - - const vehicle = existingVuexData.order?.vehicle; - const vehicleString = vehicle?.year - ? `${vehicle.year} ${vehicle.make} ${vehicle.model} - ${vehicle.style}` - : null; - bailoutInfo.push({ name: 'Referral Vehicle', value: vehicleString }); - bailoutInfo.push({ name: 'Work Order Number', value: existingVuexData.order?.workOrderNumber }); - bailoutInfo.push({ name: 'Work Order ID', value: existingVuexData.order?.workOrderId }); - bailoutInfo.push({ name: 'Parent Account Number', value: existingVuexData.order?.payment?.parentAccountNumber }); - - // - Parent Account Name - // - Client GUID - } finally { - // If any information gathered, write to session storage. - if(bailoutInfo) { - window.sessionStorage.setItem('bailoutInfo', JSON.stringify(bailoutInfo)); - } - - // Then *always* clear vuex data. - window.localStorage.removeItem('vuex'); + if(bailoutInfo) { + window.sessionStorage.setItem('bailoutInfo', JSON.stringify(bailoutInfo)); } - } else if(existingBailoutInfo) { - // Proceed with prior data. - bailoutInfo = existingBailoutInfo; + + if(headerInfo) { + window.sessionStorage.setItem('headerInfo', JSON.stringify(headerInfo)); + } + } else { + bailoutInfo = existingBailoutInfo ?? []; + headerInfo = existingHeaderInfo ?? []; } const environmentInfo = getCurrentEnvironmentData(); @@ -275,11 +370,11 @@ body { ); const entryString = `User encountered bailout page.\n${new Date()}\n${infoString ?? 'No information recoverable'}`; + const headers = generateRequestHeader(headerInfo); + const request = new Request(endpointUrl, { method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, + headers: headers, body: JSON.stringify({ entry: entryString, }), @@ -292,6 +387,38 @@ body { console.error(`=== ERROR SENDING LOGGING`); console.error(e); } + + try { + const endpointUrl = `https://${apiHostname}/analytics/api/v1/analytics/log-page-view`; + + const headers = generateRequestHeader(headerInfo); + + const payload = { + AppName: "FixMyGlass", + action: "", + applicationName: "FixMyGlassNextGen", + event: "ENTRY", + experimentsForUser: [], + pageName: "static-error", + parentAccountNumber: getFieldWithName(bailoutInfo, 'Parent Account Number') ?? 0, + referralSequenceNumber: getFieldWithName(bailoutInfo, 'Referral Seq Number'), + sessionId: getFieldWithName(bailoutInfo, 'Session Id'), + sessionKey: getFieldWithName(headerInfo, 'X-Session-Sequence-Number'), + shouldUseSessionId: false, + userId: getFieldWithName(bailoutInfo, 'User Id'), + }; + + const request = new Request(endpointUrl, { + method: 'POST', + headers: headers, + body: JSON.stringify(payload), + }); + + const response = await fetch(request); + } catch(e) { + console.error(`=== ERROR SENDING PAGEVIEW`); + console.error(e); + } } }; From 94772eafecd34dc7cf59d0730fb60deb6c015af3 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Mon, 10 Nov 2025 12:53:49 -0500 Subject: [PATCH 2/6] Reapply "Merge pull request #2930 from Safelite/feature/CASH-1620" This reverts commit c903fed88f967fb42b38923a806215b96c45058b. --- src/constants/cart-item-categories.js | 2 +- src/constants/cart-item-types.js | 2 +- src/constants/part-type-strings.js | 1 + src/constants/quote-page-discounts.js | 80 +++++++++++++ .../service-package-radio-for-afterpay.vue | 4 +- .../service-package-radio.vue | 9 +- src/fmg-components/cart/cart.vue | 79 ++++++------- src/layouts/quote/quote.spec.js | 2 +- src/layouts/quote/quote.vue | 104 ++++++++++------- .../service-package-question.spec.js | 53 ++++----- .../service-package-question.vue | 110 ++++++++---------- .../service-package-radio.vue | 7 +- src/mixins/base-mixin.js | 4 +- 13 files changed, 260 insertions(+), 197 deletions(-) create mode 100644 src/constants/quote-page-discounts.js diff --git a/src/constants/cart-item-categories.js b/src/constants/cart-item-categories.js index 6bbb960b9..5c8faafcf 100644 --- a/src/constants/cart-item-categories.js +++ b/src/constants/cart-item-categories.js @@ -3,7 +3,7 @@ const cartItemCategories = { GLASS_PARTS: "glassParts", SUPPORTING_ITEMS: "supportingItems", PROMOS: "promos", - SERVICE_PACKAGE_DISCOUNT: "servicePackageDiscount", + QUOTE_PAGE_DISCOUNT: "quotePageDiscount", }; export { cartItemCategories }; diff --git a/src/constants/cart-item-types.js b/src/constants/cart-item-types.js index 0bb418d43..8f70aeaed 100644 --- a/src/constants/cart-item-types.js +++ b/src/constants/cart-item-types.js @@ -10,7 +10,7 @@ const cartItemTypes = { PROMOS: "PROMOS", EARLY_BIRD: "EARLY BIRD", SUPPLIES_REPAIR: "SUPPLIES-REPAIR", - SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT", + QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT", DONATION: "DONATION", }; diff --git a/src/constants/part-type-strings.js b/src/constants/part-type-strings.js index 741132e28..17b96d2fb 100644 --- a/src/constants/part-type-strings.js +++ b/src/constants/part-type-strings.js @@ -10,6 +10,7 @@ const partTypeStrings = { REPAIR_FEE: "REPAIR FEE", EARLY_BIRD: "EARLY BIRD", SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT", + QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT", DONATION: "DONATION", }; diff --git a/src/constants/quote-page-discounts.js b/src/constants/quote-page-discounts.js new file mode 100644 index 000000000..2dd32d915 --- /dev/null +++ b/src/constants/quote-page-discounts.js @@ -0,0 +1,80 @@ +import { packageNames } from "./package-names"; +import { partTypeStrings } from "./part-type-strings"; + +export const quotePageDiscountTable = [ + // Repair + { + name: "Repair Glass Only", + experimentCode: "Show_GlassOnly_Repair_Discount", + partNumber: "GL RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Repair Standard", + experimentCode: "Show_Standard_Repair_Discount", + partNumber: "STD RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Repair Premium", + experimentCode: "Show_Premium_Repair_Discount", + partNumber: "PRM RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, + // Replace - No recal + { + name: "Replace Glass Only", + experimentCode: "Show_GlassOnly_Replace_Discount", + partNumber: "GL RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Replace Standard", + experimentCode: "Show_Standard_Replace_Discount", + partNumber: "STD RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Replace Premium", + experimentCode: "Show_Premium_Replace_Discount", + partNumber: "PRM RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, + // Replace - with recal + { + name: "Recal Glass Only", + experimentCode: "Show_GlassOnly_Recal_Discount", + partNumber: "GL RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Recal Standard", + experimentCode: "Show_Standard_Recal_Discount", + partNumber: "STD RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Recal Premium", + experimentCode: "Show_Premium_Recal_Discount", + partNumber: "PRM RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, +]; diff --git a/src/experiment-components/service-package-radio-for-afterpay.vue b/src/experiment-components/service-package-radio-for-afterpay.vue index 2e746e4f2..7f7e91084 100644 --- a/src/experiment-components/service-package-radio-for-afterpay.vue +++ b/src/experiment-components/service-package-radio-for-afterpay.vue @@ -145,9 +145,7 @@ export default { return "$" + decimalPrice.toFixed(2); }, hasPackageDiscount() { - return ( - this.additionalButtonData.servicePackageDiscount && this.additionalButtonData.Text - ); + return this.additionalButtonData.hasDiscount && this.additionalButtonData.Text; }, }, }; diff --git a/src/experiment-components/service-package-radio.vue b/src/experiment-components/service-package-radio.vue index ee7e12712..a116fecd8 100644 --- a/src/experiment-components/service-package-radio.vue +++ b/src/experiment-components/service-package-radio.vue @@ -4,11 +4,11 @@ class="package-label pricing-by-day-pkg-lbl" :class="[ this.buttonLabelSubCopy ? 'has-subheader' : '', - !this.additionalButtonData.servicePackageDiscount ? 'adjust-top' : '', + !this.additionalButtonData.hasDiscount ? 'adjust-top' : '', ]" for="testradio">
-
+

@@ -84,10 +84,7 @@

diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index d1bd2a939..e890e53cc 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -190,6 +190,7 @@ import { cartItemCategories } from "@/constants/cart-item-categories"; import { cartItemTypes } from "@/constants/cart-item-types"; import { coverageStatus, cartItemTypesCoveredByInsurance } from "@/constants/insurance"; import { experimentSettings } from "@/constants/experiments"; +import { quotePageDiscountTable } from "@/constants/quote-page-discounts"; export default { name: "cart", @@ -256,11 +257,11 @@ export default { return subTotal; }, - getServicePackageDiscount() { - const servicePackageDiscountLineItems = this.servicePackageDiscountCartItem; + getQuotePageDiscount() { + const quotePageDiscountLineItems = this.quotePageDiscountCartItem; let subTotal = 0; - subTotal += servicePackageDiscountLineItems?.subTotal ?? 0; + subTotal += quotePageDiscountLineItems?.subTotal ?? 0; return subTotal; }, getVapsCartItemsForSelectedPackage(packageName) { @@ -303,7 +304,8 @@ export default { getLineItemAmount(amount, useVerifyingText, category) { if (useVerifyingText) return this.verifyingCoverageText; - return category == "promos" || category == "servicePackageDiscount" + return category == cartItemCategories.PROMOS || + category == cartItemCategories.QUOTE_PAGE_DISCOUNT ? "(" + this.currencyFormatter.format(amount * -1) + ")" : this.currencyFormatter.format(amount); }, @@ -316,16 +318,21 @@ export default { if (category == cartItemCategories.VAPS || category == cartItemCategories.PROMOS) { this.saveVaps(this.lineItems); // Check if service package discount should be removed after vaps change - if ( - this.servicePackageDiscountCartItem && - this.discountPackageNames != this.packageLevel - ) { - this.lineItems.supportingItems = this.lineItems.supportingItems.filter( - (lineItemsToKeep) => - lineItemsToKeep.cartItemType != - this.servicePackageDiscountCartItem.cartItemType + if (this.quotePageDiscountCartItem) { + const existingLineItem = this.quotePageDiscountCartItem.lineItems.at(0); + const discountInfo = quotePageDiscountTable.find( + (info) => info.partNumber === existingLineItem?.partNumber ); - shouldSaveSupportingItems = true; + const packageLevelForDiscount = discountInfo?.packageLevel; + + if (this.packageLevel !== packageLevelForDiscount) { + this.lineItems.supportingItems = this.lineItems.supportingItems.filter( + (lineItemsToKeep) => + lineItemsToKeep.cartItemType != + this.quotePageDiscountCartItem.cartItemType + ); + shouldSaveSupportingItems = true; + } } } if (shouldSaveSupportingItems) { @@ -483,8 +490,8 @@ export default { cartItems.push(this.mobileFeeCartItem); } - if (this.servicePackageDiscountCartItem) { - cartItems.push(this.servicePackageDiscountCartItem); + if (this.quotePageDiscountCartItem) { + cartItems.push(this.quotePageDiscountCartItem); } if (this.premiumAppointmentDiscountCartItem) { @@ -500,12 +507,6 @@ export default { return cartItems; }, }, - discountPackageNames() { - const discountServicePackage = experimentMixin.methods.getSettingValue( - experimentSettings.PROMO_ON_PACKAGE - ); - return getDiscountedPackageName(discountServicePackage); - }, servicePackageTitleWidget() { const servicePackageNames = this.getCmsContent( this.servicePackageOptionsCmsName, @@ -550,8 +551,8 @@ export default { } packagePrice += this.getVapsPrice(this.packageLevel); - if (this.servicePackageDiscountCartItem) { - packagePrice -= this.getServicePackageDiscount(); + if (this.quotePageDiscountCartItem) { + packagePrice -= this.getQuotePageDiscount(); } return packagePrice; @@ -928,25 +929,25 @@ export default { } return cartItem; }, - servicePackageDiscountCartItemName() { + quotePageDiscountCartItemName() { return this.getCmsContent("ServicePackageDiscountTextWidget", "Text"); }, - servicePackageDiscountCartItem() { + quotePageDiscountCartItem() { let cartItem = null; - const servicePackageDiscountLineItem = this.supportingItems.find( - (lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT + const quotePageDiscountLineItem = this.supportingItems.find( + (lineItem) => lineItem.partType == partTypeStrings.QUOTE_PAGE_DISCOUNT ); - if (servicePackageDiscountLineItem) { + if (quotePageDiscountLineItem) { cartItem = { name: - this.servicePackageDiscountCartItemName + + this.quotePageDiscountCartItemName + Math.abs( - baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem) + baseMixin.methods.getTotalLineItemPrice(quotePageDiscountLineItem) ), - category: cartItemCategories.SERVICE_PACKAGE_DISCOUNT, - cartItemType: cartItemTypes.SERVICE_PACKAGE_DISCOUNT, + category: cartItemCategories.QUOTE_PAGE_DISCOUNT, + cartItemType: cartItemTypes.QUOTE_PAGE_DISCOUNT, isDisplayed: true, isRemovable: false, subTotal: 0, @@ -955,15 +956,15 @@ export default { isCoveredByInsurance: false, }; - servicePackageDiscountLineItem.cartItemType = cartItem.cartItemType; - cartItem.lineItems.push(servicePackageDiscountLineItem); + quotePageDiscountLineItem.cartItemType = cartItem.cartItemType; + cartItem.lineItems.push(quotePageDiscountLineItem); cartItem.subTotal += - (servicePackageDiscountLineItem.kitPrice ?? 0) + - (servicePackageDiscountLineItem.laborAmount ?? 0) + - (servicePackageDiscountLineItem.sellingPrice ?? 0); + (quotePageDiscountLineItem.kitPrice ?? 0) + + (quotePageDiscountLineItem.laborAmount ?? 0) + + (quotePageDiscountLineItem.sellingPrice ?? 0); - cartItem.salesTax += servicePackageDiscountLineItem.salesTax ?? 0; + cartItem.salesTax += quotePageDiscountLineItem.salesTax ?? 0; } return cartItem; @@ -972,7 +973,7 @@ export default { let cartItem = null; const otherSupportingItems = this.supportingItems.filter((item) => { - return item.partType != partTypeStrings.SERVICE_PACKAGE_DISCOUNT; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); // Don't include fees they are part of the package total let otherSupportingItemsLineItems = diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index aea32211e..5d9f3bacb 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -82,7 +82,7 @@ jest.mock("@/mixins/base-mixin", () => ({ filterOutFees(items) { return null; }, - filterOutServicePackageDiscountPart(items) { + filterOutQuotePageDiscountPart(items) { return null; }, isFormValid(form) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 8bab96d5f..78d6c24ff 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -31,10 +31,11 @@ :isRecalibrationOnOrder="isRecalibrationOnOrder" :shouldHideRecalibration="shouldHideRecalibration" @vapsItemsSelected="vapsItemsSelectedAction" - @servicePackageDiscountSelected="servicePackageDiscountSelectedAction" + @quotePageDiscountSelected="quotePageDiscountSelectedAction" @currentNumberOfPackages="currentNumberOfPackagesAction" :servicePackage="servicePackage" :activePromos="lineItems.promos" + :availableQuotePageDiscounts="quoteDiscountPartsInfo" v-on="{ 'buttonEvent.openModal': openModalAction }" validationRules="option-required" isRequired /> @@ -176,6 +177,7 @@ import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stas import { storeMutations } from "@/constants/store-mutations"; import { debugLog } from "@/helpers/debug-log-helper"; import { savePageData } from "@/router/methods/helpers/save-page-data"; +import { quotePageDiscountTable } from "../../constants/quote-page-discounts"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); @@ -186,6 +188,14 @@ const ACCEPTED_QUOTE_TYPES = { INSURANCE: "insurance", }; +function getAvailableQuotePageDiscounts() { + const activeDiscounts = quotePageDiscountTable?.filter((discountEntry) => + experimentMixin?.methods?.hasSettingEqualTo(discountEntry?.experimentCode, "true") + ); + + return activeDiscounts ?? []; +} + export default { name: "quote", async beforeRouteEnter(to, from, next) { @@ -302,29 +312,22 @@ export default { const lineItems = deepClone(store.getters.order.lineItems); lineItems.vaps = lineItems.vaps ?? []; const nullSafeGlassParts = lineItems.glassParts ?? []; - const servicePackageDiscountSettingValue = experimentMixin.methods.getSettingValue( - experimentSettings.SERVICE_PACKAGE_DISCOUNT - ); - const isServicePackageDiscount = servicePackageDiscountSettingValue === "True"; - //Service package cash discount api call when experiment is active - var servicePackageDiscountPart = []; - if (isServicePackageDiscount) { - const servicePackageDiscountPartResponse = - await baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.GET_SERVICE_PACKAGE_DISCOUNT_PART, - null, - "quote" - ); - if (servicePackageDiscountPartResponse.data) { - servicePackageDiscountPart.push(servicePackageDiscountPartResponse.data); - } - } + + const quotePageDiscountPartsInfo = getAvailableQuotePageDiscounts(); + + const quotePageDiscountParts = quotePageDiscountPartsInfo.map((partInfo) => ({ + partNumber: partInfo.partNumber, + partType: partInfo.partType, + description: partInfo.description, + isInsurable: null, + })); + const availableLineItems = [ resultMap.rainRepel, ...resultMap.supportingItems, ...resultMap.wipers, ...nullSafeGlassParts, - ...servicePackageDiscountPart, + ...quotePageDiscountParts, ]; // When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards @@ -351,7 +354,7 @@ export default { false ); - // This will remove any servicePackageDiscount item from lineItems.supportingItems + // This will remove any discount item from lineItems.supportingItems baseMixin.methods.dispatchStoreAction( storeActions.SAVE_SUPPORTING_ITEMS, resultMap.supportingItems, @@ -453,10 +456,9 @@ export default { ) : baseMixin.methods.filterOutFees(availableLineItems); - const lineItemsNoDiscount = - baseMixin.methods.filterOutServicePackageDiscountPart( - lineItemsForCalculatingPrice - ); + const lineItemsNoDiscount = baseMixin.methods.filterOutQuotePageDiscountPart( + lineItemsForCalculatingPrice + ); if (isInsuranceFromQueryString != null) { if (isInsuranceFromQueryString.toLowerCase() === "true") { @@ -580,17 +582,8 @@ export default { isRecalibrationOnOrder() { return store.getters.isRecalibrationOnOrder; }, - isServicePackageDiscountOnOrder() { - return containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.availableLineItems - ); - }, - servicePackageDiscountParts() { - return findLineItemsWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.availableLineItems - ); + isQuotePageDiscountOnOrder() { + return this.quotePageDiscountPartsInfo?.length > 0; }, shouldHideRecalibration() { return ( @@ -619,6 +612,23 @@ export default { thresholdAmount && (thresholdAmount = parseInt(thresholdAmount)); return thresholdAmount; }, + quoteDiscountPartsInfo() { + const defs = getAvailableQuotePageDiscounts(); + const withPrices = defs + .map((def) => { + const match = this.availableLineItems?.find?.( + (pricedItem) => pricedItem.partNumber === def.partNumber + ); + + return { + packageLevel: def.packageLevel, + item: match, + }; + }) + .filter((result) => result.item); + + return withPrices; + }, }, methods: { getColCount() { @@ -662,7 +672,7 @@ export default { vapsItemsSelectedAction(vapsItemsSelected) { this.lineItems.vaps = vapsItemsSelected; }, - servicePackageDiscountSelectedAction(supportingItemsSelected) { + quotePageDiscountSelectedAction(supportingItemsSelected) { this.lineItems.supportingItems = supportingItemsSelected; }, backButtonAction() { @@ -724,10 +734,10 @@ export default { false ); } - if (this.isInsuranceSelected && this.isServicePackageDiscountOnOrder) { + if (this.isInsuranceSelected && this.isQuotePageDiscountOnOrder) { let supportingItems = this.lineItems.supportingItems; supportingItems = supportingItems.filter((item) => { - return item.partType != this.servicePackageDiscountParts[0].partType; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); this.dispatchStoreAction( this.storeActions.SAVE_SUPPORTING_ITEMS, @@ -813,19 +823,23 @@ export default { lineItemsToPrice = baseMixin.methods.filterOutRecalibration(lineItemsToPrice); } - if (this.isServicePackageDiscountOnOrder) { + if (this.isQuotePageDiscountOnOrder) { lineItemsToPrice = lineItemsToPrice?.filter((item) => { - return ( - item.partType != this.servicePackageDiscountParts[0].partType - ); + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); } let price = 0; if ( - tier.additionalButtonData?.servicePackageDiscount && - this.isServicePackageDiscountOnOrder + tier.additionalButtonData?.hasDiscount && + this.isQuotePageDiscountOnOrder ) { - lineItemsToPrice.push(...this.servicePackageDiscountParts); + const parts = this.quoteDiscountPartsInfo; + const matchPart = parts.find( + (discountInfo) => discountInfo.packageLevel === tier + ); + if (matchPart) { + lineItemsToPrice.push(matchPart); + } } price += baseMixin.methods.getTierOnePackagePrice( baseMixin.methods.filterOutFees(lineItemsToPrice) diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index 523c0edce..a44dc463c 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -14,6 +14,7 @@ import { experimentSettings } from "@/constants/experiments"; import baseMixin from "@/mixins/base-mixin.js"; import { partTypeStrings } from "@/constants/part-type-strings"; import { nextTick } from "vue"; +import { packageNames } from "../../../constants/package-names"; jest.mock("@/store", () => ({ commit: jest.fn(), @@ -73,9 +74,9 @@ describe("service-package-question.vue", () => { price: 35.5, }, { - partNumber: "DISC CASHSAVE70", + partNumber: "PRM RCL CSH PKG", description: null, - partType: "SERVICE PACKAGE DISCOUNT", + partType: "QUOTE PAGE DISCOUNT", price: -70, }, ], @@ -105,13 +106,27 @@ describe("service-package-question.vue", () => { description: null, kitPrice: 0, laborAmount: 0, - partNumber: "DISC CASHSAVE70", - partType: "SERVICE PACKAGE DISCOUNT", + partNumber: "PRM RCL CSH PKG", + partType: "QUOTE PAGE DISCOUNT", salesTax: null, sellingPrice: -70, }, ], }, + availableQuotePageDiscounts: [ + { + packageLevel: packageNames.TIER_THREE, + item: { + description: null, + kitPrice: 0, + laborAmount: 0, + partNumber: "PRM RCL CSH PKG", + partType: "QUOTE PAGE DISCOUNT", + salesTax: null, + sellingPrice: -70, + }, + }, + ], activePromos: [], }; const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; @@ -136,41 +151,17 @@ describe("service-package-question.vue", () => { }); it("should return price when there is discount", () => { const wrapper = setupMocks({}); - const partType = partTypeStrings.SERVICE_PACKAGE_DISCOUNT; - wrapper.vm.isServicePackageDiscountOnOrder = containsLineItemWithPartType( - partType, - mockProps.lineItems.supportingItems - ); - const servicePackageDiscountLineItem = findLineItemsWithPartType( - partType, - mockProps.lineItems.supportingItems - ); - wrapper.vm.getServicePackageDiscountPrice(); - const price = baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem[0]); + const price = wrapper.vm.getDiscountPrice(packageNames.TIER_THREE); expect(Math.abs(price)).toEqual(70); }); - it("isServicePackageDiscountOnOrder returns true if it contains service package discount lineItems", () => { + it("isDiscountOnOrder returns true if it contains quote package discount lineItems", () => { // Arrange const wrapper = setupMocks({}); // Assert - expect(wrapper.vm.isServicePackageDiscountOnOrder).toBe(true); - }); - it("servicePackageDiscountParts should returns service package discount lineItems", () => { - // Arrange - const wrapper = setupMocks({}); - - // Assert - expect(wrapper.vm.servicePackageDiscountParts).toEqual([ - { - partNumber: "DISC CASHSAVE70", - description: null, - partType: "SERVICE PACKAGE DISCOUNT", - price: -70, - }, - ]); + expect(wrapper.vm.isDiscountOnOrder).toBe(true); }); it("should have the correct insurance pricing text when insurance is selected", () => { // Arrange diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index d1a99da08..e45147295 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -60,6 +60,7 @@ export default { servicePackage: null, isRecalibrationOnOrder: Boolean, shouldHideRecalibration: Boolean, + availableQuotePageDiscounts: null, }, data() { return { @@ -85,27 +86,18 @@ export default { selectedPackageName(newValue) { const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage); - const servicePackageDiscountPartInSelectedPackage = - this.getServicePackageDiscountPartForSelectedPackage(newValue); + const discountPartInSelectedPackage = this.getDiscountPartForSelectedPackage(newValue); let supportingItems = this.supportingLineItems; - if ( - containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - supportingItems - ) - ) { - supportingItems = supportingItems.filter( - (item) => item.partType !== partTypeStrings.SERVICE_PACKAGE_DISCOUNT - ); - } - if ( - servicePackageDiscountPartInSelectedPackage?.length > 0 && - supportingItems != null - ) { - supportingItems.push(servicePackageDiscountPartInSelectedPackage[0]); + + supportingItems = supportingItems.filter( + (item) => item.partType !== partTypeStrings.QUOTE_PAGE_DISCOUNT + ); + + if (discountPartInSelectedPackage) { + supportingItems.push(discountPartInSelectedPackage); } - this.$emit("servicePackageDiscountSelected", supportingItems); + this.$emit("quotePageDiscountSelected", supportingItems); }, servicePackage(newValue) { if (newValue !== null) { @@ -118,7 +110,7 @@ export default { return this.availableLineItems ?? []; }, supportingLineItems() { - return this.$store.getters.lineItems?.supportingItems; + return this.$store.getters.lineItems?.supportingItems ?? []; }, servicePackageAnswers() { const cmsWidgetName = this.isInsuranceSelected @@ -149,18 +141,15 @@ export default { ? this.getDiscountedPackagePriceString(answer.Name, false) : this.getDiscountedPackagePriceString( answer.Name, - this.isServicePackageDiscountOnOrder && - this.discountPackageNames == answer.Name + this.hasDiscountForPackage(answer.Name) ), buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName), additionalButtonData: { strikeThroughPrice: this.getPackagePriceString(answer.Name), - servicePackageDiscount: - this.isServicePackageDiscountOnOrder && - this.discountPackageNames == answer.Name, + hasDiscount: this.hasDiscountForPackage(answer.Name), Text: this.isInsuranceSelected ? false - : "Special: Save $" + this.getServicePackageDiscountPrice(), + : "Special: Save $" + this.getDiscountPrice(answer.Name), isInsuranceSelected: this.isInsuranceSelected, }, })); @@ -168,17 +157,8 @@ export default { this.$emit("currentNumberOfPackages", modifiedAnswers.length); return modifiedAnswers; }, - isServicePackageDiscountOnOrder() { - return containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.nullSafeAvailableLineItems - ); - }, - discountPackageNames() { - const discountServicePackage = experimentMixin.methods.getSettingValue( - experimentSettings.PROMO_ON_PACKAGE - ); - return getDiscountedPackageName(discountServicePackage); + isDiscountOnOrder() { + return this.availableQuotePageDiscounts?.length > 0; }, frontWipersApplicableForTierTwo() { return shouldFrontWipersBeAvailable( @@ -226,12 +206,6 @@ export default { isRepair() { return this.$store.getters.order.damage.isRepair; }, - servicePackageDiscountParts() { - return findLineItemsWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.nullSafeAvailableLineItems - ); - }, showRecalInServicePackages() { return this.isRecalibrationOnOrder && !this.shouldHideRecalibration; }, @@ -280,16 +254,16 @@ export default { const formattedPriceFloat = parseFloat( this.getPackagePrice(packageName, { discountedPrice: false, - servicePackageDiscount: false, + quotePageDiscount: false, }) ).toFixed(2); return "$" + formattedPriceFloat; }, - getDiscountedPackagePriceString(packageName, servicePackageDiscount) { + getDiscountedPackagePriceString(packageName, quotePageDiscount) { const formattedPriceFloat = parseFloat( this.getPackagePrice(packageName, { discountedPrice: true, - servicePackageDiscount, + quotePageDiscount, }) ).toFixed(2); @@ -298,7 +272,7 @@ export default { } return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat; }, - getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) { + getPackagePrice(packageName, { discountedPrice = false, quotePageDiscount = false }) { let lineItemsToPrice = [...this.nullSafeAvailableLineItems]; if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) { @@ -306,17 +280,20 @@ export default { } //remove service package discount part - if (this.isServicePackageDiscountOnOrder) { + if (this.isDiscountOnOrder) { lineItemsToPrice = lineItemsToPrice.filter((item) => { - return item.partType != this.servicePackageDiscountParts[0].partType; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); } if (discountedPrice) { lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos)); } - if (servicePackageDiscount) { - lineItemsToPrice.push(...this.servicePackageDiscountParts); + if (quotePageDiscount) { + const part = this.getDiscountPartForSelectedPackage(packageName); + if (part) { + lineItemsToPrice.push(part); + } } let priceFloat = this.isInsuranceSelected ? 0 @@ -328,14 +305,16 @@ export default { return priceFloat; }, - getServicePackageDiscountPrice() { - if (this.isServicePackageDiscountOnOrder) { - let price = 0; - price += baseMixin.methods.getTotalLineItemPrice( - this.servicePackageDiscountParts[0] - ); + getDiscountPrice(packageName) { + const part = this.getDiscountPartForSelectedPackage(packageName); + + if (part) { + const price = baseMixin.methods.getTotalLineItemPrice(part); + return Math.abs(price); } + + return null; }, getVapsPrice(packageName, applyPromoDiscounts = false) { const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName); @@ -398,13 +377,18 @@ export default { return vapsLineItemsForSelectedPackage; }, - getServicePackageDiscountPartForSelectedPackage(packageName) { - const selectedPackage = this.servicePackageAnswers.filter( - (item) => item.value === packageName - ); - if (selectedPackage?.[0]?.additionalButtonData?.servicePackageDiscount) { - return this.servicePackageDiscountParts; - } else return []; + getDiscountPartForSelectedPackage(packageName) { + if (this.availableQuotePageDiscounts?.length > 0) { + const match = this.availableQuotePageDiscounts.find( + (discountInfo) => discountInfo.packageLevel === packageName + ); + return match?.item; + } + + return null; + }, + hasDiscountForPackage(packageName) { + return !!this.getDiscountPartForSelectedPackage(packageName); }, combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) { const combinedLineItemArray = [...lineItemsTwo]; diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index 441a4f5cb..8bb7e921a 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -5,7 +5,7 @@ :class="[this.buttonLabelSubCopy ? 'has-subheader' : '']" for="testradio">
-
+

@@ -77,10 +77,7 @@

diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index 5204178de..813a3189a 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -129,9 +129,9 @@ export default { }); return lineItemsArray; }, - filterOutServicePackageDiscountPart(lineItems) { + filterOutQuotePageDiscountPart(lineItems) { const filteredLineItems = lineItems?.filter((item) => { - return !item?.partType?.includes(partTypeStrings.SERVICE_PACKAGE_DISCOUNT); + return !item?.partType?.includes(partTypeStrings.QUOTE_PAGE_DISCOUNT); }); return filteredLineItems; }, From 3630f1b3a72891efde1b6ca2a4775a0313dc4cfa Mon Sep 17 00:00:00 2001 From: CarlNation Date: Thu, 13 Nov 2025 01:14:14 -0500 Subject: [PATCH 3/6] CASH-1884 CASH-1884 When a customer navigates from 2.0 to heritage for insurance, receives a 6 digit referral and then returns to 2.0 without using the normal application navigation buttons, then the load session will fail because 2.0 did not use the new referral number when making the request. --- .../methods/helpers/consume-referral-info.js | 24 ++++++++++++++++--- .../methods/helpers/handle-heritage-return.js | 4 +++- src/styles/ux-variables.scss | 4 ++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/router/methods/helpers/consume-referral-info.js b/src/router/methods/helpers/consume-referral-info.js index 5c1dceafc..93ba6f7d6 100644 --- a/src/router/methods/helpers/consume-referral-info.js +++ b/src/router/methods/helpers/consume-referral-info.js @@ -3,15 +3,33 @@ import { queryStrings } from "@/constants/query-strings"; import store from "@/store"; import { storeMutations } from "@/constants/store-mutations"; import { updateOrCreateFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; export async function consumeReferralQuerystrings() { - const referralNumber = getQuerystringParameter(queryStrings.REFERRAL_NUMBER); - const parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT); - const correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID); + var referralNumber = getQuerystringParameter(queryStrings.REFERRAL_NUMBER); + var parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT); + var correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID); + var referralDate = null; + + // If no referral number in querystring, check if heritage funnel updated last. + // This would indicate a customer that went to heritage but did not return through the + // normal route. ie: left the site in search of a discount and returned without querystrings. + const didHeritageFunnelUpdateLast = getFunnelCookie()?.DidHeritageFunnelUpdateLast; + if (didHeritageFunnelUpdateLast && !referralNumber) { + referralNumber = getFunnelCookie().ReferralNumber; + parentAccount = getFunnelCookie().ReferralParentAccountNumber; + correlationId = getFunnelCookie().ReferralCorrelationId; + referralDate = getFunnelCookie().ReferralDate; + } + if (referralNumber) { store.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber); store.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccount); store.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, correlationId); + + if (referralDate) { + store.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate); + } // log(" --update cookie"); updateOrCreateFunnelCookie(); } diff --git a/src/router/methods/helpers/handle-heritage-return.js b/src/router/methods/helpers/handle-heritage-return.js index 7914c8e0e..45f98bbe1 100644 --- a/src/router/methods/helpers/handle-heritage-return.js +++ b/src/router/methods/helpers/handle-heritage-return.js @@ -2,11 +2,13 @@ import { queryStrings } from "@/constants/query-strings"; import { consumeReferralQuerystrings } from "@/router/methods/helpers/consume-referral-info"; import { loadSessionIfPresent } from "@/helpers/heritage-integration/order-helper"; import { routeData } from "@/router/constants/routes"; +import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; export async function handleHeritageReturn(to, from) { const fromHeritageFlag = to.query[queryStrings.FROM_HERITAGE]; + const didHeritageFunnelUpdateLast = getFunnelCookie()?.DidHeritageFunnelUpdateLast; - if (fromHeritageFlag) { + if (fromHeritageFlag || didHeritageFunnelUpdateLast) { // Get new referral info from querystring in case passed there. await consumeReferralQuerystrings(); diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 0c275ad51..770d95b42 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -123,8 +123,8 @@ $body-color: $gray-600; //Fonts $font-family-sans-serif: UrbanistRegular, Arial, Helvetica, sans-serif; -$font-family-monospace: - UrbanistRegular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +$font-family-monospace: UrbanistRegular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", + monospace; // stylelint-enable value-keyword-case $font-family-base: $font-family-sans-serif; $font-family-code: $font-family-monospace; From d1fea91e3012dba029d5e943b11d672031288a1f Mon Sep 17 00:00:00 2001 From: AdamCaouetteSafelite Date: Fri, 14 Nov 2025 03:35:13 -0500 Subject: [PATCH 4/6] CASH-1757: changed afterpay banner and modal --- src/digital-components/modal/modal.vue | 2 + .../afterpay-modal-banner.vue | 247 ++++++++++++++---- src/layouts/quote/quote.vue | 6 +- 3 files changed, 197 insertions(+), 58 deletions(-) diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 867e73c75..3c3efd05b 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -33,6 +33,7 @@