diff --git a/src/components/dashboard/main-content/course-enrollments/course-cards/InProgressCourseCard.jsx b/src/components/dashboard/main-content/course-enrollments/course-cards/InProgressCourseCard.jsx
index d4f6f249dc..253f957963 100644
--- a/src/components/dashboard/main-content/course-enrollments/course-cards/InProgressCourseCard.jsx
+++ b/src/components/dashboard/main-content/course-enrollments/course-cards/InProgressCourseCard.jsx
@@ -1,14 +1,22 @@
-import { useContext, useState } from 'react';
+/* eslint-disable no-unsafe-optional-chaining */
+
+import {
+ useCallback, useContext, useEffect, useState,
+} from 'react';
import PropTypes from 'prop-types';
import { useNavigate } from 'react-router-dom';
import { AppContext } from '@edx/frontend-platform/react';
+import { logError } from '@edx/frontend-platform/logging';
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import { defineMessages, FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
-import { Stack } from '@openedx/paragon';
+import { ProgressBar, Stack } from '@openedx/paragon';
+import { getConfig } from '@edx/frontend-platform/config';
import dayjs from '../../../../../utils/dayjs';
import BaseCourseCard, { getScreenReaderText } from './BaseCourseCard';
import { MarkCompleteModal } from './mark-complete-modal';
import ContinueLearningButton from './ContinueLearningButton';
+import { isExperimentVariant } from '../../../../../utils/optimizely';
+import { getProgressTabData } from './mark-complete-modal/data/service';
import Notification from './Notification';
@@ -43,6 +51,11 @@ const messages = defineMessages({
defaultMessage: 'Covered by your organization',
description: 'Text for the course info outline upgrade covered by organization in the course card dropdown menu',
},
+ completion: {
+ id: 'enterprise.learner_portal.dashboard.enrollments.course.completion',
+ defaultMessage: '{courseProgress}% completed',
+ description: 'Course progress percentage completed',
+ },
});
function useLinkToCourse({
@@ -87,6 +100,32 @@ export const InProgressCourseCard = ({
const { data: enterpriseCustomer } = useEnterpriseCustomer();
const updateCourseEnrollmentStatus = useUpdateCourseEnrollmentStatus({ enterpriseCustomer });
const isExecutiveEducation = EXECUTIVE_EDUCATION_COURSE_MODES.includes(mode);
+ const config = getConfig();
+
+ const [completionSummary, setCompletionSummary] = useState({});
+ const fetchProgressData = useCallback(
+ async (courseRun) => {
+ try {
+ const result = await getProgressTabData(courseRun);
+ setCompletionSummary(result.completionSummary);
+ } catch (error) {
+ logError(error);
+ }
+ },
+ [],
+ );
+
+ useEffect(() => {
+ fetchProgressData(courseRunId);
+ }, [fetchProgressData, courseRunId]);
+
+ const completeCount = completionSummary?.completeCount;
+ const numTotalUnits = completeCount + completionSummary?.incompleteCount + completionSummary?.lockedCount;
+ const completePercentage = completeCount ? Number(((completeCount / numTotalUnits) * 100).toFixed(0)) : 0;
+ const isExperimentVariation = isExperimentVariant(
+ config.PROGRESS_BAR_EXPERIMENT_ID,
+ config.PROGRESS_BAR_EXPERIMENT_VARIANT_ID,
+ );
const coursewareOrUpgradeLink = useLinkToCourse({
linkToCourse,
@@ -245,6 +284,13 @@ export const InProgressCourseCard = ({
{...rest}
>
{renderNotifications()}
+ {isExperimentVariation && (
+
+ )}
{
}
return getAuthenticatedHttpClient().patch(url);
};
+
+export async function getProgressTabData(courseId, targetUserId) {
+ let url = `${getConfig().LMS_BASE_URL}/api/course_home/progress/${courseId}`;
+
+ if (targetUserId) {
+ url += `/${targetUserId}/`;
+ }
+
+ try {
+ const { data } = await getAuthenticatedHttpClient().get(url);
+ const camelCasedData = camelCaseObject(data);
+ return camelCasedData;
+ } catch (error) {
+ logError(error);
+ return null;
+ }
+}
diff --git a/src/components/dashboard/main-content/course-enrollments/course-cards/styles/_CourseCard.scss b/src/components/dashboard/main-content/course-enrollments/course-cards/styles/_CourseCard.scss
index ec68b1e509..2ed9f1717b 100644
--- a/src/components/dashboard/main-content/course-enrollments/course-cards/styles/_CourseCard.scss
+++ b/src/components/dashboard/main-content/course-enrollments/course-cards/styles/_CourseCard.scss
@@ -37,3 +37,17 @@
}
}
}
+
+.pgn__progress-annotated {
+ padding-bottom: 0 !important;
+ .pgn__progress-bar--success {
+ height: 15px;
+ }
+}
+
+.pgn__progress-annotated .progress .pgn__progress-bar--success::after {
+ width: 22px;
+ height: 22px;
+ top: -0.25rem;
+ border-radius: 1rem;
+}
\ No newline at end of file
diff --git a/src/index.jsx b/src/index.jsx
index 548abe2365..0a7f59c432 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -59,6 +59,8 @@ initialize({
EXPERIMENT_2_VARIANT_2_ID: process.env.EXPERIMENT_2_VARIANT_2_ID || null,
PREQUERY_SEARCH_EXPERIMENT_ID: process.env.PREQUERY_SEARCH_EXPERIMENT_ID || null,
PREQUERY_SEARCH_EXPERIMENT_VARIANT_ID: process.env.PREQUERY_SEARCH_EXPERIMENT_VARIANT_ID || null,
+ PROGRESS_BAR_EXPERIMENT_ID: process.env.PROGRESS_BAR_EXPERIMENT_ID || null,
+ PROGRESS_BAR_EXPERIMENT_VARIANT_ID: process.env.PROGRESS_BAR_EXPERIMENT_VARIANT_ID || null,
});
},
},