diff --git a/src/components/PastWeekPassedLearnersTable/data/hooks/usePastWeekPassedLearners.js b/src/components/PastWeekPassedLearnersTable/data/hooks/usePastWeekPassedLearners.js
new file mode 100644
index 0000000000..579df42b3a
--- /dev/null
+++ b/src/components/PastWeekPassedLearnersTable/data/hooks/usePastWeekPassedLearners.js
@@ -0,0 +1,95 @@
+import {
+ useCallback, useMemo, useRef, useState,
+} from 'react';
+import { camelCaseObject } from '@edx/frontend-platform/utils';
+import debounce from 'lodash.debounce';
+import { logError } from '@edx/frontend-platform/logging';
+import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
+import EnterpriseDataApiService from '../../../../data/services/EnterpriseDataApiService';
+import EVENT_NAMES from '../../../../eventTracking';
+
+const applySortByToOptions = (sortBy, options) => {
+ if (!sortBy || sortBy.length === 0) {
+ return;
+ }
+ const apiFieldsForColumnAccessor = {
+ userEmail: { key: 'user_email' },
+ CourseTitle: { key: 'course_title' },
+ PassedDate: { key: 'passed_date' },
+ };
+ const orderingStrings = sortBy.map(({ id, desc }) => {
+ const apiFieldForColumnAccessor = apiFieldsForColumnAccessor[id];
+ if (!apiFieldForColumnAccessor) {
+ return undefined;
+ }
+ const apiFieldKey = apiFieldForColumnAccessor.key;
+ return desc ? `-${apiFieldKey}` : apiFieldKey;
+ }).filter(orderingString => !!orderingString);
+ Object.assign(options, {
+ ordering: orderingStrings.join(','),
+ });
+};
+
+const usePastWeekPassedLearners = (enterpriseId) => {
+ const shouldTrackFetchEvents = useRef(false);
+ const [isLoading, setIsLoading] = useState(true);
+ const [pastWeekPassedLearners, setPastWeekPassedLearners] = useState({
+ itemCount: 0,
+ pageCount: 0,
+ results: [],
+ });
+
+ const fetchPastWeekPassedLearners = useCallback(async (args) => {
+ try {
+ setIsLoading(true);
+ const options = {
+ page: args.pageIndex + 1,
+ pageSize: args.pageSize,
+ passedDate: 'last_week',
+ };
+ applySortByToOptions(args.sortBy, options);
+
+ const response = await EnterpriseDataApiService.fetchCourseEnrollments(enterpriseId, options);
+ const data = camelCaseObject(response.data);
+ setPastWeekPassedLearners({
+ itemCount: data.count,
+ pageCount: data.numPages ?? Math.floor(data.count / options.pageSize),
+ results: data.results,
+ });
+
+ if (shouldTrackFetchEvents.current) {
+ // track event only after original API query to avoid sending event on initial page load. instead,
+ // only track event when user performs manual data operation (e.g., pagination, sort, filter) and
+ // send all table state as event properties.
+ sendEnterpriseTrackEvent(
+ enterpriseId,
+ EVENT_NAMES.PROGRESS_REPORT.DATATABLE_SORT_BY_OR_FILTER,
+ {
+ tableId: 'completed-learners-week',
+ ...options,
+ },
+ );
+ } else {
+ // set to true to enable tracking events on future API queries
+ shouldTrackFetchEvents.current = true;
+ }
+ } catch (error) {
+ logError(error);
+ } finally {
+ setIsLoading(false);
+ }
+ }, [enterpriseId]);
+
+ const debouncedFetchPastWeekPassedLearners = useMemo(
+ () => debounce(fetchPastWeekPassedLearners, 300),
+ [fetchPastWeekPassedLearners],
+ );
+
+ return {
+ isLoading,
+ pastWeekPassedLearners,
+ fetchPastWeekPassedLearners: debouncedFetchPastWeekPassedLearners,
+ };
+};
+
+export default usePastWeekPassedLearners;
diff --git a/src/components/PastWeekPassedLearnersTable/index.jsx b/src/components/PastWeekPassedLearnersTable/index.jsx
index 2fa60f8b62..1ef4152463 100644
--- a/src/components/PastWeekPassedLearnersTable/index.jsx
+++ b/src/components/PastWeekPassedLearnersTable/index.jsx
@@ -1,66 +1,81 @@
import React from 'react';
-
+import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
-
-import TableContainer from '../../containers/TableContainer';
-import EnterpriseDataApiService from '../../data/services/EnterpriseDataApiService';
+import { DataTable } from '@openedx/paragon';
+import usePastWeekPassedLearners from './data/hooks/usePastWeekPassedLearners';
import { i18nFormatTimestamp } from '../../utils';
-const PastWeekPassedLearnersTable = () => {
- const intl = useIntl();
+const UserEmail = ({ row }) => (
+ {row.original.userEmail}
+);
- const tableColumns = [
- {
- label: intl.formatMessage({
- id: 'admin.portal.lpr.past.week.passed.learners.table.user_email.column.heading',
- defaultMessage: 'Email',
- description: 'Column heading for the user email column in the past week passed learners table',
- }),
- key: 'user_email',
- columnSortable: true,
- },
- {
- label: intl.formatMessage({
- id: 'admin.portal.lpr.past.week.passed.learners.table.course_title.column.heading',
- defaultMessage: 'Course Title',
- description: 'Column heading for the course title column in the past week passed learners table',
- }),
- key: 'course_title',
- columnSortable: true,
- },
- {
- label: intl.formatMessage({
- id: 'admin.portal.lpr.past.week.passed.learners.table.passed_date.column.heading',
- defaultMessage: 'Passed Date',
- description: 'Column heading for the passed date column in the past week passed learners table',
- }),
- key: 'passed_date',
- columnSortable: true,
- },
- ];
+UserEmail.propTypes = {
+ row: PropTypes.shape({
+ original: PropTypes.shape({
+ userEmail: PropTypes.string.isRequired,
+ }).isRequired,
+ }).isRequired,
+};
- const formatLearnerData = learners => learners.map(learner => ({
- ...learner,
- user_email: {learner.user_email},
- passed_date: i18nFormatTimestamp({ intl, timestamp: learner.passed_date }),
- }));
+const PastWeekPassedLearnersTable = ({ enterpriseId }) => {
+ const intl = useIntl();
+ const {
+ isLoading,
+ pastWeekPassedLearners: tableData,
+ fetchPastWeekPassedLearners: fetchTableData,
+ } = usePastWeekPassedLearners(enterpriseId);
return (
- EnterpriseDataApiService.fetchCourseEnrollments(
- enterpriseId,
+ i18nFormatTimestamp({ intl, timestamp: row.values.passedDate }),
+ },
+ ]}
+ initialState={{
+ pageSize: 20, // Set this according to your requirements
+ pageIndex: 0,
+ sortBy: [{ id: 'passedDate', desc: true }],
+ selectedRowsOrdered: [],
+ }}
+ fetchData={fetchTableData}
+ data={tableData.results}
+ itemCount={tableData.itemCount}
+ pageCount={tableData.pageCount}
/>
);
};
+PastWeekPassedLearnersTable.propTypes = {
+ enterpriseId: PropTypes.string.isRequired,
+};
+
export default PastWeekPassedLearnersTable;
diff --git a/src/eventTracking.js b/src/eventTracking.js
index f7dfd9872f..7525d89a36 100644
--- a/src/eventTracking.js
+++ b/src/eventTracking.js
@@ -17,6 +17,7 @@ const SUBSCRIPTION_PREFIX = `${PROJECT_NAME}.subscriptions`;
const SETTINGS_PREFIX = `${PROJECT_NAME}.settings`;
const CONTENT_HIGHLIGHTS_PREFIX = `${PROJECT_NAME}.content_highlights`;
const LEARNER_CREDIT_MANAGEMENT_PREFIX = `${PROJECT_NAME}.learner_credit_management`;
+const PROGRESS_REPORT_PREFIX = `${PROJECT_NAME}.progress_report`;
// Sub-prefixes
// Subscriptions
@@ -95,6 +96,10 @@ export const CONTENT_HIGHLIGHTS_EVENTS = {
const SETTINGS_ACCESS_PREFIX = `${SETTINGS_PREFIX}.ACCESS`;
+export const PROGRESS_REPORT_EVENTS = {
+ DATATABLE_SORT_BY_OR_FILTER: `${PROGRESS_REPORT_PREFIX}.datatable.sort_by_or_filter.changed`,
+};
+
export const SETTINGS_ACCESS_EVENTS = {
UNIVERSAL_LINK_TOGGLE: `${SETTINGS_ACCESS_PREFIX}.universal-link.toggle.clicked`,
UNIVERSAL_LINK_GENERATE: `${SETTINGS_ACCESS_PREFIX}.universal-link.generate.clicked`,
@@ -184,6 +189,7 @@ const EVENT_NAMES = {
SUBSCRIPTIONS: SUBSCRIPTION_EVENTS,
CONTENT_HIGHLIGHTS: CONTENT_HIGHLIGHTS_EVENTS,
LEARNER_CREDIT_MANAGEMENT: LEARNER_CREDIT_MANAGEMENT_EVENTS,
+ PROGRESS_REPORT: PROGRESS_REPORT_EVENTS,
};
export default EVENT_NAMES;