Skip to content

Commit 78dd94a

Browse files
committed
feat: close sidebar on mobile after selecting a unit
1 parent a9654dc commit 78dd94a

File tree

2 files changed

+66
-27
lines changed

2 files changed

+66
-27
lines changed

src/courseware/course/sidebar/sidebars/course-outline/components/SidebarUnit.jsx

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/ana
77

88
import { checkBlockCompletion } from '@src/courseware/data';
99
import { getCourseOutline } from '@src/courseware/data/selectors';
10+
import { useCourseOutlineSidebar } from '../hooks';
1011
import messages from '../messages';
1112
import UnitIcon, { UNIT_ICON_TYPES } from './UnitIcon';
1213

@@ -28,6 +29,7 @@ const SidebarUnit = ({
2829
} = unit;
2930
const dispatch = useDispatch();
3031
const { sequences = {} } = useSelector(getCourseOutline);
32+
const { handleToggleCollapse, shouldDisplayFullScreen } = useCourseOutlineSidebar();
3133

3234
const logEvent = (eventName, widgetPlacement) => {
3335
const findSequenceByUnitId = (unitId) => Object.values(sequences).find(seq => seq.unitIds.includes(unitId));
@@ -53,6 +55,11 @@ const SidebarUnit = ({
5355
const handleClick = () => {
5456
logEvent('edx.ui.lms.sequence.tab_selected', 'left');
5557
dispatch(checkBlockCompletion(courseId, sequenceId, activeUnitId));
58+
59+
// Hide the sidebar after selecting a unit on a mobile device.
60+
if (shouldDisplayFullScreen) {
61+
handleToggleCollapse();
62+
}
5663
};
5764

5865
const iconType = isLocked ? UNIT_ICON_TYPES.lock : icon;

src/courseware/course/sidebar/sidebars/course-outline/components/SidebarUnit.test.jsx

+59-27
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/ana
77

88
import { initializeMockApp, initializeTestStore } from '@src/setupTest';
99
import SidebarUnit from './SidebarUnit';
10+
import SidebarContext from '../../../SidebarContext';
11+
import { ID } from '../constants';
1012

1113
jest.mock('@edx/frontend-platform/analytics', () => ({
1214
sendTrackEvent: jest.fn(),
@@ -20,6 +22,13 @@ describe('<SidebarUnit />', () => {
2022
let unit;
2123
let sequenceId;
2224

25+
// A default context for desktop mode.
26+
const defaultSidebarContext = {
27+
toggleSidebar: jest.fn(),
28+
shouldDisplayFullScreen: false,
29+
currentSidebar: ID,
30+
};
31+
2332
const initTestStore = async (options) => {
2433
store = await initializeTestStore(options);
2534
const state = store.getState();
@@ -28,21 +37,23 @@ describe('<SidebarUnit />', () => {
2837
unit = state.courseware.courseOutline.units[sequence.unitIds[0]];
2938
};
3039

31-
function renderWithProvider(props = {}) {
40+
function renderWithProvider(props = {}, sidebarContext = defaultSidebarContext) {
3241
const { container } = render(
3342
<AppProvider store={store} wrapWithRouter={false}>
3443
<IntlProvider locale="en">
3544
<MemoryRouter>
36-
<SidebarUnit
37-
isFirst
38-
id={unit.id}
39-
courseId="course123"
40-
sequenceId={sequenceId}
41-
unit={{ ...unit, icon: 'video', isLocked: false }}
42-
isActive={false}
43-
activeUnitId={unit.id}
44-
{...props}
45-
/>
45+
<SidebarContext.Provider value={sidebarContext}>
46+
<SidebarUnit
47+
isFirst
48+
id={unit.id}
49+
courseId="course123"
50+
sequenceId={sequenceId}
51+
unit={{ ...unit, icon: 'video', isLocked: false }}
52+
isActive={false}
53+
activeUnitId={unit.id}
54+
{...props}
55+
/>
56+
</SidebarContext.Provider>
4657
</MemoryRouter>
4758
</IntlProvider>
4859
</AppProvider>,
@@ -87,21 +98,42 @@ describe('<SidebarUnit />', () => {
8798
expect(screen.getByText(unit.title)).toBeInTheDocument();
8899
});
89100

90-
it('sends log event correctly when unit is clicked', async () => {
91-
await initTestStore();
92-
renderWithProvider({ unit: { ...unit } });
93-
const logData = {
94-
id: unit.id,
95-
current_tab: 1,
96-
tab_count: 1,
97-
target_id: unit.id,
98-
target_tab: 1,
99-
widget_placement: 'left',
100-
};
101-
102-
userEvent.click(screen.getByText(unit.title));
103-
104-
expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.tab_selected', logData);
105-
expect(sendTrackingLogEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.tab_selected', logData);
101+
describe('When a unit is clicked', () => {
102+
it('sends log event correctly', async () => {
103+
await initTestStore();
104+
renderWithProvider({ unit: { ...unit } });
105+
const logData = {
106+
id: unit.id,
107+
current_tab: 1,
108+
tab_count: 1,
109+
target_id: unit.id,
110+
target_tab: 1,
111+
widget_placement: 'left',
112+
};
113+
114+
userEvent.click(screen.getByText(unit.title));
115+
116+
expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.tab_selected', logData);
117+
expect(sendTrackingLogEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.tab_selected', logData);
118+
});
119+
120+
it('leaves sidebar open in desktop mode', async () => {
121+
await initTestStore();
122+
renderWithProvider({ unit: { ...unit } });
123+
userEvent.click(screen.getByText(unit.title));
124+
125+
expect(defaultSidebarContext.toggleSidebar).not.toHaveBeenCalled();
126+
expect(window.sessionStorage.getItem('hideCourseOutlineSidebar')).toBeNull();
127+
});
128+
129+
it('closes sidebar on mobile devices', async () => {
130+
await initTestStore();
131+
renderWithProvider({ unit: { ...unit } }, { ...defaultSidebarContext, shouldDisplayFullScreen: true });
132+
userEvent.click(screen.getByText(unit.title));
133+
134+
expect(defaultSidebarContext.toggleSidebar).toHaveBeenCalledTimes(1);
135+
expect(defaultSidebarContext.toggleSidebar).toHaveBeenCalledWith(null);
136+
expect(window.sessionStorage.getItem('hideCourseOutlineSidebar')).toEqual('true');
137+
});
106138
});
107139
});

0 commit comments

Comments
 (0)