richie-education 3.1.3-dev2 → 3.1.3-dev23

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.
Files changed (86) hide show
  1. package/js/api/joanie.ts +8 -8
  2. package/js/components/ContractFrame/OrganizationContractFrame.spec.tsx +11 -19
  3. package/js/components/ContractFrame/OrganizationContractFrame.tsx +4 -4
  4. package/js/components/CourseGlimpse/index.spec.tsx +2 -0
  5. package/js/components/CourseGlimpse/index.tsx +2 -0
  6. package/js/components/CourseGlimpse/utils.ts +29 -30
  7. package/js/components/CourseGlimpseList/utils.ts +2 -2
  8. package/js/components/PurchaseButton/index.tsx +3 -3
  9. package/js/components/SaleTunnel/CredentialSaleTunnel/index.tsx +1 -3
  10. package/js/components/SaleTunnel/GenericSaleTunnel.tsx +3 -1
  11. package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +5 -3
  12. package/js/components/SaleTunnel/SubscriptionButton/index.tsx +1 -2
  13. package/js/components/SaleTunnel/index.credential.spec.tsx +5 -19
  14. package/js/components/SaleTunnel/index.full-process.spec.tsx +3 -3
  15. package/js/components/SaleTunnel/index.spec.tsx +116 -28
  16. package/js/components/SaleTunnel/index.stories.tsx +0 -1
  17. package/js/components/SaleTunnel/index.tsx +2 -2
  18. package/js/components/TeacherDashboardCourseList/index.spec.tsx +3 -3
  19. package/js/components/TeacherDashboardCourseList/index.tsx +2 -2
  20. package/js/hooks/useContractArchive/index.ts +3 -3
  21. package/js/hooks/useCourseProductUnion/index.spec.tsx +16 -18
  22. package/js/hooks/useCourseProductUnion/index.ts +7 -7
  23. package/js/hooks/useCourseProducts.ts +4 -8
  24. package/js/hooks/useDefaultOrganizationId/index.tsx +4 -7
  25. package/js/hooks/useOffering/index.ts +32 -0
  26. package/js/hooks/useTeacherCoursesSearch/index.tsx +2 -2
  27. package/js/hooks/useTeacherPendingContractsCount/index.ts +4 -4
  28. package/js/pages/DashboardCourses/index.spec.tsx +14 -14
  29. package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.spec.tsx +11 -14
  30. package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.tsx +4 -9
  31. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.spec.tsx +11 -11
  32. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.timer.spec.tsx +10 -13
  33. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +4 -4
  34. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +20 -28
  35. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.tsx +8 -11
  36. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +6 -6
  37. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.tsx +4 -4
  38. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +7 -7
  39. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx +5 -5
  40. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.spec.ts +21 -28
  41. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.ts +13 -17
  42. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +11 -13
  43. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +6 -6
  44. package/js/pages/TeacherDashboardContractsLayout/hooks/useHasContractToDownload/index.tsx +3 -3
  45. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.spec.tsx +16 -16
  46. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.tsx +4 -4
  47. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractsToSign.tsx +4 -4
  48. package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.spec.tsx +21 -21
  49. package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.ts +5 -10
  50. package/js/pages/TeacherDashboardCourseLearnersLayout/index.spec.tsx +61 -79
  51. package/js/pages/TeacherDashboardCourseLearnersLayout/index.tsx +1 -1
  52. package/js/pages/TeacherDashboardCoursesLoader/index.spec.tsx +11 -11
  53. package/js/pages/TeacherDashboardOrganizationCourseLoader/index.spec.tsx +11 -11
  54. package/js/pages/TeacherDashboardTraining/TeacherDashboardTrainingLoader.tsx +7 -7
  55. package/js/pages/TeacherDashboardTraining/index.spec.tsx +21 -29
  56. package/js/pages/TeacherDashboardTraining/index.tsx +12 -16
  57. package/js/types/Course.ts +2 -0
  58. package/js/types/Joanie.ts +34 -29
  59. package/js/types/index.ts +4 -2
  60. package/js/utils/ProductHelper/index.ts +1 -5
  61. package/js/utils/test/factories/joanie.ts +17 -25
  62. package/js/utils/test/factories/richie.ts +6 -2
  63. package/js/utils/test/mockCourseProductWithOrder.ts +4 -4
  64. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.tsx +1 -1
  65. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +1 -1
  66. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +3 -3
  67. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +1 -1
  68. package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +4 -4
  69. package/js/widgets/Dashboard/components/DashboardItem/stories.mock.ts +1 -1
  70. package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.spec.tsx +23 -28
  71. package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx +4 -8
  72. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.spec.tsx +17 -24
  73. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.tsx +18 -21
  74. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/utils.ts +4 -4
  75. package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.tsx +3 -7
  76. package/js/widgets/Dashboard/utils/teacherDashboardPaths.tsx +4 -4
  77. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/CourseProductItemFooter/index.tsx +19 -34
  78. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/_styles.scss +34 -8
  79. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/CourseRunList.tsx +3 -3
  80. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/_styles.scss +9 -0
  81. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +186 -140
  82. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +11 -2
  83. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +111 -24
  84. package/js/widgets/SyllabusCourseRunsList/index.spec.tsx +8 -8
  85. package/package.json +1 -1
  86. package/js/hooks/useCourseProductRelation/index.ts +0 -44
