From d0d63df140868e33d06866d3f03fc471e6728539 Mon Sep 17 00:00:00 2001 From: Troy Sankey Date: Mon, 11 Dec 2023 15:52:08 -0800 Subject: [PATCH] feat: Add redirect to enterprise learner dashboard When a learner tries to load the B2C course page for a course that starts in the future (error_code="course_not_started"), normally the learning MFE automatically redirects to the B2C dashboard. This change supports an alternate error_code "course_not_started_enterprise_learner" to trigger an alternative redirect to the B2B (enterprise) learner dashboard. This does two main things: 1. When the course metadata API response indicates course_access.error_code = "course_not_started_enterprise_learner" then redirect to "/redirect/enterprise-learner-dashboard". 2. When the top-level router matches path "/redirect/enterprise-learner-dashboard" then redirec to to the value of config `ENTERPRISE_LEARNER_PORTAL_URL`. ENT-8078 --- global-setup.js | 4 ++++ jest.config.js | 3 ++- src/constants.js | 2 ++ src/courseware/CoursewareContainer.test.jsx | 7 +++++++ src/courseware/CoursewareRedirectLandingPage.jsx | 4 ++++ .../CoursewareRedirectLandingPage.test.jsx | 14 ++++++++++++++ src/courseware/RedirectPage.jsx | 14 ++++++++++---- src/shared/access.js | 3 +++ 8 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 global-setup.js diff --git a/global-setup.js b/global-setup.js new file mode 100644 index 0000000000..796ea835e9 --- /dev/null +++ b/global-setup.js @@ -0,0 +1,4 @@ +// Force all tests to run in UTC to prevent tests from being sensitive to host timezone. +module.exports = async () => { + process.env.TZ = 'UTC'; +}; diff --git a/jest.config.js b/jest.config.js index c3989ceb8d..8c69451cbf 100644 --- a/jest.config.js +++ b/jest.config.js @@ -16,5 +16,6 @@ module.exports = createConfig('jest', { 'react-markdown': '/node_modules/react-markdown/react-markdown.min.js', }, testTimeout: 30000, - testEnvironment: 'jsdom' + testEnvironment: 'jsdom', + globalSetup: "./global-setup.js" }); diff --git a/src/constants.js b/src/constants.js index ac10aa3044..caac22bced 100644 --- a/src/constants.js +++ b/src/constants.js @@ -22,11 +22,13 @@ export const ROUTES = { UNSUBSCRIBE: '/goal-unsubscribe/:token', REDIRECT: '/redirect/*', DASHBOARD: 'dashboard', + ENTERPRISE_LEARNER_DASHBOARD: 'enterprise-learner-dashboard', CONSENT: 'consent', }; export const REDIRECT_MODES = { DASHBOARD_REDIRECT: 'dashboard-redirect', + ENTERPRISE_LEARNER_DASHBOARD_REDIRECT: 'enterprise-learner-dashboard-redirect', CONSENT_REDIRECT: 'consent-redirect', HOME_REDIRECT: 'home-redirect', SURVEY_REDIRECT: 'survey-redirect', diff --git a/src/courseware/CoursewareContainer.test.jsx b/src/courseware/CoursewareContainer.test.jsx index 66bc28f9e6..4cf883636f 100644 --- a/src/courseware/CoursewareContainer.test.jsx +++ b/src/courseware/CoursewareContainer.test.jsx @@ -515,5 +515,12 @@ describe('CoursewareContainer', () => { const startDate = '2/5/2013'; // This date is based on our courseMetadata factory's sample data. expect(global.location.href).toEqual(`http://localhost/redirect/dashboard?notlive=${startDate}`); }); + + it('should go to the enterprise learner dashboard for a course_not_started_enterprise_learner error code', async () => { + setUpWithDeniedStatus('course_not_started_enterprise_learner'); + await loadContainer(); + + expect(global.location.href).toEqual('http://localhost/redirect/enterprise-learner-dashboard'); + }); }); }); diff --git a/src/courseware/CoursewareRedirectLandingPage.jsx b/src/courseware/CoursewareRedirectLandingPage.jsx index 1d90f50b2e..401a206ba4 100644 --- a/src/courseware/CoursewareRedirectLandingPage.jsx +++ b/src/courseware/CoursewareRedirectLandingPage.jsx @@ -29,6 +29,10 @@ const CoursewareRedirectLandingPage = () => ( path={ROUTES.DASHBOARD} element={} /> + } + /> } diff --git a/src/courseware/CoursewareRedirectLandingPage.test.jsx b/src/courseware/CoursewareRedirectLandingPage.test.jsx index 84e39e5666..fc2c2a0a42 100644 --- a/src/courseware/CoursewareRedirectLandingPage.test.jsx +++ b/src/courseware/CoursewareRedirectLandingPage.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { MemoryRouter as Router } from 'react-router-dom'; +import { mergeConfig } from '@edx/frontend-platform'; import { render, initializeMockApp } from '../setupTest'; import CoursewareRedirectLandingPage from './CoursewareRedirectLandingPage'; @@ -11,6 +12,9 @@ jest.mock('../decode-page-route', () => jest.fn(({ children }) =>
{children describe('CoursewareRedirectLandingPage', () => { beforeEach(async () => { await initializeMockApp(); + mergeConfig({ + ENTERPRISE_LEARNER_PORTAL_URL: 'http://localhost:8734', + }, 'Add configs for URLs'); delete global.location; global.location = { assign: redirectUrl }; }); @@ -34,4 +38,14 @@ describe('CoursewareRedirectLandingPage', () => { expect(redirectUrl).toHaveBeenCalledWith('/course/course-v1:edX+DemoX+Demo_Course/home'); }); + + it('Redirects to correct enterprise dashboard URL', () => { + render( + + + , + ); + + expect(redirectUrl).toHaveBeenCalledWith('http://localhost:8734'); + }); }); diff --git a/src/courseware/RedirectPage.jsx b/src/courseware/RedirectPage.jsx index f1189a47fe..315d918608 100644 --- a/src/courseware/RedirectPage.jsx +++ b/src/courseware/RedirectPage.jsx @@ -14,20 +14,26 @@ const RedirectPage = ({ const location = useLocation(); const { consentPath } = queryString.parse(location?.search); - const BASE_URL = getConfig().LMS_BASE_URL; + const { + LMS_BASE_URL, + ENTERPRISE_LEARNER_PORTAL_URL, + } = getConfig(); switch (mode) { case REDIRECT_MODES.DASHBOARD_REDIRECT: - global.location.assign(`${BASE_URL}${pattern}${location?.search}`); + global.location.assign(`${LMS_BASE_URL}${pattern}${location?.search}`); + break; + case REDIRECT_MODES.ENTERPRISE_LEARNER_DASHBOARD_REDIRECT: + global.location.assign(ENTERPRISE_LEARNER_PORTAL_URL); break; case REDIRECT_MODES.CONSENT_REDIRECT: - global.location.assign(`${BASE_URL}${consentPath}`); + global.location.assign(`${LMS_BASE_URL}${consentPath}`); break; case REDIRECT_MODES.HOME_REDIRECT: global.location.assign(generatePath(pattern, { courseId })); break; default: - global.location.assign(`${BASE_URL}${generatePath(pattern, { courseId })}`); + global.location.assign(`${LMS_BASE_URL}${generatePath(pattern, { courseId })}`); } return null; diff --git a/src/shared/access.js b/src/shared/access.js index 4937fe7bd5..49cd30e4b4 100644 --- a/src/shared/access.js +++ b/src/shared/access.js @@ -15,6 +15,9 @@ export function getAccessDeniedRedirectUrl(courseId, activeTabSlug, courseAccess const startDate = (new Intl.DateTimeFormat(getLocale())).format(new Date(start)); url = `/redirect/dashboard?notlive=${startDate}`; break; + case 'course_not_started_enterprise_learner': + url = '/redirect/enterprise-learner-dashboard'; + break; case 'survey_required': url = `/redirect/survey/${courseId}`; break;