Skip to content

Commit 89e327b

Browse files
authored
feat: course outline header update [FC-0114] (#2823)
Modifies new course outline header and actions
1 parent 0db79f3 commit 89e327b

14 files changed

Lines changed: 204 additions & 91 deletions

File tree

src/course-outline/CourseOutline.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@
1212
.border-dashed {
1313
border: dashed;
1414
}
15+
16+
.bg-draft-status {
17+
background-color: #F4B57B;
18+
}

src/course-outline/CourseOutline.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2498,7 +2498,7 @@ describe('<CourseOutline />', () => {
24982498
expect(btn).toBeInTheDocument();
24992499
expect(await screen.findByRole('link', { name: 'View live' })).toBeInTheDocument();
25002500
expect((await screen.findAllByRole('button', { name: 'Add' })).length).toEqual(2);
2501-
expect(await screen.findByRole('button', { name: 'More actions' })).toBeInTheDocument();
2501+
expect(await screen.findByRole('button', { name: 'Course info' })).toBeInTheDocument();
25022502
const user = userEvent.setup();
25032503
await user.click(btn);
25042504
expect(await screen.findByRole('button', { name: 'Expand all' })).toBeInTheDocument();

src/course-outline/data/slice.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const initialState = {
3333
},
3434
videoSharingEnabled: false,
3535
videoSharingOptions: VIDEO_SHARING_OPTIONS.perVideo,
36+
hasChanges: false,
3637
},
3738
sectionsList: [],
3839
isCustomRelativeDatesActive: false,

src/course-outline/data/thunk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export function fetchCourseOutlineIndexQuery(courseId: string): (dispatch: any)
7171
videoSharingOptions,
7272
actions,
7373
end,
74+
hasChanges,
7475
},
7576
} = outlineIndex;
7677
dispatch(fetchOutlineIndexSuccess(outlineIndex));
@@ -80,6 +81,7 @@ export function fetchCourseOutlineIndexQuery(courseId: string): (dispatch: any)
8081
videoSharingOptions,
8182
videoSharingEnabled,
8283
endDate: end,
84+
hasChanges,
8385
}));
8486
dispatch(updateCourseActions(actions));
8587

src/course-outline/data/types.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface CourseStructure {
77
start: string,
88
end: string,
99
actions: XBlockActions,
10+
hasChanges: boolean,
1011
}
1112

1213
// TODO: Create interface for all `Object` fields in courseOutline
@@ -35,19 +36,22 @@ export interface CourseDetails {
3536
description?: string;
3637
}
3738

39+
export interface ChecklistType {
40+
totalCourseLaunchChecks: number;
41+
completedCourseLaunchChecks: number;
42+
totalCourseBestPracticesChecks: number;
43+
completedCourseBestPracticesChecks: number;
44+
}
45+
3846
export interface CourseOutlineStatusBar {
3947
courseReleaseDate: string;
4048
endDate: string;
4149
highlightsEnabledForMessaging: boolean;
4250
isSelfPaced: boolean;
43-
checklist: {
44-
totalCourseLaunchChecks: number;
45-
completedCourseLaunchChecks: number;
46-
totalCourseBestPracticesChecks: number;
47-
completedCourseBestPracticesChecks: number;
48-
};
51+
checklist: ChecklistType;
4952
videoSharingEnabled: boolean;
5053
videoSharingOptions: string;
54+
hasChanges: boolean;
5155
}
5256

