diff --git a/src/components/Admin/AdminSearchForm.jsx b/src/components/Admin/AdminSearchForm.jsx index 6b9bd1e469..fbb7ce99b7 100644 --- a/src/components/Admin/AdminSearchForm.jsx +++ b/src/components/Admin/AdminSearchForm.jsx @@ -7,11 +7,13 @@ 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 SearchBar from '../SearchBar'; import { formatTimestamp, updateUrl } from '../../utils'; import IconWithTooltip from '../IconWithTooltip'; import { withLocation, withNavigate } from '../../hoc'; +import EVENT_NAMES from '../../eventTracking'; class AdminSearchForm extends React.Component { componentDidUpdate(prevProps) { @@ -31,8 +33,8 @@ class AdminSearchForm extends React.Component { } = prevProps; if (searchQuery !== prevSearchQuery || searchCourseQuery !== prevSearchCourseQuery - || searchDateQuery !== prevSearchDateQuery || searchBudgetQuery !== prevSearchBudgetQuery - || searchGroupQuery !== prevSearchGroupQuery) { + || searchDateQuery !== prevSearchDateQuery || searchBudgetQuery !== prevSearchBudgetQuery + || searchGroupQuery !== prevSearchGroupQuery) { this.handleSearch(); } } @@ -69,6 +71,11 @@ class AdminSearchForm extends React.Component { page: 1, }; updateUrl(navigate, location.pathname, updateParams); + sendEnterpriseTrackEvent( + this.props.enterpriseId, + EVENT_NAMES.LEARNER_PROGRESS_REPORT.FILTER_BY_GROUP_DROPDOWN, + { group: event.target.value }, + ); } render() { @@ -81,7 +88,6 @@ class AdminSearchForm extends React.Component { 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'; @@ -252,7 +258,7 @@ class AdminSearchForm extends React.Component { - ) : null } + ) : null}
{ closeModal(); @@ -38,13 +42,32 @@ const CreateGroupModal = ({ groupName, }; let groupCreationResponse; - try { groupCreationResponse = await LmsApiService.createEnterpriseGroup(options); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.CREATE_GROUP_MODAL_BUTTON_SUBMIT, + { status: 'success' }, + ); + + if (isCreateGroupFileUpload) { + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.GROUP_CREATE_WITH_UPLOAD_CSV, + ); + } } catch (err) { logError(err); setCreateButtonState('error'); openSystemErrorModal(); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.CREATE_GROUP_MODAL_BUTTON_SUBMIT, + { + status: 'error', + message: err, + }, + ); } try { @@ -114,6 +137,7 @@ const CreateGroupModal = ({ onEmailAddressesChange={handleEmailAddressesChange} isGroupInvite enterpriseUUID={enterpriseUUID} + setIsCreateGroupFileUpload={setIsCreateGroupFileUpload} /> @@ -161,6 +163,7 @@ CreateGroupModalContent.propTypes = { onSetGroupName: PropTypes.func, isGroupInvite: PropTypes.bool, enterpriseUUID: PropTypes.string.isRequired, + setIsCreateGroupFileUpload: PropTypes.func, }; export default CreateGroupModalContent; diff --git a/src/components/PeopleManagement/DownloadCSVButton.jsx b/src/components/PeopleManagement/DownloadCSVButton.jsx index 96f015b2d7..39394df867 100644 --- a/src/components/PeopleManagement/DownloadCSVButton.jsx +++ b/src/components/PeopleManagement/DownloadCSVButton.jsx @@ -1,6 +1,8 @@ import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { useIntl } from '@edx/frontend-platform/i18n'; +import { connect } from 'react-redux'; +import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; import { Icon, Spinner, StatefulButton, Toast, useToggle, @@ -8,6 +10,7 @@ import { import { Download, Check } from '@openedx/paragon/icons'; import { logError } from '@edx/frontend-platform/logging'; import { downloadCsv, getTimeStampedFilename } from '../../utils'; +import EVENT_NAMES from '../../eventTracking'; const csvHeaders = ['Name', 'Email', 'Joined Organization', 'Enrollments']; @@ -16,7 +19,12 @@ const dataEntryToRow = (entry) => { return [name, email, joinedOrg, enrollments]; }; -const DownloadCsvButton = ({ testId, fetchData, totalCt }) => { +const DownloadCsvButton = ({ + enterpriseUUID, + testId, + fetchData, + totalCt, +}) => { const [buttonState, setButtonState] = useState('pageLoading'); const [isToastOpen, openToast, closeToast] = useToggle(false); const intl = useIntl(); @@ -34,8 +42,23 @@ const DownloadCsvButton = ({ testId, fetchData, totalCt }) => { downloadCsv(fileName, response.results, csvHeaders, dataEntryToRow); openToast(); setButtonState('complete'); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.DOWNLOAD_ALL_ORG_MEMBERS, + { + status: 'success', + }, + ); }).catch((err) => { logError(err); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.DOWNLOAD_ALL_ORG_MEMBERS, + { + status: 'error', + message: err, + }, + ); }); }; @@ -101,6 +124,11 @@ DownloadCsvButton.propTypes = { fetchData: PropTypes.func.isRequired, totalCt: PropTypes.number, testId: PropTypes.string, + enterpriseUUID: PropTypes.string, }; -export default DownloadCsvButton; +const mapStateToProps = state => ({ + enterpriseUUID: state.portalConfiguration.enterpriseId, +}); + +export default connect(mapStateToProps)(DownloadCsvButton); diff --git a/src/components/PeopleManagement/GroupDetailCard.jsx b/src/components/PeopleManagement/GroupDetailCard.jsx index df8eb802a9..0a104bac75 100644 --- a/src/components/PeopleManagement/GroupDetailCard.jsx +++ b/src/components/PeopleManagement/GroupDetailCard.jsx @@ -1,9 +1,13 @@ import PropTypes from 'prop-types'; import { useParams } from 'react-router'; +import { connect } from 'react-redux'; +import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; + import { Card, Hyperlink } from '@openedx/paragon'; import { ROUTE_NAMES } from '../EnterpriseApp/data/constants'; +import EVENT_NAMES from '../../eventTracking'; -const GroupDetailCard = ({ group }) => { +const GroupDetailCard = ({ enterpriseUUID, group }) => { const { enterpriseSlug } = useParams(); return ( @@ -15,6 +19,12 @@ const GroupDetailCard = ({ group }) => { { + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.VIEW_GROUP_PROGRESS_BUTTON, + ); + }} > View group @@ -29,6 +39,11 @@ GroupDetailCard.propTypes = { name: PropTypes.string.isRequired, uuid: PropTypes.string.isRequired, }).isRequired, + enterpriseUUID: PropTypes.string, }; -export default GroupDetailCard; +const mapStateToProps = state => ({ + enterpriseUUID: state.portalConfiguration.enterpriseId, +}); + +export default connect(mapStateToProps)(GroupDetailCard); diff --git a/src/components/PeopleManagement/GroupDetailPage/DownloadCsvIconButton.jsx b/src/components/PeopleManagement/GroupDetailPage/DownloadCsvIconButton.jsx index 9b48464026..39965e3091 100644 --- a/src/components/PeopleManagement/GroupDetailPage/DownloadCsvIconButton.jsx +++ b/src/components/PeopleManagement/GroupDetailPage/DownloadCsvIconButton.jsx @@ -1,7 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, useIntl } from '@edx/frontend-platform/i18n'; +import { connect } from 'react-redux'; +import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; import { Icon, IconButtonWithTooltip, Toast, useToggle, } from '@openedx/paragon'; @@ -9,10 +11,12 @@ import { Download } from '@openedx/paragon/icons'; import { logError } from '@edx/frontend-platform/logging'; import GeneralErrorModal from '../GeneralErrorModal'; import { downloadCsv, getTimeStampedFilename } from '../../../utils'; +import EVENT_NAMES from '../../../eventTracking'; const csvHeaders = ['Name', 'Email', 'Recent action', 'Enrollments']; const DownloadCsvIconButton = ({ + enterpriseUUID, fetchAllData, dataCount, testId, @@ -50,9 +54,22 @@ const DownloadCsvIconButton = ({ ))) : response.results; downloadCsv(fileName, selectedRowIdsToDownload, csvHeaders, dataEntryToRow); openToast(); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.DOWNLOAD_GROUP_MEMBERS, + { status: 'success' }, + ); }).catch((err) => { logError(err); openErrorModal(); + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.DOWNLOAD_GROUP_MEMBERS, + { + status: 'error', + message: err, + }, + ); }); }; @@ -86,6 +103,7 @@ DownloadCsvIconButton.defaultProps = { }; DownloadCsvIconButton.propTypes = { + enterpriseUUID: PropTypes.string, fetchAllData: PropTypes.func.isRequired, dataCount: PropTypes.number.isRequired, testId: PropTypes.string, @@ -95,4 +113,8 @@ DownloadCsvIconButton.propTypes = { }), }; -export default DownloadCsvIconButton; +const mapStateToProps = state => ({ + enterpriseUUID: state.portalConfiguration.enterpriseId, +}); + +export default connect(mapStateToProps)(DownloadCsvIconButton); diff --git a/src/components/PeopleManagement/GroupDetailPage/GroupDetailPage.jsx b/src/components/PeopleManagement/GroupDetailPage/GroupDetailPage.jsx index d566e2234f..6f0763b96b 100644 --- a/src/components/PeopleManagement/GroupDetailPage/GroupDetailPage.jsx +++ b/src/components/PeopleManagement/GroupDetailPage/GroupDetailPage.jsx @@ -1,10 +1,13 @@ import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; import { useParams } from 'react-router-dom'; import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import { Breadcrumb, Card, Hyperlink, Icon, IconButton, IconButtonWithTooltip, Skeleton, useToggle, } from '@openedx/paragon'; import { Delete, Edit } from '@openedx/paragon/icons'; +import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; import { useEnterpriseGroupLearnersTableData, useEnterpriseGroupUuid } from '../data/hooks'; import { ROUTE_NAMES } from '../../EnterpriseApp/data/constants'; @@ -14,8 +17,9 @@ import formatDates from '../utils'; import GroupMembersTable from './GroupMembersTable'; import AddMembersModal from '../AddMembersModal/AddMembersModal'; import { makePlural } from '../../../utils'; +import EVENT_NAMES from '../../../eventTracking'; -const GroupDetailPage = () => { +const GroupDetailPage = ({ enterpriseUUID }) => { const intl = useIntl(); const { enterpriseSlug, groupUuid } = useParams(); const { data: enterpriseGroup } = useEnterpriseGroupUuid(groupUuid); @@ -123,6 +127,12 @@ const GroupDetailPage = () => { className="btn btn-primary" target="_blank" destination={`/${enterpriseSlug}/admin/${ROUTE_NAMES.learners}?group_uuid=${groupUuid}`} + onClick={() => { + sendEnterpriseTrackEvent( + enterpriseUUID, + EVENT_NAMES.PEOPLE_MANAGEMENT.VIEW_GROUP_BUTTON, + ); + }} > View group progress @@ -168,4 +178,12 @@ const GroupDetailPage = () => { ); }; -export default GroupDetailPage; +GroupDetailPage.propTypes = { + enterpriseUUID: PropTypes.string, +}; + +const mapStateToProps = state => ({ + enterpriseUUID: state.portalConfiguration.enterpriseId, +}); + +export default connect(mapStateToProps)(GroupDetailPage); diff --git a/src/components/PeopleManagement/index.jsx b/src/components/PeopleManagement/index.jsx index a30770927f..1b4b4d1098 100644 --- a/src/components/PeopleManagement/index.jsx +++ b/src/components/PeopleManagement/index.jsx @@ -7,6 +7,7 @@ import { ActionRow, Button, Skeleton, Toast, useToggle, } from '@openedx/paragon'; import { Add } from '@openedx/paragon/icons'; +import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils'; import Hero from '../Hero'; import { SUBSIDY_TYPES } from '../../data/constants/subsidyTypes'; @@ -16,6 +17,7 @@ import { useAllFlexEnterpriseGroups } from '../learner-credit-management/data'; import ZeroState from './ZeroState'; import GroupCardGrid from './GroupCardGrid'; import PeopleManagementTable from './PeopleManagementTable'; +import EVENT_NAMES from '../../eventTracking'; const PeopleManagementPage = ({ enterpriseId }) => { const intl = useIntl(); @@ -49,6 +51,13 @@ const PeopleManagementPage = ({ enterpriseId }) => { } }, [data]); + useEffect(() => { + sendEnterpriseTrackEvent( + enterpriseId, + EVENT_NAMES.PEOPLE_MANAGEMENT.PAGE_VISIT, + ); + }, [enterpriseId]); + useEffect(() => { // parameter is for confirmation toast after deleting a group const searchParams = new URLSearchParams(window.location.search); @@ -66,6 +75,14 @@ const PeopleManagementPage = ({ enterpriseId }) => { } } + const handleOnClickCreateGroup = () => { + openModal(); + sendEnterpriseTrackEvent( + enterpriseId, + EVENT_NAMES.PEOPLE_MANAGEMENT.CREATE_GROUP_BUTTON_CLICK, + ); + }; + return ( <> @@ -101,7 +118,7 @@ const PeopleManagementPage = ({ enterpriseId }) => { )} -