diff --git a/src/course-home/data/apiHooks.test.tsx b/src/course-home/data/apiHooks.test.tsx
index 3a157dd53d..801532eba2 100644
--- a/src/course-home/data/apiHooks.test.tsx
+++ b/src/course-home/data/apiHooks.test.tsx
@@ -1,5 +1,6 @@
import { act, renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { Factory } from 'rosie';
import MockAdapter from 'axios-mock-adapter';
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
@@ -7,8 +8,8 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { initializeMockApp } from '../../setupTest';
import { ToastProvider, useToast } from '../../generic/ToastContext';
import {
- useOutlineTabData, useResetDeadlines, usePostEvent, useRequestCert, useDismissWelcomeMessage,
- useSaveWeeklyLearningGoal,
+ useOutlineTabData, useProgressTabData, useResetDeadlines, usePostEvent, useRequestCert,
+ useDismissWelcomeMessage, useSaveWeeklyLearningGoal,
} from './apiHooks';
const { loggingService } = initializeMockApp();
@@ -193,6 +194,68 @@ describe('course-home apiHooks', () => {
});
});
+ describe('useProgressTabData', () => {
+ const progressUrl = `${getConfig().LMS_BASE_URL}/api/course_home/progress/course-1`;
+
+ it('transforms the server response', async () => {
+ axiosMock.onGet(progressUrl).reply(200, Factory.build('progressTabData'));
+ const { wrapper } = buildWrapper();
+ const { result } = renderHook(() => useProgressTabData('course-1'), { wrapper });
+
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
+ expect(result.current.data.studioUrl).toEqual('http://studio.edx.org/settings/grading/course-v1:edX+Test+run');
+ expect(result.current.data.gradesFeatureIsFullyLocked).toBe(false);
+ });
+
+ it('appends the targetUserId to the request URL', async () => {
+ axiosMock.onGet(`${progressUrl}/7/`).reply(200, Factory.build('progressTabData'));
+ const { wrapper } = buildWrapper();
+ const { result } = renderHook(() => useProgressTabData('course-1', '7'), { wrapper });
+
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
+ expect(axiosMock.history.get[0].url).toEqual(`${progressUrl}/7/`);
+ });
+
+ it.each([401, 403])(
+ 'resolves to an empty object on a %s (access is handled via the metadata request)',
+ async (status) => {
+ axiosMock.onGet(progressUrl).reply(status, {});
+ const { wrapper } = buildWrapper();
+ const { result } = renderHook(() => useProgressTabData('course-1'), { wrapper });
+
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
+ expect(result.current.data).toEqual({});
+ },
+ );
+
+ it('redirects to the legacy progress page and resolves to an empty object on a 404', async () => {
+ // jsdom's location.replace is non-configurable, so we swap the whole location for the
+ // duration of this test (restored in finally so it can never bleed into another test).
+ const originalLocation = window.location;
+ const replace = jest.fn();
+ Object.defineProperty(window, 'location', { configurable: true, value: { replace } });
+ try {
+ axiosMock.onGet(progressUrl).reply(404, {});
+ const { wrapper } = buildWrapper();
+ const { result } = renderHook(() => useProgressTabData('course-1'), { wrapper });
+
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
+ expect(result.current.data).toEqual({});
+ expect(replace).toHaveBeenCalledWith(`${getConfig().LMS_BASE_URL}/courses/course-1/progress`);
+ } finally {
+ Object.defineProperty(window, 'location', { configurable: true, value: originalLocation });
+ }
+ });
+
+ it('surfaces the error on a non-handled failure', async () => {
+ axiosMock.onGet(progressUrl).reply(500);
+ const { wrapper } = buildWrapper();
+ const { result } = renderHook(() => useProgressTabData('course-1'), { wrapper });
+
+ await waitFor(() => expect(result.current.isError).toBe(true));
+ });
+ });
+
describe('useSaveWeeklyLearningGoal', () => {
const goalUrl = `${getConfig().LMS_BASE_URL}/api/course_home/save_course_goal`;
diff --git a/src/course-home/data/apiHooks.ts b/src/course-home/data/apiHooks.ts
index ada7375297..1767ccae92 100644
--- a/src/course-home/data/apiHooks.ts
+++ b/src/course-home/data/apiHooks.ts
@@ -7,6 +7,7 @@ import {
getCourseHomeCourseMetadata,
getDatesTabData,
getOutlineTabData,
+ getProgressTabData,
postCourseDeadlines,
postDismissWelcomeMessage,
postRequestCert,
@@ -74,6 +75,12 @@ export const useOutlineTabData = (courseId: string) => useQuery({
meta: { modelType: 'outline', courseId },
});
+export const useProgressTabData = (courseId: string, targetUserId?: string) => useQuery({
+ queryKey: courseHomeQueryKeys.progressTab(courseId, targetUserId),
+ queryFn: () => getProgressTabData(courseId, targetUserId),
+ meta: { modelType: 'progress', courseId },
+});
+
export const useRequestCert = () => useMutation({
mutationFn: ({ courseId }: { courseId: string }) => postRequestCert(courseId),
onError: (error) => logError(error),
diff --git a/src/course-home/data/index.js b/src/course-home/data/index.js
index 14b7826f01..f427a06bff 100644
--- a/src/course-home/data/index.js
+++ b/src/course-home/data/index.js
@@ -1,6 +1,3 @@
-export {
- fetchProgressTab,
- deprecatedSaveCourseGoal,
-} from './thunks';
+export { deprecatedSaveCourseGoal } from './thunks';
export { reducer } from './slice';
diff --git a/src/course-home/data/queryKeys.ts b/src/course-home/data/queryKeys.ts
index 15dfcd794e..c671efba99 100644
--- a/src/course-home/data/queryKeys.ts
+++ b/src/course-home/data/queryKeys.ts
@@ -5,4 +5,5 @@ export const courseHomeQueryKeys = {
metadata: (courseId: string) => [...courseHomeQueryKeys.all, 'metadata', courseId] as const,
datesTab: (courseId: string) => [...courseHomeQueryKeys.all, 'datesTab', courseId] as const,
outlineTab: (courseId: string) => [...courseHomeQueryKeys.all, 'outlineTab', courseId] as const,
+ progressTab: (courseId: string, targetUserId?: string) => [...courseHomeQueryKeys.all, 'progressTab', courseId, targetUserId] as const,
};
diff --git a/src/course-home/data/redux.test.js b/src/course-home/data/redux.test.js
index 453faf9f02..e434a6fd31 100644
--- a/src/course-home/data/redux.test.js
+++ b/src/course-home/data/redux.test.js
@@ -42,61 +42,6 @@ describe('Data layer integration tests', () => {
store = initializeStore();
});
- describe('Test fetchProgressTab', () => {
- const progressBaseUrl = `${getConfig().LMS_BASE_URL}/api/course_home/progress`;
-
- it('Should result in fetch failure if error occurs', async () => {
- axiosMock.onGet(courseMetadataUrl).networkError();
- axiosMock.onGet(`${progressBaseUrl}/${courseId}`).networkError();
-
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
-
- expect(loggingService.logError).toHaveBeenCalled();
- expect(store.getState().courseHome.courseStatus).toEqual('failed');
- });
-
- it('Should fetch, normalize, and save metadata', async () => {
- const progressTabData = Factory.build('progressTabData', { courseId });
-
- const progressUrl = `${progressBaseUrl}/${courseId}`;
-
- axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeMetadata);
- axiosMock.onGet(progressUrl).reply(200, progressTabData);
-
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
-
- const state = store.getState();
- expect(state.courseHome.courseStatus).toEqual('loaded');
- });
-
- it('Should handle the url including a targetUserId', async () => {
- const progressTabData = Factory.build('progressTabData', { courseId });
- const targetUserId = 2;
- const progressUrl = `${progressBaseUrl}/${courseId}/${targetUserId}/`;
-
- axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeMetadata);
- axiosMock.onGet(progressUrl).reply(200, progressTabData);
-
- await executeThunk(thunks.fetchProgressTab(courseId, 2), store.dispatch);
-
- const state = store.getState();
- expect(state.courseHome.targetUserId).toEqual(2);
- });
-
- it.each([401, 403, 404])(
- 'should result in fetch denied for expected errors and failed for all others',
- async (errorStatus) => {
- const progressUrl = `${progressBaseUrl}/${courseId}`;
- axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeAccessDeniedMetadata);
- axiosMock.onGet(progressUrl).reply(errorStatus, {});
-
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
-
- expect(store.getState().courseHome.courseStatus).toEqual('denied');
- },
- );
- });
-
describe('Test saveCourseGoal', () => {
it('Should save course goal', async () => {
const goalUrl = `${getConfig().LMS_BASE_URL}/api/course_home/save_course_goal`;
@@ -282,4 +227,45 @@ describe('Data layer integration tests', () => {
expect(loggingService.logError).toHaveBeenCalled();
});
});
+
+ describe('Test fetchTab', () => {
+ const liveUrl = `${getConfig().LMS_BASE_URL}/api/course_live/iframe/${courseId}/`;
+
+ it('Should fetch metadata + tab data and mark the tab loaded', async () => {
+ axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeMetadata);
+ axiosMock.onGet(liveUrl).reply(200, { iframe: 'https://example.com/live' });
+
+ await executeThunk(thunks.fetchLiveTab(courseId), store.dispatch);
+
+ expect(store.getState().courseHome.courseStatus).toEqual('loaded');
+ });
+
+ it('Should result in denied when the learner lacks course access', async () => {
+ axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeAccessDeniedMetadata);
+ axiosMock.onGet(liveUrl).reply(200, {});
+
+ await executeThunk(thunks.fetchLiveTab(courseId), store.dispatch);
+
+ expect(store.getState().courseHome.courseStatus).toEqual('denied');
+ });
+
+ it('Should result in failure when the metadata request errors', async () => {
+ axiosMock.onGet(courseMetadataUrl).networkError();
+ axiosMock.onGet(liveUrl).reply(200, {});
+
+ await executeThunk(thunks.fetchLiveTab(courseId), store.dispatch);
+
+ expect(loggingService.logError).toHaveBeenCalled();
+ expect(store.getState().courseHome.courseStatus).toEqual('failed');
+ });
+
+ it('Should result in failure when the tab data request errors', async () => {
+ axiosMock.onGet(courseMetadataUrl).reply(200, courseHomeMetadata);
+ axiosMock.onGet(liveUrl).reply(500);
+
+ await executeThunk(thunks.fetchLiveTab(courseId), store.dispatch);
+
+ expect(store.getState().courseHome.courseStatus).toEqual('failed');
+ });
+ });
});
diff --git a/src/course-home/data/thunks.js b/src/course-home/data/thunks.js
index dc1a37c446..64849b7140 100644
--- a/src/course-home/data/thunks.js
+++ b/src/course-home/data/thunks.js
@@ -2,7 +2,6 @@ import { logError } from '@edx/frontend-platform/logging';
import {
getCourseHomeCourseMetadata,
getExamsData,
- getProgressTabData,
deprecatedPostCourseGoals,
getLiveTabIframe,
} from './api';
@@ -81,10 +80,6 @@ export function fetchTab(courseId, tab, getTabData, targetUserId) {
};
}
-export function fetchProgressTab(courseId, targetUserId) {
- return fetchTab(courseId, 'progress', getProgressTabData, parseInt(targetUserId, 10) || targetUserId);
-}
-
export function fetchLiveTab(courseId) {
return fetchTab(courseId, 'live', getLiveTabIframe);
}
diff --git a/src/course-home/progress-tab/ProgressHeader.jsx b/src/course-home/progress-tab/ProgressHeader.jsx
index 6223b1fc4d..243908d136 100644
--- a/src/course-home/progress-tab/ProgressHeader.jsx
+++ b/src/course-home/progress-tab/ProgressHeader.jsx
@@ -1,22 +1,19 @@
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button } from '@openedx/paragon';
-import { useSelector } from 'react-redux';
-
-import { useModel } from '../../generic/model-store';
+import { useParams } from 'react-router-dom';
+import { useProgressData } from './hooks';
import messages from './messages';
const ProgressHeader = () => {
const intl = useIntl();
- const {
- courseId,
- targetUserId,
- } = useSelector(state => state.courseHome);
+ const { targetUserId: targetUserIdParam } = useParams();
+ const targetUserId = parseInt(targetUserIdParam, 10);
const { administrator, userId } = getAuthenticatedUser();
- const { studioUrl, username } = useModel('progress', courseId);
+ const { studioUrl, username } = useProgressData();
const viewingOtherStudentsProgressPage = (targetUserId && targetUserId !== userId);
diff --git a/src/course-home/progress-tab/ProgressTab.jsx b/src/course-home/progress-tab/ProgressTab.jsx
index 32506930bf..7cfc6961e5 100644
--- a/src/course-home/progress-tab/ProgressTab.jsx
+++ b/src/course-home/progress-tab/ProgressTab.jsx
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { useWindowSize } from '@openedx/paragon';
-import { useContextId } from '../../data/hooks';
-import { useModel } from '../../generic/model-store';
+import { useParams } from 'react-router-dom';
+
import ProgressTabCertificateStatusSidePanelSlot from '../../plugin-slots/ProgressTabCertificateStatusSidePanelSlot';
import CourseCompletion from './course-completion/CourseCompletion';
@@ -11,11 +11,13 @@ import ProgressTabCertificateStatusMainBodySlot from '../../plugin-slots/Progres
import ProgressTabCourseGradeSlot from '../../plugin-slots/ProgressTabCourseGradeSlot';
import ProgressTabGradeBreakdownSlot from '../../plugin-slots/ProgressTabGradeBreakdownSlot';
import ProgressTabRelatedLinksSlot from '../../plugin-slots/ProgressTabRelatedLinksSlot';
-import { useGetExamsData } from './hooks';
+import { useGetExamsData, useProgressData } from './hooks';
+import { useCourseHomeMeta, useProgressTabData } from '../data/apiHooks';
+import { TabWithTimer } from '../../tab-page';
-const ProgressTab = () => {
- const courseId = useContextId();
- const { disableProgressGraph, sectionScores } = useModel('progress', courseId);
+const ProgressTabContent = () => {
+ const { courseId } = useParams();
+ const { disableProgressGraph, sectionScores } = useProgressData();
const sequenceIds = useMemo(() => (
sectionScores.flatMap((section) => (section.subsections)).map((subsection) => subsection.blockKey)
@@ -53,4 +55,20 @@ const ProgressTab = () => {
);
};
+const ProgressTab = () => {
+ const { courseId, targetUserId } = useParams();
+ const metadataQuery = useCourseHomeMeta(courseId);
+ const tabDataQuery = useProgressTabData(courseId, targetUserId);
+
+ return (
+
+
+
+ );
+};
+
export default ProgressTab;
diff --git a/src/course-home/progress-tab/ProgressTab.test.jsx b/src/course-home/progress-tab/ProgressTab.test.jsx
index 2abfc286f1..d75a0c5a2c 100644
--- a/src/course-home/progress-tab/ProgressTab.test.jsx
+++ b/src/course-home/progress-tab/ProgressTab.test.jsx
@@ -1,20 +1,23 @@
import React from 'react';
+import { MemoryRouter, Routes, Route } from 'react-router-dom';
import { Factory } from 'rosie';
import { getConfig, setConfig } from '@edx/frontend-platform';
+import { AppProvider } from '@edx/frontend-platform/react';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { breakpoints } from '@openedx/paragon';
+import { QueryClientProvider } from '@tanstack/react-query';
+import { render } from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import {
- fireEvent, initializeMockApp, logUnhandledRequests, render, screen, act, waitFor,
+ createTestQueryClient, fireEvent, initializeMockApp, logUnhandledRequests, screen, within, act, waitFor,
} from '../../setupTest';
-import { appendBrowserTimezoneToUrl, executeThunk } from '../../utils';
-import * as thunks from '../data/thunks';
+import { appendBrowserTimezoneToUrl } from '../../utils';
import initializeStore from '../../store';
import ProgressTab from './ProgressTab';
-import LoadedTabPage from '../../tab-page/LoadedTabPage';
-import { TourProvider } from '../../product-tours/TourContext';
+import { UserMessagesProvider } from '../../generic/user-messages';
+import { ToastProvider } from '../../generic/ToastContext';
import messages from './grades/messages';
const mockCoursewareSearchParams = jest.fn();
@@ -64,9 +67,25 @@ describe('Progress Tab', () => {
axiosMock.onGet(progressUrl).reply(200, progressTabData);
}
- async function fetchAndRender() {
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
- await act(async () => render(, { store }));
+ async function fetchAndRender(initialEntry = `/course/${courseId}/progress`) {
+ const queryClient = createTestQueryClient(store);
+ await act(async () => render(
+
+
+
+
+
+
+ } />
+
+
+
+
+
+ ,
+ ));
+ await waitFor(() => expect(screen.queryByRole('status')).not.toBeInTheDocument());
+ return queryClient;
}
beforeEach(async () => {
@@ -96,7 +115,8 @@ describe('Progress Tab', () => {
await fetchAndRender();
sendTrackEvent.mockClear();
- const datesTabLink = screen.getByRole('link', { name: 'Dates' });
+ const relatedLinks = within(screen.getByRole('heading', { name: 'Related links' }).closest('section'));
+ const datesTabLink = relatedLinks.getByRole('link', { name: 'Dates' });
fireEvent.click(datesTabLink);
expect(sendTrackEvent).toHaveBeenCalledTimes(1);
@@ -320,7 +340,7 @@ describe('Progress Tab', () => {
await fetchAndRender();
expect(screen.getByText('locked feature')).toBeInTheDocument();
expect(screen.getByText('Unlock to view grades and work towards a certificate.')).toBeInTheDocument();
- expect(screen.getAllByRole('link', 'Unlock now')).toHaveLength(3);
+ expect(screen.getAllByRole('link', { name: 'Upgrade now' })).toHaveLength(1);
});
it('sends events on click of upgrade button in locked content header (CourseGradeHeader)', async () => {
@@ -364,7 +384,7 @@ describe('Progress Tab', () => {
expect(screen.getByText('locked feature')).toBeInTheDocument();
expect(screen.getByText('Unlock to view grades and work towards a certificate.')).toBeInTheDocument();
- const upgradeButton = screen.getAllByRole('link', 'Unlock now')[0];
+ const upgradeButton = screen.getAllByRole('link', { name: 'Upgrade now' })[0];
fireEvent.click(upgradeButton);
expect(sendTrackEvent).toHaveBeenCalledTimes(2);
@@ -1435,8 +1455,7 @@ describe('Progress Tab', () => {
masquerading_expired_course: true,
},
});
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
- await act(async () => render(..., { store }));
+ await fetchAndRender();
expect(screen.getByTestId('instructor-toolbar')).toBeInTheDocument();
expect(screen.getByText('This learner no longer has access to this course. Their access expired on', { exact: false })).toBeInTheDocument();
expect(screen.getByText('1/1/2020', { exact: false })).toBeInTheDocument();
@@ -1449,8 +1468,7 @@ describe('Progress Tab', () => {
masquerading_expired_course: false,
},
});
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
- await act(async () => render(..., { store }));
+ await fetchAndRender();
expect(screen.queryByText('This learner no longer has access to this course. Their access expired on', { exact: false })).not.toBeInTheDocument();
expect(screen.queryByText('1/1/2020', { exact: false })).not.toBeInTheDocument();
});
@@ -1464,8 +1482,7 @@ describe('Progress Tab', () => {
is_staff: false,
start: '2999-01-01T00:00:00Z',
});
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
- await act(async () => render(..., { store }));
+ await fetchAndRender();
expect(screen.getByTestId('instructor-toolbar')).toBeInTheDocument();
expect(screen.getByText('This learner does not yet have access to this course. The course starts on', { exact: false })).toBeInTheDocument();
expect(screen.getByText('1/1/2999', { exact: false })).toBeInTheDocument();
@@ -1477,8 +1494,7 @@ describe('Progress Tab', () => {
is_staff: true,
start: '2999-01-01T00:00:00Z',
});
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
- await act(async () => render(..., { store }));
+ await fetchAndRender();
expect(screen.queryByText('This learner does not yet have access to this course. The course starts on', { exact: false })).not.toBeInTheDocument();
expect(screen.queryByText('1/1/2999', { exact: false })).not.toBeInTheDocument();
});
@@ -1489,8 +1505,7 @@ describe('Progress Tab', () => {
setMetadata({ is_enrolled: true });
setTabData({ username: 'otherstudent' });
- await executeThunk(thunks.fetchProgressTab(courseId, 10), store.dispatch);
- await act(async () => render(, { store }));
+ await fetchAndRender(`/course/${courseId}/progress/10/`);
expect(screen.getByText('Course progress for otherstudent')).toBeInTheDocument();
});
@@ -1631,7 +1646,7 @@ describe('Progress Tab', () => {
section_scores: [mockSectionScores[0]], // Only first section
});
- await fetchAndRender();
+ const queryClient = await fetchAndRender();
// Verify initial API calls (2 subsections in first section)
expect(axiosMock.history.get.filter(req => req.url.includes('/api/v1/student/exam/attempt/'))).toHaveLength(2);
@@ -1639,12 +1654,14 @@ describe('Progress Tab', () => {
// Clear axios history to track new calls
axiosMock.resetHistory();
- // Update with full section scores and re-render
+ // Update with full section scores and refetch the tab query
setTabData({ section_scores: mockSectionScores });
- await executeThunk(thunks.fetchProgressTab(courseId), store.dispatch);
+ await act(async () => { await queryClient.invalidateQueries(); });
// Verify additional API calls for all subsections
- expect(axiosMock.history.get.filter(req => req.url.includes('/api/v1/student/exam/attempt/'))).toHaveLength(3);
+ await waitFor(() => expect(
+ axiosMock.history.get.filter(req => req.url.includes('/api/v1/student/exam/attempt/')),
+ ).toHaveLength(3));
});
it('should handle exam API errors gracefully without breaking ProgressTab', async () => {
diff --git a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
index e7dd2c21f9..31109250da 100644
--- a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
+++ b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
@@ -5,17 +5,18 @@ import { FormattedDate, FormattedMessage, useIntl } from '@edx/frontend-platform
import { Button, Card } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
-import { useContextId } from '../../../data/hooks';
+import { useParams } from 'react-router-dom';
import { useModel } from '../../../generic/model-store';
import { COURSE_EXIT_MODES, getCourseExitMode } from '../../../courseware/course/course-exit/utils';
import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../shared/links';
import { useRequestCert } from '../../data/apiHooks';
+import { useProgressData } from '../hooks';
import messages from './messages';
import ProgressCertificateStatusSlot from '../../../plugin-slots/ProgressCertificateStatusSlot';
const CertificateStatus = () => {
const intl = useIntl();
- const courseId = useContextId();
+ const { courseId } = useParams();
const {
entranceExamData,
@@ -39,7 +40,7 @@ const CertificateStatus = () => {
userHasPassingGrade,
verificationData,
verifiedMode,
- } = useModel('progress', courseId);
+ } = useProgressData();
const {
certificateAvailableDate,
} = certificateData || {};
diff --git a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
index a74c3a0a5c..bc47deb50f 100644
--- a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
+++ b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
@@ -1,6 +1,5 @@
import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n';
-import { useContextId } from '../../../data/hooks';
-import { useModel } from '../../../generic/model-store';
+import { useProgressData } from '../hooks';
import CompleteDonutSegment from './CompleteDonutSegment';
import IncompleteDonutSegment from './IncompleteDonutSegment';
@@ -9,7 +8,6 @@ import messages from './messages';
const CompletionDonutChart = () => {
const intl = useIntl();
- const courseId = useContextId();
const {
completionSummary: {
@@ -17,7 +15,7 @@ const CompletionDonutChart = () => {
incompleteCount,
lockedCount,
},
- } = useModel('progress', courseId);
+ } = useProgressData();
const numTotalUnits = completeCount + incompleteCount + lockedCount;
const completePercentage = completeCount ? Number(((completeCount / numTotalUnits) * 100).toFixed(0)) : 0;
diff --git a/src/course-home/progress-tab/credit-information/CreditInformation.jsx b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
index c12c4de2ec..d8803604a8 100644
--- a/src/course-home/progress-tab/credit-information/CreditInformation.jsx
+++ b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
@@ -2,20 +2,18 @@ import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { CheckCircle, WarningFilled, WatchFilled } from '@openedx/paragon/icons';
import { Hyperlink, Icon } from '@openedx/paragon';
-import { useContextId } from '../../../data/hooks';
-import { useModel } from '../../../generic/model-store';
+import { useProgressData } from '../hooks';
import { DashboardLink } from '../../../shared/links';
import messages from './messages';
const CreditInformation = () => {
const intl = useIntl();
- const courseId = useContextId();
const {
creditCourseRequirements,
- } = useModel('progress', courseId);
+ } = useProgressData();
if (!creditCourseRequirements) { return null; }
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
index d69c6eee15..3cc94f790f 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
@@ -1,7 +1,6 @@
import { useIntl } from '@edx/frontend-platform/i18n';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import CourseGradeFooter from './CourseGradeFooter';
import CourseGradeHeader from './CourseGradeHeader';
@@ -12,7 +11,6 @@ import messages from '../messages';
const CourseGrade = () => {
const intl = useIntl();
- const courseId = useContextId();
const {
creditCourseRequirements,
@@ -21,7 +19,7 @@ const CourseGrade = () => {
gradingPolicy: {
gradeRange,
},
- } = useModel('progress', courseId);
+ } = useProgressData();
const passingGrade = Number((Math.min(...Object.values(gradeRange)) * 100).toFixed(0));
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
index 6cada4cbb4..feb7c881b9 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { CheckCircle, WarningFilled } from '@openedx/paragon/icons';
import { breakpoints, Icon, useWindowSize } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import GradeRangeTooltip from './GradeRangeTooltip';
import messages from '../messages';
@@ -45,13 +44,12 @@ const NoticeRow = ({
const CourseGradeFooter = ({ passingGrade }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
assignmentTypeGradeSummary,
courseGrade: { isPassing, letterGrade },
gradingPolicy: { gradeRange },
- } = useModel('progress', courseId);
+ } = useProgressData();
const latestDueDate = getLatestDueDateInFuture(assignmentTypeGradeSummary);
const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth;
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
index f6e036de0a..6b198b7690 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
@@ -3,21 +3,22 @@ import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Locked } from '@openedx/paragon/icons';
import { Button, Icon } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
+import { useParams } from 'react-router-dom';
import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
const CourseGradeHeader = () => {
const intl = useIntl();
- const courseId = useContextId();
+ const { courseId } = useParams();
const {
org,
} = useModel('courseHomeMeta', courseId);
const {
verifiedMode,
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
const eventProperties = {
org_key: org,
diff --git a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
index 8e1c6b2985..117e89ac4c 100644
--- a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
@@ -2,15 +2,13 @@ import PropTypes from 'prop-types';
import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n';
import { OverlayTrigger, Popover } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
const CurrentGradeTooltip = ({ tooltipClassName }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
assignmentTypeGradeSummary,
@@ -18,7 +16,7 @@ const CurrentGradeTooltip = ({ tooltipClassName }) => {
isPassing,
percent,
},
- } = useModel('progress', courseId);
+ } = useProgressData();
const currentGrade = Number((percent * 100).toFixed(0));
diff --git a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
index bb45f366a2..1a8bbc4d40 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
@@ -1,8 +1,7 @@
import PropTypes from 'prop-types';
import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import CurrentGradeTooltip from './CurrentGradeTooltip';
import PassingGradeTooltip from './PassingGradeTooltip';
@@ -10,7 +9,6 @@ import messages from '../messages';
const GradeBar = ({ passingGrade }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
courseGrade: {
@@ -18,7 +16,7 @@ const GradeBar = ({ passingGrade }) => {
percent,
},
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
const currentGrade = Number((percent * 100).toFixed(0));
diff --git a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
index 9123b2cdd4..31fd6e4f58 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
@@ -6,21 +6,19 @@ import { InfoOutline } from '@openedx/paragon/icons';
import {
Icon, IconButton, OverlayTrigger, Popover,
} from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
const GradeRangeTooltip = ({ iconButtonClassName, passingGrade }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
gradesFeatureIsFullyLocked,
gradingPolicy: {
gradeRange,
},
- } = useModel('progress', courseId);
+ } = useProgressData();
const [showTooltip, setShowTooltip] = useState(false);
diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
index 6b61869888..8af43482f3 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
@@ -3,8 +3,9 @@ import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Locked } from '@openedx/paragon/icons';
import { Icon, Hyperlink } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
+import { useParams } from 'react-router-dom';
import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import { showUngradedAssignments } from '../../utils';
import DetailedGradesTable from './DetailedGradesTable';
@@ -14,7 +15,7 @@ import messages from '../messages';
const DetailedGrades = () => {
const intl = useIntl();
const { administrator } = getAuthenticatedUser();
- const courseId = useContextId();
+ const { courseId } = useParams();
const {
org,
tabs,
@@ -23,7 +24,7 @@ const DetailedGrades = () => {
gradesFeatureIsFullyLocked,
gradesFeatureIsPartiallyLocked,
sectionScores,
- } = useModel('progress', courseId);
+ } = useProgressData();
const hasSectionScores = sectionScores.length > 0;
const emptyTableMsg = showUngradedAssignments()
diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
index 723aeae49f..66f9878dc1 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
@@ -1,19 +1,17 @@
import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n';
import { DataTable } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
import SubsectionTitleCell from './SubsectionTitleCell';
import { showUngradedAssignments } from '../../utils';
const DetailedGradesTable = () => {
const intl = useIntl();
- const courseId = useContextId();
const {
sectionScores,
- } = useModel('progress', courseId);
+ } = useProgressData();
const isLocaleRtl = isRtl(getLocale());
return (
diff --git a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
index 3f856082d8..594beb25dd 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
@@ -10,21 +10,22 @@ import {
Info,
Locked,
} from '@openedx/paragon/icons';
-import { useContextId } from '../../../../data/hooks';
+import { useParams } from 'react-router-dom';
import messages from '../messages';
import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import ProblemScoreDrawer from './ProblemScoreDrawer';
const SubsectionTitleCell = ({ subsection }) => {
const intl = useIntl();
- const courseId = useContextId();
+ const { courseId } = useParams();
const {
org,
} = useModel('courseHomeMeta', courseId);
const {
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
const {
blockKey,
diff --git a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
index b84d07e27b..3ba0c7044c 100644
--- a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
@@ -2,19 +2,17 @@ import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Locked } from '@openedx/paragon/icons';
import { Icon } from '@openedx/paragon';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
const AssignmentTypeCell = ({
assignmentType, footnoteMarker, footnoteId, locked,
}) => {
const intl = useIntl();
- const courseId = useContextId();
const {
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
const lockedIcon = locked ? : '';
diff --git a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
index 199fbb42f4..7549309bc7 100644
--- a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
@@ -1,17 +1,15 @@
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
-import { useContextId } from '../../../../data/hooks';
import messages from '../messages';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
const DroppableAssignmentFootnote = ({ footnotes }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
return (
<>
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
index 6066997a9f..e966aa10a9 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
@@ -1,17 +1,14 @@
import React, { useState } from 'react';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import GradeSummaryHeader from './GradeSummaryHeader';
import GradeSummaryTable from './GradeSummaryTable';
const GradeSummary = () => {
- const courseId = useContextId();
-
const {
assignmentTypeGradeSummary,
- } = useModel('progress', courseId);
+ } = useProgressData();
const [allOfSomeAssignmentTypeIsLocked, setAllOfSomeAssignmentTypeIsLocked] = useState(false);
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
index df1ff65836..6f038c391c 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
@@ -8,18 +8,16 @@ import {
Tooltip,
} from '@openedx/paragon';
import { InfoOutline, Locked } from '@openedx/paragon/icons';
-import { useContextId } from '../../../../data/hooks';
import messages from '../messages';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
const GradeSummaryHeader = ({ allOfSomeAssignmentTypeIsLocked }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
verifiedMode,
gradesFeatureIsFullyLocked,
- } = useModel('progress', courseId);
+ } = useProgressData();
return (
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
index 44129521e1..cda32d2b1d 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n';
import { DataTable } from '@openedx/paragon';
import { Lock } from '@openedx/paragon/icons';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import AssignmentTypeCell from './AssignmentTypeCell';
import DroppableAssignmentFootnote from './DroppableAssignmentFootnote';
@@ -14,13 +13,12 @@ import messages from '../messages';
const GradeSummaryTable = ({ setAllOfSomeAssignmentTypeIsLocked }) => {
const intl = useIntl();
- const courseId = useContextId();
const {
assignmentTypeGradeSummary,
gradesFeatureIsFullyLocked,
sectionScores,
- } = useModel('progress', courseId);
+ } = useProgressData();
const footnotes = [];
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
index e8655e6eb7..903c6ebf3d 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
@@ -7,14 +7,12 @@ import {
Tooltip,
} from '@openedx/paragon';
import { InfoOutline } from '@openedx/paragon/icons';
-import { useContextId } from '../../../../data/hooks';
-import { useModel } from '../../../../generic/model-store';
+import { useProgressData } from '../../hooks';
import messages from '../messages';
const GradeSummaryTableFooter = () => {
const intl = useIntl();
- const courseId = useContextId();
const {
courseGrade: {
@@ -22,7 +20,7 @@ const GradeSummaryTableFooter = () => {
percent,
},
finalGrades,
- } = useModel('progress', courseId);
+ } = useProgressData();
const getGradePercent = (grade) => {
const percentage = grade * 100;
diff --git a/src/course-home/progress-tab/hooks.jsx b/src/course-home/progress-tab/hooks.jsx
index d1b707bc80..799d4af4a0 100644
--- a/src/course-home/progress-tab/hooks.jsx
+++ b/src/course-home/progress-tab/hooks.jsx
@@ -1,7 +1,9 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
+import { useParams } from 'react-router-dom';
import { fetchExamAttemptsData } from '../data/thunks';
+import { useProgressTabData } from '../data/apiHooks';
export function useGetExamsData(courseId, sequenceIds) {
const dispatch = useDispatch();
@@ -10,3 +12,8 @@ export function useGetExamsData(courseId, sequenceIds) {
dispatch(fetchExamAttemptsData(courseId, sequenceIds));
}, [dispatch, courseId, sequenceIds]);
}
+
+export function useProgressData() {
+ const { courseId, targetUserId } = useParams();
+ return useProgressTabData(courseId, targetUserId).data;
+}
diff --git a/src/course-home/progress-tab/related-links/RelatedLinks.jsx b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
index cf0c27db4a..f2ff1b34f8 100644
--- a/src/course-home/progress-tab/related-links/RelatedLinks.jsx
+++ b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
@@ -2,14 +2,14 @@ import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@openedx/paragon';
-import { useContextId } from '../../../data/hooks';
+import { useParams } from 'react-router-dom';
import messages from './messages';
import { useModel } from '../../../generic/model-store';
const RelatedLinks = () => {
const intl = useIntl();
- const courseId = useContextId();
+ const { courseId } = useParams();
const {
org,
tabs,
diff --git a/src/index.jsx b/src/index.jsx
index 5b7d6ba358..0f33148bb6 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -26,7 +26,6 @@ import GoalUnsubscribe from './course-home/goal-unsubscribe';
import ProgressTab from './course-home/progress-tab/ProgressTab';
import { TabContainer } from './tab-page';
-import { fetchProgressTab } from './course-home/data';
import { fetchCourse } from './courseware/data';
import { store } from './store';
import { createQueryClient } from './queryClient';
@@ -113,14 +112,7 @@ subscribe(APP_READY, () => {
path={route}
element={(
-
-
-
+
)}
/>
diff --git a/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx b/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx
index 54fccfaffc..7be22fb928 100644
--- a/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx
+++ b/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx
@@ -1,13 +1,11 @@
-import { useModel } from '@src/generic/model-store';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import React from 'react';
import DetailedGrades from '../../course-home/progress-tab/grades/detailed-grades/DetailedGrades';
import GradeSummary from '../../course-home/progress-tab/grades/grade-summary/GradeSummary';
-import { useContextId } from '../../data/hooks';
+import { useProgressData } from '../../course-home/progress-tab/hooks';
const ProgressTabGradeBreakdownSlot = () => {
- const courseId = useContextId();
- const { gradesFeatureIsFullyLocked } = useModel('progress', courseId);
+ const { gradesFeatureIsFullyLocked } = useProgressData();
const applyLockedOverlay = gradesFeatureIsFullyLocked ? 'locked-overlay' : '';
return (
{
fetch,
slice,
tab,
- isProgressTab,
} = props;
- const { courseId: courseIdFromUrl, targetUserId } = useParams();
+ const { courseId: courseIdFromUrl } = useParams();
const dispatch = useDispatch();
useEffect(() => {
// The courseId from the URL is the course we WANT to load.
- if (isProgressTab) {
- dispatch(fetch(courseIdFromUrl, targetUserId));
- } else {
- dispatch(fetch(courseIdFromUrl));
- }
+ dispatch(fetch(courseIdFromUrl));
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [courseIdFromUrl, targetUserId]);
+ }, [courseIdFromUrl]);
// The courseId from the store is the course we HAVE loaded. If the URL changes,
// we don't want the application to adjust to it until it has actually loaded the new data.
@@ -50,11 +45,6 @@ TabContainer.propTypes = {
fetch: PropTypes.func.isRequired,
slice: PropTypes.string.isRequired,
tab: PropTypes.string.isRequired,
- isProgressTab: PropTypes.bool,
-};
-
-TabContainer.defaultProps = {
- isProgressTab: false,
};
export default TabContainer;
diff --git a/src/tab-page/TabContainer.test.jsx b/src/tab-page/TabContainer.test.jsx
index fc0d5f39e4..3eb95f6ad0 100644
--- a/src/tab-page/TabContainer.test.jsx
+++ b/src/tab-page/TabContainer.test.jsx
@@ -51,32 +51,4 @@ describe('Tab Container', () => {
expect(mockDispatch).toHaveBeenCalledWith(courseId);
expect(screen.getByTestId('TabPage')).toBeInTheDocument();
});
-
- it('Should handle passing in a targetUserId', () => {
- const targetUserId = '1';
-
- render(
-
-
-
- children={[]}
-
- )}
- />
-
- ,
- );
-
- expect(mockFetch).toHaveBeenCalledTimes(1);
- expect(mockFetch).toHaveBeenCalledWith(courseId, targetUserId);
- expect(screen.getByTestId('TabPage')).toBeInTheDocument();
- });
});