diff --git a/package-lock.json b/package-lock.json index d99963ceef..69b0dbc0b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25627,4 +25627,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/components/AdminV2/AdminSearchForm.jsx b/src/components/AdminV2/AdminSearchForm.jsx index 4f62917e2a..1aa38a1b3c 100644 --- a/src/components/AdminV2/AdminSearchForm.jsx +++ b/src/components/AdminV2/AdminSearchForm.jsx @@ -19,7 +19,7 @@ import SearchBar from '../SearchBar'; const AdminSearchForm = ({ searchEnrollmentsList, searchParams: { - searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery, + searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery, searchEnrollmentQuery, }, tableData = [], budgets, @@ -37,7 +37,8 @@ const AdminSearchForm = ({ return; } searchEnrollmentsList(); - }, [searchEnrollmentsList, searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery]); + }, [searchEnrollmentsList, searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery, + searchEnrollmentQuery]); const onCourseSelect = (event) => { const updateParams = { @@ -71,6 +72,19 @@ const AdminSearchForm = ({ ); }; + const onEnrollmentSelect = (event) => { + const updateParams = { + search_enrollment: event.target.value, + page: 1, + }; + updateUrl(navigate, location.pathname, updateParams); + sendEnterpriseTrackEvent( + enterpriseId, + EVENT_NAMES.LEARNER_PROGRESS_REPORT.FILTER_BY_ENROLLMENT_DROPDOWN, + { enrollment: event.target.value }, + ); + }; + const courseTitles = Array.from(new Set(tableData.map(en => en.course_title).sort())); const courseDates = Array.from(new Set(tableData.map(en => en.course_start_date).sort().reverse())); const columnWidth = (budgets?.length || groups?.length) ? 'col-md-3' : 'col-md-6'; @@ -79,6 +93,32 @@ const AdminSearchForm = ({
+
+ + + + updateUrl(navigate, location.pathname, { + search: query, + page: 1, + })} + onClear={() => updateUrl(navigate, location.pathname, { search: undefined })} + value={searchQuery} + aria-labelledby="search-email-label" + className="py-0" + inputProps={{ 'data-hj-suppress': true }} + /> +
{groups?.length ? (
@@ -115,7 +155,79 @@ const AdminSearchForm = ({
) : null} - + {budgets?.length ? ( +
+ + + + + onBudgetSelect(e)} + > + + {budgets.map(budget => ( + + ))} + + +
+ ) : null } + {/* Filter by Enrollment */} +
+ + + + + onEnrollmentSelect(e)} + > + + + + + +
@@ -211,68 +323,7 @@ const AdminSearchForm = ({
- {budgets?.length ? ( -
- - - - - onBudgetSelect(e)} - > - - {budgets.map(budget => ( - - ))} - - -
- ) : null } -
- - - - updateUrl(navigate, location.pathname, { - search: query, - page: 1, - })} - onClear={() => updateUrl(navigate, location.pathname, { search: undefined })} - value={searchQuery} - aria-labelledby="search-email-label" - className="py-0" - inputProps={{ 'data-hj-suppress': true }} - /> -
+
@@ -291,6 +342,7 @@ AdminSearchForm.propTypes = { searchDateQuery: PropTypes.string, searchBudgetQuery: PropTypes.string, searchGroupQuery: PropTypes.string, + searchEnrollmentQuery: PropTypes.string, }).isRequired, tableData: PropTypes.arrayOf(PropTypes.shape({})), budgets: PropTypes.arrayOf(PropTypes.shape({})), diff --git a/src/components/AdminV2/index.jsx b/src/components/AdminV2/index.jsx index 4c151947f0..9624c2176f 100644 --- a/src/components/AdminV2/index.jsx +++ b/src/components/AdminV2/index.jsx @@ -119,7 +119,7 @@ const Admin = ({ }, [enterpriseId]); const getMetadataForAction = (actionSlugParam) => { - const expectedQueryParams = ['search', 'search_course', 'search_start_date', 'budget_uuid', 'group_uuid']; + const expectedQueryParams = ['search', 'search_course', 'search_start_date', 'budget_uuid', 'group_uuid', 'search_enrollment']; const filteredQueryParams = getFilteredQueryParams(location.search, expectedQueryParams); const defaultData = { @@ -357,7 +357,7 @@ const Admin = ({ const { search: searchQuery, pathname } = location; // remove the querys from the path const queryParams = new URLSearchParams(searchQuery); - ['search', 'search_course', 'search_start_date', 'budget_uuid', 'group_uuid'].forEach((searchTerm) => { + ['search', 'search_course', 'search_start_date', 'budget_uuid', 'group_uuid', 'search_enrollment'].forEach((searchTerm) => { queryParams.delete(searchTerm); }); const resetQuery = queryParams.toString(); @@ -437,6 +437,7 @@ const Admin = ({ searchDateQuery: queryParams.get('search_start_date') || '', searchBudgetQuery: queryParams.get('budget_uuid') || '', searchGroupQuery: queryParams.get('group_uuid') || '', + searchEnrollmentQuery: queryParams.get('search_enrollment') || '', }; const hasCompleteInsights = insights?.learner_engagement && insights?.learner_progress; diff --git a/src/components/AdminV2/tests/AdminSearchForm.test.jsx b/src/components/AdminV2/tests/AdminSearchForm.test.jsx index f2e30fe46a..7a69de7ed0 100644 --- a/src/components/AdminV2/tests/AdminSearchForm.test.jsx +++ b/src/components/AdminV2/tests/AdminSearchForm.test.jsx @@ -50,10 +50,10 @@ describe('', () => { render(); const formControls = await screen.findAllByTestId('admin-search-form-control'); - expect(formControls.length).toBe(2); // dropdowns + expect(formControls.length).toBe(3); // dropdowns const searchBar = await screen.findByTestId('admin-search-bar'); // search input expect(searchBar).toBeInTheDocument(); - expect(formControls[1].textContent).toContain('Choose a course'); + expect(formControls[2].textContent).toContain('Choose a course'); }); it.each([ @@ -69,6 +69,7 @@ describe('', () => { searchDateQuery: '', searchBudgetQuery: '', searchGroupQuery: '', + searchEnrollmentQuery: '', }; const { rerender } = render( @@ -196,6 +197,57 @@ describe('', () => { }, ); }); + it('selects the correct enrollment status', async () => { + const user = userEvent.setup(); + + const props = { + ...DEFAULT_PROPS, + location: { pathname: '/admin/learners' }, + }; + + render(); + + const selectElement = screen.getByLabelText('Filter by enrollment'); + + // --- Test selecting "enrolled" --- + await user.selectOptions(selectElement, 'enrolled'); + + expect(updateUrl).toHaveBeenCalledWith( + undefined, + '/admin/learners', + { + search_enrollment: 'enrolled', + page: 1, + }, + ); + + expect(sendEnterpriseTrackEvent).toHaveBeenCalledWith( + props.enterpriseId, + EVENT_NAMES.LEARNER_PROGRESS_REPORT.FILTER_BY_ENROLLMENT_DROPDOWN, + { enrollment: 'enrolled' }, + ); + + updateUrl.mockClear(); + sendEnterpriseTrackEvent.mockClear(); + + // --- Test selecting "unenrolled" --- + await user.selectOptions(selectElement, 'unenrolled'); + + expect(updateUrl).toHaveBeenCalledWith( + undefined, + '/admin/learners', + { + search_enrollment: 'unenrolled', + page: 1, + }, + ); + + expect(sendEnterpriseTrackEvent).toHaveBeenCalledWith( + props.enterpriseId, + EVENT_NAMES.LEARNER_PROGRESS_REPORT.FILTER_BY_ENROLLMENT_DROPDOWN, + { enrollment: 'unenrolled' }, + ); + }); }); describe('', () => { diff --git a/src/eventTracking.js b/src/eventTracking.js index 085fdb69a4..a862dfd0c7 100644 --- a/src/eventTracking.js +++ b/src/eventTracking.js @@ -38,6 +38,7 @@ const PEOPLE_MANAGEMENT_EVENTS = { // learner-progress-report const LEARNER_PROGRESS_REPORT_EVENTS = { FILTER_BY_GROUP_DROPDOWN: `${LEARNER_PROGRESS_REPORT_PREFIX}.group_filter.clicked`, + FILTER_BY_ENROLLMENT_DROPDOWN: `${LEARNER_PROGRESS_REPORT_PREFIX}.enrollment_filter.clicked`, }; // analytics-v2 const ANALYTICS_V2_EVENTS = { diff --git a/src/utils.js b/src/utils.js index 294b7e5de1..8a825be44a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -186,6 +186,9 @@ const getPageOptionsFromUrl = () => { if (query.has('search_start_date')) { pageOptions.search_start_date = query.get('search_start_date'); } + if (query.has('search_enrollment')) { + pageOptions.search_enrollment = query.get('search_enrollment'); + } return pageOptions; };