@@ -1,27 +1,22 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import { useParams, useSearchParams } from 'react-router';
3
3
  import useDefaultOrganizationId from 'hooks/useDefaultOrganizationId';
4
- import {
5
- CourseListItem,
6
- CourseOrderResourceQuery,
7
- CourseProductRelation,
8
- Organization,
9
- } from 'types/Joanie';
4
+ import { CourseListItem, CourseOrderResourceQuery, Offering, Organization } from 'types/Joanie';
10
5
 
11
6
  export type CourseLearnersParams = {
12
7
  courseId: CourseListItem['id'];
13
- courseProductRelationId?: CourseProductRelation['id'];
8
+ offeringId?: Offering['id'];
14
9
  organizationId?: Organization['id'];
15
10
  };
16
11
 
17
12
  const useCourseLearnersFilters = () => {
18
- const { courseId, courseProductRelationId } = useParams<CourseLearnersParams>();
13
+ const { courseId, offeringId } = useParams<CourseLearnersParams>();
19
14
  const [searchParams] = useSearchParams();
20
15
  const searchFilters: CourseOrderResourceQuery = useMemo(() => {
21
16
  return {
22
17
  course_id: courseId,
23
18
  organization_id: searchParams.get('organization_id') || undefined,
24
- course_product_relation_id: searchParams.get('course_product_relation_id') || undefined,
19
+ offering_id: searchParams.get('offering_id') || undefined,
25
20
  };
26
21
  }, Array.from(searchParams.entries()));
27
22
 
@@ -32,7 +27,7 @@ const useCourseLearnersFilters = () => {
32
27
  return {
33
28
  ...searchFilters,
34
29
  organization_id: defaultOrganizationId,
35
- course_product_relation_id: courseProductRelationId,
30
+ offering_id: offeringId,
36
31
  };
37
32
  }, [defaultOrganizationId]);
38
33
  const [filters, setFilters] = useState<CourseOrderResourceQuery>(initialFilters);
@@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event';
4
4
  import queryString from 'query-string';
5
5
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
6
6
  import {
7
- CourseProductRelationFactory,
7
+ OfferingFactory,
8
8
  NestedCourseOrderFactory,
9
9
  OrganizationFactory,
10
10
  } from 'utils/test/factories/joanie';
@@ -49,47 +49,44 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
49
49
  organizationFilterShouldBeDisplayed: true,
50
50
  },
