diff --git a/src/components/app/data/utils.js b/src/components/app/data/utils.js
index 9246382e5..7b43ec6e9 100644
--- a/src/components/app/data/utils.js
+++ b/src/components/app/data/utils.js
@@ -56,6 +56,40 @@ export function isSystemMaintenanceAlertOpen(config) {
return true;
}
+export const hasActiveLicenseOrLicenseRequest = ({ subscriptionPlan, subscriptionLicense, licenseRequests }) => (
+ !!(
+ subscriptionPlan?.isActive && subscriptionPlan.isCurrent && subscriptionLicense?.status === LICENSE_STATUS.ACTIVATED
+ ) || licenseRequests.length > 0
+);
+
+export const hasAssignedCodesOrCodeRequests = ({ couponCodesCount, couponCodeRequests }) => (
+ couponCodesCount > 0 || couponCodeRequests.length > 0
+);
+
+export const hasAutoAppliedLearnerCreditPolicies = ({ redeemableLearnerCreditPolicies }) => {
+ const autoAppliedPolicyTypes = [
+ POLICY_TYPES.PER_LEARNER_CREDIT,
+ POLICY_TYPES.PER_ENROLLMENT_CREDIT,
+ ];
+ return !!redeemableLearnerCreditPolicies.redeemablePolicies.filter(
+ policy => autoAppliedPolicyTypes.includes(policy.policyType),
+ ).length > 0;
+};
+
+export const hasAllocatedOrAcceptedAssignments = ({ redeemableLearnerCreditPolicies }) => (
+ !!(
+ redeemableLearnerCreditPolicies.learnerContentAssignments.hasAllocatedAssignments
+ || redeemableLearnerCreditPolicies.learnerContentAssignments.hasAcceptedAssignments
+ )
+);
+
+export const determineLearnerSubsidies = {
+ hasActiveLicenseOrLicenseRequest,
+ hasAssignedCodesOrCodeRequests,
+ hasAutoAppliedLearnerCreditPolicies,
+ hasAllocatedOrAcceptedAssignments,
+};
+
/**
* Determine whether learner has only content assignments available to them, based on the presence of:
* - content assignments for display (allocated or canceled)
@@ -83,29 +117,26 @@ export function determineLearnerHasContentAssignmentsOnly({
redeemableLearnerCreditPolicies,
hasCurrentEnterpriseOffers,
}) {
- const hasActiveLicense = !!(subscriptionPlan?.isActive && subscriptionLicense?.status === LICENSE_STATUS.ACTIVATED);
- const hasActiveLicenseOrLicenseRequest = hasActiveLicense || licenseRequests.length > 0;
-
- const hasAssignedCodesOrCodeRequests = couponCodesCount > 0 || couponCodeRequests.length > 0;
- const autoAppliedPolicyTypes = [
- POLICY_TYPES.PER_LEARNER_CREDIT,
- POLICY_TYPES.PER_ENROLLMENT_CREDIT,
- ];
- const hasAutoAppliedLearnerCreditPolicies = !!redeemableLearnerCreditPolicies.redeemablePolicies.filter(
- policy => autoAppliedPolicyTypes.includes(policy.policyType),
- ).length > 0;
- const hasAllocatedOrAcceptedAssignments = !!(
- redeemableLearnerCreditPolicies.learnerContentAssignments.hasAllocatedAssignments
- || redeemableLearnerCreditPolicies.learnerContentAssignments.hasAcceptedAssignments
- );
+ const hasAssignments = hasAllocatedOrAcceptedAssignments({
+ redeemableLearnerCreditPolicies,
+ });
+ // If the enterprise learner does not have any applicable assignments, we can return early to avoid additional checks
+ if (!hasAssignments) {
+ return false;
+ }
- return (
- hasAllocatedOrAcceptedAssignments
- && !hasCurrentEnterpriseOffers
- && !hasActiveLicenseOrLicenseRequest
- && !hasAssignedCodesOrCodeRequests
- && !hasAutoAppliedLearnerCreditPolicies
- );
+ // We check for any true values for the following cases. If any cases return true, this indicates that the
+ // enterprise learner is not an assignment only learner. We default return to true when no other subsidy exist
+ switch (true) {
+ case hasCurrentEnterpriseOffers:
+ return false;
+ case hasActiveLicenseOrLicenseRequest({ subscriptionPlan, subscriptionLicense, licenseRequests }):
+ return false;
+ case hasAssignedCodesOrCodeRequests({ couponCodeRequests, couponCodesCount }):
+ return false;
+ default:
+ return true;
+ }
}
/**
diff --git a/src/components/course/routes/CourseAbout.jsx b/src/components/course/routes/CourseAbout.jsx
index 1f796cf43..c0684a83e 100644
--- a/src/components/course/routes/CourseAbout.jsx
+++ b/src/components/course/routes/CourseAbout.jsx
@@ -13,7 +13,7 @@ import {
useIsAssignmentsOnlyLearner,
usePassLearnerCsodParams,
} from '../../app/data';
-import ExpiredSubscriptionModal from '../../expired-subscription-modal';
+import BlockingSubscriptionExpirationModal from '../../expired-subscription-modal';
const CourseAbout = () => {
const { data: canOnlyViewHighlightSets } = useCanOnlyViewHighlights();
@@ -29,7 +29,7 @@ const CourseAbout = () => {
return (
<>
-
+
diff --git a/src/components/dashboard/DashboardPage.jsx b/src/components/dashboard/DashboardPage.jsx
index 83b7140ad..eb977f5d9 100644
--- a/src/components/dashboard/DashboardPage.jsx
+++ b/src/components/dashboard/DashboardPage.jsx
@@ -10,7 +10,7 @@ import SubscriptionExpirationModal from './SubscriptionExpirationModal';
import { useDashboardTabs } from './data';
import { SESSION_STORAGE_KEY_LICENSE_ACTIVATION_MESSAGE, useEnterpriseCustomer, useSubscriptions } from '../app/data';
import BudgetExpiryNotification from '../budget-expiry-notification';
-import ExpiredSubscriptionModal from '../expired-subscription-modal';
+import BlockingSubscriptionExpirationModal from '../expired-subscription-modal';
const DashboardPage = () => {
const intl = useIntl();
@@ -86,13 +86,13 @@ const DashboardPage = () => {
{tabs.map((tab) => cloneElement(tab, { key: tab.props.eventKey }))}
- {/* ExpiredSubscriptionModal is specifically tailored for learners with an expired license and is
+ {/* BlockingSubscriptionExpirationModal is specifically tailored for learners with an expired license and is
triggered when the learner has hasCustomLicenseExpirationMessagingV2 enabled.
Ideally, the existing SubscriptionExpirationModal should be extended or repurposed to incorporate
this logic and support the custom messaging.
This is noted as a TO-DO, and a ticket will be created to address this enhancement.
Ticket: https://2u-internal.atlassian.net/browse/ENT-9512 */}
-
+
{subscriptions.subscriptionPlan && subscriptions.showExpirationNotifications && }
);
diff --git a/src/components/expired-subscription-modal/index.jsx b/src/components/expired-subscription-modal/index.jsx
index c92eef80f..f8f8a6aa2 100644
--- a/src/components/expired-subscription-modal/index.jsx
+++ b/src/components/expired-subscription-modal/index.jsx
@@ -1,11 +1,11 @@
import {
- useToggle, AlertModal, ActionRow, StatefulButton,
+ ActionRow, AlertModal, StatefulButton, useToggle,
} from '@openedx/paragon';
import DOMPurify from 'dompurify';
import { useState } from 'react';
import { postUnlinkUserFromEnterprise, useEnterpriseCustomer, useSubscriptions } from '../app/data';
-const ExpiredSubscriptionModal = () => {
+const BlockingSubscriptionExpirationModal = () => {
const [buttonState, setButtonState] = useState('default');
const { data: { customerAgreement, subscriptionLicense, subscriptionPlan } } = useSubscriptions();
const { data: enterpriseCustomer } = useEnterpriseCustomer();
@@ -63,4 +63,4 @@ const ExpiredSubscriptionModal = () => {
);
};
-export default ExpiredSubscriptionModal;
+export default BlockingSubscriptionExpirationModal;
diff --git a/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx b/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx
index 987683010..72602925b 100644
--- a/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx
+++ b/src/components/expired-subscription-modal/tests/ExpiredSubscriptionModal.test.jsx
@@ -2,7 +2,7 @@ import { screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import userEvent from '@testing-library/user-event';
import { AppContext } from '@edx/frontend-platform/react';
-import ExpiredSubscriptionModal from '../index';
+import BlockingSubscriptionExpirationModal from '../index';
import { postUnlinkUserFromEnterprise, useEnterpriseCustomer, useSubscriptions } from '../../app/data';
import { renderWithRouter } from '../../../utils/tests';
import { authenticatedUserFactory, enterpriseCustomerFactory } from '../../app/data/services/data/__factories__';
@@ -19,13 +19,13 @@ const mockEnterpriseCustomer = enterpriseCustomerFactory();
const defaultAppContextValue = { authenticatedUser: mockAuthenticatedUser };
const ExpiredSubscriptionModalWrapper = ({ children, appContextValue = defaultAppContextValue }) => (
-
+
{children}
-
+
);
-describe('', () => {
+describe('', () => {
beforeEach(() => {
useSubscriptions.mockReturnValue({
data: {
diff --git a/src/components/search/Search.jsx b/src/components/search/Search.jsx
index cb2fd426d..7902cc478 100644
--- a/src/components/search/Search.jsx
+++ b/src/components/search/Search.jsx
@@ -32,7 +32,7 @@ import ContentTypeSearchResultsContainer from './ContentTypeSearchResultsContain
import SearchVideo from './SearchVideo';
import { hasActivatedAndCurrentSubscription } from './utils';
import VideoBanner from '../microlearning/VideoBanner';
-import ExpiredSubscriptionModal from '../expired-subscription-modal';
+import BlockingSubscriptionExpirationModal from '../expired-subscription-modal';
function useSearchPathwayModal() {
const [isLearnerPathwayModalOpen, openLearnerPathwayModal, close] = useToggle(false);
@@ -114,7 +114,7 @@ const Search = () => {
return (
<>
-
+