Skip to content

Commit

Permalink
chore: improved SPA routes
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang committed Oct 20, 2024
1 parent 56e025a commit 6187a96
Show file tree
Hide file tree
Showing 21 changed files with 255 additions and 101 deletions.
98 changes: 61 additions & 37 deletions src/course-checklist/ChecklistSection/ChecklistItemBody.jsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,89 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useNavigate } from 'react-router';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import {
ActionRow,
Button,
Hyperlink,
Icon,
} from '@openedx/paragon';
import { useSelector } from 'react-redux';
import { CheckCircle, RadioButtonUnchecked } from '@openedx/paragon/icons';

import { getStudioHomeData } from '../../studio-home/data/selectors';
import messages from './messages';

const ChecklistItemBody = ({
courseId,
checkId,
isCompleted,
updateLink,
// injected
intl,
}) => (
<ActionRow>
<div className="mr-3" id={`icon-${checkId}`} data-testid={`icon-${checkId}`}>
{isCompleted ? (
<Icon
data-testid="completed-icon"
src={CheckCircle}
className="text-success"
style={{ height: '32px', width: '32px' }}
screenReaderText={intl.formatMessage(messages.completedItemLabel)}
/>
) : (
<Icon
data-testid="uncompleted-icon"
src={RadioButtonUnchecked}
style={{ height: '32px', width: '32px' }}
screenReaderText={intl.formatMessage(messages.uncompletedItemLabel)}
/>
)}
</div>
<div>
<div>
<FormattedMessage {...messages[`${checkId}ShortDescription`]} />
}) => {
const { waffleFlags } = useSelector(getStudioHomeData);
const navigate = useNavigate();

const handleClick = (e, url) => {
e.preventDefault();

if (waffleFlags?.ENABLE_NEW_COURSE_UPDATES_PAGE) {
navigate(`/course/${courseId}/course_info`);
} else {
window.location.href = url;
}
};

return (
<ActionRow>
<div className="mr-3" id={`icon-${checkId}`} data-testid={`icon-${checkId}`}>
{isCompleted ? (
<Icon
data-testid="completed-icon"
src={CheckCircle}
className="text-success"
style={{ height: '32px', width: '32px' }}
screenReaderText={intl.formatMessage(messages.completedItemLabel)}
/>
) : (
<Icon
data-testid="uncompleted-icon"
src={RadioButtonUnchecked}
style={{ height: '32px', width: '32px' }}
screenReaderText={intl.formatMessage(messages.uncompletedItemLabel)}
/>
)}
</div>
<div className="small">
<FormattedMessage {...messages[`${checkId}LongDescription`]} />
<div>
<div>
<FormattedMessage {...messages[`${checkId}ShortDescription`]} />
</div>
<div className="small">
<FormattedMessage {...messages[`${checkId}LongDescription`]} />
</div>
</div>
</div>
<ActionRow.Spacer />
{updateLink && (
<Hyperlink destination={updateLink} data-testid="update-hyperlink">
<Button size="sm">
<FormattedMessage {...messages.updateLinkLabel} />
</Button>
</Hyperlink>
)}
</ActionRow>
);
<ActionRow.Spacer />
{updateLink && (
<Hyperlink
destination={updateLink}
data-testid="update-hyperlink"
onClick={(e) => handleClick(e, updateLink)}
>
<Button size="sm">
<FormattedMessage {...messages.updateLinkLabel} />
</Button>
</Hyperlink>
)}
</ActionRow>
);
};

ChecklistItemBody.defaultProps = {
updateLink: null,
};

