-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default as useCourseEnrollments } from './useCourseEnrollments'; | ||
Check failure on line 1 in src/components/LearnerActivityTable/data/hooks/index.js GitHub Actions / tests (18)
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { useCallback, useMemo, useState } from 'react'; | ||
import { camelCaseObject } from '@edx/frontend-platform/utils'; | ||
import debounce from 'lodash.debounce'; | ||
import { logError } from '@edx/frontend-platform/logging'; | ||
import EnterpriseDataApiService from '../../../../data/services/EnterpriseDataApiService'; | ||
|
||
const applySortByToOptions = (sortBy, options) => { | ||
console.log(sortBy); | ||
Check warning on line 8 in src/components/LearnerActivityTable/data/hooks/useCourseEnrollments.js GitHub Actions / tests (18)
|
||
console.log(options); | ||
Check warning on line 9 in src/components/LearnerActivityTable/data/hooks/useCourseEnrollments.js GitHub Actions / tests (18)
|
||
}; | ||
|
||
const applyFiltersToOptions = (filters, options) => { | ||
console.log(filters); | ||
Check warning on line 13 in src/components/LearnerActivityTable/data/hooks/useCourseEnrollments.js GitHub Actions / tests (18)
|
||
console.log(options); | ||
Check warning on line 14 in src/components/LearnerActivityTable/data/hooks/useCourseEnrollments.js GitHub Actions / tests (18)
|
||
}; | ||
|
||
const useCourseEnrollments = (enterpriseId, learnerActivity) => { | ||
const [isLoading, setIsLoading] = useState(true); | ||
const [courseEnrollments, setCourseEnrollments] = useState({ | ||
itemCount: 0, | ||
pageCount: 0, | ||
results: [], | ||
}); | ||
|
||
const fetchCourseEnrollments = useCallback(async (args) => { | ||
try { | ||
setIsLoading(true); | ||
const options = { | ||
page: args.pageIndex + 1, | ||
pageSize: args.pageSize, | ||
learnerActivity, | ||
}; | ||
if (args.sortBy?.length > 0) { | ||
applySortByToOptions(args.sortBy, options); | ||
} | ||
if (args.filters?.length > 0) { | ||
applyFiltersToOptions(args.filters, options); | ||
} | ||
const response = await EnterpriseDataApiService.fetchCourseEnrollments(enterpriseId, options); | ||
const data = camelCaseObject(response.data); | ||
|
||
setCourseEnrollments({ | ||
itemCount: data.count, | ||
pageCount: data.numPages ?? Math.floor(data.count / options.pageSize), | ||
results: data.results, | ||
}); | ||
} catch (error) { | ||
logError(error); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}, [enterpriseId, learnerActivity]); | ||
|
||
const debouncedFetchCourseEnrollments = useMemo( | ||
() => debounce(fetchCourseEnrollments, 300), | ||
[fetchCourseEnrollments], | ||
); | ||
|
||
return { | ||
isLoading, | ||
courseEnrollments, | ||
fetchCourseEnrollments: debouncedFetchCourseEnrollments, | ||
}; | ||
}; | ||
|
||
export default useCourseEnrollments; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './hooks'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,153 +1,146 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; | ||
|
||
import TableContainer from '../../containers/TableContainer'; | ||
import { useIntl } from '@edx/frontend-platform/i18n'; | ||
import { DataTable } from '@openedx/paragon'; | ||
import { useCourseEnrollments } from './data'; | ||
import { | ||
i18nFormatTimestamp, i18nFormatPassedTimestamp, i18nFormatProgressStatus, formatPercentage, | ||
i18nFormatTimestamp, | ||
i18nFormatPassedTimestamp, | ||
i18nFormatProgressStatus, | ||
formatPercentage, | ||
} from '../../utils'; | ||
import EnterpriseDataApiService from '../../data/services/EnterpriseDataApiService'; | ||
|
||
class LearnerActivityTable extends React.Component { | ||
getTableColumns() { | ||
const { activity, intl } = this.props; | ||
const tableColumns = [ | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.user_email.column.heading', | ||
defaultMessage: 'Email', | ||
description: 'Column heading for the user email column in the learner activity table', | ||
}), | ||
key: 'user_email', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_title.column.heading', | ||
defaultMessage: 'Course Title', | ||
description: 'Column heading for the course title column in the learner activity table', | ||
}), | ||
key: 'course_title', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_list_price.column.heading', | ||
defaultMessage: 'Course Price', | ||
description: 'Column heading for the course price column in the learner activity table', | ||
}), | ||
key: 'course_list_price', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_start_date.column.heading', | ||
defaultMessage: 'Start Date', | ||
description: 'Column heading for the course start date column in the learner activity table', | ||
}), | ||
key: 'course_start_date', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_end_date.column.heading', | ||
defaultMessage: 'End Date', | ||
description: 'Column heading for the course end date column in the learner activity table', | ||
}), | ||
key: 'course_end_date', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.passed_date.column.heading', | ||
defaultMessage: 'Passed Date', | ||
description: 'Column heading for the passed date column in the learner activity table', | ||
}), | ||
key: 'passed_date', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.current_grade.column.heading', | ||
defaultMessage: 'Current Grade', | ||
description: 'Column heading for the current grade column in the learner activity table', | ||
}), | ||
key: 'current_grade', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.progress_status.column.heading', | ||
defaultMessage: 'Progress Status', | ||
description: 'Column heading for the progress status column in the learner activity table', | ||
}), | ||
key: 'progress_status', | ||
columnSortable: true, | ||
}, | ||
{ | ||
label: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.enrollment_date.column.heading', | ||
defaultMessage: 'Last Activity Date', | ||
description: 'Column heading for the last activity date column in the learner activity table', | ||
}), | ||
key: 'last_activity_date', | ||
columnSortable: true, | ||
}, | ||
]; | ||
const UserEmail = ({ row }) => ( | ||
<span data-hj-suppress>{row.original.user_email}</span> | ||
); | ||
|
||
if (activity !== 'active_past_week') { | ||
return tableColumns.filter(column => column.key !== 'passed_date'); | ||
} | ||
return tableColumns; | ||
} | ||
UserEmail.propTypes = { | ||
row: PropTypes.shape({ | ||
original: PropTypes.shape({ | ||
user_email: PropTypes.string.isRequired, | ||
}).isRequired, | ||
}).isRequired, | ||
}; | ||
|
||
formatTableData = enrollments => enrollments.map(enrollment => ({ | ||
...enrollment, | ||
user_email: <span data-hj-suppress>{enrollment.user_email}</span>, | ||
last_activity_date: i18nFormatTimestamp({ intl: this.props.intl, timestamp: enrollment.last_activity_date }), | ||
course_start_date: i18nFormatTimestamp({ intl: this.props.intl, timestamp: enrollment.course_start_date }), | ||
course_end_date: i18nFormatTimestamp({ intl: this.props.intl, timestamp: enrollment.course_end_date }), | ||
enrollment_date: i18nFormatTimestamp({ | ||
intl: this.props.intl, timestamp: enrollment.enrollment_date, | ||
}), | ||
passed_date: i18nFormatPassedTimestamp({ intl: this.props.intl, timestamp: enrollment.passed_date }), | ||
user_account_creation_date: i18nFormatTimestamp({ | ||
intl: this.props.intl, timestamp: enrollment.user_account_creation_date, | ||
}), | ||
progress_status: i18nFormatProgressStatus({ intl: this.props.intl, progressStatus: enrollment.progress_status }), | ||
course_list_price: enrollment.course_list_price ? `$${enrollment.course_list_price}` : '', | ||
current_grade: formatPercentage({ decimal: enrollment.current_grade }), | ||
})); | ||
const LearnerActivityTable = ({ enterpriseId, activity }) => { | ||
const intl = useIntl(); | ||
const { | ||
isLoading, | ||
enrolledLearners: tableData, | ||
fetchEnrolledLearners: fetchTableData, | ||
} = useCourseEnrollments(enterpriseId, { learnerActivity: activity }); | ||
|
||
render() { | ||
const { activity, id } = this.props; | ||
const columns = [ | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.user_email.column.heading', | ||
defaultMessage: 'Email', | ||
description: 'Column heading for the user email column in the learner activity table', | ||
}), | ||
accessor: 'user_email', | ||
Cell: UserEmail, | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_title.column.heading', | ||
defaultMessage: 'Course Title', | ||
description: 'Column heading for the course title column in the learner activity table', | ||
}), | ||
accessor: 'course_title', | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_list_price.column.heading', | ||
defaultMessage: 'Course Price', | ||
description: 'Column heading for the course price column in the learner activity table', | ||
}), | ||
accessor: 'course_list_price', | ||
Cell: ({ row }) => (row.values.course_list_price ? `$${row.values.course_list_price}` : ''), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_start_date.column.heading', | ||
defaultMessage: 'Start Date', | ||
description: 'Column heading for the course start date column in the learner activity table', | ||
}), | ||
accessor: 'course_start_date', | ||
Cell: ({ row }) => i18nFormatTimestamp({ intl, timestamp: row.values.course_start_date }), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.course_end_date.column.heading', | ||
defaultMessage: 'End Date', | ||
description: 'Column heading for the course end date column in the learner activity table', | ||
}), | ||
accessor: 'course_end_date', | ||
Cell: ({ row }) => i18nFormatTimestamp({ intl, timestamp: row.values.course_end_date }), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.passed_date.column.heading', | ||
defaultMessage: 'Passed Date', | ||
description: 'Column heading for the passed date column in the learner activity table', | ||
}), | ||
accessor: 'passed_date', | ||
Cell: ({ row }) => i18nFormatPassedTimestamp({ intl, timestamp: row.values.passed_date }), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.current_grade.column.heading', | ||
defaultMessage: 'Current Grade', | ||
description: 'Column heading for the current grade column in the learner activity table', | ||
}), | ||
accessor: 'current_grade', | ||
Cell: ({ row }) => formatPercentage({ decimal: row.values.current_grade }), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.progress_status.column.heading', | ||
defaultMessage: 'Progress Status', | ||
description: 'Column heading for the progress status column in the learner activity table', | ||
}), | ||
accessor: 'progress_status', | ||
Cell: ({ row }) => i18nFormatProgressStatus({ intl, progressStatus: row.values.progress_status }), | ||
}, | ||
{ | ||
Header: intl.formatMessage({ | ||
id: 'admin.portal.lpr.learner.activity.table.enrollment_date.column.heading', | ||
defaultMessage: 'Last Activity Date', | ||
description: 'Column heading for the last activity date column in the learner activity table', | ||
}), | ||
accessor: 'last_activity_date', | ||
Cell: ({ row }) => i18nFormatTimestamp({ intl, timestamp: row.values.last_activity_date }), | ||
}, | ||
]; | ||
|
||
return ( | ||
<TableContainer | ||
id={id} | ||
className={id} | ||
key={id} | ||
fetchMethod={(enterpriseId, options) => EnterpriseDataApiService.fetchCourseEnrollments( | ||
enterpriseId, | ||
{ | ||
learnerActivity: activity, | ||
...options, | ||
}, | ||
)} | ||
columns={this.getTableColumns()} | ||
formatData={this.formatTableData} | ||
tableSortable | ||
/> | ||
); | ||
if (activity !== 'active_past_week') { | ||
columns.splice(columns.findIndex(col => col.accessor === 'passed_date'), 1); | ||
} | ||
} | ||
|
||
return ( | ||
<DataTable | ||
isSortable | ||
manualSortBy | ||
isPaginated | ||
manualPagination | ||
isLoading={isLoading} | ||
columns={columns} | ||
initialState={{ | ||
pageSize: 20, // Set this according to your requirements | ||
pageIndex: 0, | ||
sortBy: [{ id: 'last_activity_date', desc: true }], | ||
}} | ||
fetchData={fetchTableData} | ||
data={tableData.results} | ||
itemCount={tableData.itemCount} | ||
pageCount={tableData.pageCount} | ||
/> | ||
); | ||
}; | ||
|
||
LearnerActivityTable.propTypes = { | ||
id: PropTypes.string.isRequired, | ||
enterpriseId: PropTypes.string.isRequired, | ||
activity: PropTypes.string.isRequired, | ||
// injected | ||
intl: intlShape.isRequired, | ||
}; | ||
|
||
export default injectIntl(LearnerActivityTable); | ||
export default LearnerActivityTable; |