51
51
  ])('$expectedLabel', async ({ nbOrganization, organizationFilterShouldBeDisplayed }) => {
52
- const courseProductRelation = CourseProductRelationFactory().one();
52
+ const offering = OfferingFactory().one();
53
53
  const organizationList = OrganizationFactory().many(nbOrganization);
54
54
  fetchMock.get(
55
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
55
+ `https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`,
56
56
  organizationList,
57
57
  );
58
58
 
59
59
  // Course sidebar query
60
- fetchMock.get(
61
- `https://joanie.endpoint/api/v1.0/course-product-relations/${courseProductRelation.id}/`,
62
- {},
63
- );
60
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/offerings/${offering.id}/`, {});
64
61
 
65
62
  // First request before finding default organizationId
66
63
  const courseOrderListQueryParams = {
67
- course_product_relation_id: courseProductRelation.id,
64
+ offering_id: offering.id,
68
65
  page: 1,
69
66
  page_size: PER_PAGE.courseLearnerList,
70
67
  };
71
68
  fetchMock.get(
72
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
69
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
73
70
  [],
74
71
  );
75
72
 
76
73
  if (organizationList.length > 0) {
77
74
  // Course sidebar query
78
75
  fetchMock.get(
79
- `https://joanie.endpoint/api/v1.0/organizations/${organizationList[0].id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
76
+ `https://joanie.endpoint/api/v1.0/organizations/${organizationList[0].id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
80
77
  [],
81
78
  );
82
79
 
83
80
  // Second request when default organizationId is fetched
84
81
  fetchMock.get(
85
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify({ organization_id: organizationList[0].id, ...courseOrderListQueryParams }, { sort: false })}`,
82
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify({ organization_id: organizationList[0].id, ...courseOrderListQueryParams }, { sort: false })}`,
86
83
  [],
87
84
  );
88
85
  }
89
86
  render(<TeacherDashboardCourseLearnersLayout />, {
90
87
  routerOptions: {
91
- path: '/:courseId/:courseProductRelationId',
92
- initialEntries: [`/${courseProductRelation.course.id}/${courseProductRelation.id}`],
88
+ path: '/:courseId/:offeringId',
89
+ initialEntries: [`/${offering.course.id}/${offering.id}`],
93
90
  },
94
91
  });
95
92
 
@@ -112,45 +109,42 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
112
109
  });
113
110
 
114
111
  it('should call onFiltersChange on organization filter change', async () => {
115
- const courseProductRelation = CourseProductRelationFactory().one();
112
+ const offering = OfferingFactory().one();
116
113
  const defaultOrganization = OrganizationFactory().one();
117
114
  const otherOrganization = OrganizationFactory().one();
118
115
  const organizationList = [defaultOrganization, otherOrganization];
119
116
 
120
117
  // Course sidebar queries
121
118
  fetchMock.get(
122
- `https://joanie.endpoint/api/v1.0/organizations/${defaultOrganization.id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
119
+ `https://joanie.endpoint/api/v1.0/organizations/${defaultOrganization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
123
120
  [],
124
121
  );
125
- fetchMock.get(
126
- `https://joanie.endpoint/api/v1.0/course-product-relations/${courseProductRelation.id}/`,
127
- {},
128
- );
122
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/offerings/${offering.id}/`, {});
129
123
 
130
124
  fetchMock.get(
131
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
125
+ `https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`,
132
126
  organizationList,
133
127
  );
134
128
  // First request before finding default organizationId
135
129
  const courseOrderListQueryParams = {
136
- course_product_relation_id: courseProductRelation.id,
130
+ offering_id: offering.id,
137
131
  page: 1,
138
132
  page_size: PER_PAGE.courseLearnerList,
139
133
  };
140
134
  fetchMock.get(
141
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
135
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
142
136
  [],
143
137
  );
144
138
  // Second request when default organizationId is fetched
145
139
  fetchMock.get(
146
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify({ organization_id: defaultOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
140
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify({ organization_id: defaultOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
147
141
  [],
148
142
  );
149
143
 
150
144
  render(<TeacherDashboardCourseLearnersLayout />, {
151
145
  routerOptions: {
152
- path: '/:courseId/:courseProductRelationId',
153
- initialEntries: [`/${courseProductRelation.course.id}/${courseProductRelation.id}`],
146
+ path: '/:courseId/:offeringId',
147
+ initialEntries: [`/${offering.course.id}/${offering.id}`],
154
148
  },
155
149
  });
156
150
 
@@ -164,60 +158,57 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
164
158
  const optionToSelect = screen.getByRole('option', { name: organizationList[1].title });
165
159
 
166
160
  fetchMock.get(
167
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify({ organization_id: otherOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
161
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify({ organization_id: otherOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
168
162
  [],
169
163
  );
170
164
  await user.click(optionToSelect);
171
165
  // onload default value is undefine and is onFiltersChange called once
172
166
  expect(
173
167
  fetchMock.called(
174
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify({ organization_id: otherOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
168
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify({ organization_id: otherOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
175
169
  ),
176
170
  ).toBe(true);
177
171
  });
178
172
 
179
- it('should render a list of course learners for a course product relation', async () => {
173
+ it('should render a list of course learners for an offering', async () => {
180
174
  const defaultOrganization = OrganizationFactory().one();
181
175
  const otherOrganization = OrganizationFactory().one();
182
176
  const organizationList = [defaultOrganization, otherOrganization];
183
- const courseProductRelation = CourseProductRelationFactory().one();
177
+ const offering = OfferingFactory().one();
184
178
  const courseOrderList = NestedCourseOrderFactory().many(3);
185
179
 
186
180
  // Course sidebar queries
187
181
  fetchMock.get(
188
- `https://joanie.endpoint/api/v1.0/organizations/${defaultOrganization.id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
182
+ `https://joanie.endpoint/api/v1.0/organizations/${defaultOrganization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
189
183
  [],
190
184
  );
191
- fetchMock.get(
192
- `https://joanie.endpoint/api/v1.0/course-product-relations/${courseProductRelation.id}/`,
193
- {},
194
- );
185
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/offerings/${offering.id}/`, {});
195
186
 
196
187
  fetchMock.get(
197
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
188
+ `https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`,
198
189
  organizationList,
199
190
  );
200
191
 
201
192
  // First request before finding default organizationId
202
193
  const courseOrderListQueryParams = {
203
- course_product_relation_id: courseProductRelation.id,
194
+ offering_id: offering.id,
204
195
  page: 1,
205
196
  page_size: PER_PAGE.courseLearnerList,
206
197
  };
207
198
  fetchMock.get(
208
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
199
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
209
200
  courseOrderList,
210
201
  );
211
202
  // Second request when default organizationId is fetched
212
203
  fetchMock.get(
213
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify({ organization_id: defaultOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
204
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify({ organization_id: defaultOrganization.id, ...courseOrderListQueryParams }, { sort: false })}`,
214
205
  courseOrderList,
