From 4ac47dfd8f11b3129daefb02d2a47102095acc7c Mon Sep 17 00:00:00 2001 From: Hamzah Ullah Date: Fri, 10 Jan 2025 16:30:32 -0500 Subject: [PATCH] fix: remove standalone find a course button --- src/components/app/data/utils.js | 75 +++++++++++++------ src/components/course/routes/CourseAbout.jsx | 4 +- src/components/dashboard/DashboardPage.jsx | 6 +- .../expired-subscription-modal/index.jsx | 6 +- .../tests/ExpiredSubscriptionModal.test.jsx | 8 +- src/components/search/Search.jsx | 4 +- 6 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/components/app/data/utils.js b/src/components/app/data/utils.js index 9246382e53..7b43ec6e90 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 1f796cf436..c0684a83e9 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 83b7140ade..eb977f5d9b 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 c92eef80f8..f8f8a6aa23 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 987683010a..72602925bd 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 cb2fd426df..7902cc4782 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 ( <> - +