From 8062894cca8070ac91462122bb4012a3743fab38 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 29 Jan 2024 21:23:55 -0500 Subject: [PATCH 001/112] CSR-1511: use coverage data from store --- src/store/index.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0e93e6c4d..4d627e7e9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1453,7 +1453,7 @@ export const actions = { ) { const order = context.state.order; const vehicle = context.state.order.vehicle; - + const payment = context.state.order.payment; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), @@ -1475,15 +1475,15 @@ export const actions = { endDate: endDate, shopAppointmentType: shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, - parentAccountNumber: context.getters.payment.parentAccountNumber, + parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, coverage: { - status: "", - deductible: 0, - additionalAuthFlag: "", + status: payment.insuranceCoverage.coverageStatus, + deductible: order.policy.currentDeductible, + additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, @@ -1521,6 +1521,7 @@ export const actions = { getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) { const order = context.state.order; const vehicle = context.state.order.vehicle; + const payment = context.state.order.payment; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), @@ -1539,15 +1540,15 @@ export const actions = { startDate: startDate, endDate: endDate, applicationName: applicationConfig.APPLICATION_NAME, - parentAccountNumber: context.getters.payment.parentAccountNumber, + parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, coverage: { - status: "", - deductible: 0, - additionalAuthFlag: "", + status: payment.insuranceCoverage.coverageStatus, + deductible: order.policy.currentDeductible, + additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, @@ -1566,6 +1567,7 @@ export const actions = { }, zipCode: order.serviceLocation.zipCode, }; + return globalMethods.callHttpClient({ method: endpoints.GetMobileTimeSlots.method, endpoint: endpoints.GetMobileTimeSlots.url, From 6839602ec032d7acd8f9fc44d17b6e4bdfaaced3 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 29 Jan 2024 22:03:41 -0500 Subject: [PATCH 002/112] CSR-1285: replace hard-coded account no. with State one --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 4d627e7e9..bb4444062 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1343,7 +1343,7 @@ export const actions = { getMobileFeePart(context, { pageNameToLog }) { const damageType = context.getters.damage.isRepair ? "Repair" : "Replace"; const parentAccountNumber = context.getters.payment.parentAccountNumber; - const billToAccountNumber = 87291; // TODO: MAKE THIS REAL + const billToAccountNumber = context.getters.payment.billToAccountNumber; return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, From 00b5038ff7b72406d7599d536bc01a13dafaa342 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:50:20 -0500 Subject: [PATCH 003/112] CSR-1072 was not setting BillToAccount CSR-1072 was not setting BillToAccount --- src/store/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index bb4444062..cdd5733ba 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -523,6 +523,8 @@ export const mutations = { state.order.payment.parentAccountNumber = sessionInformation.order.payment.parentAccountNumber; + state.order.payment.billToAccountNumber = + sessionInformation.order.payment.billToAccountNumber; state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos; state.order.serviceLocation.address = From 364e85614b288e6b835ca95d3c76c45c486f336c Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 13:25:25 -0500 Subject: [PATCH 004/112] CSR-1072 save coverage status value as string CSR-1072 save coverage status value as string --- src/constants/coverage-status.js | 18 ++++++++++++++++++ src/store/index.js | 6 ++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/constants/coverage-status.js diff --git a/src/constants/coverage-status.js b/src/constants/coverage-status.js new file mode 100644 index 000000000..7cf757aed --- /dev/null +++ b/src/constants/coverage-status.js @@ -0,0 +1,18 @@ +const coverageStatus = { + PENDING: "Pending", + NOCOMP: "NoComp", + VERIFIED: "Verified", +}; + +export function coverageStatusValue(intCoverageStatus) { + switch (intCoverageStatus) { + case 0: + return coverageStatus.PENDING; + case 1: + return coverageStatus.NOCOMP; + case 2: + return coverageStatus.VERIFIED; + default: + return null; + } +} diff --git a/src/store/index.js b/src/store/index.js index cdd5733ba..5339f7973 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -29,6 +29,7 @@ import { } from "@/helpers/promotions-helper"; import { getDateDifferenceInDays } from "@/helpers/date-helper"; import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations"; +import { coverageStatusValue } from "@/constants/coverage-status"; // Export State const getDefaultState = () => { return { @@ -559,8 +560,9 @@ export const mutations = { state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance; state.order.payment.insuranceCoverage.isVerified = sessionInformation?.order.payment.insuranceCoverage.isVerified; - state.order.payment.insuranceCoverage.coverageStatus = - sessionInformation?.order.payment.insuranceCoverage.coverageStatus; + state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue( + sessionInformation?.order.payment.insuranceCoverage.coverageStatus + ); state.order.payment.insuranceCoverage.coverageVerificationType = sessionInformation?.order.payment.insuranceCoverage.coverageVerificationType; From a0acb7ffd470e0087d0d0f330c30c850e72e1889 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:19:21 -0500 Subject: [PATCH 005/112] CSR-1072 back button for end to end CSR-1072 back button for end to end should go back to heritage --- src/layouts/service-location/service-location.vue | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 4e890e531..bf9b9495c 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -138,6 +138,7 @@ import { getServiceabilityDetails, getShopProviderData, } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; +import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { Provider } from "@/layouts/service-location/classes/provider"; @@ -438,7 +439,14 @@ export default { this.recalibrationInformationModal.openModal(); }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + if (store.getters.order.payment.isInsurance) { + navigateToHeritageFunnel({shouldSaveSession: false}); + } else { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.$route + ); + } }, updateAndSaveSupportingItems() { const supportingItems = store.getters.lineItems.supportingItems; From 0d02b5cd7aca02f78ddee1122d06be79ed03ed9f Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:33:32 -0500 Subject: [PATCH 006/112] prettier --- src/layouts/service-location/service-location.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index bf9b9495c..a12e9ff78 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -440,7 +440,7 @@ export default { }, backButtonAction() { if (store.getters.order.payment.isInsurance) { - navigateToHeritageFunnel({shouldSaveSession: false}); + navigateToHeritageFunnel({ shouldSaveSession: false }); } else { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, From ac687e55454d448a9313cb3eb877c009d1d2453c Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:40:23 +0530 Subject: [PATCH 007/112] CSR-1601 BillToAccountNumber --- src/constants/application-config.js | 1 + src/constants/store-actions.js | 1 + src/constants/store-mutations.js | 1 + src/global-methods.js | 7 +++++-- src/layouts/payment-method/payment-method.vue | 4 ++-- .../promo-modal-question/promo-modal-question.vue | 4 ++-- src/layouts/payment/payment.vue | 2 +- src/layouts/quote/quote.vue | 5 +++++ src/store/index.js | 8 ++++++++ 9 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 244882509..b8a59a129 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -11,6 +11,7 @@ const applicationConfig = { PAGE_QUERYSTRING: "fmgPage", SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass", CASH_PARENT_ACCOUNT_NUMBER: 167132, + CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER: "87291", MY_ACCOUNT: process.env.VUE_APP_MY_ACCOUNT, PIA_RESPONSE_URL: location.protocol + diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 9b6fdb865..d77237170 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -80,6 +80,7 @@ const storeActions = { SAVE_PAYMENT_TYPE: "savePaymentType", SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice", SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber", + SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber", SAVE_SUPPORTING_ITEMS: "saveSupportingItems", SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING: "saveSupportingItemsSuppressingStateResetting", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 5b0b66509..0b0338fef 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -46,6 +46,7 @@ const storeMutations = { UPDATE_REFERRAL_DATE: "updateReferralDate", UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", + UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber", UPDATE_EON: "updateEON", UPDATE_IS_INSURANCE: "updateIsInsurance", UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", diff --git a/src/global-methods.js b/src/global-methods.js index f2821343d..1d145476b 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,10 +22,13 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; - + const localhostserviceapi = "https://localhost:44317"; axios({ method: method, - url: cfDistroUrl + endpoint, + url: + (endpoint == "/schedule/api/v1/schedule/mobile-time-slots" + ? localhostserviceapi + : cfDistroUrl) + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 3bde800bf..75a8ffa0c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -244,7 +244,7 @@ export default { const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, serviceLocationCity: store.getters.order.serviceLocation.city, @@ -405,7 +405,7 @@ export default { await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: this.$store.getters.order.serviceLocation.provider.providerNumber, appointmentType: this.$store.getters.order.serviceLocation.appointmentType, diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index b4b02b3ed..9bd92cec3 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -255,14 +255,14 @@ export default { this.availableVaps, "payment-method" ); - + console.log(store.getters.payment.billToAccountNumber); if (promoCodeData.isValid) { const pricedLineItemsToTax = []; pricedLineItemsToTax.push(...promoCodeData.promoCode); const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index 365dccf01..a0f888b04 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -356,7 +356,7 @@ export default { const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, serviceLocationCity: store.getters.order.serviceLocation.city, diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5c6b2d744..12ee04c8d 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -276,6 +276,11 @@ export default { applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, false ); + this.dispatchStoreAction( + this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER, + applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER, + false + ); } if ( diff --git a/src/store/index.js b/src/store/index.js index 5339f7973..e900f2093 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -249,6 +249,9 @@ export const mutations = { updateParentAcctNumber(state, parentAcctNumber) { state.order.payment.parentAccountNumber = parentAcctNumber; }, + updateBillToAcctNumber(state, billToAcctNumber) { + state.order.payment.billToAccountNumber = billToAcctNumber; + }, updateEON(state, eon) { state.order.eon = eon; }, @@ -1484,6 +1487,7 @@ export const actions = { lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, + billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, @@ -1549,6 +1553,7 @@ export const actions = { lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, + billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, @@ -2123,6 +2128,9 @@ export const actions = { saveParentAccountNumber(context, parentAccountNumber) { context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber); }, + saveBillToAccountNumber(context, billToAccountNumber) { + context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber); + }, saveSupportingItems(context, supportingItems) { if (!deepEqual(supportingItems, context.state.order.lineItems.supportingItems)) { From 80044b34c7ac58d5659dea1ffe2031ff54970bda Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:52:05 +0530 Subject: [PATCH 008/112] Update global-methods.js --- src/global-methods.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 1d145476b..6da8c0b33 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,13 +22,9 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; - const localhostserviceapi = "https://localhost:44317"; axios({ method: method, - url: - (endpoint == "/schedule/api/v1/schedule/mobile-time-slots" - ? localhostserviceapi - : cfDistroUrl) + endpoint, + url: cfDistroUrl + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, From c644d3a7f8c556319481146a8cb009ecf8383201 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:59:26 +0530 Subject: [PATCH 009/112] Revert "Update global-methods.js" --- src/global-methods.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/global-methods.js b/src/global-methods.js index 6da8c0b33..f2821343d 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,6 +22,7 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; + axios({ method: method, url: cfDistroUrl + endpoint, From ed447dd7630d169c6c9ef20f1803827f7bbb9af6 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 21:15:53 +0530 Subject: [PATCH 010/112] Update promo-modal-question.vue --- .../payment-method/promo-modal-question/promo-modal-question.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index 9bd92cec3..adb9bee3d 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -255,7 +255,6 @@ export default { this.availableVaps, "payment-method" ); - console.log(store.getters.payment.billToAccountNumber); if (promoCodeData.isValid) { const pricedLineItemsToTax = []; pricedLineItemsToTax.push(...promoCodeData.promoCode); From 53d7aea7e103901097e4881b1db3efe2b8cd13d8 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:27:35 -0500 Subject: [PATCH 011/112] CSR-1072 CSR-1072 the sessionId is not getting saved during loadsession. this is a problem when returning from heritage. the vuex sessionId ends up blank and we do not load the dynamoDb session data because we pass a default guid to load-session --- src/store/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index 5339f7973..b61ea9084 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -577,6 +577,10 @@ export const mutations = { state.applicationUser.pageData = sessionInformation.applicationUser.pageData; state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage; + if (sessionInformation.applicationUser.savedSessionId) { + state.applicationUser.savedSessionId = sessionInformation.applicationUser.savedSessionId; + } + state.order.schedule.date = sessionInformation.order.schedule?.date; state.order.schedule.startTime = sessionInformation.order.schedule?.startTime; state.order.schedule.endTime = sessionInformation.order.schedule?.endTime; From 4eea4d4af8b34a994e867f9ea54034e36da46043 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:33:55 -0500 Subject: [PATCH 012/112] prettier --- src/store/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index b61ea9084..86aa1a669 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -578,7 +578,8 @@ export const mutations = { state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage; if (sessionInformation.applicationUser.savedSessionId) { - state.applicationUser.savedSessionId = sessionInformation.applicationUser.savedSessionId; + state.applicationUser.savedSessionId = + sessionInformation.applicationUser.savedSessionId; } state.order.schedule.date = sessionInformation.order.schedule?.date; From 48bb6ed7e7f2dfcfc88344261cbb4e00a2d4f6fb Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:27:31 -0500 Subject: [PATCH 013/112] CSR-1072 * Get set parentAccount in cookie correctly * Do not call order-items pricing when mobile fee returned no results * Allow insurance prereq to exclude supportingItems --- src/helpers/heritage-integration/cookie-helper.js | 2 +- .../service-location-helper.js | 4 ++++ src/layouts/service-location/service-location.vue | 12 ++++++++++-- src/store/index.js | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js index abb1c0a67..579993795 100644 --- a/src/helpers/heritage-integration/cookie-helper.js +++ b/src/helpers/heritage-integration/cookie-helper.js @@ -18,7 +18,7 @@ export function updateOrCreateFunnelCookie() { ReferralNumber: store.getters.order.referralNumber, ReferralDate: store.getters.order.referralDate, ReferralCorrelationId: store.getters.order.referralCorrelationId, - ReferralParentAccountNumber: store.getters.order.accountNumber, + ReferralParentAccountNumber: store.getters.order.payment.parentAccountNumber, HasDelayedClaimRegistration: wasClaimRegistrationDelayed, SuppressConceptFunnel: shouldSuppressConceptFunnel, SavedSessionId: store.getters.applicationUser.savedSessionId, diff --git a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js index 26f2e6962..6f65b2646 100644 --- a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js +++ b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js @@ -16,6 +16,10 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { false ); + if (mobileFeePart.data === null || mobileFeePart.data === undefined || mobileFeePart.data === "") { + return null; + } + // Get the Mobile Fee Part Price const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 3d0d5f588..4096f4e1d 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -349,11 +349,19 @@ export default { }, methods: { arePagePrerequisitesValid() { - return ( + // insurance drops the recycle fee on replace orders so it won't be in supportingItems + if (store.getters.payment.isInsurance && !store.getters.order.damage.isRepair) { + return ( + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null); + } + else { + return ( store.getters.lineItems.supportingItems !== null && store.getters.order.serviceLocation.zipCode !== null && store.getters.payment.isInsurance !== null - ); + ); + } }, setData(zipCodeData, serviceabilityDetails, mobileFeePart, shopProviderData) { if (zipCodeData) { diff --git a/src/store/index.js b/src/store/index.js index eeb70ec0a..cff4c71ea 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2229,6 +2229,7 @@ export const actions = { const vehicle = context.getters.order.vehicle; + // TODO: Insurance pricing...`ParentAccountNumber=${context.getters.order.payment.parentAccountNumber}` let queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + `&CTU=${ctuToUse}` + From 68b1cbc3c76ecb60e21d990b2e51f544bbc6708f Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:33:34 -0500 Subject: [PATCH 014/112] prettier --- .../service-location-helper.js | 6 +++++- src/layouts/service-location/service-location.vue | 14 +++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js index 6f65b2646..e92349ddf 100644 --- a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js +++ b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js @@ -16,7 +16,11 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { false ); - if (mobileFeePart.data === null || mobileFeePart.data === undefined || mobileFeePart.data === "") { + if ( + mobileFeePart.data === null || + mobileFeePart.data === undefined || + mobileFeePart.data === "" + ) { return null; } diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 4096f4e1d..38f46424f 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -352,14 +352,14 @@ export default { // insurance drops the recycle fee on replace orders so it won't be in supportingItems if (store.getters.payment.isInsurance && !store.getters.order.damage.isRepair) { return ( - store.getters.order.serviceLocation.zipCode !== null && - store.getters.payment.isInsurance !== null); - } - else { + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null + ); + } else { return ( - store.getters.lineItems.supportingItems !== null && - store.getters.order.serviceLocation.zipCode !== null && - store.getters.payment.isInsurance !== null + store.getters.lineItems.supportingItems !== null && + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null ); } }, From acd68f97d958f207cc2c93f801866bbbee91006c Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 7 Feb 2024 16:02:22 -0500 Subject: [PATCH 015/112] Auto-route only as far as Quote for cash users. --- .../heritage-integration/navigation-helper.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 8fdfc40bb..bd2525ac2 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -123,17 +123,21 @@ async function getLatestPageForRedirection() { const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE); const skipVin = await skipVinLookup(); + const isInsuranceUser = !!store.getters.order.payment.isInsurance; if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE; } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { - if (scheduleComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SCHEDULE; - } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SERVICE_LOCATION; - } else if (quoteComponent.methods.arePagePrerequisitesValid()) { + if (isInsuranceUser) { + if (scheduleComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.SCHEDULE; + } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.SERVICE_LOCATION; + } + } + if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.CAPABILITY_QUESTIONS; From 5e09c22e3388c86d2ee80473de0f875bae4b7749 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 7 Feb 2024 18:24:35 -0500 Subject: [PATCH 016/112] CSR-1952: include promo cart items into selected package cart items --- src/fmg-components/cart/cart.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 2d268e81a..65701db71 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -167,6 +167,12 @@ export default { }); }); + if (this.promoCartItems) { + this.promoCartItems.forEach((promoCartItem) => { + vapsCartItemsForSelectedPackage.push(promoCartItem); + }); + } + return vapsCartItemsForSelectedPackage; }, getCmsContentForVapsType(vapsType) { From 11b7f52c8fd7feae1bb8684556e918d55df13793 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 8 Feb 2024 10:51:33 -0500 Subject: [PATCH 017/112] Also remove ability for non-cash users to be routed past quote. --- src/helpers/heritage-integration/navigation-helper.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index bd2525ac2..80734adf8 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -123,20 +123,12 @@ async function getLatestPageForRedirection() { const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE); const skipVin = await skipVinLookup(); - const isInsuranceUser = !!store.getters.order.payment.isInsurance; if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE; } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { - if (isInsuranceUser) { - if (scheduleComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SCHEDULE; - } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SERVICE_LOCATION; - } - } if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { From 2dc8d429714fc776f45cdd56b2552b2cedcea8d7 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 9 Feb 2024 20:51:11 +0530 Subject: [PATCH 018/112] CSR-1438 make email optional --- src/constants/experiments.js | 1 + .../textbox-question/textbox-question.vue | 8 +++++++- .../address-lookup/address-lookup.spec.js | 13 +++++++++++++ src/layouts/address-lookup/address-lookup.vue | 6 +++++- .../customer-questions/customer-questions.vue | 5 ++++- src/layouts/estimate/estimate.spec.js | 17 +++++++++++++++-- src/layouts/estimate/estimate.vue | 5 +++-- .../license-plate-lookup.spec.js | 14 ++++++++++++-- .../license-plate-lookup.vue | 4 +++- src/layouts/vin-lookup/vin-lookup.spec.js | 7 +++++++ src/layouts/vin-lookup/vin-lookup.vue | 5 +++-- src/mixins/vin-pages-mixin.js | 12 ++++++++++++ 12 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/constants/experiments.js b/src/constants/experiments.js index b702b11bb..18ca6387d 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -8,6 +8,7 @@ const experimentSettings = { DISPLAY_AVAILABILITY_INDICATORS: "DisplayAvailabilityIndicators", PIA_EXPERIENCE: "PIA Experience", SUBMIT_ORDER_ENABLE_PIA: "SubmitOrder_Enable_PIA", + IS_EMAIL_OPTIONAL: "isEmailOptional", }; const experimentTriggers = { diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 11f232135..da41fe10b 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -121,6 +121,10 @@ export default { hideInput: Boolean, centerErrorMessage: Boolean, keyDownHandler: Function, + isEmailOptional: { + type: Boolean, + default: false, + }, }, setup(props) { const uuid = uuidv4(); @@ -193,7 +197,9 @@ export default { }, computed: { questionText() { - return this.getCmsContent(this.cmsWidgetName, "QuestionText"); + return this.isEmailOptional + ? this.getCmsContent(this.cmsWidgetName, "QuestionText") + " (optional)" + : this.getCmsContent(this.cmsWidgetName, "QuestionText"); }, value: { get: function () { diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index cce68d793..731e664dc 100644 --- a/src/layouts/address-lookup/address-lookup.spec.js +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -10,6 +10,7 @@ import { storeMutations } from "@/constants/store-mutations"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import store from "@/store"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { experimentSettings } from "@/constants/experiments"; jest.mock("@/helpers/damage-helper", () => ({ isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), @@ -641,6 +642,17 @@ describe("address-lookup.vue", () => { }); }); +const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, +}; + function setupMocks({ isZipValid = true, isZipServiceable = true, @@ -709,6 +721,7 @@ function setupMocks({ }, }, }, + mixins: [mockMixin], }) ); diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index de0e8d5aa..807bdc5ce 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -20,7 +20,11 @@ - + + :isRequired="!isEmailOptional" + :validationRules="validationRules" + :isEmailOptional="isEmailOptional" />
@@ -79,6 +81,7 @@ export default { }), }, validationRules: String, + isEmailOptional: Boolean, }, computed: { customerModel: { diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index 7d395e88d..b8517d833 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -11,6 +11,7 @@ import { settleAllPromises } from "@/helpers/layout-helper.js"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import baseMixin from "../../mixins/base-mixin"; import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js"; +import { experimentSettings } from "@/constants/experiments"; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ @@ -273,12 +274,24 @@ function setupMocks({ Answers: cmsAnswers, FunnelFooterWidget: FunnelFooterWidget, }; - + const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, + }; const apiPromise = Promise.resolve({ cmsContent }); settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [baseMixin] }); + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, mockMixin], + }); mountOptions["attachTo"] = document.body; const wrapper = shallowMount(estimate, mountOptions); diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 410c4d325..d2766f730 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -52,9 +52,10 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="emailAddress" inputId="emailAddress" - isRequired + :isRequired="!IsEmailOptional" disableAutoFill - validationRules="email-address-required|email-address-format" /> + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> "loader.gif"); jest.mock("@/assets/img/windshield.png", () => "windshield.png"); @@ -692,11 +693,20 @@ function setupMocks({ }; const apiPromise = Promise.resolve(apiResponses); - + const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, + }; settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions(mountOptionsMockData); + const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [mockMixin] }); mountOptions["attachTo"] = document.body; // append wrapper to document.body to test DOM methods const wrapper = shallowMount(licensePlateLookup, mountOptions); diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 811dbea7b..37d93cc8b 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -34,7 +34,9 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="email" customInputId="email" - validationRules="email-address-required|email-address-format" /> + :isRequired="!IsEmailOptional" + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index f25bc68db..1d7d3f493 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -3,6 +3,7 @@ import vinLookup from "./vin-lookup.vue"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js"; import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { experimentSettings } from "@/constants/experiments"; import store from "@/store"; @@ -378,5 +379,11 @@ function mockOutStubFunctions(wrapper) { const mockMixin = { methods: { getCmsContent: jest.fn(() => "placeholder CMS content"), + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), }, }; diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index c809bae70..ae197aeb0 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -53,8 +53,9 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="emailAddress" customInputId="emailAddress" - isRequired - validationRules="email-address-required|email-address-format" /> + :isRequired="!IsEmailOptional" + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> diff --git a/src/mixins/vin-pages-mixin.js b/src/mixins/vin-pages-mixin.js index a0a435000..98eb7a75b 100644 --- a/src/mixins/vin-pages-mixin.js +++ b/src/mixins/vin-pages-mixin.js @@ -2,8 +2,20 @@ import { storeActions } from "@/constants/store-actions.js"; import store from "@/store"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; +import { experimentSettings } from "@/constants/experiments"; export default { + computed: { + IsEmailOptional() { + const emailOptional = this.getSettingValue(experimentSettings.IS_EMAIL_OPTIONAL); + return emailOptional === "true"; + }, + EmailValidationRules() { + return this.IsEmailOptional + ? "email-address-format" + : "email-address-required|email-address-format"; + }, + }, methods: { async navigateForwardWithSingleCarMatch() { const pageName = this.$options?.name; From 37a59cc74e4e221b5e3a1884836d359863f5ebea Mon Sep 17 00:00:00 2001 From: Sneha Date: Fri, 9 Feb 2024 21:27:13 +0530 Subject: [PATCH 019/112] merge to release --- src/layouts/payment-method/payment-method.vue | 1 + .../promo-modal-question.spec.js | 143 ++++++++++++++++++ .../promo-modal-question.vue | 76 ++++++---- src/layouts/quote/quote.spec.js | 33 +++- src/layouts/quote/quote.vue | 75 +++++++-- .../service-package-question.spec.js | 51 +++++++ .../service-package-question.vue | 3 + 7 files changed, 334 insertions(+), 48 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 3bde800bf..ee0eee749 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -33,6 +33,7 @@ class="small mt-4" v-model="lineItems" :availableVaps="availableVaps" + pageName="payment-method" modalWidgetName="PromoModalWidget" />
diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js index 16d170e82..1dcc2ac70 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js @@ -1,5 +1,25 @@ import { mount, shallowMount } from "@vue/test-utils"; import promoModalQuestion from "./promo-modal-question"; +import { storeActions } from "@/constants/store-actions"; +import baseMixin from "@/mixins/base-mixin.js"; + +let mockReturnsForStoreActions = {}; + +jest.mock("@/mixins/base-mixin", () => ({ + ...jest.requireActual("@/mixins/base-mixin"), + methods: { + dispatchStoreActionWithLogging: jest.fn( + (action, { promoCode, addableVaps }, pageNameToLog, someBool) => { + return mockReturnsForStoreActions[action]; + } + ), + }, +})); + +afterEach(() => { + // reset store action returns + mockReturnsForStoreActions = {}; +}); jest.mock("@/digital-components/textbox-question/textbox-question", () => ({ getCmsContent: jest.fn((widgetName, cmsFieldName) => { @@ -79,4 +99,127 @@ describe("promo-modal-question.vue", () => { // Assert expect(wrapper.emitted("update:modelValue")).toEqual([[lineItems]]); }); + it("focuses on the input element when focusOnPromoInput is called", async () => { + // Arrange + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + const focusMock = jest.fn(); + const inputMock = { focus: focusMock }; + + // Mock document.getElementById to return the inputMock + jest.spyOn(document, "getElementById").mockReturnValue(inputMock); + + //Act + + wrapper.vm.focusOnPromoInput(); + await wrapper.vm.$nextTick(); + + //Assert + expect(focusMock).toHaveBeenCalled(); + }); + it("returns a validate response on applying promo", async () => { + // Arrange + const newPromo = "testPromo"; + const pageNameToLog = "testPage"; + const validateResponse = { orderPromos: [] }; + const addableVaps = []; + mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = + validateResponse; + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + // Act + + wrapper.vm.getPromoCodeData(); + + const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA, + { + newPromo, + lineItems, + addableVaps, + }, + pageNameToLog, + false + ); + + // Assert + expect(promoValidationResponse).toEqual(validateResponse); + }); + test("If promocode is valid return taxed lineItems", async () => { + //Arrange + const taxedlineItems = {}; + + mockReturnsForStoreActions[storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA] = + taxedlineItems; + + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + let promoCode = "1wiper0"; + const pricedLineItemsToTax = []; + + pricedLineItemsToTax.push(promoCode); + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + + attachTo: document.body, + }); + wrapper.vm.addPromoCode(); + + const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: "87291", + providerNumber: 2, + appointmentType: "IN_SHOP", + serviceLocationCity: "city", + serviceLocationState: "state", + serviceLocationZipCode: "12345", + pricedLineItems: pricedLineItemsToTax, + }, + + "payment-method", + + false + ); + + // Assert + + expect(taxedLineItems).toEqual(taxedlineItems); + }); }); diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index b4b02b3ed..da8d344e9 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -100,6 +100,12 @@ export default { modelValue: Object, modalWidgetName: String, availableVaps: Object, + pageName: String, + taxPromos: { + type: Boolean, + required: false, + default: true, + }, }, computed: { promoLinkText() { @@ -253,44 +259,52 @@ export default { this.promoCode, this.lineItems, this.availableVaps, - "payment-method" + this.pageName ); if (promoCodeData.isValid) { - const pricedLineItemsToTax = []; - pricedLineItemsToTax.push(...promoCodeData.promoCode); - const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, - { - billToAccountNumber: "87291", - providerNumber: - store.getters.order.serviceLocation.provider.providerNumber, - appointmentType: store.getters.order.serviceLocation.appointmentType, - serviceLocationCity: store.getters.order.serviceLocation.city, - serviceLocationState: store.getters.order.serviceLocation.state, - serviceLocationZipCode: store.getters.order.serviceLocation.zipCode, - pricedLineItems: pricedLineItemsToTax, - }, - "payment-method", - false - ); + if (this.taxPromos) { + const pricedLineItemsToTax = []; + pricedLineItemsToTax.push(...promoCodeData.promoCode); + const taxedLineItems = + await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: "87291", + providerNumber: + store.getters.order.serviceLocation.provider.providerNumber, + appointmentType: + store.getters.order.serviceLocation.appointmentType, + serviceLocationCity: store.getters.order.serviceLocation.city, + serviceLocationState: store.getters.order.serviceLocation.state, + serviceLocationZipCode: + store.getters.order.serviceLocation.zipCode, + pricedLineItems: pricedLineItemsToTax, + }, + "payment-method", + false + ); - // Match all line items to the line items as they are in the store - // and rebuild the original structure. - this.lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, this.lineItems); - const taxedVaps = mapTaxedLineItemsToStoreFormat( - taxedLineItems, - this.availableVaps - ); + // Match all line items to the line items as they are in the store + // and rebuild the original structure. + this.lineItems = mapTaxedLineItemsToStoreFormat( + taxedLineItems, + this.lineItems + ); + const taxedVaps = mapTaxedLineItemsToStoreFormat( + taxedLineItems, + this.availableVaps + ); - const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( - promoCodeData.promoCode, - taxedVaps, - this.lineItems - ); + const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( + promoCodeData.promoCode, + taxedVaps, + this.lineItems + ); + this.lineItems.vaps?.push(...getVaps); + } this.lineItems?.promos.push(...promoCodeData.promoCode); - this.lineItems.vaps?.push(...getVaps); this.closeModal(); } else { this.getErrorMessage(promoCodeData.errorCode, promoCodeData.additionalInfo); diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index dc30985a5..be68267ae 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -133,8 +133,6 @@ describe("quote.vue", () => { }; }); - wrapper.vm.pricedGlassParts = []; - //Act await wrapper.vm.forwardButtonAction(); @@ -172,8 +170,6 @@ describe("quote.vue", () => { }; }); - wrapper.vm.pricedGlassParts = []; - //Act await wrapper.vm.forwardButtonAction(); @@ -288,8 +284,8 @@ describe("quote.vue", () => { ); //Assert - expect(wrapper.vm.pricedGlassParts !== null).toBe(true); - expect(wrapper.vm.supportingItems !== null).toBe(true); + expect(wrapper.vm.lineItems !== null).toBe(true); + expect(wrapper.vm.availableVaps !== null).toBe(true); expect(wrapper.vm.availableLineItems !== null).toBe(true); // This should have its own test //expect(vm.isInsuranceSelected !== null).toBe(true); @@ -548,6 +544,31 @@ describe("quote.vue", () => { //Assert expect(wrapper.vm.isInsuranceSelected).toBe(true); }); + test("On forward button action save promos", async () => { + //Arrange + store.getters.payment = { + insuranceCoverage: {}, + isInsurance: false, + }; + store.getters.order = { + lineItems: [], + payment: { + parentAccountNumber: 167132, + }, + }; + const { wrapper } = setupMocks({ + customMountOptions: { + router: { + navigateWithSaving: jest.fn(), + }, + route: { quote }, + }, + }); + + wrapper.vm.forwardButtonAction(); + + expect(wrapper.vm.lineItems.promos !== null).toBe(true); + }); }); function setupMocks({ customMountOptions }) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5c6b2d744..8d3dbcee3 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -39,6 +39,15 @@ cmsWidgetName="AfterpayModalWidget" :lineItems="availableLineItems" /> + + { vm.setCmsContent(resultMap.cmsContent); - vm.pricedGlassParts = nullSafeGlassParts; - vm.supportingItems = resultMap.supportingItems; + vm.availableVaps = availableVaps; + vm.lineItems = lineItems; vm.availableLineItems = pricingResults; vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems); @@ -208,15 +224,17 @@ export default { data() { return { isInsuranceSelected: null, - selectedVaps: null, availableLineItems: null, - supportingItems: null, - pricedGlassParts: null, + lineItems: [], + availableVaps: [], }; }, computed: { allActivePromos() { - return this.$store.getters.order.lineItems.promos ?? []; + return this.lineItems.promos ?? []; + }, + lineItemsCloneForWatcher() { + return Object.assign({}, this.lineItems); }, }, methods: { @@ -258,7 +276,7 @@ export default { } }, vapsItemsSelectedAction(vapsItemsSelected) { - this.selectedVaps = vapsItemsSelected; + this.lineItems.vaps = vapsItemsSelected; }, backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); @@ -285,15 +303,23 @@ export default { this.supportingItems = this.filterOutFees(this.supportingItems); } - if (this.pricedGlassParts.length > 0) { + if (this.lineItems.glassParts?.length > 0) { this.dispatchStoreAction( this.storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING, - this.pricedGlassParts, + this.lineItems.glassParts, false ); } - this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); + this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false); + this.dispatchStoreAction( + storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, + { + activePromos: this.lineItems.promos, + inactivePromos: this.$store.getters.order.payment.inactivePromos, + }, + false + ); const payment = this.$store.getters.payment; if (payment.isInsurance) { @@ -310,6 +336,32 @@ export default { } }, }, + watch: { + lineItemsCloneForWatcher: { + handler(newValue, oldValue) { + if ( + !oldValue || + oldValue.length == 0 || + !oldValue.vaps || + !newValue || + newValue.length == 0 + ) { + return; + } + if (oldValue.promos.length < newValue.promos.length) { + const oldPromoCodes = oldValue.promos.map( + (promoObject) => promoObject.promoCode + ); + const newlyActivatedPromoCodes = newValue.promos.filter( + (newPromo) => !oldPromoCodes.includes(newPromo.promoCode) + ); + const alert = createPromoSuccessAlert(newlyActivatedPromoCodes[0].promoCode); + this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); + } + }, + deep: true, + }, + }, components: { funnelHeader, navbar, @@ -322,6 +374,7 @@ export default { contentGroupModal, loadingModal, afterpayModalBanner, + promoModalQuestion, }, }; 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 c156ef34c..8163c6324 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 @@ -256,6 +256,57 @@ describe("service-package-question.vue", () => { // Assert expect(wrapper.vm.selectedPackageName).toBe("TierThree"); }); + it("should select default package if promos are added", async () => { + //Arrange + mockProps.activePromos != null; + const wrapper = setupMocks({ + mountOptionsMockData: { + store: { + getters: { + order: { + damage: { + isRepair: false, + glassToReplace: [{ glassLocation: "Windshield" }], + }, + }, + lineItems: { + vaps: [], + }, + hasAnyNonWindshieldGlassParts: false, + payment: { + isInsurance: false, + }, + }, + }, + }, + }); + + //Act + wrapper.setProps({ + activePromos: [ + { + discountedLineItemIds: [ + { + 0: "428ec73c-38e4-4e14-8703-a987b0391898", + 1: "79db94d7-163c-4408-a1ec-f83e58c11992", + }, + ], + partType: "PROMO_DISCOUNT", + promoCode: "1WIPER0", + partNumber: "WIPER DISCOUNT", + laborAmount: 0, + sellingPrice: -10, + kitPrice: 0, + salesTax: null, + }, + ], + }); + const selectDefaultPackageMock = jest.spyOn(wrapper.vm, "selectDefaultPackage"); + await nextTick(); + + //Assert + expect(selectDefaultPackageMock).toHaveBeenCalled(); + }); }); describe("service-package-question.vue, matching business rules for package display", () => { // mock scenarios in figma: 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 28727f155..6b84f3557 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -63,6 +63,9 @@ export default { this.selectDefaultPackage(); } }, + activePromos() { + this.selectDefaultPackage(); + }, selectedPackageName(newValue) { const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage); From 9f527ce18d211bb3348eda88b615a353d00d8ee3 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 9 Feb 2024 12:00:00 -0500 Subject: [PATCH 020/112] CSR-1952: rearrange promo link and promos applied into cart --- src/fmg-components/cart/cart.vue | 182 +++++++++++------- src/layouts/payment-method/payment-method.vue | 10 +- 2 files changed, 113 insertions(+), 79 deletions(-) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 65701db71..59a5c8646 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -13,78 +13,94 @@ {{ getFormattedAmount("", amountDue) }}
-
-
- - - {{ getFormattedAmount("", packagePrice) }} - -
+
+
+
+ + + {{ getFormattedAmount("", packagePrice) }} + +
- -
- {{ cartItem.name }} - - - -
+ +
+ <{{ cartItem.name }}> + + + +
- -
- {{ cartItem.name }} - - - - {{ recycleFeeCartItem.name }} - - {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }} -
+ +
+ {{ cartItem.name }} + + + + {{ recycleFeeCartItem.name }} + + {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }} +
- -
- {{ subtotalText }}{{ getFormattedAmount("", subTotal) }} -
-
- {{ salesTaxText }}{{ getFormattedAmount("", salesTax) }} -
-
- {{ amountPaidText }}{{ getFormattedAmount("", amountPaid) }} -
-
- {{ amountDueText }}{{ getFormattedAmount("", amountDue) }} + +
+ {{ subtotalText }}{{ getFormattedAmount("", subTotal) }} +
+
+ {{ salesTaxText }}{{ getFormattedAmount("", salesTax) }} +
+
+ {{ amountPaidText }}{{ getFormattedAmount("", amountPaid) }} +
+
+ {{ amountDueText }}{{ getFormattedAmount("", amountDue) }} +
+
+
+ Promo code <{{ promoCode }}> applied +
@@ -96,6 +112,7 @@ import textLink from "@/ux-components/text-link/text-link"; import textBlock from "@/digital-components/text-block/text-block"; import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; +import promoModalQuestion from "@/layouts/payment-method/promo-modal-question/promo-modal-question"; // Mixins import baseMixin from "@/mixins/base-mixin.js"; @@ -198,6 +215,12 @@ export default { this.$emit("update:modelValue", this.lineItems); }, + getPromoCodeList() { + if (this.$refs["promoModalQuestion"]) { + return this.$refs["promoModalQuestion"].getPromoCodeList(); + } + return []; + }, }, computed: { screenReaderTotalAmountDueText() { @@ -796,16 +819,23 @@ export default { }, deep: true, }, + lineItems: { + handler(newValue) { + this.$emit("update:modelValue", this.lineItems); + }, + deep: true, + }, }, components: { textBlock, textLink, contentGroupModal, + promoModalQuestion, }, }; - From d9b5902ea4acb3728cfa6702b982fb43a5424380 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Mon, 26 Feb 2024 09:35:33 -0500 Subject: [PATCH 063/112] CSR-1855 CSR-1855 route to a bailout page when an api call returns a 500. 500 errors cause the current page to hang. --- src/global-methods.js | 3 +- src/layouts/bailout/bailout.vue | 79 +++++++++++++++++++++++++++++++++ src/router/index.js | 11 ++++- 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/layouts/bailout/bailout.vue diff --git a/src/global-methods.js b/src/global-methods.js index f2821343d..6d0fc7c0c 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -51,6 +51,7 @@ export default { }, (error) => { console.error(error); + console.log("Error calling: " + endpoint + " payload: " + JSON.stringify(payload)); if (logApiCall) { analyticsMixIn.methods.pushEventToGA( @@ -61,7 +62,7 @@ export default { ); } - //router.navigateError(); + router.navigateError(); return reject(error.response); } ); diff --git a/src/layouts/bailout/bailout.vue b/src/layouts/bailout/bailout.vue new file mode 100644 index 000000000..bbd1670c3 --- /dev/null +++ b/src/layouts/bailout/bailout.vue @@ -0,0 +1,79 @@ + + + \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 2373b6e48..1af870e72 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -32,8 +32,14 @@ import analyticsMixin from "@/mixins/analytics-mixin"; import { experimentTriggers } from "../constants/experiments"; import { applicationConfig } from "../constants/application-config"; import { shouldStripPromoQueryString } from "@/helpers/promotions-helper"; +import bailout from "@/layouts/bailout/bailout"; const routes = [ + { + path: "/bailout", + name: "bailout", + component: bailout, + }, { path: "/", name: "root", @@ -436,7 +442,10 @@ async function DisplayPageError() { ); baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - location.reload(); + router.push({ + path: "/", + query: { fmgPage: 'bailout' }, + }); } function isExistingFmgPageName(pageName) { From e6b2a95f14d3f85be37d081108ef7fd929a0a359 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 26 Feb 2024 09:40:30 -0500 Subject: [PATCH 064/112] prettier --- src/global-methods.js | 1 - src/layouts/bailout/bailout.vue | 2 +- src/router/index.js | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 6d0fc7c0c..c5e6102dc 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -51,7 +51,6 @@ export default { }, (error) => { console.error(error); - console.log("Error calling: " + endpoint + " payload: " + JSON.stringify(payload)); if (logApiCall) { analyticsMixIn.methods.pushEventToGA( diff --git a/src/layouts/bailout/bailout.vue b/src/layouts/bailout/bailout.vue index bbd1670c3..a7cf017b4 100644 --- a/src/layouts/bailout/bailout.vue +++ b/src/layouts/bailout/bailout.vue @@ -76,4 +76,4 @@ export default { loadingModal, }, }; - \ No newline at end of file + diff --git a/src/router/index.js b/src/router/index.js index 1af870e72..e489cbfca 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -39,7 +39,7 @@ const routes = [ path: "/bailout", name: "bailout", component: bailout, - }, + }, { path: "/", name: "root", @@ -444,7 +444,7 @@ async function DisplayPageError() { baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); router.push({ path: "/", - query: { fmgPage: 'bailout' }, + query: { fmgPage: "bailout" }, }); } From b1e823d17e8aa61f473eb9d7792bbbcbd899e7c0 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Mon, 26 Feb 2024 10:09:22 -0500 Subject: [PATCH 065/112] CSR-1982 type check in handleIFrameContentWindowMessage on payment page --- src/layouts/payment/payment.spec.js | 6 +++--- src/layouts/payment/payment.vue | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/layouts/payment/payment.spec.js b/src/layouts/payment/payment.spec.js index 717910607..34b282e8b 100644 --- a/src/layouts/payment/payment.spec.js +++ b/src/layouts/payment/payment.spec.js @@ -512,7 +512,7 @@ describe("payment.vue", () => { }); }); - describe("handleIFrameContentWindwMessage", () => { + describe("handleIFrameContentWindowMessage", () => { test("Navigates back if afterpay is closed", () => { // Arrange const event = { @@ -524,7 +524,7 @@ describe("payment.vue", () => { wrapper.vm.backButtonAction = jest.fn(); // Act - wrapper.vm.handleIFrameContentWindwMessage(event); + wrapper.vm.handleIFrameContentWindowMessage(event); // Assert expect(wrapper.vm.backButtonAction).toBeCalled(); @@ -539,7 +539,7 @@ describe("payment.vue", () => { const wrapper = setupMocks({}); // Act - wrapper.vm.handleIFrameContentWindwMessage(event); + wrapper.vm.handleIFrameContentWindowMessage(event); // Assert expect(wrapper.vm.shouldBlockInteraction).toBe(true); diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index e61e54753..bc3e365ad 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -643,17 +643,19 @@ export default { this.submitHopForm(); }, - handleIFrameContentWindwMessage(event) { - if (event.data.indexOf("afterpayClosed") > -1) { - this.backButtonAction(); - } - if (event.data.indexOf("creditCardSubmit") > -1) { - this.setUIBlock(true); + handleIFrameContentWindowMessage(event) { + if (typeof event.data === "string") { + if (event.data.indexOf("afterpayClosed") > -1) { + this.backButtonAction(); + } + if (event.data.indexOf("creditCardSubmit") > -1) { + this.setUIBlock(true); + } } }, setIFrameListener() { window.addEventListener("message", (event) => - this.handleIFrameContentWindwMessage(event) + this.handleIFrameContentWindowMessage(event) ); }, setUIBlock(val) { From 92a5411f2939cb57fc156f8c3fd7f44cb14cdc20 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 26 Feb 2024 12:53:59 -0500 Subject: [PATCH 066/112] CSR-1855 bailout spec --- src/layouts/bailout/bailout.spec.js | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/layouts/bailout/bailout.spec.js diff --git a/src/layouts/bailout/bailout.spec.js b/src/layouts/bailout/bailout.spec.js new file mode 100644 index 000000000..ebed2697a --- /dev/null +++ b/src/layouts/bailout/bailout.spec.js @@ -0,0 +1,48 @@ +// Components +import bailout from "@/layouts/bailout/bailout.vue"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("bailout.vue", () => { + test("arePagePrerequisitesValid should be true ", async () => { + //Arrange + const { wrapper } = setupMocks(); + + //Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); +}); + +function setupMocks() { + const mountOptions = getMountOptions({}); + + //Mock props + const mockMixin = { + methods: { + getCmsContent: jest.fn(), + }, + }; + + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(bailout, mountOptions); + + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.backButtonAction = jest.fn(); + + return { wrapper }; +} From 1200ded61db27feb7f072a3a6465ed5eea9886fd Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 26 Feb 2024 15:03:42 -0500 Subject: [PATCH 067/112] CSR-1855 test fix CSR-1855 test fix --- src/global-methods.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index b74b97a8a..ab80bcd7b 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -1,6 +1,7 @@ import globalMethods from "@/global-methods"; import axios from "axios"; import analyticsMixIn from "@/mixins/analytics-mixin"; +import router from "@/router"; //Mock external dependencies jest.mock("axios"); @@ -29,6 +30,7 @@ it("Global Methods - Call Http Client - Should Reject Promise", () => { isError: true, }); analyticsMixIn.methods.pushEventToGA = jest.fn(); + router.navigateError = jest.fn(); //Act globalMethods.callHttpClient(httpArgs).catch((err) => { From a0b201f31fba05ab4b043642c482b3de14a91a24 Mon Sep 17 00:00:00 2001 From: Sneha Date: Tue, 27 Feb 2024 10:33:38 +0530 Subject: [PATCH 068/112] Revert "CSR-1985" This reverts commit 6321ccc8fefae4821ae555ce8a26af76a3fad938. --- .../promo-modal-question.vue | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/fmg-components/promo-modal-question/promo-modal-question.vue b/src/fmg-components/promo-modal-question/promo-modal-question.vue index 80b945321..59c1523b2 100644 --- a/src/fmg-components/promo-modal-question/promo-modal-question.vue +++ b/src/fmg-components/promo-modal-question/promo-modal-question.vue @@ -337,7 +337,7 @@ export default { }, }; - From a0b2e94a43ed628c1db5353bb62444ff0246986f Mon Sep 17 00:00:00 2001 From: Sneha Date: Wed, 28 Feb 2024 12:05:21 +0530 Subject: [PATCH 069/112] CSR-1983 --- .../quote/service-package-question/service-package-question.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6b84f3557..2d0ba515e 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -64,7 +64,7 @@ export default { } }, activePromos() { - this.selectDefaultPackage(); + if (this.activePromos?.length) this.selectDefaultPackage(); }, selectedPackageName(newValue) { const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); From 2205b7104dce02a5b5e8c34f9cba4f215ab5869d Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Wed, 28 Feb 2024 19:14:29 +0530 Subject: [PATCH 070/112] CSR-1993 Green tint privacy --- src/assets/img/tints/Glass-NoShade-GreenTint-Privacy.svg | 1 + src/constants/tint-mapper.js | 1 + 2 files changed, 2 insertions(+) create mode 100644 src/assets/img/tints/Glass-NoShade-GreenTint-Privacy.svg diff --git a/src/assets/img/tints/Glass-NoShade-GreenTint-Privacy.svg b/src/assets/img/tints/Glass-NoShade-GreenTint-Privacy.svg new file mode 100644 index 000000000..fecc16e63 --- /dev/null +++ b/src/assets/img/tints/Glass-NoShade-GreenTint-Privacy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/constants/tint-mapper.js b/src/constants/tint-mapper.js index 519de0855..e5d1a3b30 100644 --- a/src/constants/tint-mapper.js +++ b/src/constants/tint-mapper.js @@ -33,6 +33,7 @@ const tintMap = { { name: "green tint", src: "Glass-NoShade-GreenTint.svg" }, { name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" }, { name: "blue tint", src: "Glass-NoShade-BlueTint.svg" }, + { name: "green tint privacy", src: "Glass-NoShade-GreenTint-Privacy.svg" }, // No shade or tint { name: "clear", src: "Glass-NoShade-NoTint.svg" }, From 926089272728da423ad26470baa8019d9378aa46 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:21:02 -0500 Subject: [PATCH 071/112] CSR-1855 CSR-1855 hold off on bailout page. Instead, route to vehicle page with a querystring parm that will clear state if the error occurs more than once. --- src/constants/query-strings.js | 1 + src/router/index.js | 36 ++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 5e12b0d9d..12089fca5 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -21,6 +21,7 @@ const queryStrings = { TRANS_REFERENCE_NUMBER: "auth_trans_ref_no", LAST_FOUR: "last_four", DISPLAY_PIA_ALERT: "displayPiaAlert", + PAGE_ERROR: "pageerror", }; export { queryStrings }; diff --git a/src/router/index.js b/src/router/index.js index e489cbfca..415683af3 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -335,6 +335,7 @@ async function navigate( const hasZip = getQuerystringParameter(queryStrings.ZIP_CODE); const zip = getQuerystringParameter(queryStrings.ZIP_CODE); const promo = getQuerystringParameter(queryStrings.PROMO); + const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR); if ( hasZip && @@ -350,6 +351,10 @@ async function navigate( queryStringsObject[queryStrings.PROMO] = promo; } + if (pageError) { + queryStringsObject[queryStrings.PAGE_ERROR] = pageError; + } + router.push({ name: "root", query: Object.assign(optionalQuery, queryStringsObject), @@ -442,10 +447,33 @@ async function DisplayPageError() { ); baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - router.push({ - path: "/", - query: { fmgPage: "bailout" }, - }); + const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR); + + if (pageError) { + var errorCount = Number(pageError); + if (errorCount > 1) { + deleteFunnelCookie(); + await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE); + + router.push({ + path: "/", + query: { fmgPage: "vehicle" }, + }); + } + else { + errorCount++; + router.push({ + path: "/", + query: { fmgPage: "vehicle", pageError: errorCount }, + }); + } + } + else { + router.push({ + path: "/", + query: { fmgPage: "vehicle", pageError: "1" }, + }); + } } function isExistingFmgPageName(pageName) { From ad4c113c2681410fa77cc4c33db5e30f9544ea11 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 28 Feb 2024 09:38:26 -0500 Subject: [PATCH 072/112] Fix svg image. --- src/assets/img/tints/Glass-NoShade-GreenTint.svg | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/assets/img/tints/Glass-NoShade-GreenTint.svg b/src/assets/img/tints/Glass-NoShade-GreenTint.svg index 5f5b99de0..cdf96aa3d 100644 --- a/src/assets/img/tints/Glass-NoShade-GreenTint.svg +++ b/src/assets/img/tints/Glass-NoShade-GreenTint.svg @@ -1,3 +1 @@ - - - + \ No newline at end of file From 3c8147081faaa4dcdfc1f63a2d5227df8baf2e3a Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:48:19 -0500 Subject: [PATCH 073/112] CSR-1855 CSR-1855 allow 404s to skip page error logic for no wipers or no promo --- src/global-methods.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/global-methods.js b/src/global-methods.js index c5e6102dc..bd0ea36db 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -61,7 +61,11 @@ export default { ); } - router.navigateError(); + // do not route to error logic when no wipers found or no promo found (404s) + if (error.response.status != "404") { + router.navigateError(); + } + return reject(error.response); } ); From 0c8ff997265eabc30ee8d374b32bc0be2141ffbc Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:53:38 -0500 Subject: [PATCH 074/112] CSR-1855 prettier --- src/router/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index 415683af3..1b4166922 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -448,7 +448,9 @@ async function DisplayPageError() { baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR); - + + // we use the pageError querystring as a counter to how many times a user has experienced an error and been routed here. + // once they receive more than 1 pageerrors, we'll reset their state to hopefully correct any issues they may be having. if (pageError) { var errorCount = Number(pageError); if (errorCount > 1) { @@ -459,16 +461,14 @@ async function DisplayPageError() { path: "/", query: { fmgPage: "vehicle" }, }); - } - else { + } else { errorCount++; router.push({ path: "/", query: { fmgPage: "vehicle", pageError: errorCount }, }); } - } - else { + } else { router.push({ path: "/", query: { fmgPage: "vehicle", pageError: "1" }, From cbaf479d0492717bebd7b3d8689c37d1d191c050 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Thu, 29 Feb 2024 06:56:11 -0500 Subject: [PATCH 075/112] CSR-1072 move insurance loss fields to damage object to match ISS comment out nav to insurance page until it's working. currently breaking the insurance flow for QA. --- src/layouts/quote/quote.vue | 13 +++++++++---- src/store/index.js | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5672c05e6..c1dd44145 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -327,10 +327,15 @@ export default { const payment = this.$store.getters.payment; if (payment.isInsurance) { - this.$router.navigateWithSaving( - this.navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE, - this.$route - ); + navigateToHeritageFunnel({ + shouldSaveSession: true, + pageNameToLog: "quote", + loadingModal: this.$refs.loadingModal, + }); + // this.$router.navigateWithSaving( + // this.navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE, + // this.$route + // ); } else { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_CASH, diff --git a/src/store/index.js b/src/store/index.js index 5114bc95c..4db6b9fc2 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -84,6 +84,8 @@ const getDefaultState = () => { partQuestionAnswers: null, moldingQuestionAnswers: null, capabilityQuestionAnswers: null, + dateOfLoss: null, + damageCause: null, }, lineItems: { glassParts: null, @@ -123,8 +125,6 @@ const getDefaultState = () => { policy: { currentDeductible: 0, policyNumber: null, - dateOfLoss: null, - lossCause: null, isItac: false, additionalAuthFlag: null, isNoComp: false, @@ -514,6 +514,8 @@ export const mutations = { state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace; state.order.damage.isRepair = sessionInformation.order.damage.isRepair; state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips; + state.order.damage.dateOfLoss = sessionInformation.order.damage?.lossDate; + state.order.damage.damageCause = sessionInformation.order.damage?.damageCause; state.order.damage.partQuestionAnswers = sessionInformation.order.damage.partQuestionAnswers; @@ -599,8 +601,6 @@ export const mutations = { state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag; state.order.policy.isItac = sessionInformation.order.policy?.isItac; state.order.policy.policyNumber = sessionInformation.order.policy?.policyNumber; - state.order.policy.dateOfLoss = sessionInformation.order.policy?.lossDate; - state.order.policy.lossCause = sessionInformation.order.policy?.lossCause; state.order.policy.insuranceCompanyName = sessionInformation.order.policy?.insuranceCompanyName; state.order.policy.isNoComp = sessionInformation.order.policy?.noComprehensive; From 9838b231d3bd9f36cb90d1f263fa1f5c5ac594a1 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:14:01 -0500 Subject: [PATCH 076/112] CSR-1072 incorrect name CSR-1072 incorrect name --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 4db6b9fc2..06a5631d3 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -514,7 +514,7 @@ export const mutations = { state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace; state.order.damage.isRepair = sessionInformation.order.damage.isRepair; state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips; - state.order.damage.dateOfLoss = sessionInformation.order.damage?.lossDate; + state.order.damage.dateOfLoss = sessionInformation.order.damage?.dateOfLoss; state.order.damage.damageCause = sessionInformation.order.damage?.damageCause; state.order.damage.partQuestionAnswers = From 763956caef803eca3dbc7c5404959a6e785bb34a Mon Sep 17 00:00:00 2001 From: Leah Schumann Date: Thu, 29 Feb 2024 09:35:07 -0500 Subject: [PATCH 077/112] Frontend Logging --- src/App.vue | 19 +++++++++ src/constants/logger.js | 6 +++ src/constants/logging-endpoints.js | 8 ++++ src/global-methods.js | 51 ++++++++++++++++++++---- src/helpers/logger.js | 62 ++++++++++++++++++++++++++++++ src/main.js | 17 ++++++++ src/router/index.js | 2 + 7 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 src/constants/logger.js create mode 100644 src/constants/logging-endpoints.js create mode 100644 src/helpers/logger.js diff --git a/src/App.vue b/src/App.vue index 31fb663c3..bbaf78622 100644 --- a/src/App.vue +++ b/src/App.vue @@ -12,6 +12,7 @@ import { handleAnyComponentFocus } from "@/helpers/button-question-focus-helper"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import { showFmgLoadingModal } from "@/helpers/loading-modal-helper"; + export default { name: "app", setup() { @@ -33,6 +34,24 @@ export default { loadingModal, }, }; + +// Add a global Javascript exception handler for logging exceptions, this handler will log when there is an uncaught exception +window.onerror = (msg, url, line, col, error) => { + // Log the windows error + // Note that col & error are new to the HTML 5 spec and may not be + // supported in every browser. It worked for me in Chrome. + global.$logger.logError(msg, { + url: url, + line: line, + column: col ?? "", + error: error ?? "", + }); + + // If you return true, then error alerts (like in older versions of + // Internet Explorer) will be suppressed. + var suppressErrorAlert = true; + return suppressErrorAlert; +};