215
206
  );
216
207
 
217
208
  render(<TeacherDashboardCourseLearnersLayout />, {
218
209
  routerOptions: {
219
- path: '/:courseId/:courseProductRelationId',
220
- initialEntries: [`/${courseProductRelation.course.id}/${courseProductRelation.id}`],
210
+ path: '/:courseId/:offeringId',
211
+ initialEntries: [`/${offering.course.id}/${offering.id}`],
221
212
  },
222
213
  });
223
214
 
@@ -239,42 +230,39 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
239
230
 
240
231
  it('should render a list of course learners for an organization', async () => {
241
232
  const organization = OrganizationFactory().one();
242
- const courseProductRelation = CourseProductRelationFactory().one();
233
+ const offering = OfferingFactory().one();
243
234
  const courseOrderList = NestedCourseOrderFactory().many(3);
244
235
 
245
236
  // Course sidebar queries
246
237
  fetchMock.get(
247
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
238
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
248
239
  [],
249
240
  );
250
241
  fetchMock.get(
251
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/${courseProductRelation.id}/`,
242
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/${offering.id}/`,
252
243
  {},
253
244
  );
254
245
 
255
246
  // before default organization's fetched, we query all organization to decide if we should display organization filter or not.
256
- fetchMock.get(
257
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
258
- [organization],
259
- );
247
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`, [
248
+ organization,
249
+ ]);
260
250
 
261
251
  const courseOrderListQueryParams = {
262
252
  organization_id: organization.id,
263
- course_product_relation_id: courseProductRelation.id,
253
+ offering_id: offering.id,
264
254
  page: 1,
265
255
  page_size: PER_PAGE.courseLearnerList,
266
256
  };
267
257
  fetchMock.get(
268
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
258
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
269
259
  courseOrderList,
270
260
  );
271
261
 
272
262
  render(<TeacherDashboardCourseLearnersLayout />, {
273
263
  routerOptions: {
274
- path: '/:organizationId/:courseId/:courseProductRelationId',
275
- initialEntries: [
276
- `/${organization.id}/${courseProductRelation.course.id}/${courseProductRelation.id}`,
277
- ],
264
+ path: '/:organizationId/:courseId/:offeringId',
265
+ initialEntries: [`/${organization.id}/${offering.course.id}/${offering.id}`],
278
266
  },
279
267
  });
280
268
 
@@ -294,41 +282,38 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
294
282
 
295
283
  it('should render an empty table if there are no course learners', async () => {
296
284
  const organization = OrganizationFactory().one();
297
- const courseProductRelation = CourseProductRelationFactory().one();
285
+ const offering = OfferingFactory().one();
298
286
 
299
287
  // Course sidebar queries
300
288
  fetchMock.get(
301
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
289
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
302
290
  [],
303
291
  );
304
292
  fetchMock.get(
305
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/${courseProductRelation.id}/`,
293
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/${offering.id}/`,
306
294
  {},
307
295
  );
308
296
 
309
297
  // before default organization's fetched, we query all organization to decide if we should display organization filter or not.
310
- fetchMock.get(
311
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
312
- [organization],
313
- );
298
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`, [
299
+ organization,
300
+ ]);
314
301
 
315
302
  const courseOrderListQueryParams = {
316
303
  organization_id: organization.id,
317
- course_product_relation_id: courseProductRelation.id,
304
+ offering_id: offering.id,
318
305
  page: 1,
319
306
  page_size: PER_PAGE.courseLearnerList,
320
307
  };
321
308
  fetchMock.get(
322
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
309
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
323
310
  [],
324
311
  );
325
312
 
326
313
  render(<TeacherDashboardCourseLearnersLayout />, {
327
314
  routerOptions: {
328
- path: '/:organizationId/:courseId/:courseProductRelationId',
329
- initialEntries: [
330
- `/${organization.id}/${courseProductRelation.course.id}/${courseProductRelation.id}`,
331
- ],
315
+ path: '/:organizationId/:courseId/:offeringId',
316
+ initialEntries: [`/${organization.id}/${offering.course.id}/${offering.id}`],
332
317
  },
333
318
  });
334
319
 
@@ -341,41 +326,38 @@ describe('pages/TeacherDashboardCourseLearnersLayout', () => {
341
326
 
342
327
  it('should render an error banner if an error occured during course learners fetching', async () => {
343
328
  const organization = OrganizationFactory().one();
344
- const courseProductRelation = CourseProductRelationFactory().one();
329
+ const offering = OfferingFactory().one();
345
330
 
346
331
  // Course sidebar queries
347
332
  fetchMock.get(
348
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?course_product_relation_id=${courseProductRelation.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
333
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=${PER_PAGE.teacherContractList}`,
349
334
  [],
350
335
  );
351
336
  fetchMock.get(
352
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/${courseProductRelation.id}/`,
337
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/${offering.id}/`,
353
338
  {},
354
339
  );
355
340
 
356
341
  // before default organization's fetched, we query all organization to decide if we should display organization filter or not.
357
- fetchMock.get(
358
- `https://joanie.endpoint/api/v1.0/organizations/?course_product_relation_id=${courseProductRelation.id}`,
359
- [organization],
360
- );
342
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`, [
343
+ organization,
344
+ ]);
361
345
 
362
346
  const courseOrderListQueryParams = {
363
347
  organization_id: organization.id,
364
- course_product_relation_id: courseProductRelation.id,
348
+ offering_id: offering.id,
365
349
  page: 1,
366
350
  page_size: PER_PAGE.courseLearnerList,
367
351
  };
368
352
  fetchMock.get(
369
- `https://joanie.endpoint/api/v1.0/courses/${courseProductRelation.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
353
+ `https://joanie.endpoint/api/v1.0/courses/${offering.course.id}/orders/?${queryString.stringify(courseOrderListQueryParams, { sort: false })}`,
370
354
  new Response('', { status: HttpStatusCode.NOT_FOUND }),
371
355
  );
372
356
 
373
357
  render(<TeacherDashboardCourseLearnersLayout />, {
374
358
  routerOptions: {
375
- path: '/:organizationId/:courseId/:courseProductRelationId',
376
- initialEntries: [
377
- `/${organization.id}/${courseProductRelation.course.id}/${courseProductRelation.id}`,
378
- ],
359
+ path: '/:organizationId/:courseId/:offeringId',
360
+ initialEntries: [`/${organization.id}/${offering.course.id}/${offering.id}`],
379
361
  },
380
362
  });
381
363
 
@@ -65,7 +65,7 @@ export const TeacherDashboardCourseLearnersLayout = () => {
65
65
  const {
66
66
  items: organizations,
67
67
  states: { isFetched: isOrganizationFetched },
68
- } = useOrganizations({ course_product_relation_id: filters.course_product_relation_id });
68
+ } = useOrganizations({ offering_id: filters.offering_id });
69
69
  const {
70
70
  items: courseOrders,
71
71
  meta,
@@ -2,7 +2,7 @@ import { screen, waitFor } from '@testing-library/react';
2
2
  import fetchMock from 'fetch-mock';
3
3
  import userEvent from '@testing-library/user-event';
4
4
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
5
- import { CourseListItemFactory, CourseProductRelationFactory } from 'utils/test/factories/joanie';
5
+ import { CourseListItemFactory, OfferingFactory } from 'utils/test/factories/joanie';
6
6
  import { expectNoSpinner } from 'utils/test/expectSpinner';
7
7
  import { mockPaginatedResponse } from 'utils/test/mockPaginatedResponse';
8
8
  import { PER_PAGE } from 'settings';
@@ -48,19 +48,19 @@ describe('components/TeacherDashboardCoursesLoader', () => {
48
48
  mockPaginatedResponse(CourseListItemFactory().many(15), 15, false),
49
49
  );
50
50
  fetchMock.get(
51
- `https://joanie.endpoint/api/v1.0/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
52
- mockPaginatedResponse(CourseProductRelationFactory().many(15), 15, false),
51
+ `https://joanie.endpoint/api/v1.0/offerings/?product_type=credential&page=1&page_size=${perPage}`,
52
+ mockPaginatedResponse(OfferingFactory().many(15), 15, false),
53
53
  );
54
54
 
55
55
  render(<TeacherDashboardCoursesLoader />);
56
56
  await expectNoSpinner('Loading courses...');
57
57
 
58
58
  nbApiCalls += 1; // course api call
59
- nbApiCalls += 1; // course-product-relations api call
59
+ nbApiCalls += 1; // offerings api call
60
60
  const calledUrls = fetchMock.calls().map((call) => call[0]);
61
61
  expect(calledUrls).toHaveLength(nbApiCalls);
62
62
  expect(calledUrls).toContain(
63
- `https://joanie.endpoint/api/v1.0/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
63
+ `https://joanie.endpoint/api/v1.0/offerings/?product_type=credential&page=1&page_size=${perPage}`,
64
64
  );
65
65
 
66
66
  // section titles
@@ -80,8 +80,8 @@ describe('components/TeacherDashboardCoursesLoader', () => {
80
80
  mockPaginatedResponse(CourseListItemFactory().many(15), 15, false),
81
81
  );
82
82
  fetchMock.get(
83
- `https://joanie.endpoint/api/v1.0/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
84
- mockPaginatedResponse(CourseProductRelationFactory().many(15), 15, false),
83
+ `https://joanie.endpoint/api/v1.0/offerings/?product_type=credential&page=1&page_size=${perPage}`,
84
+ mockPaginatedResponse(OfferingFactory().many(15), 15, false),
85
85
  );
86
86
 
87
87
  render(<TeacherDashboardCoursesLoader />);
@@ -93,22 +93,22 @@ describe('components/TeacherDashboardCoursesLoader', () => {
93
93
  mockPaginatedResponse(CourseListItemFactory().many(5), 5, false),
94
94
  );
95
95
  fetchMock.get(
96
- `https://joanie.endpoint/api/v1.0/course-product-relations/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
97
- mockPaginatedResponse(CourseProductRelationFactory().many(5), 5, false),
96
+ `https://joanie.endpoint/api/v1.0/offerings/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
97
+ mockPaginatedResponse(OfferingFactory().many(5), 5, false),
98
98
  );
99
99
  const user = userEvent.setup();
100
100
  await user.type(screen.getByRole('textbox', { name: /Search/ }), 'text query');
101
101
  await user.click(screen.getByRole('button', { name: /Search/ }));
102
102
 
103
103
  nbApiCalls = 1; // course api call
104
- nbApiCalls += 1; // course-product-relations api call
104
+ nbApiCalls += 1; // offerings api call
105
105
  const calledUrls = fetchMock.calls().map((call) => call[0]);
106
106
  expect(calledUrls).toHaveLength(nbApiCalls);
107
107
  expect(calledUrls).toContain(
108
108
  `https://joanie.endpoint/api/v1.0/courses/?query=text+query&has_listed_course_runs=true&page=1&page_size=${perPage}`,
109
109
  );
110
110
  expect(calledUrls).toContain(
111
- `https://joanie.endpoint/api/v1.0/course-product-relations/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
111
+ `https://joanie.endpoint/api/v1.0/offerings/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
112
112
  );
113
113
 
114
114
  await waitFor(() => {
@@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event';
4
4
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
5
5
  import {
6
6
  CourseListItemFactory,
7
- CourseProductRelationFactory,
7
+ OfferingFactory,
8
8
  OrganizationFactory,
9
9
  } from 'utils/test/factories/joanie';
10
10
  import { expectNoSpinner } from 'utils/test/expectSpinner';
@@ -59,8 +59,8 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
59
59
  mockPaginatedResponse(CourseListItemFactory().many(15), 15, false),
60
60
  );
61
61
  fetchMock.get(
62
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
63
- mockPaginatedResponse(CourseProductRelationFactory().many(15), 15, false),
62
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/?product_type=credential&page=1&page_size=${perPage}`,
63
+ mockPaginatedResponse(OfferingFactory().many(15), 15, false),
64
64
  );
65
65
  fetchMock.get(
66
66
  `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?signature_state=half_signed&page=1`,
@@ -76,7 +76,7 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
76
76
  await expectNoSpinner('Loading courses...');
77
77
 
78
78
  nbApiCalls += 1; // course api call
79
- nbApiCalls += 1; // course-product-relations api call
79
+ nbApiCalls += 1; // offerings api call
80
80
  nbApiCalls += 1; // contracts api call
81
81
  const calledUrls = fetchMock.calls().map((call) => call[0]);
82
82
  expect(calledUrls).toHaveLength(nbApiCalls);
@@ -84,7 +84,7 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
84
84
  `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/courses/?has_listed_course_runs=true&page=1&page_size=${perPage}`,
85
85
  );
86
86
  expect(calledUrls).toContain(
87
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
87
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/?product_type=credential&page=1&page_size=${perPage}`,
88
88
  );
89
89
  await expectNoSpinner('Loading organization...');
90
90
 
@@ -117,8 +117,8 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
117
117
  mockPaginatedResponse(CourseListItemFactory().many(15), 15, false),
118
118
  );
119
119
  fetchMock.get(
120
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
121
- mockPaginatedResponse(CourseProductRelationFactory().many(15), 15, false),
120
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/?product_type=credential&page=1&page_size=${perPage}`,
121
+ mockPaginatedResponse(OfferingFactory().many(15), 15, false),
122
122
  );
123
123
 
124
124
  render(<TeacherDashboardOrganizationCourseLoader />, {
@@ -136,22 +136,22 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
136
136
  mockPaginatedResponse(CourseListItemFactory().many(5), 5, false),
137
137
  );
138
138
  fetchMock.get(
139
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
140
- mockPaginatedResponse(CourseProductRelationFactory().many(5), 5, false),
139
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
140
+ mockPaginatedResponse(OfferingFactory().many(5), 5, false),
141
141
  );
142
142
  const user = userEvent.setup();
143
143
  await user.type(screen.getByRole('textbox', { name: /Search/ }), 'text query');
144
144
  await user.click(screen.getByRole('button', { name: /Search/ }));
145
145
 
146
146
  nbApiCalls = 1; // course api call
147
- nbApiCalls += 1; // course-product-relations api call
147
+ nbApiCalls += 1; // offerings api call
148
148
  const calledUrls = fetchMock.calls().map((call) => call[0]);
149
149
  expect(calledUrls).toHaveLength(nbApiCalls);
150
150
  expect(calledUrls).toContain(
151
151
  `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/courses/?query=text+query&has_listed_course_runs=true&page=1&page_size=${perPage}`,
152
152
  );
153
153
  expect(calledUrls).toContain(
154
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
154
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/?query=text+query&product_type=credential&page=1&page_size=${perPage}`,
155
155
  );
156
156
 
157
157
  await waitFor(() => {
@@ -1,10 +1,10 @@
1
1
  import { FormattedMessage, defineMessages } from 'react-intl';
2
2
  import { useParams } from 'react-router';
3
3
 
4
+ import { useOffering } from 'hooks/useOffering';
4
5
  import { DashboardLayout } from 'widgets/Dashboard/components/DashboardLayout';
5
6
  import { TeacherDashboardCourseSidebar } from 'widgets/Dashboard/components/TeacherDashboardCourseSidebar';
6
7
  import { Spinner } from 'components/Spinner';
7
- import { useCourseProductRelation } from 'hooks/useCourseProductRelation';
8
8
  import { useBreadcrumbsPlaceholders } from 'hooks/useBreadcrumbsPlaceholders';
9
9
  import { TeacherDashboardTraining } from '.';
10
10
 
@@ -22,17 +22,17 @@ const messages = defineMessages({
22
22
  });
23
23
 
24
24
  export const TeacherDashboardTrainingLoader = () => {
25
- const { courseProductRelationId, organizationId } = useParams<{
26
- courseProductRelationId: string;
25
+ const { offeringId, organizationId } = useParams<{
26
+ offeringId: string;
27
27
  organizationId?: string;
28
28
  }>();
29
29
 
30
30
  const {
31
- item: courseProductRelation,
31
+ item: offering,
32
32
  states: { fetching },
33
- } = useCourseProductRelation(courseProductRelationId, { organization_id: organizationId });
33
+ } = useOffering(offeringId, { organization_id: organizationId });
34
34
  useBreadcrumbsPlaceholders({
35
- courseTitle: courseProductRelation?.product.title ?? '',
35
+ courseTitle: offering?.product.title ?? '',
36
36
  });
37
37
  return (
38
38
  <DashboardLayout sidebar={<TeacherDashboardCourseSidebar />}>
@@ -48,7 +48,7 @@ export const TeacherDashboardTrainingLoader = () => {
48
48
  </span>
49
49
  </Spinner>
50
50
  ) : (
51
- <TeacherDashboardTraining courseProductRelation={courseProductRelation} />
51
+ <TeacherDashboardTraining offering={offering} />
52
52
  )}
53
53
  </DashboardLayout>
54
54
  );