richie-education 3.1.3-dev11 → 3.1.3-dev12
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 +8 -8
- package/js/components/ContractFrame/OrganizationContractFrame.spec.tsx +11 -20
- package/js/components/ContractFrame/OrganizationContractFrame.tsx +4 -4
- package/js/components/CourseGlimpse/utils.ts +22 -35
- package/js/components/CourseGlimpseList/utils.ts +2 -2
- package/js/components/PurchaseButton/index.tsx +3 -3
- package/js/components/SaleTunnel/GenericSaleTunnel.tsx +3 -10
- package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +2 -2
- package/js/components/SaleTunnel/index.full-process.spec.tsx +3 -3
- package/js/components/SaleTunnel/index.spec.tsx +5 -5
- package/js/components/SaleTunnel/index.tsx +2 -2
- package/js/components/TeacherDashboardCourseList/index.spec.tsx +3 -3
- package/js/components/TeacherDashboardCourseList/index.tsx +2 -2
- package/js/hooks/useContractArchive/index.ts +3 -3
- package/js/hooks/useCourseProductUnion/index.spec.tsx +16 -18
- package/js/hooks/useCourseProductUnion/index.ts +7 -7
- package/js/hooks/useCourseProducts.ts +4 -8
- package/js/hooks/useDefaultOrganizationId/index.tsx +4 -7
- package/js/hooks/useOffer/index.ts +32 -0
- package/js/hooks/useTeacherCoursesSearch/index.tsx +4 -4
- package/js/hooks/useTeacherPendingContractsCount/index.ts +4 -4
- package/js/pages/DashboardCourses/index.spec.tsx +14 -17
- package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.spec.tsx +8 -14
- package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.tsx +4 -12
- package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.spec.tsx +11 -11
- package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.timer.spec.tsx +10 -13
- package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +4 -4
- package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +20 -28
- package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.tsx +8 -11
- package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +6 -6
- package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.tsx +4 -4
- package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +7 -7
- package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx +5 -5
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.spec.ts +21 -28
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.ts +13 -23
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +11 -13
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +6 -6
- package/js/pages/TeacherDashboardContractsLayout/hooks/useHasContractToDownload/index.tsx +3 -6
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.spec.tsx +16 -16
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.tsx +4 -4
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractsToSign.tsx +4 -7
- package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.spec.tsx +21 -21
- package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.ts +5 -10
- package/js/pages/TeacherDashboardCourseLearnersLayout/index.spec.tsx +61 -79
- package/js/pages/TeacherDashboardCourseLearnersLayout/index.tsx +1 -1
- package/js/pages/TeacherDashboardCoursesLoader/index.spec.tsx +11 -11
- package/js/pages/TeacherDashboardOrganizationCourseLoader/index.spec.tsx +11 -11
- package/js/pages/TeacherDashboardTraining/TeacherDashboardTrainingLoader.tsx +7 -7
- package/js/pages/TeacherDashboardTraining/index.spec.tsx +25 -33
- package/js/pages/TeacherDashboardTraining/index.tsx +12 -20
- package/js/types/Joanie.ts +17 -19
- package/js/utils/test/factories/joanie.ts +3 -3
- package/js/utils/test/mockCourseProductWithOrder.ts +4 -4
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +3 -3
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +4 -4
- package/js/widgets/Dashboard/components/DashboardItem/stories.mock.ts +1 -1
- package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.spec.tsx +23 -28
- package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx +4 -8
- package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.spec.tsx +17 -27
- package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.tsx +16 -25
- package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/utils.ts +4 -4
- package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.tsx +3 -7
- package/js/widgets/Dashboard/utils/teacherDashboardPaths.tsx +4 -4
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/CourseProductItemFooter/index.tsx +9 -13
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +63 -87
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +2 -2
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +20 -34
- package/js/widgets/SyllabusCourseRunsList/index.spec.tsx +8 -8
- package/package.json +1 -1
- package/js/hooks/useCourseProductRelation/index.ts +0 -44
package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.spec.tsx
CHANGED
|
@@ -28,7 +28,7 @@ describe('<ContractNavLink />', () => {
|
|
|
28
28
|
fetchMock.get('https://joanie.endpoint/api/v1.0/organizations/', []);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
it('should render a ContractNavLink with route and label when neither organizationId and
|
|
31
|
+
it('should render a ContractNavLink with route and label when neither organizationId and offerId are given', () => {
|
|
32
32
|
const link: MenuLink = {
|
|
33
33
|
to: '/dummy/url/',
|
|
34
34
|
label: 'My contract navigation link',
|
|
@@ -45,31 +45,31 @@ describe('<ContractNavLink />', () => {
|
|
|
45
45
|
it.each([
|
|
46
46
|
{
|
|
47
47
|
organizationId: faker.string.uuid(),
|
|
48
|
-
|
|
48
|
+
offerId: undefined,
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
organizationId: faker.string.uuid(),
|
|
52
|
-
|
|
52
|
+
offerId: faker.string.uuid(),
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
organizationId: undefined,
|
|
56
|
-
|
|
56
|
+
offerId: faker.string.uuid(),
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
organizationId: undefined,
|
|
60
|
-
|
|
60
|
+
offerId: undefined,
|
|
61
61
|
},
|
|
62
62
|
])(
|
|
63
|
-
'should never render Badge for organizationId: $organizationId and courseProductId: $
|
|
64
|
-
async ({ organizationId,
|
|
63
|
+
'should never render Badge for organizationId: $organizationId and courseProductId: $offerId',
|
|
64
|
+
async ({ organizationId, offerId }) => {
|
|
65
65
|
let contractQueryParams: ContractResourceQuery = {
|
|
66
66
|
signature_state: ContractState.LEARNER_SIGNED,
|
|
67
67
|
page: 1,
|
|
68
68
|
page_size: PER_PAGE.teacherContractList,
|
|
69
69
|
};
|
|
70
|
-
if (
|
|
70
|
+
if (offerId) {
|
|
71
71
|
contractQueryParams = {
|
|
72
|
-
|
|
72
|
+
offer_id: offerId,
|
|
73
73
|
...contractQueryParams,
|
|
74
74
|
};
|
|
75
75
|
}
|
|
@@ -94,7 +94,7 @@ describe('<ContractNavLink />', () => {
|
|
|
94
94
|
label: 'My contract navigation link',
|
|
95
95
|
}}
|
|
96
96
|
organizationId={organizationId}
|
|
97
|
-
|
|
97
|
+
offerId={offerId}
|
|
98
98
|
/>,
|
|
99
99
|
);
|
|
100
100
|
|
|
@@ -112,25 +112,25 @@ describe('<ContractNavLink />', () => {
|
|
|
112
112
|
// with 1 contracts to sign
|
|
113
113
|
{
|
|
114
114
|
organizationId: faker.string.uuid(),
|
|
115
|
-
|
|
115
|
+
offerId: undefined,
|
|
116
116
|
nbContractsToSign: 1,
|
|
117
117
|
expectedBadgeCount: 1,
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
organizationId: faker.string.uuid(),
|
|
121
|
-
|
|
121
|
+
offerId: faker.string.uuid(),
|
|
122
122
|
nbContractsToSign: 1,
|
|
123
123
|
expectedBadgeCount: 1,
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
organizationId: undefined,
|
|
127
|
-
|
|
127
|
+
offerId: faker.string.uuid(),
|
|
128
128
|
nbContractsToSign: 1,
|
|
129
129
|
expectedBadgeCount: undefined,
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
organizationId: undefined,
|
|
133
|
-
|
|
133
|
+
offerId: undefined,
|
|
134
134
|
nbContractsToSign: 1,
|
|
135
135
|
expectedBadgeCount: undefined,
|
|
136
136
|
},
|
|
@@ -138,44 +138,39 @@ describe('<ContractNavLink />', () => {
|
|
|
138
138
|
// with 0 contracts to sign
|
|
139
139
|
{
|
|
140
140
|
organizationId: faker.string.uuid(),
|
|
141
|
-
|
|
141
|
+
offerId: undefined,
|
|
142
142
|
nbContractsToSign: 0,
|
|
143
143
|
expectedBadgeCount: undefined,
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
organizationId: faker.string.uuid(),
|
|
147
|
-
|
|
147
|
+
offerId: faker.string.uuid(),
|
|
148
148
|
nbContractsToSign: 0,
|
|
149
149
|
expectedBadgeCount: undefined,
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
organizationId: undefined,
|
|
153
|
-
|
|
153
|
+
offerId: faker.string.uuid(),
|
|
154
154
|
nbContractsToSign: 0,
|
|
155
155
|
expectedBadgeCount: undefined,
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
158
|
organizationId: undefined,
|
|
159
|
-
|
|
159
|
+
offerId: undefined,
|
|
160
160
|
nbContractsToSign: 0,
|
|
161
161
|
expectedBadgeCount: undefined,
|
|
162
162
|
},
|
|
163
163
|
])(
|
|
164
|
-
'should render Badge (count: $expectedBadgeCount) for nb contracts to sign: $nbContractsToSign, organizationId: $organizationId and courseProductId: $
|
|
165
|
-
async ({
|
|
166
|
-
nbContractsToSign,
|
|
167
|
-
organizationId,
|
|
168
|
-
courseProductRelationId,
|
|
169
|
-
expectedBadgeCount,
|
|
170
|
-
}) => {
|
|
164
|
+
'should render Badge (count: $expectedBadgeCount) for nb contracts to sign: $nbContractsToSign, organizationId: $organizationId and courseProductId: $offerId',
|
|
165
|
+
async ({ nbContractsToSign, organizationId, offerId, expectedBadgeCount }) => {
|
|
171
166
|
let contractQueryParams: ContractResourceQuery = {
|
|
172
167
|
signature_state: ContractState.LEARNER_SIGNED,
|
|
173
168
|
page: 1,
|
|
174
169
|
page_size: PER_PAGE.teacherContractList,
|
|
175
170
|
};
|
|
176
|
-
if (
|
|
171
|
+
if (offerId) {
|
|
177
172
|
contractQueryParams = {
|
|
178
|
-
|
|
173
|
+
offer_id: offerId,
|
|
179
174
|
...contractQueryParams,
|
|
180
175
|
};
|
|
181
176
|
}
|
|
@@ -199,7 +194,7 @@ describe('<ContractNavLink />', () => {
|
|
|
199
194
|
label: 'My contract navigation link',
|
|
200
195
|
}}
|
|
201
196
|
organizationId={organizationId}
|
|
202
|
-
|
|
197
|
+
offerId={offerId}
|
|
203
198
|
/>,
|
|
204
199
|
);
|
|
205
200
|
|
package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSearchParams } from 'react-router';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { MenuLink } from 'widgets/Dashboard/components/DashboardSidebar';
|
|
4
|
-
import { ContractState,
|
|
4
|
+
import { ContractState, Offer, 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';
|
|
@@ -11,18 +11,14 @@ import MenuNavLink from '../MenuNavLink';
|
|
|
11
11
|
interface ContractNavLinkProps {
|
|
12
12
|
link: MenuLink;
|
|
13
13
|
organizationId?: Organization['id'];
|
|
14
|
-
|
|
14
|
+
offerId?: Offer['id'];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const ContractNavLink = ({
|
|
18
|
-
link,
|
|
19
|
-
organizationId,
|
|
20
|
-
courseProductRelationId,
|
|
21
|
-
}: ContractNavLinkProps) => {
|
|
17
|
+
const ContractNavLink = ({ link, organizationId, offerId }: ContractNavLinkProps) => {
|
|
22
18
|
const defaultOrganizationId = useDefaultOrganizationId();
|
|
23
19
|
const { contracts: pendingContracts, pendingContractCount } = useTeacherPendingContractsCount({
|
|
24
20
|
organizationId: organizationId || defaultOrganizationId,
|
|
25
|
-
|
|
21
|
+
offerId,
|
|
26
22
|
});
|
|
27
23
|
const contractAbilities = useContractAbilities(pendingContracts);
|
|
28
24
|
const canSignContracts = contractAbilities.can(ContractActions.SIGN);
|
|
@@ -4,11 +4,7 @@ import { createIntl } from 'react-intl';
|
|
|
4
4
|
import { generatePath } from 'react-router';
|
|
5
5
|
import { CourseListItem } from 'types/Joanie';
|
|
6
6
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
7
|
-
import {
|
|
8
|
-
CourseFactory,
|
|
9
|
-
CourseProductRelationFactory,
|
|
10
|
-
OrganizationFactory,
|
|
11
|
-
} from 'utils/test/factories/joanie';
|
|
7
|
+
import { CourseFactory, OfferFactory, OrganizationFactory } from 'utils/test/factories/joanie';
|
|
12
8
|
import { expectNoSpinner } from 'utils/test/expectSpinner';
|
|
13
9
|
import { render } from 'utils/test/render';
|
|
14
10
|
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
@@ -65,14 +61,14 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
65
61
|
label: 'course',
|
|
66
62
|
course: CourseFactory().one(),
|
|
67
63
|
organization: undefined,
|
|
68
|
-
|
|
64
|
+
offer: undefined,
|
|
69
65
|
expectedRoutes: [TeacherDashboardPaths.COURSE_GENERAL_INFORMATION],
|
|
70
66
|
},
|
|
71
67
|
{
|
|
72
68
|
label: 'training',
|
|
73
69
|
course: CourseFactory().one(),
|
|
74
70
|
organization: undefined,
|
|
75
|
-
|
|
71
|
+
offer: OfferFactory().one(),
|
|
76
72
|
expectedRoutes: [
|
|
77
73
|
TeacherDashboardPaths.COURSE_PRODUCT,
|
|
78
74
|
TeacherDashboardPaths.COURSE_PRODUCT_CONTRACTS,
|
|
@@ -83,14 +79,14 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
83
79
|
label: "organization's course",
|
|
84
80
|
course: CourseFactory().one(),
|
|
85
81
|
organization: OrganizationFactory().one(),
|
|
86
|
-
|
|
82
|
+
offer: undefined,
|
|
87
83
|
expectedRoutes: [TeacherDashboardPaths.ORGANIZATION_COURSE_GENERAL_INFORMATION],
|
|
88
84
|
},
|
|
89
85
|
{
|
|
90
86
|
label: "organization's training",
|
|
91
87
|
course: CourseFactory().one(),
|
|
92
88
|
organization: OrganizationFactory().one(),
|
|
93
|
-
|
|
89
|
+
offer: OfferFactory().one(),
|
|
94
90
|
expectedRoutes: [
|
|
95
91
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT,
|
|
96
92
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT_CONTRACTS,
|
|
@@ -99,20 +95,20 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
99
95
|
},
|
|
100
96
|
])(
|
|
101
97
|
'should display menu items for "$label" route',
|
|
102
|
-
async ({ course, organization,
|
|
98
|
+
async ({ course, organization, offer, expectedRoutes }) => {
|
|
103
99
|
// mock api for organization's training
|
|
104
|
-
if (organization &&
|
|
100
|
+
if (organization && offer) {
|
|
105
101
|
// fetching training's contracts
|
|
106
102
|
nbApiRequest += 1;
|
|
107
103
|
fetchMock.get(
|
|
108
|
-
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?
|
|
104
|
+
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offer_id=${offer.id}&signature_state=half_signed&page=1&page_size=25`,
|
|
109
105
|
[],
|
|
110
106
|
);
|
|
111
107
|
// fetching organization's training
|
|
112
108
|
nbApiRequest += 1;
|
|
113
109
|
fetchMock.get(
|
|
114
|
-
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/
|
|
115
|
-
|
|
110
|
+
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offers/${offer.id}/`,
|
|
111
|
+
offer,
|
|
116
112
|
);
|
|
117
113
|
} else if (organization) {
|
|
118
114
|
// fetching organization's course
|
|
@@ -121,18 +117,12 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
121
117
|
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/courses/${course.id}/`,
|
|
122
118
|
course,
|
|
123
119
|
);
|
|
124
|
-
} else if (
|
|
120
|
+
} else if (offer) {
|
|
125
121
|
// fetching training
|
|
126
122
|
nbApiRequest += 1;
|
|
127
|
-
fetchMock.get(
|
|
128
|
-
`https://joanie.endpoint/api/v1.0/course-product-relations/${courseProductRelation.id}/`,
|
|
129
|
-
courseProductRelation,
|
|
130
|
-
);
|
|
123
|
+
fetchMock.get(`https://joanie.endpoint/api/v1.0/offers/${offer.id}/`, offer);
|
|
131
124
|
nbApiRequest += 1;
|
|
132
|
-
fetchMock.get(
|
|
133
|
-
`https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
|
|
134
|
-
[],
|
|
135
|
-
);
|
|
125
|
+
fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offer_id=${offer.id}`, []);
|
|
136
126
|
} else {
|
|
137
127
|
// mock api for course
|
|
138
128
|
nbApiRequest += 1;
|
|
@@ -142,9 +132,9 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
142
132
|
let routePath = '/:courseId';
|
|
143
133
|
let initialEntry = `/${course.id}`;
|
|
144
134
|
|
|
145
|
-
if (
|
|
146
|
-
routePath += '/:
|
|
147
|
-
initialEntry += `/${
|
|
135
|
+
if (offer) {
|
|
136
|
+
routePath += '/:offerId';
|
|
137
|
+
initialEntry += `/${offer.id}`;
|
|
148
138
|
}
|
|
149
139
|
if (organization) {
|
|
150
140
|
routePath = '/:organizationId' + routePath;
|
|
@@ -168,7 +158,7 @@ describe('<TeacherDashboardCourseSidebar/>', () => {
|
|
|
168
158
|
generatePath(expectedRoute, {
|
|
169
159
|
organizationId: organization ? organization.id : null,
|
|
170
160
|
courseId: course.id,
|
|
171
|
-
|
|
161
|
+
offerId: offer ? offer.id : null,
|
|
172
162
|
}),
|
|
173
163
|
);
|
|
174
164
|
});
|
|
@@ -2,12 +2,12 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
|
2
2
|
import { generatePath, useParams } from 'react-router';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
import { capitalize } from 'lodash-es';
|
|
5
|
+
import { useOffer } from 'hooks/useOffer';
|
|
5
6
|
import { DashboardSidebar, MenuLink } from 'widgets/Dashboard/components/DashboardSidebar';
|
|
6
7
|
import { getDashboardRouteLabel } from 'widgets/Dashboard/utils/dashboardRoutes';
|
|
7
8
|
import { useCourse } from 'hooks/useCourses';
|
|
8
9
|
import { Spinner } from 'components/Spinner';
|
|
9
10
|
import { Icon, IconTypeEnum } from 'components/Icon';
|
|
10
|
-
import { useCourseProductRelation } from 'hooks/useCourseProductRelation';
|
|
11
11
|
import { TeacherDashboardPaths } from 'widgets/Dashboard/utils/teacherDashboardPaths';
|
|
12
12
|
import ContractNavLink from '../DashboardSidebar/components/ContractNavLink';
|
|
13
13
|
import { getMenuRoutes } from './utils';
|
|
@@ -41,11 +41,11 @@ export const TeacherDashboardCourseSidebar = () => {
|
|
|
41
41
|
const {
|
|
42
42
|
organizationId: routeOrganizationId,
|
|
43
43
|
courseId: routeCourseId,
|
|
44
|
-
|
|
44
|
+
offerId: routeofferId = '',
|
|
45
45
|
} = useParams<{
|
|
46
46
|
organizationId?: string;
|
|
47
47
|
courseId: string;
|
|
48
|
-
|
|
48
|
+
offerId: string;
|
|
49
49
|
}>();
|
|
50
50
|
|
|
51
51
|
const {
|
|
@@ -54,38 +54,29 @@ export const TeacherDashboardCourseSidebar = () => {
|
|
|
54
54
|
} = useCourse(
|
|
55
55
|
routeCourseId,
|
|
56
56
|
{ organization_id: routeOrganizationId },
|
|
57
|
-
{ enabled: !
|
|
57
|
+
{ enabled: !routeofferId },
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const {
|
|
61
|
-
item:
|
|
62
|
-
states: { fetching:
|
|
63
|
-
} =
|
|
64
|
-
|
|
61
|
+
item: offer,
|
|
62
|
+
states: { fetching: offerFetching },
|
|
63
|
+
} = useOffer(
|
|
64
|
+
routeofferId,
|
|
65
65
|
{
|
|
66
66
|
organization_id: routeOrganizationId,
|
|
67
67
|
},
|
|
68
|
-
{ enabled: !!
|
|
68
|
+
{ enabled: !!routeofferId },
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
const fetching = useMemo(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
);
|
|
75
|
-
const product = useMemo(
|
|
76
|
-
() => (courseProductRelation ? courseProductRelation.product : undefined),
|
|
77
|
-
[courseProductRelation],
|
|
78
|
-
);
|
|
79
|
-
const course = useMemo(
|
|
80
|
-
() => (courseProductRelation ? courseProductRelation.course : singleCourse),
|
|
81
|
-
[courseProductRelation, singleCourse],
|
|
82
|
-
);
|
|
71
|
+
const fetching = useMemo(() => courseFetching || offerFetching, [courseFetching, offerFetching]);
|
|
72
|
+
const product = useMemo(() => (offer ? offer.product : undefined), [offer]);
|
|
73
|
+
const course = useMemo(() => (offer ? offer.course : singleCourse), [offer, singleCourse]);
|
|
83
74
|
|
|
84
75
|
const getMenuLinkFromPath = (basePath: TeacherDashboardPaths) => {
|
|
85
76
|
const path = generatePath(basePath, {
|
|
86
77
|
organizationId: routeOrganizationId ?? '',
|
|
87
78
|
courseId: routeCourseId ?? '',
|
|
88
|
-
|
|
79
|
+
offerId: routeofferId ?? '',
|
|
89
80
|
});
|
|
90
81
|
const menuLink: MenuLink = {
|
|
91
82
|
to: path,
|
|
@@ -102,7 +93,7 @@ export const TeacherDashboardCourseSidebar = () => {
|
|
|
102
93
|
<ContractNavLink
|
|
103
94
|
link={menuLink}
|
|
104
95
|
organizationId={routeOrganizationId}
|
|
105
|
-
|
|
96
|
+
offerId={routeofferId}
|
|
106
97
|
/>
|
|
107
98
|
);
|
|
108
99
|
}
|
|
@@ -112,10 +103,10 @@ export const TeacherDashboardCourseSidebar = () => {
|
|
|
112
103
|
const menuLinkList = useMemo(
|
|
113
104
|
() =>
|
|
114
105
|
getMenuRoutes({
|
|
115
|
-
|
|
106
|
+
offerId: routeofferId,
|
|
116
107
|
organizationId: routeOrganizationId,
|
|
117
108
|
}).map(getMenuLinkFromPath),
|
|
118
|
-
[routeOrganizationId,
|
|
109
|
+
[routeOrganizationId, routeofferId],
|
|
119
110
|
);
|
|
120
111
|
|
|
121
112
|
return (
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { TeacherDashboardPaths } from 'widgets/Dashboard/utils/teacherDashboardPaths';
|
|
2
2
|
|
|
3
3
|
interface GetMenuRoutesArgs {
|
|
4
|
-
|
|
4
|
+
offerId?: string;
|
|
5
5
|
organizationId?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export const getMenuRoutes = ({
|
|
8
|
+
export const getMenuRoutes = ({ offerId, organizationId }: GetMenuRoutesArgs) => {
|
|
9
9
|
if (organizationId) {
|
|
10
|
-
if (
|
|
10
|
+
if (offerId) {
|
|
11
11
|
return [
|
|
12
12
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT,
|
|
13
13
|
TeacherDashboardPaths.ORGANIZATION_PRODUCT_CONTRACTS,
|
|
@@ -17,7 +17,7 @@ export const getMenuRoutes = ({ courseProductRelationId, organizationId }: GetMe
|
|
|
17
17
|
return [TeacherDashboardPaths.ORGANIZATION_COURSE_GENERAL_INFORMATION];
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
if (
|
|
20
|
+
if (offerId) {
|
|
21
21
|
return [
|
|
22
22
|
TeacherDashboardPaths.COURSE_PRODUCT,
|
|
23
23
|
TeacherDashboardPaths.COURSE_PRODUCT_CONTRACTS,
|
|
@@ -24,9 +24,9 @@ const messages = defineMessages({
|
|
|
24
24
|
export const TeacherDashboardOrganizationSidebar = () => {
|
|
25
25
|
const intl = useIntl();
|
|
26
26
|
const getRouteLabel = getDashboardRouteLabel(intl);
|
|
27
|
-
const { organizationId,
|
|
27
|
+
const { organizationId, offerId } = useParams<{
|
|
28
28
|
organizationId: string;
|
|
29
|
-
|
|
29
|
+
offerId?: string;
|
|
30
30
|
}>();
|
|
31
31
|
const {
|
|
32
32
|
item: organization,
|
|
@@ -43,11 +43,7 @@ export const TeacherDashboardOrganizationSidebar = () => {
|
|
|
43
43
|
|
|
44
44
|
if (basePath === TeacherDashboardPaths.ORGANIZATION_CONTRACTS) {
|
|
45
45
|
menuLink.component = (
|
|
46
|
-
<ContractNavLink
|
|
47
|
-
link={menuLink}
|
|
48
|
-
organizationId={organizationId}
|
|
49
|
-
courseProductRelationId={courseProductRelationId}
|
|
50
|
-
/>
|
|
46
|
+
<ContractNavLink link={menuLink} organizationId={organizationId} offerId={offerId} />
|
|
51
47
|
);
|
|
52
48
|
}
|
|
53
49
|
|
|
@@ -9,14 +9,14 @@ export enum TeacherDashboardPaths {
|
|
|
9
9
|
ORGANIZATION = `${ROOT}/organizations/:organizationId`,
|
|
10
10
|
ORGANIZATION_CONTRACTS = `${ORGANIZATION}/contracts`,
|
|
11
11
|
ORGANIZATION_COURSES = `${ORGANIZATION}/courses`,
|
|
12
|
-
ORGANIZATION_PRODUCT = `${ORGANIZATION_COURSES}/:courseId/products/:
|
|
12
|
+
ORGANIZATION_PRODUCT = `${ORGANIZATION_COURSES}/:courseId/products/:offerId`,
|
|
13
13
|
ORGANIZATION_COURSE_CONTRACTS = `${ORGANIZATION_COURSES}/:courseId/contracts`,
|
|
14
|
-
ORGANIZATION_PRODUCT_CONTRACTS = `${ORGANIZATION_COURSES}/:courseId/products/:
|
|
15
|
-
ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST = `${ORGANIZATION_COURSES}/:courseId/products/:
|
|
14
|
+
ORGANIZATION_PRODUCT_CONTRACTS = `${ORGANIZATION_COURSES}/:courseId/products/:offerId/contracts`,
|
|
15
|
+
ORGANIZATION_COURSE_PRODUCT_LEARNER_LIST = `${ORGANIZATION_COURSES}/:courseId/products/:offerId/learners`,
|
|
16
16
|
ORGANIZATION_COURSE_GENERAL_INFORMATION = `${ORGANIZATION_COURSES}/:courseId/information`,
|
|
17
17
|
COURSE = `${TEACHER_COURSES}/:courseId`,
|
|
18
18
|
COURSE_GENERAL_INFORMATION = `${COURSE}/information`,
|
|
19
|
-
COURSE_PRODUCT = `${COURSE}/products/:
|
|
19
|
+
COURSE_PRODUCT = `${COURSE}/products/:offerId`,
|
|
20
20
|
COURSE_PRODUCT_LEARNER_LIST = `${COURSE_PRODUCT}/learners`,
|
|
21
21
|
COURSE_PRODUCT_CONTRACTS = `${COURSE_PRODUCT}/contracts`,
|
|
22
22
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FormattedMessage, defineMessages } from 'react-intl';
|
|
2
2
|
import PurchaseButton from 'components/PurchaseButton';
|
|
3
|
-
import {
|
|
3
|
+
import { Offer, CredentialProduct } from 'types/Joanie';
|
|
4
4
|
import { PacedCourse } from 'types';
|
|
5
5
|
|
|
6
6
|
const messages = defineMessages({
|
|
@@ -24,17 +24,13 @@ other {# remaining seats}
|
|
|
24
24
|
|
|
25
25
|
interface CourseProductItemFooterProps {
|
|
26
26
|
course: PacedCourse;
|
|
27
|
-
|
|
27
|
+
offer: Offer;
|
|
28
28
|
canPurchase: boolean;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const CourseProductItemFooter = ({
|
|
32
|
-
course,
|
|
33
|
-
courseProductRelation,
|
|
34
|
-
canPurchase,
|
|
35
|
-
}: CourseProductItemFooterProps) => {
|
|
31
|
+
const CourseProductItemFooter = ({ course, offer, canPurchase }: CourseProductItemFooterProps) => {
|
|
36
32
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37
|
-
const { seats, nb_seats_available } =
|
|
33
|
+
const { seats, nb_seats_available } = offer;
|
|
38
34
|
const hasSeatsLimit = seats && nb_seats_available !== undefined;
|
|
39
35
|
const hasNoSeatsAvailable = hasSeatsLimit && nb_seats_available === 0;
|
|
40
36
|
if (hasNoSeatsAvailable)
|
|
@@ -47,10 +43,10 @@ const CourseProductItemFooter = ({
|
|
|
47
43
|
<div className="product-widget__footer__order-group">
|
|
48
44
|
<PurchaseButton
|
|
49
45
|
course={course}
|
|
50
|
-
product={
|
|
51
|
-
|
|
52
|
-
organizations={
|
|
53
|
-
isWithdrawable={
|
|
46
|
+
product={offer.product as CredentialProduct}
|
|
47
|
+
offer={offer}
|
|
48
|
+
organizations={offer.organizations}
|
|
49
|
+
isWithdrawable={offer.is_withdrawable}
|
|
54
50
|
disabled={!canPurchase}
|
|
55
51
|
buttonProps={{ fullWidth: true }}
|
|
56
52
|
/>
|
|
@@ -58,7 +54,7 @@ const CourseProductItemFooter = ({
|
|
|
58
54
|
<p className="product-widget__footer__message">
|
|
59
55
|
<FormattedMessage
|
|
60
56
|
{...messages.nbSeatsAvailable}
|
|
61
|
-
values={{ nb:
|
|
57
|
+
values={{ nb: offer.nb_seats_available }}
|
|
62
58
|
/>
|
|
63
59
|
</p>
|
|
64
60
|
)}
|