Skip to content

Commit 99a44e2

Browse files
author
Ahtesham Quraish
committed
fix: rebase with master
2 parents 652bfff + 0e1550a commit 99a44e2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2859
-715
lines changed

CODEOWNERS

Lines changed: 0 additions & 2 deletions
This file was deleted.

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/CourseAuthoringRoutes.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import ScheduleAndDetails from './schedule-and-details';
1717
import { GradingSettings } from './grading-settings';
1818
import CourseTeam from './course-team/CourseTeam';
1919
import { CourseUpdates } from './course-updates';
20-
import { CourseUnit } from './course-unit';
20+
import { CourseUnit, SubsectionUnitRedirect } from './course-unit';
2121
import { Certificates } from './certificates';
2222
import CourseExportPage from './export-page/CourseExportPage';
2323
import CourseOptimizerPage from './optimizer-page/CourseOptimizerPage';
@@ -82,6 +82,10 @@ const CourseAuthoringRoutes = () => {
8282
path="custom-pages/*"
8383
element={<PageWrap><CustomPages courseId={courseId} /></PageWrap>}
8484
/>
85+
<Route
86+
path="/subsection/:subsectionId"
87+
element={<PageWrap><SubsectionUnitRedirect courseId={courseId} /></PageWrap>}
88+
/>
8589
{DECODED_ROUTES.COURSE_UNIT.map((path) => (
8690
<Route
8791
key={path}

src/course-outline/CourseOutline.test.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ describe('<CourseOutline />', () => {
17671767
.reply(200, { dummy: 'value' });
17681768
const expectedSection = moveSubsection([
17691769
...courseOutlineIndexMock.courseStructure.childInfo.children,
1770-
], 0, 0, 1)[0][0];
1770+
] as unknown as XBlock[], 0, 0, 1)[0][0];
17711771
axiosMock
17721772
.onGet(getXBlockApiUrl(section.id))
17731773
.reply(200, expectedSection);
@@ -1805,7 +1805,7 @@ describe('<CourseOutline />', () => {
18051805
.reply(200, { dummy: 'value' });
18061806
const expectedSections = moveSubsectionOver([
18071807
...courseOutlineIndexMock.courseStructure.childInfo.children,
1808-
], 1, 0, 0, firstSection.childInfo.children.length + 1)[0];
1808+
] as unknown as XBlock[], 1, 0, 0, firstSection.childInfo.children.length + 1)[0];
18091809
axiosMock
18101810
.onGet(getXBlockApiUrl(firstSection.id))
18111811
.reply(200, expectedSections[0]);
@@ -1842,7 +1842,7 @@ describe('<CourseOutline />', () => {
18421842
.reply(200, { dummy: 'value' });
18431843
const expectedSections = moveSubsectionOver([
18441844
...courseOutlineIndexMock.courseStructure.childInfo.children,
1845-
], 0, lastSubsectionIdx, 1, 0)[0];
1845+
] as unknown as XBlock[], 0, lastSubsectionIdx, 1, 0)[0];
18461846
axiosMock
18471847
.onGet(getXBlockApiUrl(section.id))
18481848
.reply(200, expectedSections[0]);
@@ -1929,7 +1929,9 @@ describe('<CourseOutline />', () => {
19291929
axiosMock
19301930
.onPut(getCourseItemApiUrl(store.getState().courseOutline.sectionsList[1].childInfo.children[1].id))
19311931
.reply(200, { dummy: 'value' });
1932-
const expectedSection = moveUnit([...courseOutlineIndexMock.courseStructure.childInfo.children], 1, 1, 0, 1)[0][1];
1932+
const expectedSection = moveUnit([
1933+
...courseOutlineIndexMock.courseStructure.childInfo.children,
1934+
] as unknown as XBlock[], 1, 1, 0, 1)[0][1];
19331935
axiosMock
19341936
.onGet(getXBlockApiUrl(section.id))
19351937
.reply(200, expectedSection);
@@ -1970,7 +1972,7 @@ describe('<CourseOutline />', () => {
19701972
.reply(200, { dummy: 'value' });
19711973
const expectedSections = moveUnitOver([
19721974
...courseOutlineIndexMock.courseStructure.childInfo.children,
1973-
], 1, 1, 0, 1, 0, firstSubsection.childInfo.children.length)[0];
1975+
] as unknown as XBlock[], 1, 1, 0, 1, 0, firstSubsection.childInfo.children.length)[0];
19741976
axiosMock
19751977
.onGet(getXBlockApiUrl(section.id))
19761978
.reply(200, expectedSections[1]);
@@ -2004,7 +2006,7 @@ describe('<CourseOutline />', () => {
20042006
.onPut(getCourseItemApiUrl(firstSectionLastSubsection.id))
20052007
.reply(200, { dummy: 'value' });
20062008
const expectedSections = moveUnitOver(
2007-
[...courseOutlineIndexMock.courseStructure.childInfo.children],
2009+
[...courseOutlineIndexMock.courseStructure.childInfo.children] as unknown as XBlock[],
20082010
1,
20092011
0,
20102012
0,
@@ -2050,7 +2052,7 @@ describe('<CourseOutline />', () => {
20502052
.reply(200, { dummy: 'value' });
20512053
const expectedSections = moveUnitOver([
20522054
...courseOutlineIndexMock.courseStructure.childInfo.children,
2053-
], 1, 0, lastUnitIdx, 1, 1, 0)[0];
2055+
] as unknown as XBlock[], 1, 0, lastUnitIdx, 1, 1, 0)[0];
20542056
axiosMock
20552057
.onGet(getXBlockApiUrl(section.id))
20562058
.reply(200, expectedSections[1]);
@@ -2086,7 +2088,7 @@ describe('<CourseOutline />', () => {
20862088
.onPut(getCourseItemApiUrl(thirdSectionFirstSubsection.id))
20872089
.reply(200, { dummy: 'value' });
20882090
const expectedSections = moveUnitOver(
2089-
[...courseOutlineIndexMock.courseStructure.childInfo.children],
2091+
[...courseOutlineIndexMock.courseStructure.childInfo.children] as unknown as XBlock[],
20902092
1,
20912093
lastSubIndex,
20922094
lastUnitIdx,
@@ -2173,7 +2175,7 @@ describe('<CourseOutline />', () => {
21732175
.reply(200, { dummy: 'value' });
21742176
const expectedSection = moveSubsection([
21752177
...courseOutlineIndexMock.courseStructure.childInfo.children,
2176-
], 0, 1, 0)[0][0];
2178+
] as unknown as XBlock[], 0, 1, 0)[0][0];
21772179
axiosMock
21782180
.onGet(getXBlockApiUrl(section.id))
21792181
.reply(200, expectedSection);
@@ -2236,7 +2238,7 @@ describe('<CourseOutline />', () => {
22362238
axiosMock
22372239
.onPut(getCourseItemApiUrl(subsection.id))
22382240
.reply(200, { dummy: 'value' });
2239-
const expectedSection = moveUnit([...sections], 2, 0, 1, 0)[0][2];
2241+
const expectedSection = moveUnit([...sections] as unknown as XBlock[], 2, 0, 1, 0)[0][2];
22402242
axiosMock
22412243
.onGet(getXBlockApiUrl(section.id))
22422244
.reply(200, expectedSection);
@@ -2270,7 +2272,7 @@ describe('<CourseOutline />', () => {
22702272
axiosMock
22712273
.onPut(getCourseItemApiUrl(subsection.id))
22722274
.reply(500);
2273-
const expectedSection = moveUnit([...sections], 2, 0, 1, 0)[0][2];
2275+
const expectedSection = moveUnit([...sections] as unknown as XBlock[], 2, 0, 1, 0)[0][2];
22742276
axiosMock
22752277
.onGet(getXBlockApiUrl(section.id))
22762278
.reply(200, expectedSection);

src/course-outline/data/apiHooks.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { useMutation } from '@tanstack/react-query';
1+
import { useMutation, useQuery } from '@tanstack/react-query';
22
import { createCourseXblock } from '@src/course-unit/data/api';
3+
import { getCourseItem } from './api';
34

45
export const courseOutlineQueryKeys = {
56
all: ['courseOutline'],
67
/**
78
* Base key for data specific to a course in outline
89
*/
910
contentLibrary: (courseId?: string) => [...courseOutlineQueryKeys.all, courseId],
11+
courseItemId: (itemId?: string) => [...courseOutlineQueryKeys.all, itemId],
12+
1013
};
1114

1215
/**
@@ -22,3 +25,11 @@ export const useCreateCourseBlock = (
2225
callback?.(data.locator, data.parent_locator);
2326
},
2427
});
28+
29+
export const useCourseItemData = (itemId?: string, enabled: boolean = true) => (
30+
useQuery({
31+
queryKey: courseOutlineQueryKeys.courseItemId(itemId),
32+
queryFn: () => getCourseItem(itemId!),
33+
enabled: enabled && itemId !== undefined,
34+
})
35+
);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { Col, Icon, Row } from '@openedx/paragon';
2+
import { ArrowRight, DragIndicator } from '@openedx/paragon/icons';
3+
import { ContainerType } from '@src/generic/key-utils';
4+
import { getItemStatusBorder } from '../utils';
5+
6+
interface ItemProps {
7+
displayName: string;
8+
status: string;
9+
}
10+
11+
interface CourseItemOverlayProps extends ItemProps {
12+
category: string;
13+
}
14+
15+
const commonStyle = {
16+
padding: '1rem 1.5rem',
17+
marginBottom: '1.5rem',
18+
borderRadius: '0.35rem',
19+
boxShadow: '0 0 .125rem rgba(0, 0, 0, .15), 0 0 .25rem rgba(0, 0, 0, .15)',
20+
};
21+
22+
const DragIndicatorBtn = () => (
23+
<button
24+
key="drag-to-reorder-icon"
25+
className="btn-icon btn-icon-secondary btn-icon-md"
26+
type="button"
27+
>
28+
<span className="btn-icon__icon-container">
29+
<Icon src={DragIndicator} />
30+
</span>
31+
</button>
32+
);
33+
34+
const SectionCard = ({ status, displayName }: ItemProps) => {
35+
const style = {
36+
...commonStyle,
37+
paddingTop: '2rem',
38+
paddingBottom: '5rem',
39+
...getItemStatusBorder(status),
40+
};
41+
42+
return (
43+
<Row
44+
style={style}
45+
className="mx-0 bg-white"
46+
>
47+
<Col className="extend-margin px-0">
48+
<div className="item-card-header h3">
49+
<Icon src={ArrowRight} className="mr-2" />
50+
{displayName}
51+
</div>
52+
</Col>
53+
<DragIndicatorBtn />
54+
</Row>
55+
);
56+
};
57+
58+
const SubsectionCard = ({ status, displayName }: ItemProps) => {
59+
const style = {
60+
...commonStyle,
61+
paddingTop: '1rem',
62+
paddingBottom: '2.5rem',
63+
...getItemStatusBorder(status),
64+
};
65+
66+
return (
67+
<Row
68+
style={style}
69+
className="mx-0 bg-light-200"
70+
>
71+
<Col className="extend-margin px-0">
72+
<div className="item-card-header h4 pt-2">
73+
<Icon src={ArrowRight} className="mr-2" />
74+
{displayName}
75+
</div>
76+
</Col>
77+
<DragIndicatorBtn />
78+
</Row>
79+
);
80+
};
81+
82+
const UnitCard = ({ status, displayName }: ItemProps) => {
83+
const style = {
84+
...commonStyle,
85+
paddingBottom: '1.5rem',
86+
...getItemStatusBorder(status),
87+
};
88+
89+
return (
90+
<Row
91+
style={style}
92+
className="mx-0 bg-white"
93+
>
94+
<Col className="extend-margin px-0">
95+
<div className="item-card-header h5 pt-3">
96+
{displayName}
97+
</div>
98+
</Col>
99+
<DragIndicatorBtn />
100+
</Row>
101+
);
102+
};
103+
104+
const CourseItemOverlay = ({ category, displayName, status }: CourseItemOverlayProps) => {
105+
switch (category) {
106+
case ContainerType.Chapter:
107+
return <SectionCard displayName={displayName} status={status} />;
108+
case ContainerType.Sequential:
109+
return <SubsectionCard displayName={displayName} status={status} />;
110+
case ContainerType.Vertical:
111+
return <UnitCard displayName={displayName} status={status} />;
112+
default:
113+
throw new Error(`Invalid course item type: ${category}`);
114+
}
115+
};
116+
117+
export default CourseItemOverlay;

src/course-outline/drag-helper/DragContextProvider.jsx

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { UniqueIdentifier } from '@dnd-kit/core';
2+
import React from 'react';
3+
4+
interface DragContextProviderProps {
5+
activeId: UniqueIdentifier | null,
6+
overId: UniqueIdentifier | null,
7+
children?: React.ReactNode,
8+
}
9+
10+
export const DragContext = React.createContext<DragContextProviderProps>({
11+
activeId: null,
12+
overId: null,
13+
children: null,
14+
});
15+
16+
const DragContextProvider = ({ activeId, overId, children }: DragContextProviderProps) => {
17+
const contextValue = React.useMemo(() => ({
18+
activeId,
19+
overId,
20+
}), [activeId, overId]);
21+
return (
22+
<DragContext.Provider
23+
value={contextValue}
24+
>
25+
{children}
26+
</DragContext.Provider>
27+
);
28+
};
29+
30+
export default DragContextProvider;

0 commit comments

Comments
 (0)