From 0c14daf20ea0639b1d2d8aba984317e0ed553104 Mon Sep 17 00:00:00 2001 From: Brian Beggs Date: Wed, 30 Oct 2024 18:42:38 -0400 Subject: [PATCH] chore: Gate expiration subs modal by license state as well as feature toggle. (#1216) (#1217) --- .../data/services/subsidies/subscriptions.js | 4 +- .../services/subsidies/subscriptions.test.js | 56 ++++++++++++++++++- .../expired-subscription-modal/index.jsx | 10 +++- .../tests/ExpiredSubscriptionModal.test.jsx | 52 ++++++++++++++--- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/components/app/data/services/subsidies/subscriptions.js b/src/components/app/data/services/subsidies/subscriptions.js index 04ac8f8b31..be36c5d739 100644 --- a/src/components/app/data/services/subsidies/subscriptions.js +++ b/src/components/app/data/services/subsidies/subscriptions.js @@ -236,7 +236,9 @@ export async function fetchSubscriptions(enterpriseUUID) { if (customerAgreement) { subscriptionsData.customerAgreement = customerAgreement; } - subscriptionsData.showExpirationNotifications = !(customerAgreement?.disableExpirationNotifications); + subscriptionsData.showExpirationNotifications = ( + !customerAgreement?.disableExpirationNotifications && !customerAgreement?.hasCustomLicenseExpirationMessaging + ); // Sort licenses within each license status by whether the associated subscription plans // are current; current plans should be prioritized over non-current plans. diff --git a/src/components/app/data/services/subsidies/subscriptions.test.js b/src/components/app/data/services/subsidies/subscriptions.test.js index 83661b2f5b..c622835805 100644 --- a/src/components/app/data/services/subsidies/subscriptions.test.js +++ b/src/components/app/data/services/subsidies/subscriptions.test.js @@ -66,6 +66,9 @@ describe('fetchSubscriptions', () => { daysUntilExpiration: 30, startDate: dayjs().subtract(15, 'days').toISOString(), expirationDate: dayjs().add(30, 'days').toISOString(), + disableExpirationNotifications: false, + hasCustomLicenseExpirationMessaging: false, + expectedShowExpirationNotifications: true, }, { licenseStatus: LICENSE_STATUS.ACTIVATED, @@ -74,6 +77,9 @@ describe('fetchSubscriptions', () => { daysUntilExpiration: 30, startDate: dayjs().subtract(15, 'days').toISOString(), expirationDate: dayjs().add(30, 'days').toISOString(), + disableExpirationNotifications: false, + hasCustomLicenseExpirationMessaging: false, + expectedShowExpirationNotifications: true, }, { licenseStatus: LICENSE_STATUS.ACTIVATED, @@ -82,6 +88,9 @@ describe('fetchSubscriptions', () => { daysUntilExpiration: 0, startDate: dayjs().subtract(15, 'days').toISOString(), expirationDate: dayjs().toISOString(), + disableExpirationNotifications: false, + hasCustomLicenseExpirationMessaging: false, + expectedShowExpirationNotifications: true, }, { licenseStatus: LICENSE_STATUS.UNASSIGNED, @@ -90,6 +99,45 @@ describe('fetchSubscriptions', () => { daysUntilExpiration: 30, startDate: dayjs().subtract(15, 'days').toISOString(), expirationDate: dayjs().add(30, 'days').toISOString(), + disableExpirationNotifications: false, + hasCustomLicenseExpirationMessaging: false, + expectedShowExpirationNotifications: true, + }, + // Custom subs messaging with standard expiration still enabled + { + licenseStatus: LICENSE_STATUS.ACTIVATED, + isSubscriptionPlanActive: true, + isSubscriptionPlanCurrent: false, + daysUntilExpiration: -10, + startDate: dayjs().subtract(15, 'days').toISOString(), + expirationDate: dayjs().subtract(10, 'days').toISOString(), + disableExpirationNotifications: false, + hasCustomLicenseExpirationMessaging: true, + expectedShowExpirationNotifications: false, + }, + // Disabled standard expiration, with custom subs expiration enabled + { + licenseStatus: LICENSE_STATUS.ACTIVATED, + isSubscriptionPlanActive: true, + isSubscriptionPlanCurrent: false, + daysUntilExpiration: -10, + startDate: dayjs().subtract(15, 'days').toISOString(), + expirationDate: dayjs().subtract(10, 'days').toISOString(), + disableExpirationNotifications: true, + hasCustomLicenseExpirationMessaging: true, + expectedShowExpirationNotifications: false, + }, + // Disabled standard expiration, no custom subs expiration + { + licenseStatus: LICENSE_STATUS.ACTIVATED, + isSubscriptionPlanActive: true, + isSubscriptionPlanCurrent: false, + daysUntilExpiration: -10, + startDate: dayjs().subtract(15, 'days').toISOString(), + expirationDate: dayjs().subtract(10, 'days').toISOString(), + disableExpirationNotifications: true, + hasCustomLicenseExpirationMessaging: false, + expectedShowExpirationNotifications: false, }, ])('returns subscriptions (%s)', async ({ licenseStatus, @@ -98,6 +146,9 @@ describe('fetchSubscriptions', () => { daysUntilExpiration, startDate, expirationDate, + disableExpirationNotifications, + hasCustomLicenseExpirationMessaging, + expectedShowExpirationNotifications, }) => { const mockSubscriptionLicense = { uuid: 'test-license-uuid', @@ -114,7 +165,8 @@ describe('fetchSubscriptions', () => { const mockResponse = { customerAgreement: { uuid: 'test-customer-agreement-uuid', - disableExpirationNotifications: false, + disableExpirationNotifications, + hasCustomLicenseExpirationMessaging, }, results: [mockSubscriptionLicense], }; @@ -157,7 +209,7 @@ describe('fetchSubscriptions', () => { subscriptionLicense: isLicenseApplicable ? updatedMockSubscriptionLicense : null, subscriptionLicenses: [updatedMockSubscriptionLicense], shouldShowActivationSuccessMessage: false, - showExpirationNotifications: true, + showExpirationNotifications: expectedShowExpirationNotifications, }; expect(response).toEqual(expectedResult); }); diff --git a/src/components/expired-subscription-modal/index.jsx b/src/components/expired-subscription-modal/index.jsx index c9f53ae902..d37054eaa9 100644 --- a/src/components/expired-subscription-modal/index.jsx +++ b/src/components/expired-subscription-modal/index.jsx @@ -5,13 +5,17 @@ import DOMPurify from 'dompurify'; import { useSubscriptions } from '../app/data'; const ExpiredSubscriptionModal = () => { - const { data: { customerAgreement, subscriptionLicense } } = useSubscriptions(); + const { data: { customerAgreement, subscriptionLicense, subscriptionPlan } } = useSubscriptions(); const [isOpen] = useToggle(true); - const displaySubscriptionExpirationModal = customerAgreement?.hasCustomLicenseExpirationMessaging - && !subscriptionLicense?.subscriptionPlan.isCurrent; + const displaySubscriptionExpirationModal = ( + customerAgreement?.hasCustomLicenseExpirationMessaging + && subscriptionLicense && !subscriptionPlan.isCurrent + ); + if (!displaySubscriptionExpirationModal) { return null; } + return ( {customerAgreement.modalHeaderText}} diff --git a/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx b/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx index 8d70752a97..727045f787 100644 --- a/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx +++ b/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx @@ -22,9 +22,10 @@ describe('', () => { urlForButtonInModal: null, }, subscriptionLicense: { - subscriptionPlan: { - isCurrent: true, - }, + uuid: '123', + }, + subscriptionPlan: { + isCurrent: true, }, }, }); @@ -46,9 +47,10 @@ describe('', () => { urlForButtonInModal: '/renew', }, subscriptionLicense: { - subscriptionPlan: { - isCurrent: true, - }, + uuid: '123', + }, + subscriptionPlan: { + isCurrent: true, }, }, }); @@ -57,6 +59,25 @@ describe('', () => { expect(container).toBeEmptyDOMElement(); }); + test('does not renderwithrouter if learner does not have a license', () => { + useSubscriptions.mockReturnValue({ + data: { + customerAgreement: { + hasCustomLicenseExpirationMessaging: true, + modalHeaderText: 'Expired Subscription', + buttonLabelInModal: 'Continue Learning', + expiredSubscriptionModalMessaging: '

Your subscription has expired.

', + urlForButtonInModal: '/renew', + }, + subscriptionLicense: null, + subscriptionPlan: null, + }, + }); + + const { container } = renderWithRouter(); + expect(container).toBeEmptyDOMElement(); + }); + test('renderwithrouters modal with messaging when `hasCustomLicenseExpirationMessaging` is true and license is expired', () => { useSubscriptions.mockReturnValue({ data: { @@ -68,9 +89,10 @@ describe('', () => { urlForButtonInModal: '/renew', }, subscriptionLicense: { - subscriptionPlan: { - isCurrent: false, - }, + uuid: '123', + }, + subscriptionPlan: { + isCurrent: false, }, }, }); @@ -97,6 +119,12 @@ describe('', () => { expiredSubscriptionModalMessaging: '

Your subscription has expired.

', urlForButtonInModal: '/renew', }, + subscriptionLicense: { + uuid: '123', + }, + subscriptionPlan: { + isCurrent: false, + }, }, }); @@ -114,6 +142,12 @@ describe('', () => { expiredSubscriptionModalMessaging: '

Your subscription has expired.

', urlForButtonInModal: 'https://example.com', }, + subscriptionLicense: { + uuid: '123', + }, + subscriptionPlan: { + isCurrent: false, + }, }, });