diff --git a/src/components/Admin/index.jsx b/src/components/Admin/index.jsx index 5fa3f64c5d..37fbf17dea 100644 --- a/src/components/Admin/index.jsx +++ b/src/components/Admin/index.jsx @@ -290,7 +290,6 @@ class Admin extends React.Component { insights, insightsLoading, } = this.props; - const queryParams = new URLSearchParams(search || ''); const queryParamsLength = Array.from(queryParams.entries()).length; const filtersActive = queryParamsLength !== 0 && !(queryParamsLength === 1 && queryParams.has('ordering')); diff --git a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx index 6b2430f189..e8f5a6d3bd 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx +++ b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx @@ -3,13 +3,14 @@ import { getEnterpriseBudgetExpiringAlertCookieName, getEnterpriseBudgetExpiringModalCookieName, getExpirationMetadata, - getNonExpiredBudgets, + getExpiredAndNonExpiredBudgets, } from '../utils'; const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, alertClose) => { const [notification, setNotification] = useState(null); const [expirationThreshold, setExpirationThreshold] = useState(null); const [modal, setModal] = useState(null); + const [isNonExpiredBudget, setisNonExpiredBudget] = useState(false); useEffect(() => { if (!budgets || budgets.length === 0) { @@ -20,18 +21,19 @@ const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, aler // expired and non-expired budgets. In that case, we only want // to determine the expiry threshold from the set of *non-expired* budgets, // so that the alert and modal below do not falsely signal. - let budgetsToConsiderForExpirationMessaging = budgets; + let budgetsToConsiderForExpirationMessaging = []; - const nonExpiredBudgets = getNonExpiredBudgets(budgets); - const hasNonExpiredBudgets = nonExpiredBudgets.length > 0; + const { nonExpiredBudgets, expiredBudgets } = getExpiredAndNonExpiredBudgets(budgets); - // If the length of all budgets is different from the length of non-expired budgets, - // then there exists at least one expired budget (note that we already early-returned - // above if there are zero total budgets). - const hasExpiredBudgets = budgets.length !== nonExpiredBudgets.length; + // Consider the length of each budget + const hasNonExpiredBudgets = nonExpiredBudgets.length > 0; - if (hasNonExpiredBudgets && hasExpiredBudgets) { + // If an unexpired budget exists, set budgetsToConsiderForExpirationMessaging to nonExpiredBudgets + if (hasNonExpiredBudgets) { budgetsToConsiderForExpirationMessaging = nonExpiredBudgets; + setisNonExpiredBudget(true); + } else { + budgetsToConsiderForExpirationMessaging = expiredBudgets; } const earliestExpiryBudget = budgetsToConsiderForExpirationMessaging.reduce( @@ -97,7 +99,7 @@ const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, aler }; return { - notification, modal, dismissModal, dismissAlert, + notification, modal, dismissModal, dismissAlert, isNonExpiredBudget, }; }; diff --git a/src/components/BudgetExpiryAlertAndModal/data/utils.js b/src/components/BudgetExpiryAlertAndModal/data/utils.js index 12a944d450..9812d78e0a 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/utils.js +++ b/src/components/BudgetExpiryAlertAndModal/data/utils.js @@ -5,9 +5,12 @@ import ExpiryThresholds from './expiryThresholds'; dayjs.extend(duration); -export const getNonExpiredBudgets = (budgets) => { +export const getExpiredAndNonExpiredBudgets = (budgets) => { const today = dayjs(); - return budgets.filter((budget) => today <= dayjs(budget.end)); + return { + nonExpiredBudgets: budgets.filter((budget) => today <= dayjs(budget.end)), + expiredBudgets: budgets.filter((budget) => today > dayjs(budget.end)), + }; }; export const getExpirationMetadata = (endDateStr) => { diff --git a/src/components/BudgetExpiryAlertAndModal/index.jsx b/src/components/BudgetExpiryAlertAndModal/index.jsx index 89566847ac..9eb1429f92 100644 --- a/src/components/BudgetExpiryAlertAndModal/index.jsx +++ b/src/components/BudgetExpiryAlertAndModal/index.jsx @@ -17,7 +17,7 @@ import EVENT_NAMES from '../../eventTracking'; import useExpiry from './data/hooks/useExpiry'; -const BudgetExpiryAlertAndModal = ({ enterpriseUUID, enterpriseFeatures }) => { +const BudgetExpiryAlertAndModal = ({ enterpriseUUID, enterpriseFeatures, disableExpiryMessagingForLearnerCredit }) => { const [modalIsOpen, modalOpen, modalClose] = useToggle(false); const [alertIsOpen, alertOpen, alertClose] = useToggle(false); @@ -46,7 +46,7 @@ const BudgetExpiryAlertAndModal = ({ enterpriseUUID, enterpriseFeatures }) => { }); const { - notification, modal, dismissModal, dismissAlert, + notification, modal, dismissModal, dismissAlert, isNonExpiredBudget, } = useExpiry( enterpriseUUID, budgets, @@ -64,6 +64,10 @@ const BudgetExpiryAlertAndModal = ({ enterpriseUUID, enterpriseFeatures }) => { }; }, [modal, notification]); + if (isNonExpiredBudget && disableExpiryMessagingForLearnerCredit) { + return null; + } + return ( <> {notification && ( @@ -141,6 +145,7 @@ const BudgetExpiryAlertAndModal = ({ enterpriseUUID, enterpriseFeatures }) => { const mapStateToProps = state => ({ enterpriseUUID: state.portalConfiguration.enterpriseId, enterpriseFeatures: state.portalConfiguration.enterpriseFeatures, + disableExpiryMessagingForLearnerCredit: state.portalConfiguration.disableExpiryMessagingForLearnerCredit, }); BudgetExpiryAlertAndModal.propTypes = { @@ -148,6 +153,7 @@ BudgetExpiryAlertAndModal.propTypes = { enterpriseFeatures: PropTypes.shape({ topDownAssignmentRealTimeLcm: PropTypes.bool.isRequired, }), + disableExpiryMessagingForLearnerCredit: PropTypes.bool.isRequired, }; export default connect(mapStateToProps)(BudgetExpiryAlertAndModal); diff --git a/src/containers/EnterpriseApp/index.jsx b/src/containers/EnterpriseApp/index.jsx index 2e7e49cc8f..cc5d3ffed6 100644 --- a/src/containers/EnterpriseApp/index.jsx +++ b/src/containers/EnterpriseApp/index.jsx @@ -7,12 +7,12 @@ import { toggleSidebarToggle } from '../../data/actions/sidebar'; const mapStateToProps = (state) => { const enterpriseListState = state.table['enterprise-list'] || {}; - return { enterprises: enterpriseListState.data, error: state.portalConfiguration.error, + disableExpiryMessagingForLearnerCredit: state.portalConfiguration.disableExpiryMessagingForLearnerCredit, enableCodeManagementScreen: state.portalConfiguration.enableCodeManagementScreen, - enableSubscriptionManagementScreen: state.portalConfiguration.enableSubscriptionManagementScreen, // eslint-disable-line max-len + enableSubscriptionManagementScreen: state.portalConfiguration.enableSubscriptionManagementScreen, enableSamlConfigurationScreen: state.portalConfiguration.enableSamlConfigurationScreen, enableAnalyticsScreen: state.portalConfiguration.enableAnalyticsScreen, enableLearnerPortal: state.portalConfiguration.enableLearnerPortal, diff --git a/src/data/reducers/portalConfiguration.js b/src/data/reducers/portalConfiguration.js index 3c7a19435e..cfae1ee448 100644 --- a/src/data/reducers/portalConfiguration.js +++ b/src/data/reducers/portalConfiguration.js @@ -15,6 +15,7 @@ const initialState = { enterpriseSlug: null, enterpriseBranding: null, identityProvider: null, + disableExpiryMessagingForLearnerCredit: false, enableCodeManagementScreen: false, enableReportingConfigScreen: false, enableSubscriptionManagementScreen: false, @@ -50,6 +51,7 @@ const portalConfiguration = (state = initialState, action) => { enterpriseSlug: action.payload.data.slug, enterpriseBranding: action.payload.data.branding_configuration, identityProvider: action.payload.data.identity_provider, + disableExpiryMessagingForLearnerCredit: action.payload.data.disable_expiry_messaging_for_learner_credit, enableCodeManagementScreen: action.payload.data.enable_portal_code_management_screen, enableReportingConfigScreen: action.payload.data.enable_portal_reporting_config_screen, enableSubscriptionManagementScreen: action.payload.data.enable_portal_subscription_management_screen, // eslint-disable-line max-len @@ -76,6 +78,7 @@ const portalConfiguration = (state = initialState, action) => { enterpriseSlug: null, enterpriseBranding: null, identityProvider: null, + disableExpiryMessagingForLearnerCredit: false, enableCodeManagementScreen: false, enableReportingConfigScreen: false, enableSubscriptionManagementScreen: false, @@ -100,6 +103,7 @@ const portalConfiguration = (state = initialState, action) => { enterpriseSlug: null, enterpriseBranding: null, identityProvider: null, + disableExpiryMessagingForLearnerCredit: null, enableCodeManagementScreen: false, enableReportingConfigScreen: false, enableSubscriptionManagementScreen: false,