From d507d68d634d15c241b6063d5d41625ab598cf67 Mon Sep 17 00:00:00 2001 From: Peter Kulko Date: Mon, 7 Oct 2024 16:58:42 +0300 Subject: [PATCH] chore: improved SPA routes --- package.json | 2 +- run-build-for-gh-deps.sh | 39 +++++ src/CourseAuthoringPage.jsx | 3 +- .../ChecklistSection/ChecklistItemBody.jsx | 125 ++++++++------ .../ChecklistSection/ChecklistItemComment.jsx | 19 ++- .../ChecklistSection/ChecklistSection.jsx | 18 +-- .../ChecklistSection.test.jsx | 152 +++++++----------- src/course-checklist/CourseChecklist.jsx | 6 +- src/course-checklist/utils.js | 12 -- src/course-outline/hooks.jsx | 6 +- src/course-outline/status-bar/StatusBar.jsx | 21 +-- src/course-unit/breadcrumbs/Breadcrumbs.jsx | 14 +- .../breadcrumbs/Breadcrumbs.test.jsx | 87 +++++++--- src/custom-pages/CustomPages.jsx | 16 +- src/custom-pages/CustomPages.test.jsx | 11 ++ src/data/api.js | 16 ++ src/data/selectors.js | 2 + src/data/slice.js | 22 +++ src/data/thunks.js | 21 ++- src/generic/help-sidebar/HelpSidebar.jsx | 24 ++- src/generic/help-sidebar/HelpSidebarLink.jsx | 18 ++- .../help-sidebar/HelpSidebarLink.test.jsx | 46 ++++++ .../grading-sidebar/GradingSidebar.test.jsx | 39 ++--- .../ExperimentConfigurationsSection.test.jsx | 8 + .../index.jsx | 4 +- src/group-configurations/index.jsx | 1 + src/header/Header.tsx | 20 ++- src/header/hooks.js | 35 ++-- src/hooks.test.ts | 119 ++++++++++++++ src/hooks.ts | 6 +- src/pages-and-resources/PagesAndResources.jsx | 2 +- src/pages-and-resources/pages/PageCard.jsx | 5 +- .../pages/PageCard.test.jsx | 60 +++++-- src/pages-and-resources/pages/PageGrid.jsx | 6 +- .../pages/PageSettingButton.jsx | 44 ++++- .../pages/PageSettingButton.test.jsx | 85 ++++++++++ src/studio-home/card-item/CardItem.test.tsx | 2 +- src/studio-home/card-item/index.tsx | 12 +- src/studio-home/hooks.jsx | 2 + .../VerifyEmailLayout.test.jsx | 34 +++- src/textbooks/Textbooks.jsx | 11 +- src/textbooks/hooks.jsx | 8 +- src/utils.js | 4 - src/utils.test.js | 131 ++++++++++++++- 44 files changed, 991 insertions(+), 327 deletions(-) create mode 100644 run-build-for-gh-deps.sh delete mode 100644 src/course-checklist/utils.js create mode 100644 src/data/selectors.js create mode 100644 src/generic/help-sidebar/HelpSidebarLink.test.jsx create mode 100644 src/hooks.test.ts create mode 100644 src/pages-and-resources/pages/PageSettingButton.test.jsx diff --git a/package.json b/package.json index b59524e96b..48270ed454 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "extends @edx/browserslist-config" ], "scripts": { - "build": "fedx-scripts webpack", + "build": "sh run-build-for-gh-deps.sh", "i18n_extract": "fedx-scripts formatjs extract", "stylelint": "stylelint \"plugins/**/*.scss\" \"src/**/*.scss\" \"scss/**/*.scss\" --config .stylelintrc.json", "lint": "npm run stylelint && fedx-scripts eslint --ext .js --ext .jsx --ext .ts --ext .tsx .", diff --git a/run-build-for-gh-deps.sh b/run-build-for-gh-deps.sh new file mode 100644 index 0000000000..996601553f --- /dev/null +++ b/run-build-for-gh-deps.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# TODO: This file is temporary and will be removed after testing + +log() { + echo "=============================== $1 ===============================" +} + +run_command() { + echo "\$ $1" + eval $1 +} + +log "Starting deployment script" +run_command "pwd" + +# frontend-component-header +log "Processing frontend-component-header" +run_command "cd node_modules/@edx/" || exit +log "Current directory: $(pwd)" +run_command "rm -rf frontend-component-header" +run_command "mkdir frontend-component-header" || exit +run_command "git clone -b Peter_Kulko/use-SPA-functionality --single-branch https://github.com/raccoongang/frontend-component-header.git frontend-component-header-temp" +run_command "cd frontend-component-header-temp" || exit +log "Current directory: $(pwd)" +run_command "npm ci" || exit +run_command "npm run build" || exit +run_command "cp -r dist ../frontend-component-header/" || exit +run_command "cp -r package.json ../frontend-component-header/" || exit +run_command "cd .." +run_command "rm -rf frontend-component-header-temp" +run_command "cd ../.." || exit +log "Current directory: $(pwd)" + +# webpack +log "Running webpack" +run_command "fedx-scripts webpack" + +log "Deployment script finished." \ No newline at end of file diff --git a/src/CourseAuthoringPage.jsx b/src/CourseAuthoringPage.jsx index 41da0bc232..6b8e968277 100644 --- a/src/CourseAuthoringPage.jsx +++ b/src/CourseAuthoringPage.jsx @@ -7,7 +7,7 @@ import { } from 'react-router-dom'; import { StudioFooter } from '@edx/frontend-component-footer'; import Header from './header'; -import { fetchCourseDetail } from './data/thunks'; +import { fetchCourseDetail, fetchWaffleFlags } from './data/thunks'; import { useModel } from './generic/model-store'; import NotFoundAlert from './generic/NotFoundAlert'; import PermissionDeniedAlert from './generic/PermissionDeniedAlert'; @@ -21,6 +21,7 @@ const CourseAuthoringPage = ({ courseId, children }) => { useEffect(() => { dispatch(fetchCourseDetail(courseId)); + dispatch(fetchWaffleFlags(courseId)); }, [courseId]); useEffect(() => { diff --git a/src/course-checklist/ChecklistSection/ChecklistItemBody.jsx b/src/course-checklist/ChecklistSection/ChecklistItemBody.jsx index f48bdc69b3..703dd8c414 100644 --- a/src/course-checklist/ChecklistSection/ChecklistItemBody.jsx +++ b/src/course-checklist/ChecklistSection/ChecklistItemBody.jsx @@ -1,70 +1,95 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n'; -import { - ActionRow, - Button, - Hyperlink, - Icon, -} from '@openedx/paragon'; +import { Link } from 'react-router-dom'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { ActionRow, Button, Icon } from '@openedx/paragon'; +import { useSelector } from 'react-redux'; import { CheckCircle, RadioButtonUnchecked } from '@openedx/paragon/icons'; +import { getConfig } from '@edx/frontend-platform'; + +import { getWaffleFlags } from '../../data/selectors'; import messages from './messages'; +const getUpdateLinks = (courseId, waffleFlags) => { + const baseUrl = getConfig().STUDIO_BASE_URL; + const isLegacyGradingUrl = !waffleFlags.useNewGradingPage; + const isLegacyCertificateUrl = !waffleFlags.useNewCertificatesPage; + const isLegacyCourseDatesUrl = !waffleFlags.useNewScheduleDetailsPage; + const isLegacyOutlineUrl = !waffleFlags.useNewCourseOutlinePage; + + return { + welcomeMessage: `/course/${courseId}/course_info`, + gradingPolicy: isLegacyGradingUrl + ? `${baseUrl}/settings/grading/${courseId}` : `/course/${courseId}/settings/grading`, + certificate: isLegacyCertificateUrl + ? `${baseUrl}/certificates/${courseId}` : `/course/${courseId}/certificates`, + courseDates: isLegacyCourseDatesUrl + ? `${baseUrl}/settings/details/${courseId}#schedule` : `/course/${courseId}/settings/details/#schedule`, + proctoringEmail: `${baseUrl}/pages-and-resources/proctoring/settings`, + outline: isLegacyOutlineUrl ? `${baseUrl}/course/${courseId}` : `/course/${courseId}`, + }; +}; + const ChecklistItemBody = ({ + courseId, checkId, isCompleted, - updateLink, - // injected - intl, -}) => ( - -
- {isCompleted ? ( - - ) : ( - - )} -
-
-
- +}) => { + const intl = useIntl(); + const waffleFlags = useSelector(getWaffleFlags); + const updateLinks = getUpdateLinks(courseId, waffleFlags); + + return ( + +
+ {isCompleted ? ( + + ) : ( + + )}
-
- +
+
+ +
+
+ +
-
- - {updateLink && ( - - - - )} -
-); + + {updateLinks?.[checkId] && ( + + + + )} + + ); +}; ChecklistItemBody.defaultProps = { updateLink: null, }; ChecklistItemBody.propTypes = { + courseId: PropTypes.string.isRequired, checkId: PropTypes.string.isRequired, isCompleted: PropTypes.bool.isRequired, updateLink: PropTypes.string, - // injected - intl: intlShape.isRequired, }; -export default injectIntl(ChecklistItemBody); +export default ChecklistItemBody; diff --git a/src/course-checklist/ChecklistSection/ChecklistItemComment.jsx b/src/course-checklist/ChecklistSection/ChecklistItemComment.jsx index 92fb83ea32..deec84f2c3 100644 --- a/src/course-checklist/ChecklistSection/ChecklistItemComment.jsx +++ b/src/course-checklist/ChecklistSection/ChecklistItemComment.jsx @@ -1,15 +1,23 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; import { injectIntl, FormattedMessage, FormattedNumber } from '@edx/frontend-platform/i18n'; -import { Hyperlink, Icon } from '@openedx/paragon'; +import { Icon } from '@openedx/paragon'; +import { Link } from 'react-router-dom'; import { ModeComment } from '@openedx/paragon/icons'; +import { getConfig } from '@edx/frontend-platform'; +import { getWaffleFlags } from '../../data/selectors'; import messages from './messages'; const ChecklistItemComment = ({ + courseId, checkId, - outlineUrl, data, }) => { + const waffleFlags = useSelector(getWaffleFlags); + + const getPathToCourseOutlinePage = (assignmentId) => (waffleFlags.useNewCourseOutlinePage + ? `/course/${courseId}#${assignmentId}` : `${getConfig().STUDIO_BASE_URL}/course/${courseId}#${assignmentId}`); + const commentWrapper = (comment) => (
@@ -79,9 +87,9 @@ const ChecklistItemComment = ({
    {gradedAssignmentsOutsideDateRange.map(assignment => (
  • - + {assignment.displayName} - +
  • ))}
@@ -96,6 +104,7 @@ const ChecklistItemComment = ({ }; ChecklistItemComment.propTypes = { + courseId: PropTypes.string.isRequired, checkId: PropTypes.string.isRequired, outlineUrl: PropTypes.string.isRequired, data: PropTypes.oneOfType([ diff --git a/src/course-checklist/ChecklistSection/ChecklistSection.jsx b/src/course-checklist/ChecklistSection/ChecklistSection.jsx index 46fe71889c..3b11b6e05b 100644 --- a/src/course-checklist/ChecklistSection/ChecklistSection.jsx +++ b/src/course-checklist/ChecklistSection/ChecklistSection.jsx @@ -10,11 +10,11 @@ import ChecklistItemComment from './ChecklistItemComment'; import { checklistItems } from './utils/courseChecklistData'; const ChecklistSection = ({ + courseId, dataHeading, data, idPrefix, isLoading, - updateLinks, }) => { const dataList = checklistItems[idPrefix]; const getCompletionCountID = () => (`${idPrefix}-completion-count`); @@ -37,8 +37,6 @@ const ChecklistSection = ({ {checks.map(check => { const checkId = check.id; const isCompleted = values[checkId]; - const updateLink = updateLinks?.[checkId]; - const outlineUrl = updateLinks.outline; return (
- +
- +
); @@ -61,11 +59,11 @@ const ChecklistSection = ({ }; ChecklistSection.defaultProps = { - updateLinks: {}, data: {}, }; ChecklistSection.propTypes = { + courseId: PropTypes.string.isRequired, dataHeading: PropTypes.string.isRequired, data: PropTypes.oneOfType([ PropTypes.shape({ @@ -129,14 +127,6 @@ ChecklistSection.propTypes = { ]), idPrefix: PropTypes.string.isRequired, isLoading: PropTypes.bool.isRequired, - updateLinks: PropTypes.shape({ - welcomeMessage: PropTypes.string, - gradingPolicy: PropTypes.string, - certificate: PropTypes.string, - courseDates: PropTypes.string, - proctoringEmail: PropTypes.string, - outline: PropTypes.string, - }), }; export default injectIntl(ChecklistSection); diff --git a/src/course-checklist/ChecklistSection/ChecklistSection.test.jsx b/src/course-checklist/ChecklistSection/ChecklistSection.test.jsx index 1c8317c903..c4ad7f3262 100644 --- a/src/course-checklist/ChecklistSection/ChecklistSection.test.jsx +++ b/src/course-checklist/ChecklistSection/ChecklistSection.test.jsx @@ -1,59 +1,49 @@ -/* eslint-disable */ -import { - render, - within, - screen, -} from '@testing-library/react'; +import { within, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform'; -import { AppProvider } from '@edx/frontend-platform/react'; -import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { camelCaseObject } from '@edx/frontend-platform'; -import initializeStore from '../../store'; -import { initialState,generateCourseLaunchData } from '../factories/mockApiResponses'; -import messages from './messages'; -import ChecklistSection from './index'; +import { initializeMocks, render } from '../../testUtils'; +import { getApiWaffleFlagsUrl } from '../../data/api'; +import { fetchWaffleFlags } from '../../data/thunks'; +import { generateCourseLaunchData } from '../factories/mockApiResponses'; +import { executeThunk } from '../../utils'; import { checklistItems } from './utils/courseChecklistData'; -import getUpdateLinks from '../utils'; +import messages from './messages'; + +import ChecklistSection from '.'; const testData = camelCaseObject(generateCourseLaunchData()); +const courseId = '123'; const defaultProps = { + courseId, data: testData, dataHeading: 'Test checklist', idPrefix: 'launchChecklist', - updateLinks: getUpdateLinks('courseId'), isLoading: false, }; const testChecklistData = checklistItems[defaultProps.idPrefix]; -const completedItemIds = ['welcomeMessage', 'courseDates'] +const completedItemIds = ['welcomeMessage', 'courseDates']; const renderComponent = (props) => { - render( - - - - - , - ); + render(); }; -let store; - describe('ChecklistSection', () => { - beforeEach(() => { - initializeMockApp({ - authenticatedUser: { - userId: 3, - username: 'abc123', - administrator: false, - roles: [], - }, - }); - store = initializeStore(initialState); + beforeEach(async () => { + const { axiosMock, reduxStore } = initializeMocks(); + axiosMock + .onGet(getApiWaffleFlagsUrl(courseId)) + .reply(200, { + useNewGradingPage: true, + useNewCertificatesPage: true, + useNewScheduleDetailsPage: true, + useNewCourseOutlinePage: true, + }); + await executeThunk(fetchWaffleFlags(courseId), reduxStore.dispatch); }); it('a heading using the dataHeading prop', () => { @@ -64,6 +54,7 @@ describe('ChecklistSection', () => { it('completion count text', () => { renderComponent(defaultProps); + const completionText = `${completedItemIds.length}/6 completed`; expect(screen.getByTestId('completion-subheader').textContent).toEqual(completionText); }); @@ -122,7 +113,7 @@ describe('ChecklistSection', () => { grades: { ...defaultProps.data.grades, sumOfWeights: 1, - } + }, }, }; renderComponent(props); @@ -154,7 +145,7 @@ describe('ChecklistSection', () => { ...defaultProps.data.assignments, assignmentsWithDatesAfterEnd: [], assignmentsWithOraDatesBeforeStart: [], - } + }, }, }; renderComponent(props); @@ -183,73 +174,52 @@ describe('ChecklistSection', () => { expect(assigmentLinks[1].textContent).toEqual('ORA subsection'); }); }); -}); -testChecklistData.forEach((check) => { - describe(`check with id '${check.id}'`, () => { - let checkItem; + describe('Checklist Component', () => { + let checklistData; + let updateLinks; + beforeEach(() => { - initializeMockApp({ - authenticatedUser: { - userId: 3, - username: 'abc123', - administrator: false, - roles: [], - }, - }); - store = initializeStore(initialState); renderComponent(defaultProps); - checkItem = screen.getAllByTestId(`checklist-item-${check.id}`); - }); - it('renders', () => { - expect(checkItem).toHaveLength(1); - }); - - it('has correct icon', () => { - const icon = screen.getAllByTestId(`icon-${check.id}`) - - expect(icon).toHaveLength(1); + checklistData = testChecklistData.map((item) => ({ + itemId: item.id, + checklistItem: screen.getAllByTestId(`checklist-item-${item.id}`), + icon: screen.getAllByTestId(`icon-${item.id}`), + shortDescription: messages[`${item.id}ShortDescription`].defaultMessage, + longDescription: messages[`${item.id}LongDescription`].defaultMessage, + })); - const { queryByTestId } = within(icon[0]); - if (completedItemIds.includes(check.id)) { - expect(queryByTestId('completed-icon')).not.toBeNull(); - } else { - expect(queryByTestId('uncompleted-icon')).not.toBeNull(); - } + updateLinks = screen.getAllByTestId('update-link'); }); - it('has correct short description', () => { - const { getByText } = within(checkItem[0]); - const shortDescription = messages[`${check.id}ShortDescription`].defaultMessage; - expect(getByText(shortDescription)).toBeVisible(); - }); + it('should display the correct icons based on completion status', () => { + checklistData.forEach(({ itemId, icon }) => { + const { queryByTestId } = within(icon[0]); - it('has correct long description', () => { - const { getByText } = within(checkItem[0]); - const longDescription = messages[`${check.id}LongDescription`].defaultMessage; - expect(getByText(longDescription)).toBeVisible(); + if (completedItemIds.includes(itemId)) { + expect(queryByTestId('completed-icon')).not.toBeNull(); + } else { + expect(queryByTestId('uncompleted-icon')).not.toBeNull(); + } + }); }); - describe('has correct link', () => { - const links = getUpdateLinks('courseId') - const shouldShowLink = Object.keys(links).includes(check.id); - - if (shouldShowLink) { - it('with a Hyperlink', () => { - const { getByRole, getByText } = within(checkItem[0]); + it('should display short and long descriptions for each checklist item', () => { + checklistData.forEach(({ checklistItem, shortDescription, longDescription }) => { + const { getByText } = within(checklistItem[0]); - expect(getByText('Update')).toBeVisible(); - - expect(getByRole('link').href).toMatch(links[check.id]); - }); - } else { - it('without a Hyperlink', () => { - const { queryByText } = within(checkItem[0]); + expect(getByText(shortDescription)).toBeVisible(); + expect(getByText(longDescription)).toBeVisible(); + }); + }); - expect(queryByText('Update')).toBeNull(); + it('should have valid update links for each checklist item', () => { + checklistData.forEach(({ itemId }) => { + updateLinks.forEach((link) => { + expect(link).toHaveAttribute('href', updateLinks[itemId]); }); - } + }); }); }); }); diff --git a/src/course-checklist/CourseChecklist.jsx b/src/course-checklist/CourseChecklist.jsx index 5766bfe45e..8c15a11dc0 100644 --- a/src/course-checklist/CourseChecklist.jsx +++ b/src/course-checklist/CourseChecklist.jsx @@ -13,7 +13,6 @@ import AriaLiveRegion from './AriaLiveRegion'; import { RequestStatus } from '../data/constants'; import ChecklistSection from './ChecklistSection'; import { fetchCourseLaunchQuery, fetchCourseBestPracticesQuery } from './data/thunks'; -import getUpdateLinks from './utils'; const CourseChecklist = ({ courseId, @@ -23,7 +22,6 @@ const CourseChecklist = ({ const dispatch = useDispatch(); const courseDetails = useModel('courseDetails', courseId); const enableQuality = getConfig().ENABLE_CHECKLIST_QUALITY === 'true'; - const updateLinks = getUpdateLinks(courseId); useEffect(() => { dispatch(fetchCourseLaunchQuery({ courseId })); @@ -66,19 +64,19 @@ const CourseChecklist = ({ /> {enableQuality && ( )} diff --git a/src/course-checklist/utils.js b/src/course-checklist/utils.js deleted file mode 100644 index 3e6b549ff0..0000000000 --- a/src/course-checklist/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -import { getConfig } from '@edx/frontend-platform'; - -const getUpdateLinks = (courseId) => ({ - welcomeMessage: `${getConfig().STUDIO_BASE_URL}/course_info/${courseId}`, - gradingPolicy: `${getConfig().STUDIO_BASE_URL}/settings/grading/${courseId}`, - certificate: `${getConfig().STUDIO_BASE_URL}/certificates/${courseId}`, - courseDates: `${getConfig().STUDIO_BASE_URL}/settings/details/${courseId}#schedule`, - proctoringEmail: 'pages-and-resources/proctoring/settings', - outline: `${getConfig().STUDIO_BASE_URL}/course/${courseId}`, -}); - -export default getUpdateLinks; diff --git a/src/course-outline/hooks.jsx b/src/course-outline/hooks.jsx index 25b9d8bedd..9038a222be 100644 --- a/src/course-outline/hooks.jsx +++ b/src/course-outline/hooks.jsx @@ -6,6 +6,7 @@ import { getConfig } from '@edx/frontend-platform'; import { copyToClipboard } from '../generic/data/thunks'; import { getSavingStatus as getGenericSavingStatus } from '../generic/data/selectors'; +import { getWaffleFlags } from '../data/selectors'; import { RequestStatus } from '../data/constants'; import { COURSE_BLOCK_NAMES } from './constants'; import { @@ -58,6 +59,7 @@ import { const useCourseOutline = ({ courseId }) => { const dispatch = useDispatch(); const navigate = useNavigate(); + const waffleFlags = useSelector(getWaffleFlags); const { reindexLink, @@ -112,7 +114,7 @@ const useCourseOutline = ({ courseId }) => { }; const getUnitUrl = (locator) => { - if (getConfig().ENABLE_UNIT_PAGE === 'true') { + if (getConfig().ENABLE_UNIT_PAGE === 'true' || waffleFlags.useNewUnitPage) { return `/course/${courseId}/container/${locator}`; } return `${getConfig().STUDIO_BASE_URL}/container/${locator}`; @@ -120,7 +122,7 @@ const useCourseOutline = ({ courseId }) => { const openUnitPage = (locator) => { const url = getUnitUrl(locator); - if (getConfig().ENABLE_UNIT_PAGE === 'true') { + if (getConfig().ENABLE_UNIT_PAGE === 'true' || waffleFlags.useNewUnitPage) { navigate(url); } else { window.location.assign(url); diff --git a/src/course-outline/status-bar/StatusBar.jsx b/src/course-outline/status-bar/StatusBar.jsx index ed8fa28309..b4e25fd357 100644 --- a/src/course-outline/status-bar/StatusBar.jsx +++ b/src/course-outline/status-bar/StatusBar.jsx @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import moment from 'moment/moment'; import PropTypes from 'prop-types'; import { FormattedDate, useIntl } from '@edx/frontend-platform/i18n'; @@ -6,11 +6,14 @@ import { getConfig } from '@edx/frontend-platform/config'; import { Button, Hyperlink, Form, Stack, useToggle, } from '@openedx/paragon'; +import { Link } from 'react-router-dom'; import { AppContext } from '@edx/frontend-platform/react'; +import { useSelector } from 'react-redux'; import { ContentTagsDrawerSheet } from '../../content-tags-drawer'; import TagCount from '../../generic/tag-count'; import { useHelpUrls } from '../../help-urls/hooks'; +import { getWaffleFlags } from '../../data/selectors'; import { VIDEO_SHARING_OPTIONS } from '../constants'; import { useContentTagsCount } from '../../generic/data/apiHooks'; import messages from './messages'; @@ -43,6 +46,7 @@ const StatusBar = ({ }) => { const intl = useIntl(); const { config } = useContext(AppContext); + const waffleFlags = useSelector(getWaffleFlags); const { courseReleaseDate, @@ -62,7 +66,6 @@ const StatusBar = ({ const courseReleaseDateObj = moment.utc(courseReleaseDate, 'MMM DD, YYYY at HH:mm UTC', true); const checkListTitle = `${completedCourseLaunchChecks + completedCourseBestPracticesChecks}/${totalCourseLaunchChecks + totalCourseBestPracticesChecks}`; - const checklistDestination = () => new URL(`checklists/${courseId}`, config.STUDIO_BASE_URL).href; const scheduleDestination = () => new URL(`settings/details/${courseId}#schedule`, config.STUDIO_BASE_URL).href; const { @@ -82,10 +85,9 @@ const StatusBar = ({ <> - {courseReleaseDateObj.isValid() ? ( ) : courseReleaseDate} - + @@ -107,13 +109,12 @@ const StatusBar = ({ - {checkListTitle} {intl.formatMessage(messages.checklistCompleted)} - +
diff --git a/src/course-unit/breadcrumbs/Breadcrumbs.jsx b/src/course-unit/breadcrumbs/Breadcrumbs.jsx index 8dd34cfc52..26bfa53562 100644 --- a/src/course-unit/breadcrumbs/Breadcrumbs.jsx +++ b/src/course-unit/breadcrumbs/Breadcrumbs.jsx @@ -1,12 +1,14 @@ import { useSelector } from 'react-redux'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Dropdown, Icon } from '@openedx/paragon'; +import { Link } from 'react-router-dom'; import { ArrowDropDown as ArrowDropDownIcon, ChevronRight as ChevronRightIcon, } from '@openedx/paragon/icons'; +import { getConfig } from '@edx/frontend-platform'; -import { createCorrectInternalRoute } from '../../utils'; +import { getWaffleFlags } from '../../data/selectors'; import { getCourseSectionVertical } from '../data/selectors'; import messages from './messages'; @@ -14,6 +16,10 @@ const Breadcrumbs = () => { const intl = useIntl(); const { ancestorXblocks } = useSelector(getCourseSectionVertical); const [section, subsection] = ancestorXblocks ?? []; + const waffleFlags = useSelector(getWaffleFlags); + + const getPathToCourseOutlinePage = (url) => (waffleFlags.useNewCourseOutlinePage + ? url : `${getConfig().STUDIO_BASE_URL}${url}`); return (