From 320bdd1a6c03e0426bad963c4d58b1b3ce7036b9 Mon Sep 17 00:00:00 2001 From: mahamakifdar19 Date: Fri, 6 Oct 2023 11:38:55 +0500 Subject: [PATCH] feat: display ai analytics section on LPR page --- .../AIAnalyticsSummary/data/hooks.js | 35 + src/components/Admin/AIAnalyticsSummary.jsx | 100 + .../Admin/AIAnalyticsSummary.test.jsx | 87 + .../Admin/AIAnalyticsSummarySkeleton.jsx | 11 + src/components/Admin/Admin.test.jsx | 67 + .../AIAnalyticsSummary.test.jsx.snap | 109 + .../Admin/__snapshots__/Admin.test.jsx.snap | 2270 +++++++++++++++-- src/components/Admin/index.jsx | 20 + src/containers/AdminPage/AdminPage.test.jsx | 4 + src/containers/AdminPage/index.jsx | 9 + src/data/actions/dashboardInsights.js | 41 + src/data/constants/dashboardInsights.js | 11 + src/data/reducers/dashboardInsights.js | 47 + src/data/reducers/index.js | 2 + src/data/services/EnterpriseDataApiService.js | 7 + src/data/services/LmsApiService.js | 5 + 16 files changed, 2627 insertions(+), 198 deletions(-) create mode 100644 src/components/AIAnalyticsSummary/data/hooks.js create mode 100644 src/components/Admin/AIAnalyticsSummary.jsx create mode 100644 src/components/Admin/AIAnalyticsSummary.test.jsx create mode 100644 src/components/Admin/AIAnalyticsSummarySkeleton.jsx create mode 100644 src/components/Admin/__snapshots__/AIAnalyticsSummary.test.jsx.snap create mode 100644 src/data/actions/dashboardInsights.js create mode 100644 src/data/constants/dashboardInsights.js create mode 100644 src/data/reducers/dashboardInsights.js diff --git a/src/components/AIAnalyticsSummary/data/hooks.js b/src/components/AIAnalyticsSummary/data/hooks.js new file mode 100644 index 0000000000..c957872483 --- /dev/null +++ b/src/components/AIAnalyticsSummary/data/hooks.js @@ -0,0 +1,35 @@ +import { useEffect, useState } from 'react'; +import { logError } from '@edx/frontend-platform/logging'; +import LmsApiService from '../../../data/services/LmsApiService'; + +const useAIAnalyticsSummary = (enterpriseId, insights) => { + const [isLoading, setIsLoading] = useState(true); + const [analyticsSummaryData, setAnalyticsSummaryData] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + setIsLoading(true); + const response = await LmsApiService.generateAIAnalyticsSummary(enterpriseId, insights); + setAnalyticsSummaryData(response.data); + } catch (error) { + logError(error); + } finally { + setIsLoading(false); + } + }; + + if (enterpriseId && insights) { + fetchData(); + } else { + setIsLoading(false); + } + }, [enterpriseId, insights]); + + return { + isLoading, + data: analyticsSummaryData, + }; +}; + +export default useAIAnalyticsSummary; diff --git a/src/components/Admin/AIAnalyticsSummary.jsx b/src/components/Admin/AIAnalyticsSummary.jsx new file mode 100644 index 0000000000..416765956a --- /dev/null +++ b/src/components/Admin/AIAnalyticsSummary.jsx @@ -0,0 +1,100 @@ +import React, { useState } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { + Button, Card, Stack, Badge, +} from '@edx/paragon'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { AutoFixHigh, Groups } from '@edx/paragon/icons'; +import useAIAnalyticsSummary from '../AIAnalyticsSummary/data/hooks'; + +const AnalyticsDetailCard = ({ onClose, data }) => ( + + + + Beta + + +

{data || 'No insights found..'}

+ +
+ +
+
+); + +AnalyticsDetailCard.propTypes = { + onClose: PropTypes.func.isRequired, + data: PropTypes.string, +}; + +const AIAnalyticsSummary = ({ enterpriseId, insights }) => { + const [showSummarizeCard, setShowSummarizeCard] = useState(false); + const [showTrackProgressCard, setShowTrackProgressCard] = useState(false); + + const analyticsSummary = useAIAnalyticsSummary(enterpriseId, insights); + + const toggleSummarizeCard = () => { + setShowSummarizeCard(!showSummarizeCard); + setShowTrackProgressCard(false); + }; + + const toggleTrackProgressCard = () => { + setShowTrackProgressCard(!showTrackProgressCard); + setShowSummarizeCard(false); + }; + + return ( + <> + + + + + {showSummarizeCard && ( + setShowSummarizeCard(false)} + /> + )} + {showTrackProgressCard && ( + setShowTrackProgressCard(false)} + /> + )} + + ); +}; + +const mapStateToProps = state => ({ + insights: state.dashboardInsights.insights, +}); + +AIAnalyticsSummary.propTypes = { + enterpriseId: PropTypes.string.isRequired, + insights: PropTypes.objectOf(PropTypes.shape), +}; + +export default connect(mapStateToProps)(AIAnalyticsSummary); diff --git a/src/components/Admin/AIAnalyticsSummary.test.jsx b/src/components/Admin/AIAnalyticsSummary.test.jsx new file mode 100644 index 0000000000..22ee4f1571 --- /dev/null +++ b/src/components/Admin/AIAnalyticsSummary.test.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { Provider } from 'react-redux'; +import renderer from 'react-test-renderer'; +import configureMockStore from 'redux-mock-store'; +import { MemoryRouter } from 'react-router-dom'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import thunk from 'redux-thunk'; +import AIAnalyticsSummary from './AIAnalyticsSummary'; + +const mockedInsights = { + learner_progress: { + enterprise_customer_uuid: 'aac56d39-f38d-4510-8ef9-085cab048ea9', + enterprise_customer_name: 'Microsoft Corporation', + active_subscription_plan: true, + assigned_licenses: 0, + activated_licenses: 0, + assigned_licenses_percentage: 0.0, + activated_licenses_percentage: 0.0, + active_enrollments: 1026, + at_risk_enrollment_less_than_one_hour: 26, + at_risk_enrollment_end_date_soon: 15, + at_risk_enrollment_dormant: 918, + created_at: '2023-10-02T03:24:17Z', + }, + learner_engagement: { + enterprise_customer_uuid: 'aac56d39-f38d-4510-8ef9-085cab048ea9', + enterprise_customer_name: 'Microsoft Corporation', + enrolls: 49, + enrolls_prior: 45, + passed: 2, + passed_prior: 0, + engage: 67, + engage_prior: 50, + hours: 62, + hours_prior: 49, + contract_end_date: '2022-06-13T00:00:00Z', + active_contract: false, + created_at: '2023-10-02T03:24:40Z', + }, +}; +const mockStore = configureMockStore([thunk]); +const store = mockStore({ + portalConfiguration: { + enterpriseId: 'test-enterprise-id', + }, + dashboardInsights: mockedInsights, +}); + +const AIAnalyticsSummaryWrapper = props => ( + + + + , + + + +); + +describe('', () => { + it('should render action buttons correctly', () => { + const tree = renderer + .create(( + + )) + .toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('should display AnalyticsDetailCard when Summarize Analytics button is clicked', () => { + const wrapper = mount(); + wrapper.find('[data-testid="summarize-analytics"]').first().simulate('click'); + + const tree = renderer + .create() + .toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/Admin/AIAnalyticsSummarySkeleton.jsx b/src/components/Admin/AIAnalyticsSummarySkeleton.jsx new file mode 100644 index 0000000000..b44e6da4bd --- /dev/null +++ b/src/components/Admin/AIAnalyticsSummarySkeleton.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Skeleton, Stack } from '@edx/paragon'; + +const AIAnalyticsSummarySkeleton = () => ( + + + + +); + +export default AIAnalyticsSummarySkeleton; diff --git a/src/components/Admin/Admin.test.jsx b/src/components/Admin/Admin.test.jsx index 4362ae6805..1dad753b64 100644 --- a/src/components/Admin/Admin.test.jsx +++ b/src/components/Admin/Admin.test.jsx @@ -36,6 +36,10 @@ const store = mockStore({ number_of_users: 3, course_completions: 1, }, + dashboardInsights: { + loading: null, + insights: null, + }, }); const AdminWrapper = props => ( @@ -61,6 +65,8 @@ const AdminWrapper = props => ( url: '/', }} {...props} + fetchDashboardInsights={() => {}} + clearDashboardInsights={() => {}} /> @@ -77,6 +83,7 @@ describe('', () => { courseCompletions: 1, lastUpdatedDate: '2018-07-31T23:14:35Z', numberOfUsers: 3, + insights: null, }; describe('renders correctly', () => { @@ -290,6 +297,66 @@ describe('', () => { .toJSON(); expect(tree).toMatchSnapshot(); }); + + it('with no dashboard insights data', () => { + const insights = null; + const tree = renderer + .create(( + + )) + .toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + describe('with dashboard insights data', () => { + it('renders dashboard insights data correctly', () => { + const insights = { + learner_progress: { + enterprise_customer_uuid: 'aac56d39-f38d-4510-8ef9-085cab048ea9', + enterprise_customer_name: 'Microsoft Corporation', + active_subscription_plan: true, + assigned_licenses: 0, + activated_licenses: 0, + assigned_licenses_percentage: 0.0, + activated_licenses_percentage: 0.0, + active_enrollments: 1026, + at_risk_enrollment_less_than_one_hour: 26, + at_risk_enrollment_end_date_soon: 15, + at_risk_enrollment_dormant: 918, + created_at: '2023-10-02T03:24:17Z', + }, + learner_engagement: { + enterprise_customer_uuid: 'aac56d39-f38d-4510-8ef9-085cab048ea9', + enterprise_customer_name: 'Microsoft Corporation', + enrolls: 49, + enrolls_prior: 45, + passed: 2, + passed_prior: 0, + engage: 67, + engage_prior: 50, + hours: 62, + hours_prior: 49, + contract_end_date: '2022-06-13T00:00:00Z', + active_contract: false, + created_at: '2023-10-02T03:24:40Z', + }, + }; + const tree = renderer + .create(( + + )) + .toJSON(); + + expect(tree).toMatchSnapshot(); + }); + }); }); describe('handle changes to enterpriseId prop', () => { diff --git a/src/components/Admin/__snapshots__/AIAnalyticsSummary.test.jsx.snap b/src/components/Admin/__snapshots__/AIAnalyticsSummary.test.jsx.snap new file mode 100644 index 0000000000..569654d848 --- /dev/null +++ b/src/components/Admin/__snapshots__/AIAnalyticsSummary.test.jsx.snap @@ -0,0 +1,109 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should display AnalyticsDetailCard when Summarize Analytics button is clicked 1`] = ` +Array [ +
+ + +
, + ",", +] +`; + +exports[` should render action buttons correctly 1`] = ` +Array [ +
+ + +
, + ",", +] +`; diff --git a/src/components/Admin/__snapshots__/Admin.test.jsx.snap b/src/components/Admin/__snapshots__/Admin.test.jsx.snap index fd763719cf..5fdf48d830 100644 --- a/src/components/Admin/__snapshots__/Admin.test.jsx.snap +++ b/src/components/Admin/__snapshots__/Admin.test.jsx.snap @@ -34,6 +34,13 @@ exports[` renders correctly calls fetchDashboardAnalytics prop 1`] = ` +
+
+
@@ -197,6 +204,13 @@ exports[` renders correctly with dashboard analytics data renders # cou
+
+
+
@@ -910,6 +924,13 @@ exports[` renders correctly with dashboard analytics data renders # of
+
+
+
@@ -1623,6 +1644,13 @@ exports[` renders correctly with dashboard analytics data renders # of
+
+
+
@@ -2340,6 +2368,13 @@ exports[` renders correctly with dashboard analytics data renders colla
+
+
+
@@ -3200,6 +3235,13 @@ exports[` renders correctly with dashboard analytics data renders full
+
+
+
@@ -4060,6 +4102,13 @@ exports[` renders correctly with dashboard analytics data renders inact
+
+
+
@@ -4777,6 +4826,13 @@ exports[` renders correctly with dashboard analytics data renders inact
+
+
+
@@ -5494,6 +5550,13 @@ exports[` renders correctly with dashboard analytics data renders learn
+
+
+
@@ -6211,6 +6274,13 @@ exports[` renders correctly with dashboard analytics data renders regis
+
+
+
@@ -6924,6 +6994,13 @@ exports[` renders correctly with dashboard analytics data renders top a
+
+
+
@@ -7607,7 +7684,7 @@ exports[` renders correctly with dashboard analytics data renders top a `; -exports[` renders correctly with error state 1`] = ` +exports[` renders correctly with dashboard insights data renders dashboard insights data correctly 1`] = `
renders correctly with error state 1`] = `
- - -
+
+ + + Track Progress +
- Loading... - - Loading - +
+

+ + 3 + + + + + + +

+

+ total number of learners registered +

+
+
+
+
+ +
+ +
- -
-

- Full Report -

-
-
+ + 1 + + + + + + + +

+ learners enrolled in at least one course +

+
+
+ +
+
+
+
+
+
+

+ + 1 + + + + + + +

+

+ active learners in the past week +

+
+
+ +
+
+
+
+
+
+

+ + 1 + + + + + + +

+

+ course completions +

+
+
+ +
+
+ +
+
+
+ Loading... + + Loading + +
+
+
+
+
+
+
+

+ Full Report +

+
+
+
+
+
+
+
+
+
+
+
+
+ Showing data as of + July 31, 2018 +
+
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+ +
+
+ + + +
+
+
+
+
+
+
+
+
+
+ +`; + +exports[` renders correctly with error state 1`] = ` +
+
+
+

+ Learner Progress Report +

+
+
+ edX logo +
+
+
+
+
+

+ Overview +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+ Hey, nice to see you +
+

+ Try refreshing your screen + Network Error +

+
+
+
+
+
+
+
+
+ Loading... + + Loading + +
+
+
+
+
+
+
+

+ Full Report +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[` renders correctly with loading state 1`] = ` +
+
+
+

+ Learner Progress Report +

+
+
+ edX logo +
+
+
+
+
+

+ Overview +

+
+
+
+
+
+
+
+
+
+ Loading... +
+ + + ‌ + +
+
+ + + ‌ + +
+
+ + + ‌ + +
+
+ + + ‌ + +
+
+
+
+
+
+
+
+ Loading... + + Loading + +
+
+
+
+
+
+
+

+ Full Report +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[` renders correctly with no dashboard analytics data 1`] = ` +
+
+ Loading... +
+ + + ‌ + +
+
+ + + ‌ + +
+
+
+`; + +exports[` renders correctly with no dashboard insights data 1`] = ` +
+
+
+

+ Learner Progress Report +

+
+
+ edX logo +
+
+
+
+
+

+ Overview +

+
+
+
+
+
+
+
+
+
+
+

+ + 3 + + + + + + +

+

+ total number of learners registered +

+
+
+
+
+ +
+ +
+
+
+
+ className="card" + > +
+

+ + 1 + + + + + + +

+

+ learners enrolled in at least one course +

+
+
+ +
+
+
+
+
+
+

+ + 1 + + + + + + +

+

+ active learners in the past week +

+
+
+
-
-
-
-
-
-
-
-
-`; - -exports[` renders correctly with loading state 1`] = ` -
-
-
-

- Learner Progress Report -

-
-
- edX logo -
-
-
-
-
-

- Overview -

-
-
-
- Loading... -
- - - ‌ - -
-
- - - ‌ - -
-
- + + 1 + + + + + + + +

+ course completions +

+
+
+
- - ‌ - -
- - - +
+
+ Details +
+
+ + + + + + Show details + + +
+
+ +
+ +
@@ -7908,6 +9617,216 @@ exports[` renders correctly with loading state 1`] = `
+
+
+ Showing data as of + July 31, 2018 +
+
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+ +
+
+ + + +
+
+
+
+
+
@@ -7916,48 +9835,3 @@ exports[` renders correctly with loading state 1`] = `
`; - -exports[` renders correctly with no dashboard analytics data 1`] = ` -
-
- Loading... -
- - - ‌ - -
-
- - - ‌ - -
-
-
-`; diff --git a/src/components/Admin/index.jsx b/src/components/Admin/index.jsx index 45db4b5059..b5ccee0bc3 100644 --- a/src/components/Admin/index.jsx +++ b/src/components/Admin/index.jsx @@ -24,12 +24,15 @@ import { formatTimestamp } from '../../utils'; import AdminCardsSkeleton from './AdminCardsSkeleton'; import { SubscriptionData } from '../subscriptions'; import EmbeddedSubscription from './EmbeddedSubscription'; +import AIAnalyticsSummary from './AIAnalyticsSummary'; +import AIAnalyticsSummarySkeleton from './AIAnalyticsSummarySkeleton'; class Admin extends React.Component { componentDidMount() { const { enterpriseId } = this.props; if (enterpriseId) { this.props.fetchDashboardAnalytics(enterpriseId); + this.props.fetchDashboardInsights(enterpriseId); } } @@ -37,12 +40,14 @@ class Admin extends React.Component { const { enterpriseId } = this.props; if (enterpriseId && enterpriseId !== prevProps.enterpriseId) { this.props.fetchDashboardAnalytics(enterpriseId); + this.props.fetchDashboardInsights(enterpriseId); } } componentWillUnmount() { // Clear the overview data this.props.clearDashboardAnalytics(); + this.props.clearDashboardInsights(); } getMetadataForAction(actionSlug) { @@ -281,6 +286,8 @@ class Admin extends React.Component { enterpriseId, match, location: { search }, + insights, + insightsLoading, } = this.props; const { params: { actionSlug } } = match; @@ -309,6 +316,13 @@ class Admin extends React.Component {

Overview

+
+
+ {insightsLoading ? : ( + insights && + )} +
+
{(error || loading) ? (
@@ -402,11 +416,15 @@ Admin.defaultProps = { }, csv: null, table: null, + insightsLoading: false, + insights: null, }; Admin.propTypes = { fetchDashboardAnalytics: PropTypes.func.isRequired, clearDashboardAnalytics: PropTypes.func.isRequired, + fetchDashboardInsights: PropTypes.func.isRequired, + clearDashboardInsights: PropTypes.func.isRequired, enterpriseId: PropTypes.string, searchEnrollmentsList: PropTypes.func.isRequired, location: PropTypes.shape({ @@ -431,6 +449,8 @@ Admin.propTypes = { }).isRequired, }).isRequired, table: PropTypes.shape({}), + insightsLoading: PropTypes.bool, + insights: PropTypes.objectOf(PropTypes.shape), }; export default Admin; diff --git a/src/containers/AdminPage/AdminPage.test.jsx b/src/containers/AdminPage/AdminPage.test.jsx index 29c0770f40..2e30fbade3 100644 --- a/src/containers/AdminPage/AdminPage.test.jsx +++ b/src/containers/AdminPage/AdminPage.test.jsx @@ -28,6 +28,10 @@ const store = mockStore({ table: { enrollments: {}, }, + dashboardInsights: { + loading: null, + insights: null, + }, }); describe('', () => { diff --git a/src/containers/AdminPage/index.jsx b/src/containers/AdminPage/index.jsx index 675cb1fbf5..502f7d18b6 100644 --- a/src/containers/AdminPage/index.jsx +++ b/src/containers/AdminPage/index.jsx @@ -9,6 +9,7 @@ import { import Admin from '../../components/Admin'; import { paginateTable } from '../../data/actions/table'; import EnterpriseDataApiService from '../../data/services/EnterpriseDataApiService'; +import { fetchDashboardInsights, clearDashboardInsights } from '../../data/actions/dashboardInsights'; const mapStateToProps = state => ({ loading: state.dashboardAnalytics.loading, @@ -21,6 +22,8 @@ const mapStateToProps = state => ({ enterpriseId: state.portalConfiguration.enterpriseId, csv: state.csv, table: state.table, + insightsLoading: state.dashboardInsights.loading, + insights: state.dashboardInsights.insights, }); const mapDispatchToProps = dispatch => ({ @@ -33,6 +36,12 @@ const mapDispatchToProps = dispatch => ({ searchEnrollmentsList: () => { dispatch(paginateTable('enrollments', EnterpriseDataApiService.fetchCourseEnrollments)); }, + fetchDashboardInsights: (enterpriseId) => { + dispatch(fetchDashboardInsights(enterpriseId)); + }, + clearDashboardInsights: () => { + dispatch(clearDashboardInsights()); + }, }); export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Admin)); diff --git a/src/data/actions/dashboardInsights.js b/src/data/actions/dashboardInsights.js new file mode 100644 index 0000000000..b9b65a040d --- /dev/null +++ b/src/data/actions/dashboardInsights.js @@ -0,0 +1,41 @@ +import { logError } from '@edx/frontend-platform/logging'; +import { + FETCH_DASHBOARD_INSIGHTS_REQUEST, + FETCH_DASHBOARD_INSIGHTS_SUCCESS, + FETCH_DASHBOARD_INSIGHTS_FAILURE, + CLEAR_DASHBOARD_INSIGHTS, +} from '../constants/dashboardInsights'; +import EnterpriseDataApiService from '../services/EnterpriseDataApiService'; + +const fetchDashboardInsightsRequest = () => ({ type: FETCH_DASHBOARD_INSIGHTS_REQUEST }); +const fetchDashboardInsightsSuccess = data => ({ + type: FETCH_DASHBOARD_INSIGHTS_SUCCESS, + payload: { data }, +}); +const fetchDashboardInsightsFailure = error => ({ + type: FETCH_DASHBOARD_INSIGHTS_FAILURE, + payload: { error }, +}); + +const fetchDashboardInsights = enterpriseId => ( + (dispatch) => { + dispatch(fetchDashboardInsightsRequest()); + return EnterpriseDataApiService.fetchDashboardInsights(enterpriseId) + .then((response) => { + dispatch(fetchDashboardInsightsSuccess(response.data)); + }) + .catch((error) => { + logError(error); + dispatch(fetchDashboardInsightsFailure(error)); + }); + } +); + +const clearDashboardInsights = () => dispatch => (dispatch({ + type: CLEAR_DASHBOARD_INSIGHTS, +})); + +export { + fetchDashboardInsights, + clearDashboardInsights, +}; diff --git a/src/data/constants/dashboardInsights.js b/src/data/constants/dashboardInsights.js new file mode 100644 index 0000000000..05b81a28e9 --- /dev/null +++ b/src/data/constants/dashboardInsights.js @@ -0,0 +1,11 @@ +const FETCH_DASHBOARD_INSIGHTS_REQUEST = 'FETCH_DASHBOARD_INSIGHTS_REQUEST'; +const FETCH_DASHBOARD_INSIGHTS_SUCCESS = 'FETCH_DASHBOARD_INSIGHTS_SUCCESS'; +const FETCH_DASHBOARD_INSIGHTS_FAILURE = 'FETCH_DASHBOARD_INSIGHTS_FAILURE'; +const CLEAR_DASHBOARD_INSIGHTS = 'CLEAR_DASHBOARD_INSIGHTS'; + +export { + FETCH_DASHBOARD_INSIGHTS_REQUEST, + FETCH_DASHBOARD_INSIGHTS_SUCCESS, + FETCH_DASHBOARD_INSIGHTS_FAILURE, + CLEAR_DASHBOARD_INSIGHTS, +}; diff --git a/src/data/reducers/dashboardInsights.js b/src/data/reducers/dashboardInsights.js new file mode 100644 index 0000000000..6c25972617 --- /dev/null +++ b/src/data/reducers/dashboardInsights.js @@ -0,0 +1,47 @@ +import { + FETCH_DASHBOARD_INSIGHTS_REQUEST, + FETCH_DASHBOARD_INSIGHTS_SUCCESS, + FETCH_DASHBOARD_INSIGHTS_FAILURE, + CLEAR_DASHBOARD_INSIGHTS, +} from '../constants/dashboardInsights'; + +const initialState = { + loading: false, + error: null, + insights: null, +}; + +const dashboardInsights = (state = initialState, action) => { + switch (action.type) { + case FETCH_DASHBOARD_INSIGHTS_REQUEST: + return { + ...state, + loading: true, + error: null, + }; + case FETCH_DASHBOARD_INSIGHTS_SUCCESS: + return { + ...state, + loading: false, + insights: action.payload.data, + }; + case FETCH_DASHBOARD_INSIGHTS_FAILURE: + return { + ...state, + loading: false, + error: action.payload.error, + insights: null, + }; + case CLEAR_DASHBOARD_INSIGHTS: + return { + ...state, + loading: false, + error: null, + insights: null, + }; + default: + return state; + } +}; + +export default dashboardInsights; diff --git a/src/data/reducers/index.js b/src/data/reducers/index.js index 27b18f99f5..c3d5abfaf3 100644 --- a/src/data/reducers/index.js +++ b/src/data/reducers/index.js @@ -13,6 +13,7 @@ import licenseRevoke from './licenseRevoke'; import emailTemplate from './emailTemplate'; import licenseRemind from './licenseRemind'; import userSubscription from './userSubscription'; +import dashboardInsights from './dashboardInsights'; const identityReducer = (state) => { const newState = { ...state }; @@ -36,6 +37,7 @@ const rootReducer = combineReducers({ emailTemplate, licenseRemind, userSubscription, + dashboardInsights, }); export default rootReducer; diff --git a/src/data/services/EnterpriseDataApiService.js b/src/data/services/EnterpriseDataApiService.js index bf00da3de6..ef7b5078e5 100644 --- a/src/data/services/EnterpriseDataApiService.js +++ b/src/data/services/EnterpriseDataApiService.js @@ -9,6 +9,8 @@ class EnterpriseDataApiService { static enterpriseBaseUrl = `${configuration.DATA_API_BASE_URL}/enterprise/api/v1/enterprise/`; + static enterpriseAdminBaseUrl = `${configuration.DATA_API_BASE_URL}/enterprise/api/v1/admin/`; + static fetchDashboardAnalytics(enterpriseId) { const url = `${EnterpriseDataApiService.enterpriseBaseUrl}${enterpriseId}/enrollments/overview/`; return EnterpriseDataApiService.apiClient().get(url); @@ -111,6 +113,11 @@ class EnterpriseDataApiService { const url = `${EnterpriseDataApiService.enterpriseBaseUrl}${enterpriseId}/${endpoint}/?${queryParams.toString()}`; return EnterpriseDataApiService.apiClient().get(url); } + + static fetchDashboardInsights(enterpriseId) { + const url = `${EnterpriseDataApiService.enterpriseAdminBaseUrl}insights/${enterpriseId}`; + return EnterpriseDataApiService.apiClient().get(url); + } } export default EnterpriseDataApiService; diff --git a/src/data/services/LmsApiService.js b/src/data/services/LmsApiService.js index 2ed35e8274..31bc12fce7 100644 --- a/src/data/services/LmsApiService.js +++ b/src/data/services/LmsApiService.js @@ -379,6 +379,11 @@ class LmsApiService { }; return LmsApiService.apiClient().put(`${LmsApiService.apiCredentialsUrl}${enterpriseUUID}/regenerate_credentials`, requestData); } + + static generateAIAnalyticsSummary(enterpriseUUID, formData) { + const url = `${LmsApiService.baseUrl}/enterprise/api/v1/analytics-summary/${enterpriseUUID}/`; + return LmsApiService.apiClient().post(url, formData); + } } export default LmsApiService;