diff --git a/src/components/AdminV2/AdminCards.jsx b/src/components/AdminV2/AdminCards.jsx index cb592b8f83..15c950fcb5 100644 --- a/src/components/AdminV2/AdminCards.jsx +++ b/src/components/AdminV2/AdminCards.jsx @@ -1,105 +1,107 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Award, Check, Groups, RemoveRedEye, } from '@openedx/paragon/icons'; import NumberCard from './cards/NumberCard'; -class AdminCards extends React.Component { - constructor(props) { - super(props); - const { intl } = this.props; +const AdminCards = ({ + activeLearners, + numberOfUsers, + courseCompletions, + enrolledLearners, +}) => { + const intl = useIntl(); - this.cards = { - numberOfUsers: { - ref: React.createRef(), - description: intl.formatMessage({ - id: 'adminPortal.cards.registeredLearners', - defaultMessage: 'total number of learners registered', + const cards = { + numberOfUsers: { + ref: React.createRef(), + description: intl.formatMessage({ + id: 'adminPortal.cards.registeredLearners', + defaultMessage: 'total number of learners registered', + }), + icon: Groups, + actions: [{ + label: intl.formatMessage({ + id: 'adminPortal.cards.registeredUnenrolledLearners', + defaultMessage: 'Which learners are registered but not yet enrolled in any courses?', }), - icon: Groups, - actions: [{ - label: intl.formatMessage({ - id: 'adminPortal.cards.registeredUnenrolledLearners', - defaultMessage: 'Which learners are registered but not yet enrolled in any courses?', - }), - slug: 'registered-unenrolled-learners', - }], - }, - enrolledLearners: { - ref: React.createRef(), - description: intl.formatMessage({ - id: 'adminPortal.cards.enrolledOneCourse', - defaultMessage: 'learners enrolled in at least one course', + slug: 'registered-unenrolled-learners', + }], + }, + enrolledLearners: { + ref: React.createRef(), + description: intl.formatMessage({ + id: 'adminPortal.cards.enrolledOneCourse', + defaultMessage: 'learners enrolled in at least one course', + }), + icon: Check, + actions: [{ + label: intl.formatMessage({ + id: 'adminPortal.cards.enrolledLearners', + defaultMessage: 'How many courses are learners enrolled in?', }), - icon: Check, - actions: [{ - label: intl.formatMessage({ - id: 'adminPortal.cards.enrolledLearners', - defaultMessage: 'How many courses are learners enrolled in?', - }), - slug: 'enrolled-learners', - }, { - label: intl.formatMessage({ - id: 'adminPortal.cards.enrolledLearnersInactiveCourses', - defaultMessage: 'Who is no longer enrolled in a current course?', - }), - slug: 'enrolled-learners-inactive-courses', - }], - }, - activeLearners: { - ref: React.createRef(), - description: intl.formatMessage({ - id: 'adminPortal.cards.activeLearnersPastWeek', - defaultMessage: 'active learners in the past week', + slug: 'enrolled-learners', + }, { + label: intl.formatMessage({ + id: 'adminPortal.cards.enrolledLearnersInactiveCourses', + defaultMessage: 'Who is no longer enrolled in a current course?', }), - icon: RemoveRedEye, - actions: [{ - label: intl.formatMessage({ - id: 'adminPortal.cards.learnersActiveWeek', - defaultMessage: 'Who are my top active learners?', - }), - slug: 'learners-active-week', - }, { - label: intl.formatMessage({ - id: 'adminPortal.cards.learnersInactiveWeek', - defaultMessage: 'Who has not been active for over a week?', - }), - slug: 'learners-inactive-week', - }, { - label: intl.formatMessage({ - id: 'adminPortal.cards.learnersInactiveMonth', - defaultMessage: 'Who has not been active for over a month?', - }), - slug: 'learners-inactive-month', - }], - }, - courseCompletions: { - ref: React.createRef(), - description: 'course completions', - icon: Award, - actions: [{ - label: intl.formatMessage({ - id: 'adminPortal.cards.completedLearners', - defaultMessage: 'How many courses have been completed by learners?', - }), - slug: 'completed-learners', - }, { - label: intl.formatMessage({ - id: 'adminPortal.cards.completedLearnersWeek', - defaultMessage: 'Who completed a course in the past week?', - }), - slug: 'completed-learners-week', - }], - }, - }; - } + slug: 'enrolled-learners-inactive-courses', + }], + }, + activeLearners: { + ref: React.createRef(), + description: intl.formatMessage({ + id: 'adminPortal.cards.activeLearnersPastWeek', + defaultMessage: 'active learners in the past week', + }), + icon: RemoveRedEye, + actions: [{ + label: intl.formatMessage({ + id: 'adminPortal.cards.learnersActiveWeek', + defaultMessage: 'Who are my top active learners?', + }), + slug: 'learners-active-week', + }, { + label: intl.formatMessage({ + id: 'adminPortal.cards.learnersInactiveWeek', + defaultMessage: 'Who has not been active for over a week?', + }), + slug: 'learners-inactive-week', + }, { + label: intl.formatMessage({ + id: 'adminPortal.cards.learnersInactiveMonth', + defaultMessage: 'Who has not been active for over a month?', + }), + slug: 'learners-inactive-month', + }], + }, + courseCompletions: { + ref: React.createRef(), + description: 'course completions', + icon: Award, + actions: [{ + label: intl.formatMessage({ + id: 'adminPortal.cards.completedLearners', + defaultMessage: 'How many courses have been completed by learners?', + }), + slug: 'completed-learners', + }, { + label: intl.formatMessage({ + id: 'adminPortal.cards.completedLearnersWeek', + defaultMessage: 'Who completed a course in the past week?', + }), + slug: 'completed-learners-week', + }], + }, + }; - renderCard({ title, cardKey }) { - const card = this.cards[cardKey]; + const renderCard = ({ title, cardKey }) => { + const card = cards[cardKey]; return (
); - } - - render() { - const { - activeLearners, - numberOfUsers, - courseCompletions, - enrolledLearners, - } = this.props; + }; - const data = { - activeLearners: activeLearners.past_week, - numberOfUsers, - courseCompletions, - enrolledLearners, - }; + const data = { + activeLearners: activeLearners.past_week, + numberOfUsers, + courseCompletions, + enrolledLearners, + }; - return Object.keys(this.cards).map(cardKey => ( - this.renderCard({ - title: data[cardKey], - cardKey, - }) - )); - } -} + return Object.keys(cards).map(cardKey => ( + renderCard({ + title: data[cardKey], + cardKey, + }) + )); +}; AdminCards.propTypes = { activeLearners: PropTypes.shape({ @@ -149,8 +142,6 @@ AdminCards.propTypes = { numberOfUsers: PropTypes.number.isRequired, courseCompletions: PropTypes.number.isRequired, enrolledLearners: PropTypes.number.isRequired, - // injected - intl: intlShape.isRequired, }; -export default injectIntl(AdminCards); +export default AdminCards; diff --git a/src/components/AdminV2/AdminSearchForm.jsx b/src/components/AdminV2/AdminSearchForm.jsx index d727b9b41c..4f62917e2a 100644 --- a/src/components/AdminV2/AdminSearchForm.jsx +++ b/src/components/AdminV2/AdminSearchForm.jsx @@ -1,51 +1,45 @@ /* eslint-disable camelcase */ -import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import { useEffect, useRef } from 'react'; import { Form } from '@openedx/paragon'; import { Info } from '@openedx/paragon/icons'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; -import SearchBar from '../SearchBar'; +import EVENT_NAMES from '../../eventTracking'; +import { withLocation, withNavigate } from '../../hoc'; import { formatTimestamp, updateUrl } from '../../utils'; import IconWithTooltip from '../IconWithTooltip'; -import { withLocation, withNavigate } from '../../hoc'; -import EVENT_NAMES from '../../eventTracking'; import { TRACK_LEARNER_PROGRESS_TARGETS } from '../ProductTours/AdminOnboardingTours/constants'; +import SearchBar from '../SearchBar'; -class AdminSearchForm extends React.Component { - componentDidUpdate(prevProps) { - const { - searchParams: { - searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery, - }, - } = this.props; - const { - searchParams: { - searchQuery: prevSearchQuery, - searchCourseQuery: prevSearchCourseQuery, - searchDateQuery: prevSearchDateQuery, - searchBudgetQuery: prevSearchBudgetQuery, - searchGroupQuery: prevSearchGroupQuery, - }, - } = prevProps; +const AdminSearchForm = ({ + searchEnrollmentsList, + searchParams: { + searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery, + }, + tableData = [], + budgets, + groups, + navigate, + location, + enterpriseId, +}) => { + const intl = useIntl(); + const isFirstRender = useRef(true); - if (searchQuery !== prevSearchQuery || searchCourseQuery !== prevSearchCourseQuery - || searchDateQuery !== prevSearchDateQuery || searchBudgetQuery !== prevSearchBudgetQuery - || searchGroupQuery !== prevSearchGroupQuery) { - this.handleSearch(); + useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + return; } - } - - handleSearch() { - this.props.searchEnrollmentsList(); - } + searchEnrollmentsList(); + }, [searchEnrollmentsList, searchQuery, searchCourseQuery, searchDateQuery, searchBudgetQuery, searchGroupQuery]); - onCourseSelect(event) { - const { navigate, location } = this.props; + const onCourseSelect = (event) => { const updateParams = { search_course: event.target.value, page: 1, @@ -54,249 +48,236 @@ class AdminSearchForm extends React.Component { updateParams.search_start_date = ''; } updateUrl(navigate, location.pathname, updateParams); - } + }; - onBudgetSelect(event) { - const { navigate, location } = this.props; + const onBudgetSelect = (event) => { const updateParams = { budget_uuid: event.target.value, page: 1, }; updateUrl(navigate, location.pathname, updateParams); - } + }; - onGroupSelect(event) { - const { navigate, location } = this.props; + const onGroupSelect = (event) => { const updateParams = { group_uuid: event.target.value, page: 1, }; updateUrl(navigate, location.pathname, updateParams); sendEnterpriseTrackEvent( - this.props.enterpriseId, + enterpriseId, EVENT_NAMES.LEARNER_PROGRESS_REPORT.FILTER_BY_GROUP_DROPDOWN, { group: event.target.value }, ); - } - - render() { - const { - intl, - tableData, - budgets, - groups, - searchParams: { - searchCourseQuery, searchDateQuery, searchQuery, searchBudgetQuery, searchGroupQuery, - }, - } = this.props; + }; - 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'; + 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'; - return ( -