From 26de2cebeb2f1525f4962a621a9b40c292e27c1a Mon Sep 17 00:00:00 2001 From: Carla Duarte Date: Wed, 6 Jan 2021 15:10:29 -0500 Subject: [PATCH] AA-545: Add course in progress CourseExit variant (#334) --- .../course/course-exit/CourseExit.jsx | 3 + .../course/course-exit/CourseExit.test.jsx | 14 +++++ .../course/course-exit/CourseInProgress.jsx | 63 +++++++++++++++++++ .../course/course-exit/CourseNonPassing.jsx | 2 +- src/courseware/course/course-exit/index.js | 4 +- src/courseware/course/course-exit/messages.js | 13 ++++ src/courseware/course/course-exit/utils.js | 26 +++++--- .../SequenceNavigation.jsx | 6 +- .../sequence-navigation/UnitNavigation.jsx | 6 +- .../__factories__/courseBlocks.factory.js | 5 +- .../__factories__/courseMetadata.factory.js | 10 +++ src/courseware/data/api.js | 3 +- 12 files changed, 137 insertions(+), 18 deletions(-) create mode 100644 src/courseware/course/course-exit/CourseInProgress.jsx diff --git a/src/courseware/course/course-exit/CourseExit.jsx b/src/courseware/course/course-exit/CourseExit.jsx index c008590f..a45d4261 100644 --- a/src/courseware/course/course-exit/CourseExit.jsx +++ b/src/courseware/course/course-exit/CourseExit.jsx @@ -7,6 +7,7 @@ import { useSelector } from 'react-redux'; import { Redirect } from 'react-router-dom'; import CourseCelebration from './CourseCelebration'; +import CourseInProgress from './CourseInProgress'; import CourseNonPassing from './CourseNonPassing'; import { COURSE_EXIT_MODES, getCourseExitMode } from './utils'; import messages from './messages'; @@ -18,6 +19,8 @@ function CourseExit({ intl }) { let body = null; if (mode === COURSE_EXIT_MODES.nonPassing) { body = (); + } else if (mode === COURSE_EXIT_MODES.inProgress) { + body = (); } else if (mode === COURSE_EXIT_MODES.celebration) { body = (); } else { diff --git a/src/courseware/course/course-exit/CourseExit.test.jsx b/src/courseware/course/course-exit/CourseExit.test.jsx index 105962aa..817c7f7d 100644 --- a/src/courseware/course/course-exit/CourseExit.test.jsx +++ b/src/courseware/course/course-exit/CourseExit.test.jsx @@ -13,6 +13,7 @@ import initializeStore from '../../../store'; import executeThunk from '../../../utils'; import CourseCelebration from './CourseCelebration'; import CourseExit from './CourseExit'; +import CourseInProgress from './CourseInProgress'; import CourseNonPassing from './CourseNonPassing'; initializeMockApp(); @@ -293,4 +294,17 @@ describe('Course Exit Pages', () => { expect(screen.getByRole('link', { name: 'View grades' })).toBeInTheDocument(); }); }); + + describe('Course in progress experience', () => { + it('Displays link to dates tab', async () => { + setMetadata({ user_has_passing_grade: false }); + const courseBlocks = buildSimpleCourseBlocks(defaultMetadata.id, defaultMetadata.name, + { hasScheduledContent: true }); + axiosMock.onGet(courseBlocksUrlRegExp).reply(200, courseBlocks); + + await fetchAndRender(); + expect(screen.getByText('More content is coming soon!')).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'View course schedule' })).toBeInTheDocument(); + }); + }); }); diff --git a/src/courseware/course/course-exit/CourseInProgress.jsx b/src/courseware/course/course-exit/CourseInProgress.jsx new file mode 100644 index 00000000..4106bc15 --- /dev/null +++ b/src/courseware/course/course-exit/CourseInProgress.jsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react'; + +import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { Helmet } from 'react-helmet'; +import { useSelector } from 'react-redux'; +import { Alert, Button } from '@edx/paragon'; +import { getConfig } from '@edx/frontend-platform'; + +import { useModel } from '../../../generic/model-store'; + +import CatalogSuggestion from './CatalogSuggestion'; +import DashboardFootnote from './DashboardFootnote'; +import messages from './messages'; +import { logClick, logVisit } from './utils'; + +function CourseInProgress({ intl }) { + const { courseId } = useSelector(state => state.courseware); + const { org, tabs } = useModel('courses', courseId); + const { administrator } = getAuthenticatedUser(); + + // Get dates tab link for 'view course schedule' button + const datesTab = tabs.find(tab => tab.slug === 'dates'); + const datesTabLink = datesTab && datesTab.url; + + useEffect(() => logVisit(org, courseId, administrator, 'in_progress'), [org, courseId, administrator]); + + return ( + <> + + {`${intl.formatMessage(messages.endOfCourseTitle)} | ${getConfig().SITE_NAME}`} + +
+
+ { intl.formatMessage(messages.courseInProgressHeader) } +
+ +
+
{ intl.formatMessage(messages.courseInProgressDescription) }
+ {datesTabLink && ( + + )} +
+
+ + +
+ + ); +} + +CourseInProgress.propTypes = { + intl: intlShape.isRequired, +}; + +export default injectIntl(CourseInProgress); diff --git a/src/courseware/course/course-exit/CourseNonPassing.jsx b/src/courseware/course/course-exit/CourseNonPassing.jsx index bb15a4b8..63b23328 100644 --- a/src/courseware/course/course-exit/CourseNonPassing.jsx +++ b/src/courseware/course/course-exit/CourseNonPassing.jsx @@ -40,7 +40,7 @@ function CourseNonPassing({ intl }) { {progressLink && (