5357
export interface CourseOutlineState {

src/course-outline/header-navigations/HeaderActions.test.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ describe('<HeaderActions />', () => {
4747

4848
expect(await screen.findByRole('button', { name: messages.addButton.defaultMessage })).toBeInTheDocument();
4949
expect(await screen.findByRole('button', { name: messages.viewLiveButton.defaultMessage })).toBeInTheDocument();
50-
expect(await screen.findByRole('button', { name: messages.moreActionsButtonAriaLabel.defaultMessage })).toBeInTheDocument();
5150
});
5251

5352
it('calls the correct handlers when clicking buttons', async () => {
@@ -67,17 +66,13 @@ describe('<HeaderActions />', () => {
6766
expect(await screen.findByRole('button', { name: messages.addButton.defaultMessage })).toBeDisabled();
6867
});
6968

70-
it('should change pages using the dropdown button', async () => {
69+
it('should show course info on click', async () => {
7170
renderComponent();
7271

7372
// Click on the dropdown button
74-
await userEvent.click(screen.getByRole('button', { name: 'More actions' }));
75-
76-
// Select the Help option
77-
const helpButton = screen.getByRole('button', { name: 'Help' });
78-
await userEvent.click(helpButton);
73+
await userEvent.click(screen.getByRole('button', { name: 'Course info' }));
7974

8075
// Check if the current page change is called
81-
expect(setCurrentPageKeyMock).toHaveBeenCalledWith('help');
76+
expect(setCurrentPageKeyMock).toHaveBeenCalledWith('info');
8277
});
8378
});

src/course-outline/header-navigations/HeaderActions.tsx

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { useIntl } from '@edx/frontend-platform/i18n';
22
import {
3-
Button, Dropdown, Icon, OverlayTrigger, Stack, Tooltip,
3+
Button, OverlayTrigger, Stack, Tooltip,
44
} from '@openedx/paragon';
55
import {
6-
Add as IconAdd, FindInPage, ViewSidebar,
6+
Add as IconAdd, FindInPage, InfoOutline,
77
} from '@openedx/paragon/icons';
88

99
import { OutlinePageErrors, XBlockActions } from '@src/data/types';
10-
import type { SidebarPage } from '@src/generic/sidebar';
1110

12-
import { type OutlineSidebarPageKeys, useOutlineSidebarContext } from '../outline-sidebar/OutlineSidebarContext';
11+
import { useOutlineSidebarContext } from '../outline-sidebar/OutlineSidebarContext';
1312

1413
import messages from './messages';
15-
import { getOutlineSidebarPages } from '../outline-sidebar/sidebarPages';
1614

1715
export interface HeaderActionsProps {
1816
actions: {
@@ -29,12 +27,27 @@ const HeaderActions = ({
2927
}: HeaderActionsProps) => {
3028
const intl = useIntl();
3129
const { lmsLink } = actions;
32-
const sidebarPages = getOutlineSidebarPages();
3330

3431
const { setCurrentPageKey } = useOutlineSidebarContext();
3532

3633
return (
3734
<Stack direction="horizontal" gap={3}>
35+
<OverlayTrigger
36+
placement="bottom"
37+
overlay={(
38+
<Tooltip id={intl.formatMessage(messages.courseInfoButtonTooltip)}>
39+
{intl.formatMessage(messages.courseInfoButtonTooltip)}
40+
</Tooltip>
41+
)}
42+
>
43+
<Button
44+
iconBefore={InfoOutline}
45+
onClick={() => setCurrentPageKey('info')}
46+
variant="outline-primary"
47+
>
48+
{intl.formatMessage(messages.courseInfoButton)}
49+
</Button>
50+
</OverlayTrigger>
3851
{courseActions.childAddable && (
3952
<OverlayTrigger
4053
placement="bottom"
@@ -71,31 +84,6 @@ const HeaderActions = ({
7184
{intl.formatMessage(messages.viewLiveButton)}
7285
</Button>
7386
</OverlayTrigger>
74-
<Dropdown>
75-
<Dropdown.Toggle
76-
id="dropdown-toggle-with-iconbutton"
77-
as={Button}
78-
variant="outline-primary"
79-
aria-label={intl.formatMessage(messages.moreActionsButtonAriaLabel)}
80-
>
81-
<Icon src={ViewSidebar} />
82-
</Dropdown.Toggle>
83-
<Dropdown.Menu className="mt-1">
84-
{Object.entries(sidebarPages).filter(([, page]) => !page.hideFromActionMenu)
85-
.map(([key, page]: [OutlineSidebarPageKeys, SidebarPage]) => (
86-
<Dropdown.Item
87-
key={key}
88-
onClick={() => setCurrentPageKey(key)}
89-
>
90-
<Stack direction="horizontal" gap={2}>
91-
<Icon src={page.icon} />
92-
{intl.formatMessage(page.title)}
93-
</Stack>
94-
</Dropdown.Item>
95-
))}
96-
</Dropdown.Menu>
97-
</Dropdown>
98-
9987
</Stack>
10088
);
10189
};

src/course-outline/header-navigations/messages.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,20 @@ const messages = defineMessages({
3434
id: 'course-authoring.course-outline.header-navigations.button.view-live',
3535
defaultMessage: 'View live',
3636
},
37-
moreActionsButtonAriaLabel: {
38-
id: 'course-authoring.course-outline.header-navigations.button.more-actions.aria-label',
39-
defaultMessage: 'More actions',
40-
description: 'More actions button aria label in course outline',
37+
courseInfoButtonTooltip: {
38+
id: 'course-authoring.course-outline.header-navigations.button.course.info.tooltip',
39+
defaultMessage: 'Click to open course info in sidebar',
40+
description: 'Tooltip text of course info button',
41+
},
42+
courseInfoButton: {
43+
id: 'course-authoring.course-outline.header-navigations.button.course.info',
44+
defaultMessage: 'Course info',
45+
description: 'Course info button in course outline header',
4146
},
4247
viewLiveButtonTooltip: {
4348
id: 'course-authoring.course-outline.header-navigations.button.view-live.tooltip',
4449
defaultMessage: 'Click to open the courseware in the LMS in a new tab',
50+
description: 'Tooltip text of view live button',
4551
},
4652
});
4753

src/course-outline/outline-sidebar/sidebarPages.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export const getOutlineSidebarPages = (): OutlineSidebarPages => {
4040
component: AddSidebar,
4141
icon: Plus,
4242
title: messages.sidebarButtonAdd,
43-
hideFromActionMenu: true,
4443
},
4544
} satisfies OutlineSidebarPages;
4645
};

src/course-outline/status-bar/LegacyStatusBar.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const statusBarData: CourseOutlineStatusBar = {
5050
highlightsEnabledForMessaging: true,
5151
videoSharingEnabled: true,
5252
videoSharingOptions: VIDEO_SHARING_OPTIONS.allOn,
53+
hasChanges: true,
5354
};
5455

5556
const queryClient = new QueryClient();

0 commit comments

Comments
 (0)