From e88da1bd774e3e6c9905e037115b1362ae536cda Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 5 Feb 2024 21:45:03 +0530 Subject: [PATCH 1/2] CSR-1764 --- .../menu-modal/menu-modal.spec.js | 67 +++++++++++++- .../funnel-header/menu-modal/menu-modal.vue | 1 + src/layouts/payment-method/payment-method.vue | 1 + .../promo-modal-question.vue | 72 ++++++++------- src/layouts/quote/quote.vue | 89 ++++++++++++++++++- .../service-package-question.vue | 3 + 6 files changed, 199 insertions(+), 34 deletions(-) diff --git a/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js b/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js index 3d0843e10..101d15914 100644 --- a/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js +++ b/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js @@ -1 +1,66 @@ -test.todo("some test to be written in the future"); +import { mount, shallowMount } from "@vue/test-utils"; +import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal.vue"; + +describe("menu-modal.vue", () => { + it("Should return text Footer Navigation", async () => { + // Act + const wrapper = shallowMount(menuModal); + + // Assert + const footerModalLabel = wrapper.find("h5"); + + // Expect + expect(footerModalLabel.text()).toContain("Footer Navigation"); + }); + + it("Should return footer text as Safelite Group", async () => { + // Act + const wrapper = shallowMount(menuModal); + + // Assert + const modalFooter = wrapper.find("div.modal-footer"); + + // Expect + expect(modalFooter.text()).toContain("Safelite Group"); + }); + + it("Should return Terms of use text link text", async () => { + // Act + const wrapper = shallowMount(menuModal); + + // Expect + expect(wrapper.html()).toContain("Terms of use"); + }); + + it('Should return "Your privacy choices" text link text', async () => { + // Act + const wrapper = mount(menuModal); + + // Expect + expect(wrapper.html()).toContain("Your privacy choices"); + }); + + test('Icon for link to "Privacy Policies" page is displayed with the correct alternate text', () => { + // NOTE: We need a way to target a specific component so we can be sure that + // an icon is coming from a specific component. + // That requires an additional prop in the component. Will hold off on adding the prop + // until there is more clarity on how we handle shared components. + // For now the test is below is the best we can do. + + // Arrange + const wrapper = mount(menuModal); + + // Expect + const icon = wrapper.find('[data-id="ccpa-icon"]'); + expect(icon.isVisible()).toBe(true); + expect(icon.attributes("alt")).toBe("Your privacy choices"); + }); + + it("Should return Warranty text link text", async () => { + // Act + const wrapper = shallowMount(menuModal); + + // Expect + expect(wrapper.html()).toContain("Warranty"); + }); +}); diff --git a/src/fmg-components/funnel-header/menu-modal/menu-modal.vue b/src/fmg-components/funnel-header/menu-modal/menu-modal.vue index dd77ea7fa..44fe23c88 100644 --- a/src/fmg-components/funnel-header/menu-modal/menu-modal.vue +++ b/src/fmg-components/funnel-header/menu-modal/menu-modal.vue @@ -53,6 +53,7 @@ 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.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index b4b02b3ed..a68ff4dbe 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,7 @@ export default { modelValue: Object, modalWidgetName: String, availableVaps: Object, + pageName: String, }, computed: { promoLinkText() { @@ -253,44 +254,51 @@ 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.pageName == "payment-method") { + 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 - ); - - const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( - promoCodeData.promoCode, - taxedVaps, - this.lineItems - ); + // 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 + ); + 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.vue b/src/layouts/quote/quote.vue index f26d24cf7..ff552ee82 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -39,6 +39,14 @@ cmsWidgetName="AfterpayModalWidget" :lineItems="availableLineItems" /> + + { + const errorAlert = createPromoErrorAlert(promoCode); + this.$refs.funnelHeader.pushGlobalAlert(errorAlert, errorAlert.shouldAutoFade); + }); + } + }, backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); }, @@ -294,6 +341,14 @@ export default { } this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, 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) { @@ -309,6 +364,37 @@ 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); + } else if ( + oldValue.promos.length == newValue.promos.length && + oldValue.vaps.length != newValue.vaps.length + ) { + this.revalidatePromos(); + } + }, + deep: true, + }, + }, components: { funnelHeader, navbar, @@ -321,6 +407,7 @@ export default { contentGroupModal, loadingModal, afterpayModalBanner, + promoModalQuestion, }, }; 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 4068f50e5d779270fbd13f68bdc0abcfcf7df1b0 Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 5 Feb 2024 22:09:57 +0530 Subject: [PATCH 2/2] removing menu modal changes --- .../menu-modal/menu-modal.spec.js | 67 +------------------ .../funnel-header/menu-modal/menu-modal.vue | 1 - 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js b/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js index 101d15914..3d0843e10 100644 --- a/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js +++ b/src/fmg-components/funnel-header/menu-modal/menu-modal.spec.js @@ -1,66 +1 @@ -import { mount, shallowMount } from "@vue/test-utils"; -import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal.vue"; - -describe("menu-modal.vue", () => { - it("Should return text Footer Navigation", async () => { - // Act - const wrapper = shallowMount(menuModal); - - // Assert - const footerModalLabel = wrapper.find("h5"); - - // Expect - expect(footerModalLabel.text()).toContain("Footer Navigation"); - }); - - it("Should return footer text as Safelite Group", async () => { - // Act - const wrapper = shallowMount(menuModal); - - // Assert - const modalFooter = wrapper.find("div.modal-footer"); - - // Expect - expect(modalFooter.text()).toContain("Safelite Group"); - }); - - it("Should return Terms of use text link text", async () => { - // Act - const wrapper = shallowMount(menuModal); - - // Expect - expect(wrapper.html()).toContain("Terms of use"); - }); - - it('Should return "Your privacy choices" text link text', async () => { - // Act - const wrapper = mount(menuModal); - - // Expect - expect(wrapper.html()).toContain("Your privacy choices"); - }); - - test('Icon for link to "Privacy Policies" page is displayed with the correct alternate text', () => { - // NOTE: We need a way to target a specific component so we can be sure that - // an icon is coming from a specific component. - // That requires an additional prop in the component. Will hold off on adding the prop - // until there is more clarity on how we handle shared components. - // For now the test is below is the best we can do. - - // Arrange - const wrapper = mount(menuModal); - - // Expect - const icon = wrapper.find('[data-id="ccpa-icon"]'); - expect(icon.isVisible()).toBe(true); - expect(icon.attributes("alt")).toBe("Your privacy choices"); - }); - - it("Should return Warranty text link text", async () => { - // Act - const wrapper = shallowMount(menuModal); - - // Expect - expect(wrapper.html()).toContain("Warranty"); - }); -}); +test.todo("some test to be written in the future"); diff --git a/src/fmg-components/funnel-header/menu-modal/menu-modal.vue b/src/fmg-components/funnel-header/menu-modal/menu-modal.vue index 44fe23c88..dd77ea7fa 100644 --- a/src/fmg-components/funnel-header/menu-modal/menu-modal.vue +++ b/src/fmg-components/funnel-header/menu-modal/menu-modal.vue @@ -53,7 +53,6 @@