From 9ba101e3e7bb4ced0775070c449ee5cf67d6caff Mon Sep 17 00:00:00 2001 From: Saleem Latif Date: Wed, 25 Sep 2024 12:46:32 +0500 Subject: [PATCH] feat: Updated leaderboard data table to use new API endpoint. --- .../AdvanceAnalyticsV2/DownloadCSV.jsx | 119 ------------------ .../AdvanceAnalyticsV2/data/hooks.test.jsx | 4 +- .../tabs/AnalyticsTable.jsx | 2 +- .../AdvanceAnalyticsV2/tabs/Leaderboard.jsx | 4 +- .../tabs/Leaderboard.test.jsx | 16 +-- .../tests/DownloadCSV.test.jsx | 89 ------------- .../tests/EnterpriseDataApiService.test.js | 4 +- 7 files changed, 15 insertions(+), 223 deletions(-) delete mode 100644 src/components/AdvanceAnalyticsV2/DownloadCSV.jsx delete mode 100644 src/components/AdvanceAnalyticsV2/tests/DownloadCSV.test.jsx diff --git a/src/components/AdvanceAnalyticsV2/DownloadCSV.jsx b/src/components/AdvanceAnalyticsV2/DownloadCSV.jsx deleted file mode 100644 index 38cd389263..0000000000 --- a/src/components/AdvanceAnalyticsV2/DownloadCSV.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import React, { useState } from 'react'; -import { saveAs } from 'file-saver'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import PropTypes from 'prop-types'; -import { logError } from '@edx/frontend-platform/logging'; -import { - Toast, StatefulButton, Icon, Spinner, useToggle, -} from '@openedx/paragon'; -import { Download, Check, Close } from '@openedx/paragon/icons'; -import EnterpriseDataApiService from '../../data/services/EnterpriseDataApiService'; -import simulateURL from './data/utils'; - -const DownloadCSV = ({ - startDate, endDate, chartType, activeTab, granularity, calculation, enterpriseId, -}) => { - const [buttonState, setButtonState] = useState('default'); - const [isOpen, open, close] = useToggle(false); - const intl = useIntl(); - - const getFileName = (contentDisposition) => { - let filename = `${activeTab} from (${startDate}-${endDate}).csv`; // Default filename - - // Extract the filename from the content-disposition header if it exists - if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { - const matches = /filename="([^"]+)"/.exec(contentDisposition); - if (matches != null && matches[1]) { - [, filename] = matches; - } - } - return filename; - }; - - const downloadCsv = () => { - setButtonState('pending'); - const chartUrl = simulateURL(activeTab, chartType); - EnterpriseDataApiService.fetchPlotlyChartsCSV(enterpriseId, chartUrl, { - start_date: startDate, - end_date: endDate, - granularity, - calculation, - chart_type: chartType, - response_type: 'csv', - }).then((response) => { - const contentDisposition = response.headers['content-disposition']; - const filename = getFileName(contentDisposition); - - const blob = new Blob([response.data], { type: 'text/csv' }); - saveAs(blob, filename); - open(); - setButtonState('complete'); - }).catch((error) => { - setButtonState('error'); - logError(error); - }); - }; - - const toastText = intl.formatMessage({ - id: 'adminPortal.LPRV2.downloadCSV.toast', - defaultMessage: 'CSV Downloaded', - description: 'Toast message for the download button in the LPR V2 page.', - }); - return ( -
- { isOpen - && ( - - {toastText} - - )} - , - pending: , - complete: , - error: , - }} - disabledStates={['pending']} - onClick={downloadCsv} - /> -
- ); -}; - -DownloadCSV.propTypes = { - startDate: PropTypes.string.isRequired, - endDate: PropTypes.string.isRequired, - chartType: PropTypes.string.isRequired, - activeTab: PropTypes.string.isRequired, - granularity: PropTypes.string.isRequired, - calculation: PropTypes.string.isRequired, - enterpriseId: PropTypes.string.isRequired, -}; - -export default DownloadCSV; diff --git a/src/components/AdvanceAnalyticsV2/data/hooks.test.jsx b/src/components/AdvanceAnalyticsV2/data/hooks.test.jsx index ff3037155b..8f197e477f 100644 --- a/src/components/AdvanceAnalyticsV2/data/hooks.test.jsx +++ b/src/components/AdvanceAnalyticsV2/data/hooks.test.jsx @@ -27,11 +27,11 @@ const mockAnalyticsCompletionsChartsData = { const mockAnalyticsLeaderboardTableData = [ { email: 'user@example.com', - dailySessions: 243, + sessionCount: 243, learningTimeSeconds: 1111, learningTimeHours: 3.4, averageSessionLength: 1.6, - courseCompletions: 4, + courseCompletionCount: 4, }, ]; diff --git a/src/components/AdvanceAnalyticsV2/tabs/AnalyticsTable.jsx b/src/components/AdvanceAnalyticsV2/tabs/AnalyticsTable.jsx index 1ca1c59626..2935d134fd 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/AnalyticsTable.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/AnalyticsTable.jsx @@ -21,7 +21,7 @@ const AnalyticsTable = ({ }) => { const intl = useIntl(); const [currentPage, setCurrentPage] = useState(0); - const pageSize = 50; + const pageSize = 20; const { isFetching, data, diff --git a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.jsx b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.jsx index 31825aab75..6dd04a9364 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.jsx @@ -50,7 +50,7 @@ const Leaderboard = ({ startDate, endDate, enterpriseId }) => { description: 'Label for the daily sessions column in the leaderboard table', }), - accessor: 'dailySessions', + accessor: 'sessionCount', }, { Header: intl.formatMessage({ @@ -67,7 +67,7 @@ const Leaderboard = ({ startDate, endDate, enterpriseId }) => { defaultMessage: 'Course Completions', description: 'Label for the course completions column in the leaderboard table', }), - accessor: 'courseCompletions', + accessor: 'courseCompletionCount', }, ]} /> diff --git a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx index 7af2e74066..0d56699b70 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx @@ -28,24 +28,24 @@ const mockLeaderboardData = { results: [ { email: 'user100@example.com', - daily_sessions: 74, + session_count: 74, learning_time_hours: 13.1, average_session_length: 1.8, - course_completions: 3, + course_completion_count: 3, }, { email: 'user200@example.com', - daily_sessions: 48, + session_count: 48, learning_time_hours: 131.9, average_session_length: 2.7, - course_completions: 1, + course_completion_count: 1, }, { email: 'user300@example.com', - daily_sessions: 92, + session_count: 92, learning_time_hours: 130, average_session_length: 1.4, - course_completions: 3, + course_completion_count: 3, }, ], }; @@ -134,9 +134,9 @@ describe('Leaderboard Component', () => { const rowCells = within(rows[index + 1]).getAllByRole('cell'); // Skip header row expect(rowCells[0]).toHaveTextContent(user.email); expect(rowCells[1]).toHaveTextContent(user.learning_time_hours); - expect(rowCells[2]).toHaveTextContent(user.daily_sessions); + expect(rowCells[2]).toHaveTextContent(user.session_count); expect(rowCells[3]).toHaveTextContent(user.average_session_length); - expect(rowCells[4]).toHaveTextContent(user.course_completions); + expect(rowCells[4]).toHaveTextContent(user.course_completion_count); }); }); }); diff --git a/src/components/AdvanceAnalyticsV2/tests/DownloadCSV.test.jsx b/src/components/AdvanceAnalyticsV2/tests/DownloadCSV.test.jsx deleted file mode 100644 index dc03ae5a3f..0000000000 --- a/src/components/AdvanceAnalyticsV2/tests/DownloadCSV.test.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react'; -import { IntlProvider } from '@edx/frontend-platform/i18n'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { saveAs } from 'file-saver'; -import { logError } from '@edx/frontend-platform/logging'; -import DownloadCSV from '../DownloadCSV'; -import '@testing-library/jest-dom/extend-expect'; -import EnterpriseDataApiService from '../../../data/services/EnterpriseDataApiService'; - -jest.mock('file-saver', () => ({ - ...jest.requireActual('file-saver'), - saveAs: jest.fn(), -})); - -jest.mock('@edx/frontend-platform/logging', () => ({ - ...jest.requireActual('@edx/frontend-platform/logging'), - logError: jest.fn(), -})); - -jest.mock('../../../data/services/EnterpriseDataApiService', () => ({ - fetchPlotlyChartsCSV: jest.fn(), -})); - -const DEFAULT_PROPS = { - startDate: '2021-01-01', - endDate: '2025-01-31', - chartType: 'completions-over-time', - activeTab: 'completions', - granularity: 'Daily', - calculation: 'Total', - enterpriseId: 'test_enterprise_id', -}; -describe('DownloadCSV', () => { - const flushPromises = () => new Promise(setImmediate); - - it('renders download csv button correctly', async () => { - render( - - - , - ); - - expect(screen.getByTestId('plotly-charts-download-csv-button')).toBeInTheDocument(); - }); - - it('handles successful CSV download', async () => { - const mockResponse = { - headers: { - 'content-disposition': 'attachment; filename="completions.csv"', - }, - data: 'CSV data', - }; - EnterpriseDataApiService.fetchPlotlyChartsCSV.mockResolvedValueOnce(mockResponse); - - render( - - - , - ); - - // Click the download button. - userEvent.click(screen.getByTestId('plotly-charts-download-csv-button')); - await flushPromises(); - - expect(saveAs).toHaveBeenCalledWith( - new Blob([mockResponse.data], { type: 'text/csv' }), - 'completions.csv', - ); - }); - - it('handles error during CSV download', async () => { - const mockError = new Error('Failed to download CSV'); - EnterpriseDataApiService.fetchPlotlyChartsCSV.mockRejectedValueOnce(mockError); - - render( - - - , - ); - - // Click the download button. - userEvent.click(screen.getByTestId('plotly-charts-download-csv-button')); - await flushPromises(); - - expect(logError).toHaveBeenCalledWith(mockError); - expect(screen.getByText('Error')).toBeInTheDocument(); - }); -}); diff --git a/src/data/services/tests/EnterpriseDataApiService.test.js b/src/data/services/tests/EnterpriseDataApiService.test.js index 318099d753..d3f7249c02 100644 --- a/src/data/services/tests/EnterpriseDataApiService.test.js +++ b/src/data/services/tests/EnterpriseDataApiService.test.js @@ -18,11 +18,11 @@ const mockAnalyticsSkillsData = { const mockAnalyticsLeaderboardTableData = [ { email: 'user@example.com', - dailySessions: 243, + sessionCount: 243, learningTimeSeconds: 1111, learningTimeHours: 3.4, averageSessionLength: 1.6, - courseCompletions: 4, + courseCompletionCount: 4, }, ];