diff --git a/src/helpers/promotions-helper.js b/src/helpers/promotions-helper.js index 1689d9550..40ef6cafd 100644 --- a/src/helpers/promotions-helper.js +++ b/src/helpers/promotions-helper.js @@ -16,6 +16,10 @@ export const addableVapsPromoPartNumbers = [ promoPartNumberStrings.WIPER_DISCOUNT_PART_NUMBER, ]; +const promoErrorCodes = { + CANNOT_COMBINE: "SimilarPromoAlreadyOnOrder" +}; + export const pagesToStripPromoQueryStringFrom = ["quote", "payment-method"]; export function getPromosWithAddableVaps(promoList) { @@ -110,6 +114,73 @@ export async function revalidatePromosAndValidateNewPromo( return { validatePromoResponse, revalidatePromoResponse }; } +export function buildToastMessagesFromRevalidateOrValidatePromoResponse(promoResponse, oldActivePromos = [], oldInactivePromos = []) { + console.log('oldActivePromos', oldActivePromos); + console.log('oldInactivePromos', oldInactivePromos); + console.log('promoResponse', promoResponse); + const alerts = []; + // Revalidate always has an "errors" array + if (promoResponse.errors) { + const oldPromoCodes = oldActivePromos.map(promo => getPromoCodeWithoutBundleIdentifier(promo.promoCode)); + const activePromoCodesFromResponse = []; + // consolidate bundle promos to avoid displaying multiple toast messages for one bundle + promoResponse.promoLineItems.forEach(newPromo => { + const promoCodeToDisplay = getPromoCodeWithoutBundleIdentifier(newPromo.promoCode); + if (!activePromoCodesFromResponse.includes(promoCodeToDisplay)) { + activePromoCodesFromResponse.push(promoCodeToDisplay); + } + }); + console.log('oldPromoCodes', oldPromoCodes); + console.log('activePromoCodesFromResponse', activePromoCodesFromResponse); + const newlyActivatedPromoCodes = activePromoCodesFromResponse.filter(newPromoCode => !oldPromoCodes.includes(newPromoCode)); + const newlyInactivatedPromos = promoResponse.errors.filter(error => !oldInactivePromos.includes(error.promoCode)); + newlyActivatedPromoCodes.forEach(newlyActivatedPromoCode => { + alerts.push({ + messageHeadline: "Promo applied!", + messageCopy: `Promo "${newlyActivatedPromoCode}" was successfully applied to your cart.`, + type: "alert-success", + isDismissible: true, + shouldAutoFade: true, + }); + }); + newlyInactivatedPromos.forEach(newlyInactivatedPromo => { + console.log(newlyInactivatedPromo); + alerts.push({ + messageHeadline: "Promo error", + messageCopy: `Sorry, promo code "${newlyInactivatedPromo}" is not valid`, + type: "alert-danger", + isDismissible: true, + shouldAutoFade: false, + }); + }); + } else { + if (promoResponse.orderPromos) { + let promoCodeToDisplay = getPromoCodeWithoutBundleIdentifier(promoResponse.orderPromos[0].promoCode); + alerts.push({ + messageHeadline: "Promo applied!", + messageCopy: `Promo "${promoCodeToDisplay}" was successfully applied to your cart.`, + type: "alert-success", + isDismissible: true, + shouldAutoFade: true, + }); + } else { + const alertToPush = { + messageHeadline: "Promo error", + type: "alert-danger", + shouldAutoFade: false, + isDismissible: true, + } + if (promoResponse.errorCode == promoErrorCodes.CANNOT_COMBINE) { + alertToPush.messageCopy = `Sorry, promo code "${promoResponse.promoCode}" cannot be combined with ${promoResponse.additionalInfo[0]}`; + } else { + alertToPush.messageCopy = `Sorry, promo code "${promoResponse.promoCode}" is not valid`; + } + alerts.push(alertToPush); + } + } + return alerts; +} + export function getPromosThatMatchLineItemsOnOrder(promos, lineItemsOnOrder) { const matchingPromos = []; promos.forEach((promo) => { @@ -152,6 +223,11 @@ export function getVapsThatNeedToBeAddedToSatisfyPromos( } } +// bundle promos look like: "bundlePromo/###"" for each promo, this returns "bundlePromo" only +export function getPromoCodeWithoutBundleIdentifier(promoCode) { + return promoCode.substring(0, promoCode.indexOf("/")); +} + export function shouldStripPromoQueryString(fmgPageQueryValue) { return pagesToStripPromoQueryStringFrom.includes(fmgPageQueryValue); } diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 6e87235b0..33b338a6e 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -88,7 +88,7 @@ import { paymentMethods } from "@/constants/payment-method-constants"; import { experimentSettings } from "@/constants/experiments"; import { revalidatePromosAndValidateNewPromo, - getPromosWithAddableVaps, + buildToastMessagesFromRevalidateOrValidatePromoResponse, getVapsThatNeedToBeAddedToSatisfyPromos, } from "@/helpers/promotions-helper"; import { queryStrings } from "@/constants/query-strings"; @@ -169,8 +169,11 @@ export default { ); // Promo logic - const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO); + // Populate the previous state of promos for toast message usage in "next()" + const oldActivePromos = store.getters.lineItems.promos?.slice(0); + const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0); + const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO); const { validatePromoResponse, revalidatePromoResponse } = await revalidatePromosAndValidateNewPromo( promoCodeFromQueryString, @@ -219,8 +222,18 @@ export default { vm.setCmsContent(resultMap.cmsContent); vm.availableLineItems = taxedAvailableLineItems; vm.lineItems = lineItems; - vm.updateFooterButtonText(vm.customCtaCopy); + + if (revalidatePromoResponse) { + const validateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(revalidatePromoResponse, oldActivePromos, oldInactivePromos); + if (validateAlerts.length) { + vm.$refs.funnelHeader.triggerGlobalAlert(validateAlerts[0], validateAlerts[0].shouldAutoFade); + } + } + if (validatePromoResponse) { + const validateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(validatePromoResponse); + vm.$refs.funnelHeader.triggerGlobalAlert(validateAlerts[0], validateAlerts[0].shouldAutoFade); + } }); }, data() { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index e6f34101f..46f36b330 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -80,7 +80,8 @@ import { Form, defineRule } from "vee-validate"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { applicationConfig } from "@/constants/application-config"; import { payWithInsuranceStates } from "@/constants/pay-with-insurance-states"; -import { revalidatePromosAndValidateNewPromo } from "@/helpers/promotions-helper"; +import { revalidatePromosAndValidateNewPromo, + buildToastMessagesFromRevalidateOrValidatePromoResponse } from "@/helpers/promotions-helper"; import { queryStrings } from "@/constants/query-strings"; import { getQuerystringParameter } from "@/helpers/querystring-helper"; @@ -151,6 +152,10 @@ export default { ); // Promo logic + // Populate the previous state of promos for toast message usage in "next()" + const oldActivePromos = store.getters.lineItems.promos?.slice(0); + const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0); + const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO); const { validatePromoResponse, revalidatePromoResponse } = @@ -169,6 +174,17 @@ export default { vm.availableLineItems = pricingResults; vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems); vm.newValidatedPromos = validatePromoResponse?.orderPromos; + + if (revalidatePromoResponse) { + const validateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(revalidatePromoResponse, oldActivePromos, oldInactivePromos); + if (validateAlerts.length) { + vm.$refs.funnelHeader.triggerGlobalAlert(validateAlerts[0], validateAlerts[0].shouldAutoFade); + } + } + if (validatePromoResponse) { + const validateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(validatePromoResponse); + vm.$refs.funnelHeader.triggerGlobalAlert(validateAlerts[0], validateAlerts[0].shouldAutoFade); + } }); }, data() { diff --git a/src/store/index.js b/src/store/index.js index e2915a1af..d0a570b50 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2104,6 +2104,7 @@ export const actions = { addGuidToLineItemsIfNotAlreadyThere(vaps); context.commit(storeMutations.UPDATE_VAPS, vaps); }, + // COMBINE THESE savePromos(context, promos) { context.commit(storeMutations.UPDATE_PROMOS, promos); },