diff --git a/src/Configuration/Customers/CustomerDetailView/CustomerPlanContainer.jsx b/src/Configuration/Customers/CustomerDetailView/CustomerPlanContainer.jsx index 872687491..b96e245b1 100644 --- a/src/Configuration/Customers/CustomerDetailView/CustomerPlanContainer.jsx +++ b/src/Configuration/Customers/CustomerDetailView/CustomerPlanContainer.jsx @@ -1,23 +1,25 @@ -import { useState } from 'react'; -import { useParams } from 'react-router-dom'; +import { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { Form, Skeleton } from '@openedx/paragon'; -import useAllAssociatedPlans from '../data/hooks/useAllAssociatedPlans'; import LearnerCreditPlanCard from './LearnerCreditPlanCard'; import SubscriptionPlanCard from './SubscriptionPlanCard'; -const CustomerPlanContainer = ({ slug }) => { - const { id } = useParams(); - const { - activePolicies, - activeSubscriptions, - countOfActivePlans, - countOfAllPlans, - inactivePolicies, - inactiveSubscriptions, - isLoading, - } = useAllAssociatedPlans(id); +const CustomerPlanContainer = ({ + slug, + activePolicies, + activeSubscriptions, + countOfActivePlans, + countOfAllPlans, + inactivePolicies, + inactiveSubscriptions, + isLoading, +}) => { const [showInactive, setShowInactive] = useState(false); + useEffect(() => { + if (!countOfActivePlans && countOfAllPlans) { + setShowInactive(true); + } + }, []); const renderActivePoliciesCard = activePolicies.map(policy => ( )); @@ -31,19 +33,13 @@ const CustomerPlanContainer = ({ slug }) => { )); - const hasActivePlans = activePolicies.length > 0 || renderActiveSubscriptions.length > 0; - - if (!hasActivePlans) { - return null; - } - return (
{!isLoading ? (

Associated subsidy plans ({showInactive ? countOfAllPlans : countOfActivePlans})

- {(countOfAllPlans !== countOfActivePlans) && ( + {(countOfAllPlans > countOfActivePlans && countOfActivePlans) ? ( { > Show inactive - )} + ) : null}

{renderActivePoliciesCard} @@ -73,6 +69,35 @@ const CustomerPlanContainer = ({ slug }) => { CustomerPlanContainer.propTypes = { slug: PropTypes.string.isRequired, + activePolicies: PropTypes.arrayOf(PropTypes.shape({ + uuid: PropTypes.string.isRequired, + subsidyActiveDatetime: PropTypes.string.isRequired, + subsidyExpirationDatetime: PropTypes.string.isRequired, + policyType: PropTypes.string.isRequired, + created: PropTypes.string.isRequired, + })).isRequired, + activeSubscriptions: PropTypes.arrayOf(PropTypes.shape({ + uuid: PropTypes.string.isRequired, + startDate: PropTypes.string.isRequired, + expirationDate: PropTypes.string.isRequired, + created: PropTypes.string.isRequired, + })).isRequired, + countOfActivePlans: PropTypes.number.isRequired, + countOfAllPlans: PropTypes.number.isRequired, + inactivePolicies: PropTypes.arrayOf(PropTypes.shape({ + uuid: PropTypes.string.isRequired, + subsidyActiveDatetime: PropTypes.string.isRequired, + subsidyExpirationDatetime: PropTypes.string.isRequired, + policyType: PropTypes.string.isRequired, + created: PropTypes.string.isRequired, + })).isRequired, + inactiveSubscriptions: PropTypes.arrayOf(PropTypes.shape({ + uuid: PropTypes.string.isRequired, + startDate: PropTypes.string.isRequired, + expirationDate: PropTypes.string.isRequired, + created: PropTypes.string.isRequired, + })).isRequired, + isLoading: PropTypes.bool.isRequired, }; export default CustomerPlanContainer; diff --git a/src/Configuration/Customers/CustomerDetailView/CustomerViewContainer.jsx b/src/Configuration/Customers/CustomerDetailView/CustomerViewContainer.jsx index c8f5c41e3..4e3d2c344 100644 --- a/src/Configuration/Customers/CustomerDetailView/CustomerViewContainer.jsx +++ b/src/Configuration/Customers/CustomerDetailView/CustomerViewContainer.jsx @@ -13,12 +13,14 @@ import { getEnterpriseCustomer } from '../data/utils'; import CustomerIntegrations from './CustomerIntegrations'; import EnterpriseCustomerUsersTable from './EnterpriseCustomerUsersTable'; import CustomerPlanContainer from './CustomerPlanContainer'; +import useAllAssociatedPlans from '../data/hooks/useAllAssociatedPlans'; const CustomerViewContainer = () => { const { id } = useParams(); const [enterpriseCustomer, setEnterpriseCustomer] = useState({}); const [isLoading, setIsLoading] = useState(true); const intl = useIntl(); + const associatedPlans = useAllAssociatedPlans(id); const fetchData = useCallback( async () => { @@ -38,6 +40,23 @@ const CustomerViewContainer = () => { fetchData(); }, []); + const renderPlanContainer = () => { + if (!isLoading && !associatedPlans.isLoading && associatedPlans.countOfAllPlans) { + return ( + + + + ); + } + if (!associatedPlans.isLoading && !associatedPlans.countOfAllPlans) { + return false; + } + if (associatedPlans.isLoading) { + return ; + } + return null; + }; + return (
{!isLoading ? ( @@ -64,11 +83,9 @@ const CustomerViewContainer = () => { - - {!isLoading ? : } - + {renderPlanContainer()} - + { isLoading, enterpriseUsersTableData, fetchEnterpriseUsersData, + showTable, } = useCustomerUsersTableData(id); - if (!enterpriseUsersTableData.itemCount) { - return null; - } - return (
-

Associated users ({enterpriseUsersTableData.itemCount})

-
- + {showTable ? ( +
+

Associated users {enterpriseUsersTableData.itemCount > 0 + && ({enterpriseUsersTableData.itemCount})} +

+
+ +
+ ) : null}
); }; diff --git a/src/Configuration/Customers/CustomerDetailView/tests/CustomerPlanContainer.test.jsx b/src/Configuration/Customers/CustomerDetailView/tests/CustomerPlanContainer.test.jsx index c7f4c87ab..d2bea405f 100644 --- a/src/Configuration/Customers/CustomerDetailView/tests/CustomerPlanContainer.test.jsx +++ b/src/Configuration/Customers/CustomerDetailView/tests/CustomerPlanContainer.test.jsx @@ -5,7 +5,6 @@ import userEvent from '@testing-library/user-event'; import { getConfig } from '@edx/frontend-platform'; import { IntlProvider } from '@edx/frontend-platform/i18n'; -import useAllAssociatedPlans from '../../data/hooks/useAllAssociatedPlans'; import { formatDate } from '../../data/utils'; import CustomerPlanContainer from '../CustomerPlanContainer'; @@ -19,11 +18,6 @@ jest.mock('@edx/frontend-platform', () => ({ getConfig: jest.fn(), })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ id: 'test-uuid' }), -})); - const CUSTOMER_SLUG = 'test-slug'; describe('CustomerPlanContainer', () => { @@ -44,7 +38,7 @@ describe('CustomerPlanContainer', () => { ENTERPRISE_ACCESS_BASE_URL: 'http:www.enterprise-access.com', LICENSE_MANAGER_URL: 'http:www.license-manager.com', })); - useAllAssociatedPlans.mockReturnValue({ + const mockProps = { isLoading: false, activePolicies: [{ subsidyActiveDatetime: '2024-08-23T20:02:57.651943Z', @@ -71,10 +65,10 @@ describe('CustomerPlanContainer', () => { policyType: 'learnerCredit', isSubsidyActive: false, }], - }); + }; render( - + , ); const djangoLinks = screen.getAllByRole('link', { name: 'Open in Django' }); @@ -99,26 +93,4 @@ describe('CustomerPlanContainer', () => { await waitFor(() => expect(screen.getByText('Associated subsidy plans (3)')).toBeInTheDocument()); expect(screen.getByText('Inactive')).toBeInTheDocument(); }); - it('does not render CustomerPlanContainer data', async () => { - getConfig.mockImplementation(() => ({ - ADMIN_PORTAL_BASE_URL: 'http://www.testportal.com', - ENTERPRISE_ACCESS_BASE_URL: 'http:www.enterprise-access.com', - LICENSE_MANAGER_URL: 'http:www.license-manager.com', - })); - useAllAssociatedPlans.mockReturnValue({ - isLoading: false, - activePolicies: [], - activeSubscriptions: [], - countOfActivePlans: 0, - countOfAllPlans: 0, - inactiveSubscriptions: [], - inactivePolicies: [], - }); - render( - - - , - ); - expect(screen.queryByText('Associated subsidy plans (0)')).not.toBeInTheDocument(); - }); }); diff --git a/src/Configuration/Customers/CustomerDetailView/tests/EnterpriseCustomerUsersTable.test.jsx b/src/Configuration/Customers/CustomerDetailView/tests/EnterpriseCustomerUsersTable.test.jsx index d9bc38dc2..4fde961e5 100644 --- a/src/Configuration/Customers/CustomerDetailView/tests/EnterpriseCustomerUsersTable.test.jsx +++ b/src/Configuration/Customers/CustomerDetailView/tests/EnterpriseCustomerUsersTable.test.jsx @@ -33,6 +33,7 @@ const mockData = { ], }, fetchEnterpriseUsersData: mockFetchEnterpriseUsersData, + showTable: true, }; jest.mock('../../data/hooks/useCustomerUsersTableData'); diff --git a/src/Configuration/Customers/data/hooks/useCustomerUsersTableData.js b/src/Configuration/Customers/data/hooks/useCustomerUsersTableData.js index ab673e938..e7e52efc4 100644 --- a/src/Configuration/Customers/data/hooks/useCustomerUsersTableData.js +++ b/src/Configuration/Customers/data/hooks/useCustomerUsersTableData.js @@ -1,5 +1,5 @@ import { - useCallback, useMemo, useState, + useCallback, useMemo, useState, useEffect, } from 'react'; import { camelCaseObject } from '@edx/frontend-platform/utils'; import { logError } from '@edx/frontend-platform/logging'; @@ -9,6 +9,7 @@ import LmsApiService from '../../../../data/services/EnterpriseApiService'; const useCustomerUsersTableData = (enterpriseUuid) => { const [isLoading, setIsLoading] = useState(true); + const [showTable, setShowTable] = useState(false); const [enterpriseUsersTableData, setEnterpriseUsersTableData] = useState({ itemCount: 0, pageCount: 0, @@ -66,10 +67,23 @@ const useCustomerUsersTableData = (enterpriseUuid) => { [fetchEnterpriseUsersData], ); + useEffect(() => { + const args = { + pageIndex: 0, + filters: [], + sortBy: [], + }; + fetchEnterpriseUsersData(args); + if (enterpriseUsersTableData.itemCount) { + setShowTable(true); + } + }, [fetchEnterpriseUsersData, enterpriseUsersTableData.itemCount]); + return { isLoading, enterpriseUsersTableData, fetchEnterpriseUsersData: debouncedFetchEnterpriseUsersData, + showTable, }; };