ChecklistItemBody.propTypes = {
courseId: PropTypes.string.isRequired,
checkId: PropTypes.string.isRequired,
isCompleted: PropTypes.bool.isRequired,
updateLink: PropTypes.string,
Expand Down
4 changes: 3 additions & 1 deletion src/course-checklist/ChecklistSection/ChecklistSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ChecklistItemComment from './ChecklistItemComment';
import { checklistItems } from './utils/courseChecklistData';

const ChecklistSection = ({
courseId,
dataHeading,
data,
idPrefix,
Expand Down Expand Up @@ -46,7 +47,7 @@ const ChecklistSection = ({
data-testid={`checklist-item-${checkId}`}
key={checkId}
>
<ChecklistItemBody {...{ checkId, isCompleted, updateLink }} />
<ChecklistItemBody courseId={courseId} {...{ checkId, isCompleted, updateLink }} />
<div data-testid={`comment-section-${checkId}`}>
<ChecklistItemComment {...{ checkId, outlineUrl, data }} />
</div>
Expand All @@ -66,6 +67,7 @@ ChecklistSection.defaultProps = {
};

ChecklistSection.propTypes = {
courseId: PropTypes.string.isRequired,
dataHeading: PropTypes.string.isRequired,
data: PropTypes.oneOfType([
PropTypes.shape({
Expand Down
1 change: 1 addition & 0 deletions src/course-checklist/CourseChecklist.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const CourseChecklist = ({
/>
<Stack gap={4}>
<ChecklistSection
courseId={courseId}
dataHeading={intl.formatMessage(messages.launchChecklistLabel)}
data={launchData}
idPrefix="launchChecklist"
Expand Down
6 changes: 4 additions & 2 deletions src/course-outline/hooks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { copyToClipboard } from '../generic/data/thunks';
import { getSavingStatus as getGenericSavingStatus } from '../generic/data/selectors';
import { RequestStatus } from '../data/constants';
import { COURSE_BLOCK_NAMES } from './constants';
import { getStudioHomeData } from '../studio-home/data/selectors';
import {
setCurrentItem,
setCurrentSection,
Expand Down Expand Up @@ -58,6 +59,7 @@ import {
const useCourseOutline = ({ courseId }) => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { waffleFlags } = useSelector(getStudioHomeData);

const {
reindexLink,
Expand Down Expand Up @@ -112,15 +114,15 @@ const useCourseOutline = ({ courseId }) => {
};

const getUnitUrl = (locator) => {
if (getConfig().ENABLE_UNIT_PAGE === 'true') {
if (getConfig().ENABLE_UNIT_PAGE === 'true' || waffleFlags?.ENABLE_NEW_UNIT_PAGE) {
return `/course/${courseId}/container/${locator}`;
}
return `${getConfig().STUDIO_BASE_URL}/container/${locator}`;
};

const openUnitPage = (locator) => {
const url = getUnitUrl(locator);
if (getConfig().ENABLE_UNIT_PAGE === 'true') {
if (getConfig().ENABLE_UNIT_PAGE === 'true' || waffleFlags?.ENABLE_NEW_UNIT_PAGE) {
navigate(url);
} else {
window.location.assign(url);
Expand Down
21 changes: 11 additions & 10 deletions src/course-outline/status-bar/StatusBar.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
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';
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 { getStudioHomeData } from '../../studio-home/data/selectors';

import { ContentTagsDrawerSheet } from '../../content-tags-drawer';
import TagCount from '../../generic/tag-count';
Expand Down Expand Up @@ -43,6 +46,7 @@ const StatusBar = ({
}) => {
const intl = useIntl();
const { config } = useContext(AppContext);
const { waffleFlags } = useSelector(getStudioHomeData);

const {
courseReleaseDate,
Expand All @@ -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 {
Expand All @@ -82,10 +85,9 @@ const StatusBar = ({
<>
<Stack direction="horizontal" gap={3.5} className="d-flex align-items-stretch outline-status-bar" data-testid="outline-status-bar">
<StatusBarItem title={intl.formatMessage(messages.startDateTitle)}>
<Hyperlink
<Link
className="small"
destination={scheduleDestination()}
showLaunchIcon={false}
to={waffleFlags?.ENABLE_NEW_SCHEDULE_AND_DETAILS_PAGE ? `/course/${courseId}/settings/details/#schedule` : scheduleDestination()}
>
{courseReleaseDateObj.isValid() ? (
<FormattedDate
Expand All @@ -97,7 +99,7 @@ const StatusBar = ({
minute="numeric"
/>
) : courseReleaseDate}
</Hyperlink>
</Link>
</StatusBarItem>
<StatusBarItem title={intl.formatMessage(messages.pacingTypeTitle)}>
<span className="small">
Expand All @@ -107,13 +109,12 @@ const StatusBar = ({
</span>
</StatusBarItem>
<StatusBarItem title={intl.formatMessage(messages.checklistTitle)}>
<Hyperlink
<Link
className="small"
destination={checklistDestination()}
showLaunchIcon={false}
to={`/course/${courseId}/checklists`}
>
{checkListTitle} {intl.formatMessage(messages.checklistCompleted)}
</Hyperlink>
</Link>
</StatusBarItem>
<StatusBarItem title={intl.formatMessage(messages.highlightEmailsTitle)}>
<div className="d-flex align-items-center">
Expand Down
18 changes: 16 additions & 2 deletions src/course-unit/breadcrumbs/Breadcrumbs.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import { useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Dropdown, Icon } from '@openedx/paragon';
import { useNavigate } 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 { getCourseSectionVertical } from '../data/selectors';
import { getStudioHomeData } from '../../studio-home/data/selectors';
import messages from './messages';

const Breadcrumbs = () => {
const intl = useIntl();
const { ancestorXblocks } = useSelector(getCourseSectionVertical);
const [section, subsection] = ancestorXblocks ?? [];
const navigate = useNavigate();
const { waffleFlags } = useSelector(getStudioHomeData);

const handleClick = (e, url) => {
e.preventDefault();
if (waffleFlags?.ENABLE_NEW_COURSE_OUTLINE_PAGE) {
navigate(url);
} else {
window.location.href = `${getConfig().STUDIO_BASE_URL}/${url}`;
}
};

return (
<nav className="d-flex align-center mb-2.5">
Expand All @@ -31,7 +45,7 @@ const Breadcrumbs = () => {
{section.children.map(({ url, displayName }) => (
<Dropdown.Item
key={url}
href={createCorrectInternalRoute(url)}
onClick={(e) => handleClick(e, createCorrectInternalRoute(`${url}`))}
className="small"
data-testid="breadcrumbs-section-dropdown-item"
>
Expand Down Expand Up @@ -60,7 +74,7 @@ const Breadcrumbs = () => {
{subsection.children.map(({ url, displayName }) => (
<Dropdown.Item
key={url}
href={createCorrectInternalRoute(url)}
onClick={(e) => handleClick(e, createCorrectInternalRoute(`${url}`))}
className="small"
data-testid="breadcrumbs-subsection-dropdown-item"
>
Expand Down
24 changes: 18 additions & 6 deletions src/generic/help-sidebar/HelpSidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import classNames from 'classnames';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import { getStudioHomeData } from '../../studio-home/data/selectors';

import { otherLinkURLParams } from './constants';
import messages from './messages';
Expand All @@ -25,6 +26,7 @@ const HelpSidebar = ({
scheduleAndDetails,
groupConfigurations,
} = otherLinkURLParams;
const { waffleFlags } = useSelector(getStudioHomeData);

const showOtherLink = (params) => !pathname.includes(params);
const generateLegacyURL = (urlParameter) => {
Expand Down Expand Up @@ -55,36 +57,46 @@ const HelpSidebar = ({
<ul className="p-0 mb-0">
{showOtherLink(scheduleAndDetails) && (
<HelpSidebarLink
pathToPage={scheduleAndDetailsDestination}
pathToPage={waffleFlags?.ENABLE_NEW_SCHEDULE_AND_DETAILS_PAGE
? `/course/${courseId}/${scheduleAndDetails}` : scheduleAndDetailsDestination}
title={intl.formatMessage(
messages.sidebarLinkToScheduleAndDetails,
)}
isNewPage={waffleFlags?.ENABLE_NEW_SCHEDULE_AND_DETAILS_PAGE}
/>
)}
{showOtherLink(grading) && (
<HelpSidebarLink
pathToPage={gradingDestination}
pathToPage={waffleFlags?.ENABLE_NEW_GRADING_PAGE
? `/course/${courseId}/${grading}` : gradingDestination}
title={intl.formatMessage(messages.sidebarLinkToGrading)}
isNewPage={waffleFlags?.ENABLE_NEW_GRADING_PAGE}
/>
)}
{showOtherLink(courseTeam) && (
<HelpSidebarLink
pathToPage={courseTeamDestination}
pathToPage={waffleFlags?.ENABLE_NEW_COURSE_TEAM_PAGE
? `/course/${courseId}/${courseTeam}` : courseTeamDestination}
title={intl.formatMessage(messages.sidebarLinkToCourseTeam)}
isNewPage={waffleFlags?.ENABLE_NEW_COURSE_TEAM_PAGE}
/>
)}
{showOtherLink(groupConfigurations) && (
<HelpSidebarLink
pathToPage={groupConfigurationsDestination}
pathToPage={waffleFlags?.ENABLE_NEW_GROUP_CONFIGURATIONS_PAGE
? `/course/${courseId}/${groupConfigurations}` : groupConfigurationsDestination}
title={intl.formatMessage(
messages.sidebarLinkToGroupConfigurations,
)}
isNewPage={waffleFlags?.ENABLE_NEW_GROUP_CONFIGURATIONS_PAGE}
/>
)}
{showOtherLink(advancedSettings) && (
<HelpSidebarLink
pathToPage={advancedSettingsDestination}
pathToPage={waffleFlags?.ENABLE_NEW_ADVANCED_SETTINGS_PAGE
? `/course/${courseId}/${advancedSettings}` : advancedSettingsDestination}
title={intl.formatMessage(messages.sidebarLinkToAdvancedSettings)}
isNewPage={waffleFlags?.ENABLE_NEW_ADVANCED_SETTINGS_PAGE}
/>
)}
{proctoredExamSettingsUrl && (
Expand Down
Loading

0 comments on commit 6187a96

Please sign in to comment.