richie-education 2.25.0-b2.dev103 → 2.25.0-b2.dev111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/api/joanie.ts +13 -0
- package/js/hooks/useCourseOrders/index.ts +32 -0
- package/js/{pages/TeacherDashboardContractsLayout/hooks → hooks}/useDefaultOrganizationId/index.spec.tsx +6 -42
- package/js/hooks/useOrganizations/index.ts +4 -4
- package/js/hooks/useResources/index.tsx +2 -0
- package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.spec.tsx +68 -83
- package/js/pages/TeacherDashboardContractsLayout/components/ContractFiltersBar/index.spec.tsx +21 -62
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.tsx +1 -1
- package/js/pages/TeacherDashboardContractsLayout/styles.scss +0 -4
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.spec.tsx +62 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx +123 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnersFiltersBar/index.spec.tsx +70 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnersFiltersBar/index.tsx +31 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.spec.tsx +158 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.ts +44 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/index.spec.tsx +385 -0
- package/js/pages/TeacherDashboardCourseLearnersLayout/index.tsx +141 -0
- package/js/settings/index.ts +1 -7
- package/js/settings/settings.prod.ts +1 -0
- package/js/types/Joanie.ts +47 -0
- package/js/utils/OrderHelper/index.ts +5 -1
- package/js/utils/test/factories/cunningham.ts +13 -0
- package/js/utils/test/factories/joanie.ts +44 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateMessage/index.tsx +8 -2
- package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx +1 -1
- package/js/widgets/Dashboard/components/FilterOrganization/index.tsx +27 -10
- package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.spec.tsx +36 -76
- package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/utils.ts +6 -1
- package/js/widgets/Dashboard/utils/teacherRouteMessages.tsx +23 -0
- package/js/widgets/Dashboard/utils/teacherRoutes.tsx +31 -0
- package/package.json +1 -1
- package/scss/objects/_dashboard.scss +7 -0
- /package/js/{pages/TeacherDashboardContractsLayout/hooks → hooks}/useDefaultOrganizationId/index.tsx +0 -0
|
@@ -36,12 +36,24 @@ import {
|
|
|
36
36
|
OrderGroup,
|
|
37
37
|
CertificateProduct,
|
|
38
38
|
CredentialProduct,
|
|
39
|
+
NestedCourseOrder,
|
|
40
|
+
UserLight,
|
|
41
|
+
ContractLight,
|
|
42
|
+
DefinitionResourcesProduct,
|
|
39
43
|
} from 'types/Joanie';
|
|
40
44
|
import { CourseStateFactory } from 'utils/test/factories/richie';
|
|
41
45
|
import { FactoryHelper } from 'utils/test/factories/helper';
|
|
42
46
|
import { JoanieUserApiAbilityActions, JoanieUserProfile } from 'types/User';
|
|
43
47
|
import { factory } from './factories';
|
|
44
48
|
|
|
49
|
+
export const UserLightFactory = factory((): UserLight => {
|
|
50
|
+
return {
|
|
51
|
+
id: faker.string.uuid(),
|
|
52
|
+
username: faker.internet.userName(),
|
|
53
|
+
full_name: faker.person.fullName(),
|
|
54
|
+
email: faker.internet.email(),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
45
57
|
export const JoanieUserProfileFactory = factory((): JoanieUserProfile => {
|
|
46
58
|
return {
|
|
47
59
|
id: faker.string.uuid(),
|
|
@@ -131,6 +143,14 @@ export const ContractFactory = factory((): Contract => {
|
|
|
131
143
|
};
|
|
132
144
|
});
|
|
133
145
|
|
|
146
|
+
export const ContractLightFactory = factory((): ContractLight => {
|
|
147
|
+
return {
|
|
148
|
+
id: faker.string.uuid(),
|
|
149
|
+
student_signed_on: faker.date.past().toISOString(),
|
|
150
|
+
organization_signed_on: null,
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
|
|
134
154
|
export const OrganizationFactory = factory((): Organization => {
|
|
135
155
|
return {
|
|
136
156
|
id: faker.string.uuid(),
|
|
@@ -203,6 +223,14 @@ export const CertificateCourseProductFactory = factory((): CourseProduct => {
|
|
|
203
223
|
// factories.js need a feature that return a random factory from a list.
|
|
204
224
|
export const ProductFactory = CredentialProductFactory;
|
|
205
225
|
|
|
226
|
+
export const DefinitionResourcesProductFactory = factory((): DefinitionResourcesProduct => {
|
|
227
|
+
return {
|
|
228
|
+
id: faker.string.uuid(),
|
|
229
|
+
certificate_definition_id: null,
|
|
230
|
+
contract_definition_id: null,
|
|
231
|
+
};
|
|
232
|
+
});
|
|
233
|
+
|
|
206
234
|
export const CourseRunFactory = factory((): CourseRun => {
|
|
207
235
|
return {
|
|
208
236
|
course: CourseLightFactory().one(),
|
|
@@ -273,6 +301,22 @@ export const OrderGroupFullFactory = factory((): OrderGroup => {
|
|
|
273
301
|
};
|
|
274
302
|
});
|
|
275
303
|
|
|
304
|
+
export const NestedCourseOrderFactory = factory((): NestedCourseOrder => {
|
|
305
|
+
return {
|
|
306
|
+
id: faker.string.uuid(),
|
|
307
|
+
created_on: faker.date.past().toISOString(),
|
|
308
|
+
owner: UserLightFactory().one(),
|
|
309
|
+
course_id: faker.string.uuid(),
|
|
310
|
+
product_id: faker.string.uuid(),
|
|
311
|
+
state: OrderState.VALIDATED,
|
|
312
|
+
enrollment_id: faker.string.uuid(),
|
|
313
|
+
organization: OrganizationFactory().one(),
|
|
314
|
+
certificate_id: faker.string.uuid(),
|
|
315
|
+
product: DefinitionResourcesProductFactory().one(),
|
|
316
|
+
contract: ContractLightFactory().one(),
|
|
317
|
+
};
|
|
318
|
+
});
|
|
319
|
+
|
|
276
320
|
export const CourseProductRelationFactory = factory((): CourseProductRelation => {
|
|
277
321
|
return {
|
|
278
322
|
id: faker.string.uuid(),
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { FormattedMessage, defineMessages } from 'react-intl';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CertificateOrder,
|
|
5
|
+
CredentialOrder,
|
|
6
|
+
OrderState,
|
|
7
|
+
ContractDefinition,
|
|
8
|
+
NestedCourseOrder,
|
|
9
|
+
} from 'types/Joanie';
|
|
4
10
|
import { StringHelper } from 'utils/StringHelper';
|
|
5
11
|
import { handle } from 'utils/errors/handle';
|
|
6
12
|
import { OrderHelper } from 'utils/OrderHelper';
|
|
@@ -52,7 +58,7 @@ export const messages = defineMessages({
|
|
|
52
58
|
});
|
|
53
59
|
|
|
54
60
|
interface OrderStateMessageProps {
|
|
55
|
-
order: CredentialOrder | CertificateOrder;
|
|
61
|
+
order: CredentialOrder | CertificateOrder | NestedCourseOrder;
|
|
56
62
|
contractDefinition?: ContractDefinition;
|
|
57
63
|
}
|
|
58
64
|
|
package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { ContractState, CourseProductRelation, Organization } from 'types/Joanie
|
|
|
5
5
|
import useTeacherPendingContractsCount from 'hooks/useTeacherPendingContractsCount';
|
|
6
6
|
import { ContractActions } from 'utils/AbilitiesHelper/types';
|
|
7
7
|
import useContractAbilities from 'hooks/useContractAbilities';
|
|
8
|
-
import useDefaultOrganizationId from '
|
|
8
|
+
import useDefaultOrganizationId from 'hooks/useDefaultOrganizationId';
|
|
9
9
|
import MenuNavLink from '../MenuNavLink';
|
|
10
10
|
|
|
11
11
|
interface ContractNavLinkProps {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { defineMessages, useIntl } from 'react-intl';
|
|
2
2
|
import { Select, SelectProps } from '@openfun/cunningham-react';
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useEffect, useMemo } from 'react';
|
|
4
4
|
import { useOrganizations } from 'hooks/useOrganizations';
|
|
5
5
|
import { Spinner } from 'components/Spinner';
|
|
6
|
+
import { Organization } from 'types/Joanie';
|
|
6
7
|
|
|
7
8
|
export const messages = defineMessages({
|
|
8
9
|
organizationFilterLabel: {
|
|
@@ -10,20 +11,35 @@ export const messages = defineMessages({
|
|
|
10
11
|
description: 'Use as organization filter label',
|
|
11
12
|
id: 'components.ListFilterOrganization.organizationFilterLabel',
|
|
12
13
|
},
|
|
14
|
+
allOrganizationOption: {
|
|
15
|
+
defaultMessage: 'All organizations',
|
|
16
|
+
description: 'Use as organization filter option label for "all organizations"',
|
|
17
|
+
id: 'components.ListFilterOrganization.allOrganizationOption',
|
|
18
|
+
},
|
|
13
19
|
});
|
|
14
20
|
|
|
15
21
|
interface FilterOrganizationProps {
|
|
16
22
|
defaultValue?: string;
|
|
23
|
+
organizationList?: Organization[];
|
|
17
24
|
onChange: ({ organization_id }: { organization_id?: string }) => void;
|
|
25
|
+
clearable?: boolean;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
|
-
const FilterOrganization = ({
|
|
28
|
+
const FilterOrganization = ({
|
|
29
|
+
defaultValue,
|
|
30
|
+
organizationList,
|
|
31
|
+
onChange,
|
|
32
|
+
clearable = false,
|
|
33
|
+
}: FilterOrganizationProps) => {
|
|
21
34
|
const intl = useIntl();
|
|
22
35
|
const {
|
|
23
|
-
items:
|
|
36
|
+
items: fetchedOrganizationList,
|
|
24
37
|
states: { isFetched },
|
|
25
|
-
} = useOrganizations();
|
|
26
|
-
|
|
38
|
+
} = useOrganizations(undefined, { enabled: !organizationList });
|
|
39
|
+
const isReady = useMemo(() => {
|
|
40
|
+
return organizationList || isFetched;
|
|
41
|
+
}, [organizationList, isFetched]);
|
|
42
|
+
const organizations = organizationList || fetchedOrganizationList;
|
|
27
43
|
const organizationOptions = organizations.map((organization) => ({
|
|
28
44
|
label: organization.title,
|
|
29
45
|
value: organization.id,
|
|
@@ -35,21 +51,22 @@ const FilterOrganization = ({ defaultValue, onChange }: FilterOrganizationProps)
|
|
|
35
51
|
};
|
|
36
52
|
|
|
37
53
|
useEffect(() => {
|
|
38
|
-
if (
|
|
54
|
+
if (!clearable && isReady && defaultValue === undefined) {
|
|
39
55
|
onChange({ organization_id: organizationOptions[0]?.value });
|
|
40
56
|
}
|
|
41
57
|
}, [defaultValue, isFetched]);
|
|
42
58
|
|
|
43
|
-
if (!
|
|
59
|
+
if (!isReady) {
|
|
60
|
+
return <Spinner />;
|
|
61
|
+
}
|
|
44
62
|
|
|
45
63
|
return (
|
|
46
64
|
<Select
|
|
47
65
|
label={intl.formatMessage(messages.organizationFilterLabel)}
|
|
48
66
|
options={organizationOptions}
|
|
49
|
-
defaultValue={defaultValue
|
|
67
|
+
defaultValue={defaultValue}
|
|
50
68
|
onChange={handleChange}
|
|
51
|
-
|
|
52
|
-
clearable={false}
|
|
69
|
+
clearable={clearable}
|
|
53
70
|
searchable={true}
|
|
54
71
|
/>
|
|
55
72
|
);
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import fetchMock from 'fetch-mock';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { CunninghamProvider } from '@openfun/cunningham-react';
|
|
7
|
-
import { PropsWithChildren } from 'react';
|
|
8
|
-
import { CourseListItem, CourseProductRelation, Organization } from 'types/Joanie';
|
|
9
|
-
import {
|
|
10
|
-
RichieContextFactory as mockRichieContextFactory,
|
|
11
|
-
UserFactory,
|
|
12
|
-
} from 'utils/test/factories/richie';
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import { createIntl } from 'react-intl';
|
|
4
|
+
import { CourseListItem } from 'types/Joanie';
|
|
5
|
+
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
13
6
|
import {
|
|
14
7
|
TEACHER_DASHBOARD_ROUTE_LABELS,
|
|
15
8
|
TeacherDashboardPaths,
|
|
16
9
|
} from 'widgets/Dashboard/utils/teacherRouteMessages';
|
|
17
|
-
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
18
|
-
import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
|
|
19
10
|
|
|
20
11
|
import {
|
|
21
12
|
CourseFactory,
|
|
@@ -23,6 +14,8 @@ import {
|
|
|
23
14
|
OrganizationFactory,
|
|
24
15
|
} from 'utils/test/factories/joanie';
|
|
25
16
|
import { expectNoSpinner } from 'utils/test/expectSpinner';
|
|
17
|
+
import { render } from 'utils/test/render';
|
|
18
|
+
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
26
19
|
import { TeacherDashboardCourseSidebar, messages } from '.';
|
|
27
20
|
|
|
28
21
|
jest.mock('utils/context', () => ({
|
|
@@ -41,58 +34,11 @@ jest.mock('utils/indirection/window', () => ({
|
|
|
41
34
|
|
|
42
35
|
const intl = createIntl({ locale: 'en' });
|
|
43
36
|
|
|
44
|
-
interface RenderTeacherDashboardCourseSidebarProps {
|
|
45
|
-
courseId: CourseListItem['id'];
|
|
46
|
-
organizationId?: Organization['id'];
|
|
47
|
-
courseProductRelationId?: CourseProductRelation['id'];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const Wrapper = ({
|
|
51
|
-
children,
|
|
52
|
-
courseId,
|
|
53
|
-
organizationId,
|
|
54
|
-
courseProductRelationId,
|
|
55
|
-
}: PropsWithChildren<RenderTeacherDashboardCourseSidebarProps>) => {
|
|
56
|
-
let routePath = '/:courseId';
|
|
57
|
-
let initialEntry = `/${courseId}`;
|
|
58
|
-
|
|
59
|
-
if (courseProductRelationId) {
|
|
60
|
-
routePath += '/:courseProductRelationId';
|
|
61
|
-
initialEntry += `/${courseProductRelationId}`;
|
|
62
|
-
}
|
|
63
|
-
if (organizationId) {
|
|
64
|
-
routePath = '/:organizationId' + routePath;
|
|
65
|
-
initialEntry = `/${organizationId}` + initialEntry;
|
|
66
|
-
}
|
|
67
|
-
return (
|
|
68
|
-
<IntlProvider locale="en">
|
|
69
|
-
<QueryClientProvider client={createTestQueryClient({ user: UserFactory().one() })}>
|
|
70
|
-
<JoanieSessionProvider>
|
|
71
|
-
<CunninghamProvider>
|
|
72
|
-
<MemoryRouter initialEntries={[initialEntry]}>
|
|
73
|
-
<Routes>
|
|
74
|
-
<Route path={routePath} element={children} />
|
|
75
|
-
</Routes>
|
|
76
|
-
</MemoryRouter>
|
|
77
|
-
</CunninghamProvider>
|
|
78
|
-
</JoanieSessionProvider>
|
|
79
|
-
</QueryClientProvider>
|
|
80
|
-
</IntlProvider>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
37
|
describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
38
|
+
const joanieSessionData = setupJoanieSession();
|
|
85
39
|
let nbApiRequest: number;
|
|
86
40
|
beforeEach(() => {
|
|
87
|
-
|
|
88
|
-
nbApiRequest = 3;
|
|
89
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/orders/', []);
|
|
90
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/addresses/', []);
|
|
91
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', []);
|
|
92
|
-
});
|
|
93
|
-
afterEach(() => {
|
|
94
|
-
jest.clearAllMocks();
|
|
95
|
-
fetchMock.restore();
|
|
41
|
+
nbApiRequest = joanieSessionData.nbSessionApiRequest;
|
|
96
42
|
});
|
|
97
43
|
|
|
98
44
|
it('should display syllabus link', async () => {
|
|
@@ -100,11 +46,12 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
100
46
|
fetchMock.get(`https://joanie.endpoint/api/v1.0/courses/${course.id}/`, course);
|
|
101
47
|
nbApiRequest += 1; // call to course
|
|
102
48
|
|
|
103
|
-
render(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
49
|
+
render(<TeacherDashboardCourseSidebar />, {
|
|
50
|
+
routerOptions: {
|
|
51
|
+
path: '/:courseId',
|
|
52
|
+
initialEntries: [`/${course.id}`],
|
|
53
|
+
},
|
|
54
|
+
});
|
|
108
55
|
|
|
109
56
|
await expectNoSpinner('Loading course...');
|
|
110
57
|
const link = screen.getByRole('link', {
|
|
@@ -129,6 +76,7 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
129
76
|
expectedRoutes: [
|
|
130
77
|
TeacherDashboardPaths.COURSE_PRODUCT,
|
|
131
78
|
TeacherDashboardPaths.COURSE_CONTRACTS,
|
|
79
|
+
TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST,
|
|
132
80
|
],
|
|
133
81
|
},
|
|
134
82
|
{
|
|
@@ -146,6 +94,7 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
146
94
|
expectedRoutes: [
|
|
147
95
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT,
|
|
148
96
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT_CONTRACTS,
|
|
97
|
+
TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST,
|
|
149
98
|
],
|
|
150
99
|
},
|
|
151
100
|
])(
|
|
@@ -179,21 +128,32 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
179
128
|
`https://joanie.endpoint/api/v1.0/course-product-relations/${courseProductRelation.id}/`,
|
|
180
129
|
courseProductRelation,
|
|
181
130
|
);
|
|
131
|
+
nbApiRequest += 1;
|
|
132
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/organizations/', []);
|
|
182
133
|
} else {
|
|
183
134
|
// mock api for course
|
|
184
135
|
nbApiRequest += 1;
|
|
185
136
|
fetchMock.get(`https://joanie.endpoint/api/v1.0/courses/${course.id}/`, course);
|
|
186
137
|
}
|
|
187
138
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
139
|
+
let routePath = '/:courseId';
|
|
140
|
+
let initialEntry = `/${course.id}`;
|
|
141
|
+
|
|
142
|
+
if (courseProductRelation) {
|
|
143
|
+
routePath += '/:courseProductRelationId';
|
|
144
|
+
initialEntry += `/${courseProductRelation.id}`;
|
|
145
|
+
}
|
|
146
|
+
if (organization) {
|
|
147
|
+
routePath = '/:organizationId' + routePath;
|
|
148
|
+
initialEntry = `/${organization.id}` + initialEntry;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
render(<TeacherDashboardCourseSidebar />, {
|
|
152
|
+
routerOptions: {
|
|
153
|
+
path: routePath,
|
|
154
|
+
initialEntries: [initialEntry],
|
|
155
|
+
},
|
|
156
|
+
});
|
|
197
157
|
|
|
198
158
|
await expectNoSpinner('Loading course...');
|
|
199
159
|
expectedRoutes.forEach((expectedRoute) => {
|
|
@@ -11,13 +11,18 @@ export const getMenuRoutes = ({ courseProductRelationId, organizationId }: GetMe
|
|
|
11
11
|
return [
|
|
12
12
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT,
|
|
13
13
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT_CONTRACTS,
|
|
14
|
+
TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST,
|
|
14
15
|
];
|
|
15
16
|
}
|
|
16
17
|
return [TeacherDashboardPaths.ORGANIZATION_COURSE_GENERAL_INFORMATION];
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
if (courseProductRelationId) {
|
|
20
|
-
return [
|
|
21
|
+
return [
|
|
22
|
+
TeacherDashboardPaths.COURSE_PRODUCT,
|
|
23
|
+
TeacherDashboardPaths.COURSE_PRODUCT_CONTRACTS,
|
|
24
|
+
TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST,
|
|
25
|
+
];
|
|
21
26
|
}
|
|
22
27
|
return [TeacherDashboardPaths.COURSE_GENERAL_INFORMATION];
|
|
23
28
|
};
|
|
@@ -12,10 +12,12 @@ export enum TeacherDashboardPaths {
|
|
|
12
12
|
ORGANIZATION_PRODUCT = '/teacher/organizations/{organizationId}/courses/{courseId}/products/{courseProductRelationId}',
|
|
13
13
|
ORGANIZATION_COURSE_CONTRACTS = '/teacher/organizations/{organizationId}/courses/{courseId}/contracts',
|
|
14
14
|
ORGANIZATION_PRODUCT_CONTRACTS = '/teacher/organizations/{organizationId}/courses/{courseId}/products/{courseProductRelationId}/contracts',
|
|
15
|
+
ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST = '/teacher/organizations/{organizationId}/courses/{courseId}/products/{courseProductRelationId}/learners',
|
|
15
16
|
ORGANIZATION_COURSE_GENERAL_INFORMATION = '/teacher/organizations/{organizationId}/courses/{courseId}/information',
|
|
16
17
|
COURSE = '/teacher/courses/{courseId}',
|
|
17
18
|
COURSE_GENERAL_INFORMATION = '/teacher/courses/{courseId}/information',
|
|
18
19
|
COURSE_PRODUCT = '/teacher/courses/{courseId}/products/{courseProductRelationId}',
|
|
20
|
+
COURSE_PRODUCT_LEARNER_LIST = '/teacher/courses/{courseId}/products/{courseProductRelationId}/learners',
|
|
19
21
|
COURSE_CONTRACTS = '/teacher/courses/{courseId}/contracts',
|
|
20
22
|
COURSE_PRODUCT_CONTRACTS = '/teacher/courses/{courseId}/products/{courseProductRelationId}/contracts',
|
|
21
23
|
}
|
|
@@ -69,6 +71,12 @@ export const TEACHER_DASHBOARD_ROUTE_PATHS = defineMessages<TeacherDashboardPath
|
|
|
69
71
|
defaultMessage:
|
|
70
72
|
'/teacher/organizations/{organizationId}/courses/{courseId}/products/{courseProductRelationId}',
|
|
71
73
|
},
|
|
74
|
+
[TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST]: {
|
|
75
|
+
id: 'components.TeacherDashboard.TeacherDashboardRoutes.organization.course.product.learnerList.path',
|
|
76
|
+
description: "The path to display the organization product's learner list view.",
|
|
77
|
+
defaultMessage:
|
|
78
|
+
'/teacher/organizations/{organizationId}/courses/{courseId}/products/{courseProductRelationId}/learners',
|
|
79
|
+
},
|
|
72
80
|
[TeacherDashboardPaths.COURSE]: {
|
|
73
81
|
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.path',
|
|
74
82
|
description: 'The path to display the course view.',
|
|
@@ -84,6 +92,11 @@ export const TEACHER_DASHBOARD_ROUTE_PATHS = defineMessages<TeacherDashboardPath
|
|
|
84
92
|
description: 'The path to display the product view.',
|
|
85
93
|
defaultMessage: '/teacher/courses/{courseId}/products/{courseProductRelationId}',
|
|
86
94
|
},
|
|
95
|
+
[TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST]: {
|
|
96
|
+
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.product.learnerList.path',
|
|
97
|
+
description: "The path to display the product's learner list view.",
|
|
98
|
+
defaultMessage: '/teacher/courses/{courseId}/products/{courseProductRelationId}/learners',
|
|
99
|
+
},
|
|
87
100
|
[TeacherDashboardPaths.COURSE_CONTRACTS]: {
|
|
88
101
|
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.contracts.path',
|
|
89
102
|
description: 'The path to display a course contracts view.',
|
|
@@ -143,6 +156,11 @@ export const TEACHER_DASHBOARD_ROUTE_LABELS = defineMessages<TeacherDashboardPat
|
|
|
143
156
|
description: 'Label of the organization product view.',
|
|
144
157
|
defaultMessage: 'General information',
|
|
145
158
|
},
|
|
159
|
+
[TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST]: {
|
|
160
|
+
id: 'components.TeacherDashboard.TeacherDashboardRoutes.organization.course.product.learnerList.label',
|
|
161
|
+
description: "Label to display the organization product's learner list view.",
|
|
162
|
+
defaultMessage: 'Learners',
|
|
163
|
+
},
|
|
146
164
|
[TeacherDashboardPaths.COURSE]: {
|
|
147
165
|
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.label',
|
|
148
166
|
description: 'Label of the course root view.',
|
|
@@ -158,6 +176,11 @@ export const TEACHER_DASHBOARD_ROUTE_LABELS = defineMessages<TeacherDashboardPat
|
|
|
158
176
|
description: 'Label of the product view.',
|
|
159
177
|
defaultMessage: 'General information',
|
|
160
178
|
},
|
|
179
|
+
[TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST]: {
|
|
180
|
+
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.product.learnerList.label',
|
|
181
|
+
description: "Label to display the product's learner list view.",
|
|
182
|
+
defaultMessage: 'Learners',
|
|
183
|
+
},
|
|
161
184
|
[TeacherDashboardPaths.COURSE_CONTRACTS]: {
|
|
162
185
|
id: 'components.TeacherDashboard.TeacherDashboardRoutes.course.contracts.label',
|
|
163
186
|
description: 'Label of the course contracts view.',
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from 'widgets/Dashboard/utils/teacherRouteMessages';
|
|
15
15
|
import { TeacherDashboardCourseLoader } from 'pages/TeacherDashboardCourseLoader';
|
|
16
16
|
import { TeacherDashboardTrainingLoader } from 'pages/TeacherDashboardTraining';
|
|
17
|
+
import { TeacherDashboardCourseLearnersLayout } from 'pages/TeacherDashboardCourseLearnersLayout';
|
|
17
18
|
|
|
18
19
|
export function getTeacherDashboardRoutes() {
|
|
19
20
|
const intl = useIntl();
|
|
@@ -81,6 +82,19 @@ export function getTeacherDashboardRoutes() {
|
|
|
81
82
|
],
|
|
82
83
|
},
|
|
83
84
|
},
|
|
85
|
+
{
|
|
86
|
+
path: getRoutePath(TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST, {
|
|
87
|
+
courseId: ':courseId',
|
|
88
|
+
courseProductRelationId: ':courseProductRelationId',
|
|
89
|
+
}),
|
|
90
|
+
element: <TeacherDashboardCourseLearnersLayout />,
|
|
91
|
+
handle: {
|
|
92
|
+
crumbLabel:
|
|
93
|
+
TEACHER_DASHBOARD_ROUTE_LABELS[
|
|
94
|
+
TeacherDashboardPaths.COURSE_PRODUCT_LEARNER_LIST
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
84
98
|
],
|
|
85
99
|
},
|
|
86
100
|
{
|
|
@@ -176,6 +190,23 @@ export function getTeacherDashboardRoutes() {
|
|
|
176
190
|
],
|
|
177
191
|
},
|
|
178
192
|
},
|
|
193
|
+
{
|
|
194
|
+
path: getRoutePath(
|
|
195
|
+
TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST,
|
|
196
|
+
{
|
|
197
|
+
organizationId: ':organizationId',
|
|
198
|
+
courseId: ':courseId',
|
|
199
|
+
courseProductRelationId: ':courseProductRelationId',
|
|
200
|
+
},
|
|
201
|
+
),
|
|
202
|
+
element: <TeacherDashboardCourseLearnersLayout />,
|
|
203
|
+
handle: {
|
|
204
|
+
crumbLabel:
|
|
205
|
+
TEACHER_DASHBOARD_ROUTE_LABELS[
|
|
206
|
+
TeacherDashboardPaths.ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
179
210
|
],
|
|
180
211
|
},
|
|
181
212
|
],
|
package/package.json
CHANGED
/package/js/{pages/TeacherDashboardContractsLayout/hooks → hooks}/useDefaultOrganizationId/index.tsx
RENAMED
|
File without changes
|