richie-education 3.1.3-dev12 → 3.1.3-dev17

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 (73) hide show
  1. package/js/api/joanie.ts +8 -8
  2. package/js/components/ContractFrame/OrganizationContractFrame.spec.tsx +12 -11
  3. package/js/components/ContractFrame/OrganizationContractFrame.tsx +4 -4
  4. package/js/components/CourseGlimpse/utils.ts +28 -22
  5. package/js/components/CourseGlimpseList/utils.ts +2 -2
  6. package/js/components/PurchaseButton/index.tsx +3 -3
  7. package/js/components/SaleTunnel/GenericSaleTunnel.tsx +3 -3
  8. package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +5 -3
  9. package/js/components/SaleTunnel/index.full-process.spec.tsx +3 -3
  10. package/js/components/SaleTunnel/index.spec.tsx +76 -63
  11. package/js/components/SaleTunnel/index.tsx +2 -2
  12. package/js/components/TeacherDashboardCourseList/index.spec.tsx +3 -3
  13. package/js/components/TeacherDashboardCourseList/index.tsx +2 -2
  14. package/js/hooks/useContractArchive/index.ts +3 -3
  15. package/js/hooks/useCourseProductUnion/index.spec.tsx +16 -16
  16. package/js/hooks/useCourseProductUnion/index.ts +7 -7
  17. package/js/hooks/useCourseProducts.ts +4 -4
  18. package/js/hooks/useDefaultOrganizationId/index.tsx +4 -4
  19. package/js/hooks/useOffering/index.ts +32 -0
  20. package/js/hooks/useTeacherCoursesSearch/index.tsx +4 -4
  21. package/js/hooks/useTeacherPendingContractsCount/index.ts +4 -4
  22. package/js/pages/DashboardCourses/index.spec.tsx +17 -14
  23. package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.spec.tsx +11 -8
  24. package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.tsx +6 -3
  25. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.spec.tsx +11 -11
  26. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.timer.spec.tsx +10 -10
  27. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +4 -4
  28. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +5 -5
  29. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.tsx +8 -8
  30. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +6 -6
  31. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.tsx +4 -4
  32. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +7 -7
  33. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx +5 -5
  34. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.spec.ts +21 -21
  35. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.ts +19 -13
  36. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +11 -11
  37. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +6 -6
  38. package/js/pages/TeacherDashboardContractsLayout/hooks/useHasContractToDownload/index.tsx +6 -3
  39. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.spec.tsx +16 -16
  40. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters/index.tsx +4 -4
  41. package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractsToSign.tsx +7 -4
  42. package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.spec.tsx +21 -21
  43. package/js/pages/TeacherDashboardCourseLearnersLayout/hooks/useCourseLearnersFilters/index.ts +5 -5
  44. package/js/pages/TeacherDashboardCourseLearnersLayout/index.spec.tsx +55 -55
  45. package/js/pages/TeacherDashboardCourseLearnersLayout/index.tsx +1 -1
  46. package/js/pages/TeacherDashboardCoursesLoader/index.spec.tsx +11 -11
  47. package/js/pages/TeacherDashboardOrganizationCourseLoader/index.spec.tsx +11 -11
  48. package/js/pages/TeacherDashboardTraining/TeacherDashboardTrainingLoader.tsx +7 -7
  49. package/js/pages/TeacherDashboardTraining/index.spec.tsx +25 -25
  50. package/js/pages/TeacherDashboardTraining/index.tsx +16 -12
  51. package/js/types/Joanie.ts +27 -20
  52. package/js/utils/test/factories/joanie.ts +14 -11
  53. package/js/utils/test/mockCourseProductWithOrder.ts +4 -4
  54. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.tsx +1 -1
  55. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +1 -1
  56. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +3 -3
  57. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +1 -1
  58. package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +4 -4
  59. package/js/widgets/Dashboard/components/DashboardItem/stories.mock.ts +1 -1
  60. package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.spec.tsx +23 -23
  61. package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.tsx +4 -4
  62. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.spec.tsx +20 -17
  63. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/index.tsx +22 -16
  64. package/js/widgets/Dashboard/components/TeacherDashboardCourseSidebar/utils.ts +4 -4
  65. package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.tsx +3 -3
  66. package/js/widgets/Dashboard/utils/teacherDashboardPaths.tsx +4 -4
  67. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/CourseProductItemFooter/index.tsx +14 -14
  68. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +105 -75
  69. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +6 -4
  70. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +27 -20
  71. package/js/widgets/SyllabusCourseRunsList/index.spec.tsx +8 -8
  72. package/package.json +1 -1
  73. package/js/hooks/useOffer/index.ts +0 -32
@@ -11,7 +11,7 @@ import {
11
11
  UserFactory,
12
12
  } from 'utils/test/factories/richie';
13
13
  import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
14
- import { OfferFactory, OrganizationFactory } from 'utils/test/factories/joanie';
14
+ import { OfferingFactory, OrganizationFactory } from 'utils/test/factories/joanie';
15
15
  import { createTestQueryClient } from 'utils/test/createTestQueryClient';
16
16
  import { expectNoSpinner } from 'utils/test/expectSpinner';
17
17
  import { DashboardBreadcrumbsProvider } from 'widgets/Dashboard/contexts/DashboardBreadcrumbsContext';
@@ -46,9 +46,9 @@ describe('components/TeacherDashboardTrainingLoader', () => {
46
46
  });
47
47
 
48
48
  it('should render TeacherDashboardTrainingLoader page', async () => {
49
- const offer = OfferFactory().one();
50
- fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offer_id=${offer.id}`, []);
51
- fetchMock.get(`https://joanie.endpoint/api/v1.0/offers/${offer.id}/`, offer);
49
+ const offering = OfferingFactory().one();
50
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/?offering_id=${offering.id}`, []);
51
+ fetchMock.get(`https://joanie.endpoint/api/v1.0/offerings/${offering.id}/`, offering);
52
52
 
53
53
  const user = UserFactory().one();
54
54
  render(
@@ -61,12 +61,12 @@ describe('components/TeacherDashboardTrainingLoader', () => {
61
61
  router={createMemoryRouter(
62
62
  [
63
63
  {
64
- path: ':offerId',
64
+ path: ':offeringId',
65
65
  element: <TeacherDashboardTrainingLoader />,
66
66
  },
67
67
  ],
68
68
  {
69
- initialEntries: [`/${offer.id}`],
69
+ initialEntries: [`/${offering.id}`],
70
70
  },
71
71
  )}
72
72
  />
@@ -82,10 +82,10 @@ describe('components/TeacherDashboardTrainingLoader', () => {
82
82
  await expectNoSpinner('Loading course...');
83
83
 
84
84
  nbApiCalls += 1; // organizations api call
85
- nbApiCalls += 1; // offers api call
85
+ nbApiCalls += 1; // offerings api call
86
86
  const calledUrls = fetchMock.calls().map((call) => call[0]);
87
87
  expect(calledUrls).toHaveLength(nbApiCalls);
88
- expect(calledUrls).toContain(`https://joanie.endpoint/api/v1.0/offers/${offer.id}/`);
88
+ expect(calledUrls).toContain(`https://joanie.endpoint/api/v1.0/offerings/${offering.id}/`);
89
89
 
90
90
  // main titles
91
91
  expect(
@@ -94,28 +94,28 @@ describe('components/TeacherDashboardTrainingLoader', () => {
94
94
  }),
95
95
  ).toBeInTheDocument();
96
96
 
97
- expect(screen.getAllByRole('heading', { name: capitalize(offer.product.title) })).toHaveLength(
98
- 2,
99
- );
97
+ expect(
98
+ screen.getAllByRole('heading', { name: capitalize(offering.product.title) }),
99
+ ).toHaveLength(2);
100
100
 
101
- const nbCourseRun = offer.product.target_courses.reduce(
101
+ const nbCourseRun = offering.product.target_courses.reduce(
102
102
  (acc, course) => acc + course.course_runs.length,
103
103
  0,
104
104
  );
105
105
  expect(screen.getAllByRole('link', { name: 'Go to course area' })).toHaveLength(nbCourseRun);
106
106
  });
107
107
 
108
- it('should fetch offer with organization id if there is one in the path', async () => {
108
+ it('should fetch offering with organization id if there is one in the path', async () => {
109
109
  const organization = OrganizationFactory().one();
110
- const offer = OfferFactory({
110
+ const offering = OfferingFactory({
111
111
  organizations: [organization],
112
112
  }).one();
113
113
  fetchMock.get(
114
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offers/${offer.id}/`,
115
- offer,
114
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/${offering.id}/`,
115
+ offering,
116
116
  );
117
117
  fetchMock.get(
118
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offer_id=${offer.id}&signature_state=half_signed&page=1&page_size=25`,
118
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?offering_id=${offering.id}&signature_state=half_signed&page=1&page_size=25`,
119
119
  [],
120
120
  );
121
121
 
@@ -130,12 +130,12 @@ describe('components/TeacherDashboardTrainingLoader', () => {
130
130
  router={createMemoryRouter(
131
131
  [
132
132
  {
133
- path: '/:organizationId/:offerId',
133
+ path: '/:organizationId/:offeringId',
134
134
  element: <TeacherDashboardTrainingLoader />,
135
135
  },
136
136
  ],
137
137
  {
138
- initialEntries: [`/${organization.id}/${offer.id}`],
138
+ initialEntries: [`/${organization.id}/${offering.id}`],
139
139
  },
140
140
  )}
141
141
  />
@@ -151,11 +151,11 @@ describe('components/TeacherDashboardTrainingLoader', () => {
151
151
  await expectNoSpinner('Loading course...');
152
152
 
153
153
  nbApiCalls += 1; // contracts api call
154
- nbApiCalls += 1; // offers api call
154
+ nbApiCalls += 1; // offerings api call
155
155
  const calledUrls = fetchMock.calls().map((call) => call[0]);
156
156
  expect(calledUrls).toHaveLength(nbApiCalls);
157
157
  expect(calledUrls).toContain(
158
- `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offers/${offer.id}/`,
158
+ `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/offerings/${offering.id}/`,
159
159
  );
160
160
 
161
161
  // main titles
@@ -165,11 +165,11 @@ describe('components/TeacherDashboardTrainingLoader', () => {
165
165
  }),
166
166
  ).toBeInTheDocument();
167
167
 
168
- expect(screen.getAllByRole('heading', { name: capitalize(offer.product.title) })).toHaveLength(
169
- 2,
170
- );
168
+ expect(
169
+ screen.getAllByRole('heading', { name: capitalize(offering.product.title) }),
170
+ ).toHaveLength(2);
171
171
 
172
- const nbCourseRun = offer.product.target_courses.reduce(
172
+ const nbCourseRun = offering.product.target_courses.reduce(
173
173
  (acc, course) => acc + course.course_runs.length,
174
174
  0,
175
175
  );
@@ -6,33 +6,33 @@ import { DashboardLayout } from 'widgets/Dashboard/components/DashboardLayout';
6
6
  import { DashboardCard } from 'widgets/Dashboard/components/DashboardCard';
7
7
  import { Icon, IconTypeEnum } from 'components/Icon';
8
8
  import Banner, { BannerType } from 'components/Banner';
9
- import { Offer } from 'types/Joanie';
9
+ import { Offering } from 'types/Joanie';
10
10
 
11
11
  const messages = defineMessages({
12
- errorNoOffer: {
12
+ errorNoOffering: {
13
13
  defaultMessage: "This product doesn't exist",
14
- description: 'Message displayed when requested offer is not found',
15
- id: 'components.TeacherDashboardTraining.errorNoOffer',
14
+ description: 'Message displayed when requested offering is not found',
15
+ id: 'components.TeacherDashboardTraining.errorNoOffering',
16
16
  },
17
17
  });
18
18
 
19
19
  interface TeacherDashboardTrainingProps {
20
- offer: Offer;
20
+ offering: Offering;
21
21
  }
22
22
 
23
- export const TeacherDashboardTraining = ({ offer }: TeacherDashboardTrainingProps) => {
23
+ export const TeacherDashboardTraining = ({ offering }: TeacherDashboardTrainingProps) => {
24
24
  const intl = useIntl();
25
- return offer ? (
25
+ return offering ? (
26
26
  <div className="teacher-course-page">
27
27
  <DashboardCard
28
28
  className="icon-arrow-right-rounded"
29
29
  header={
30
30
  <div>
31
31
  <div className="dashboard__title_container--small">
32
- <h2 className="dashboard__title--large">{capitalize(offer.product.title)}</h2>
32
+ <h2 className="dashboard__title--large">{capitalize(offering.product.title)}</h2>
33
33
  </div>
34
- {offer.product.description && (
35
- <div className="dashboard__quote">{offer.product.description}</div>
34
+ {offering.product.description && (
35
+ <div className="dashboard__quote">{offering.product.description}</div>
36
36
  )}
37
37
  </div>
38
38
  }
@@ -40,7 +40,7 @@ export const TeacherDashboardTraining = ({ offer }: TeacherDashboardTrainingProp
40
40
  fullWidth
41
41
  />
42
42
  <DashboardLayout.NestedSection>
43
- {offer.product.target_courses.map((course) => (
43
+ {offering.product.target_courses.map((course) => (
44
44
  <DashboardLayout.Section key={`course_target_${course.code}`}>
45
45
  <DashboardCard
46
46
  className="icon-arrow-right-rounded"
@@ -62,7 +62,11 @@ export const TeacherDashboardTraining = ({ offer }: TeacherDashboardTrainingProp
62
62
  </DashboardLayout.NestedSection>
63
63
  </div>
64
64
  ) : (
65
- <Banner message={intl.formatMessage(messages.errorNoOffer)} type={BannerType.ERROR} rounded />
65
+ <Banner
66
+ message={intl.formatMessage(messages.errorNoOffering)}
67
+ type={BannerType.ERROR}
68
+ rounded
69
+ />
66
70
  );
67
71
  };
68
72
 
@@ -38,7 +38,7 @@ export interface Organization {
38
38
  }
39
39
 
40
40
  export interface OrganizationResourceQuery extends ResourcesQuery {
41
- offer_id?: Offer['id'];
41
+ offering_id?: Offering['id'];
42
42
  }
43
43
 
44
44
  export interface ContractDefinition {
@@ -174,7 +174,7 @@ export interface DefinitionResourcesProduct {
174
174
  contract_definition_id: Nullable<ContractDefinition['id']>;
175
175
  }
176
176
 
177
- export interface OfferLight {
177
+ export interface OfferingLight {
178
178
  id: string;
179
179
  course: CourseLight;
180
180
  organizations: Organization[];
@@ -182,18 +182,25 @@ export interface OfferLight {
182
182
  created_on: string;
183
183
  }
184
184
 
185
- export interface Offer extends OfferLight {
186
- is_withdrawable: boolean;
185
+ export interface OfferingRule {
187
186
  discounted_price: Nullable<number>;
188
187
  discount_rate: Nullable<number>;
189
188
  discount_amount: Nullable<number>;
190
189
  discount_start: Nullable<string>;
191
190
  discount_end: Nullable<string>;
192
191
  description: Nullable<string>;
193
- nb_seats_available: Nullable<number>;
194
- seats: Nullable<number>;
192
+ nb_available_seats: Nullable<number>;
193
+ has_seat_limit: boolean;
194
+ has_seats_left: boolean;
195
+ }
196
+
197
+ export interface Offering extends OfferingLight {
198
+ is_withdrawable: boolean;
199
+ rules: OfferingRule;
195
200
  }
196
- export function isOffer(entity: CourseListItem | OfferLight | RichieCourse): entity is OfferLight {
201
+ export function isOffering(
202
+ entity: CourseListItem | OfferingLight | RichieCourse,
203
+ ): entity is OfferingLight {
197
204
  return 'course' in entity && 'product' in entity;
198
205
  }
199
206
 
@@ -238,7 +245,7 @@ export interface Enrollment {
238
245
  was_created_by_order: boolean;
239
246
  created_on: string;
240
247
  orders: OrderEnrollment[];
241
- offers: Offer[];
248
+ offerings: Offering[];
242
249
  certificate_id: Nullable<string>;
243
250
  }
244
251
  export const isEnrollment = (obj: unknown | Enrollment | OpenEdXEnrollment): obj is Enrollment => {
@@ -252,7 +259,7 @@ export const isEnrollment = (obj: unknown | Enrollment | OpenEdXEnrollment): obj
252
259
  'was_created_by_order' in obj &&
253
260
  'created_on' in obj &&
254
261
  'orders' in obj &&
255
- 'offers' in obj &&
262
+ 'offerings' in obj &&
256
263
  'certificate_id' in obj
257
264
  );
258
265
  };
@@ -402,7 +409,7 @@ export interface NestedCourseOrder {
402
409
 
403
410
  export interface CourseOrderResourceQuery extends PaginatedResourceQuery {
404
411
  course_id?: CourseListItem['id'];
405
- offer_id?: Offer['id'];
412
+ offering_id?: Offering['id'];
406
413
  organization_id?: Organization['id'];
407
414
  product_id?: Product['id'];
408
415
  }
@@ -537,8 +544,8 @@ export interface CourseProductQueryFilters extends ResourcesQuery {
537
544
  id?: Product['id'];
538
545
  course_id?: CourseListItem['id'];
539
546
  }
540
- export interface OfferQueryFilters extends PaginatedResourceQuery {
541
- id?: Offer['id'];
547
+ export interface OfferingQueryFilters extends PaginatedResourceQuery {
548
+ id?: Offering['id'];
542
549
  organization_id?: Organization['id'];
543
550
  product_type?: ProductType;
544
551
  query?: string;
@@ -551,7 +558,7 @@ export enum ContractState {
551
558
  }
552
559
  export interface ContractResourceQuery extends PaginatedResourceQuery {
553
560
  organization_id?: Organization['id'];
554
- offer_id?: Offer['id'];
561
+ offering_id?: Offering['id'];
555
562
  contract_ids?: Contract['id'][];
556
563
  signature_state?: ContractState;
557
564
  }
@@ -559,7 +566,7 @@ export interface ContractResourceQuery extends PaginatedResourceQuery {
559
566
  export interface OrganizationContractSignatureLinksFilters {
560
567
  contracts_ids?: string[];
561
568
  organization_id: Organization['id'];
562
- offer_ids?: Offer['id'][];
569
+ offering_ids?: Offering['id'][];
563
570
  }
564
571
 
565
572
  export interface ContractInvitationLinkResponse {
@@ -653,10 +660,10 @@ interface APIUser {
653
660
  check: (id: string) => Promise<Response>;
654
661
  create: ({
655
662
  organization_id,
656
- offer_id,
663
+ offering_id,
657
664
  }: {
658
665
  organization_id?: Organization['id'];
659
- offer_id?: Offer['id'];
666
+ offering_id?: Offering['id'];
660
667
  }) => Promise<{ url: string }>;
661
668
  get: (id: string) => Promise<File>;
662
669
  };
@@ -672,7 +679,7 @@ export interface API {
672
679
  ? Promise<Nullable<CourseListItem>>
673
680
  : Promise<PaginatedResponse<CourseListItem>>;
674
681
  products: {
675
- get(filters?: CourseProductQueryFilters): Promise<Nullable<Offer>>;
682
+ get(filters?: CourseProductQueryFilters): Promise<Nullable<Offering>>;
676
683
  paymentSchedule: {
677
684
  get(filters?: CourseProductQueryFilters): Promise<Nullable<PaymentSchedule>>;
678
685
  };
@@ -705,12 +712,12 @@ export interface API {
705
712
  filters?: CourseRunFilters,
706
713
  ): CourseRunFilters extends { id: string } ? Promise<Nullable<CourseRun>> : Promise<CourseRun>;
707
714
  };
708
- offers: {
715
+ offerings: {
709
716
  get<Filters extends PaginatedResourceQuery = PaginatedResourceQuery>(
710
717
  filters?: Filters,
711
718
  ): Filters extends { id: string }
712
- ? Promise<Nullable<Offer>>
713
- : Promise<PaginatedResponse<OfferLight>>;
719
+ ? Promise<Nullable<Offering>>
720
+ : Promise<PaginatedResponse<OfferingLight>>;
714
721
  };
715
722
  contractDefinitions: {
716
723
  previewTemplate(id: string): Promise<File>;
@@ -12,7 +12,7 @@ import {
12
12
  CourseLight,
13
13
  CourseListItem,
14
14
  CourseProduct,
15
- Offer,
15
+ Offering,
16
16
  CourseRun,
17
17
  CredentialOrder,
18
18
  CredentialProduct,
@@ -89,7 +89,7 @@ export const EnrollmentFactory = factory((): Enrollment => {
89
89
  id: faker.string.uuid(),
90
90
  course_run: CourseRunWithCourseFactory().one(),
91
91
  is_active: true,
92
- offers: OfferFactory().many(1),
92
+ offerings: OfferingFactory().many(1),
93
93
  state: EnrollmentState.SET,
94
94
  was_created_by_order: false,
95
95
  created_on: faker.date.past({ years: 1 }).toISOString(),
@@ -309,7 +309,7 @@ export const NestedCourseOrderFactory = factory((): NestedCourseOrder => {
309
309
  };
310
310
  });
311
311
 
312
- export const OfferFactory = factory((): Offer => {
312
+ export const OfferingFactory = factory((): Offering => {
313
313
  return {
314
314
  id: faker.string.uuid(),
315
315
  created_on: faker.date.past().toISOString(),
@@ -317,14 +317,17 @@ export const OfferFactory = factory((): Offer => {
317
317
  product: ProductFactory().one(),
318
318
  organizations: OrganizationFactory().many(1),
319
319
  is_withdrawable: true,
320
- discounted_price: null,
321
- discount_rate: null,
322
- discount_amount: null,
323
- discount_start: null,
324
- discount_end: null,
325
- description: null,
326
- seats: null,
327
- nb_seats_available: null,
320
+ rules: {
321
+ discounted_price: null,
322
+ discount_rate: null,
323
+ discount_amount: null,
324
+ discount_start: null,
325
+ discount_end: null,
326
+ description: null,
327
+ nb_available_seats: null,
328
+ has_seat_limit: false,
329
+ has_seats_left: true,
330
+ },
328
331
  };
329
332
  });
330
333
 
@@ -3,14 +3,14 @@ import { CredentialOrder } from 'types/Joanie';
3
3
  import {
4
4
  ContractDefinitionFactory,
5
5
  CourseFactory,
6
- OfferFactory,
6
+ OfferingFactory,
7
7
  ProductFactory,
8
8
  } from 'utils/test/factories/joanie';
9
9
 
10
10
  export const mockCourseProductWithOrder = (order: CredentialOrder) => {
11
11
  const courseCode = order.course.code;
12
12
  const productId = order.product_id;
13
- const offer = OfferFactory({
13
+ const offering = OfferingFactory({
14
14
  product: ProductFactory({
15
15
  id: order.product_id,
16
16
  contract_definition: order.contract ? ContractDefinitionFactory().one() : undefined,
@@ -22,7 +22,7 @@ export const mockCourseProductWithOrder = (order: CredentialOrder) => {
22
22
 
23
23
  fetchMock.get(
24
24
  `https://joanie.endpoint/api/v1.0/courses/${courseCode}/products/${productId}/`,
25
- offer,
25
+ offering,
26
26
  );
27
- return offer;
27
+ return offering;
28
28
  };
@@ -33,7 +33,7 @@ export const DashboardItemEnrollment = ({ enrollment }: DashboardItemCourseRunPr
33
33
  </div>
34
34
  </div>,
35
35
  ];
36
- enrollment.offers.forEach(({ product, is_withdrawable }) => {
36
+ enrollment.offerings.forEach(({ product, is_withdrawable }) => {
37
37
  if (isCertificateProduct(product)) {
38
38
  partialFooterList.push(
39
39
  <ProductCertificateFooter
@@ -249,7 +249,7 @@ describe('<ProductCertificateFooter/>', () => {
249
249
  course,
250
250
  }).one(),
251
251
  }).one();
252
- enrollment.offers[0].product = CertificateProductFactory().one();
252
+ enrollment.offerings[0].product = CertificateProductFactory().one();
253
253
 
254
254
  fetchMock.get(
255
255
  `https://joanie.endpoint/api/v1.0/enrollments/?was_created_by_order=false&is_active=true&page=1&page_size=${PER_PAGE.useOrdersEnrollments}`,
@@ -67,15 +67,15 @@ export const DashboardItemOrder = ({
67
67
  }: DashboardItemOrderProps) => {
68
68
  const { course } = order;
69
69
  const intl = useIntl();
70
- const { item: offer } = useCourseProduct({
70
+ const { item: offering } = useCourseProduct({
71
71
  product_id: order.product_id,
72
72
  course_id: course.code,
73
73
  });
74
- const { product } = offer || {};
74
+ const { product } = offering || {};
75
75
  const needsSignature = OrderHelper.orderNeedsSignature(order);
76
76
  const needsPaymentMethod = order.state === OrderState.TO_SAVE_PAYMENT_METHOD;
77
77
  const isActive = OrderHelper.isActive(order);
78
- const isProductPurchasable = ProductHelper.isPurchasable(offer?.product);
78
+ const isProductPurchasable = ProductHelper.isPurchasable(offering?.product);
79
79
  const isNotResumable = !isActive && !isProductPurchasable;
80
80
  const canEnroll = OrderHelper.allowEnrollment(order);
81
81
 
@@ -57,7 +57,7 @@ describe('<DashboardItemOrder/> Contract', () => {
57
57
  contract: ContractFactory({ student_signed_on: null }).one(),
58
58
  }).one();
59
59
 
60
- // learner dashboard course page do one call to offer per order
60
+ // learner dashboard course page do one call to offering per order
61
61
  const { product } = mockCourseProductWithOrder(order);
62
62
 
63
63
  // overwrite useOmniscientOrders call
@@ -94,7 +94,7 @@ const Installment = ({ order }: Props) => {
94
94
 
95
95
  const PaymentMethodManager = ({ order }: Props) => {
96
96
  const needsPaymentMethod = order.state === OrderState.TO_SAVE_PAYMENT_METHOD;
97
- const { item: offer, states } = useCourseProduct({
97
+ const { item: offering, states } = useCourseProduct({
98
98
  course_id: order.course.code,
99
99
  product_id: order.product_id,
100
100
  });
@@ -118,9 +118,9 @@ const PaymentMethodManager = ({ order }: Props) => {
118
118
  )}
119
119
  <SaleTunnel
120
120
  {...modal}
121
- product={offer.product as CredentialProduct}
122
- course={offer.course}
123
- isWithdrawable={offer.is_withdrawable}
121
+ product={offering.product as CredentialProduct}
122
+ course={offering.course}
123
+ isWithdrawable={offering.is_withdrawable}
124
124
  />
125
125
  </>
126
126
  );
@@ -25,6 +25,6 @@ export const enrollment: Enrollment = {
25
25
  },
26
26
  languages: ['en'],
27
27
  },
28
- offers: [],
28
+ offerings: [],
29
29
  certificate_id: null,
30
30
  };
@@ -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 offerId are given', () => {
31
+ it('should render a ContractNavLink with route and label when neither organizationId and offeringId 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
- offerId: undefined,
48
+ offeringId: undefined,
49
49
  },
50
50
  {
51
51
  organizationId: faker.string.uuid(),
52
- offerId: faker.string.uuid(),
52
+ offeringId: faker.string.uuid(),
53
53
  },
54
54
  {
55
55
  organizationId: undefined,
56
- offerId: faker.string.uuid(),
56
+ offeringId: faker.string.uuid(),
57
57
  },
58
58
  {
59
59
  organizationId: undefined,
60
- offerId: undefined,
60
+ offeringId: undefined,
61
61
  },
62
62
  ])(
63
- 'should never render Badge for organizationId: $organizationId and courseProductId: $offerId',
64
- async ({ organizationId, offerId }) => {
63
+ 'should never render Badge for organizationId: $organizationId and courseProductId: $offeringId',
64
+ async ({ organizationId, offeringId }) => {
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 (offerId) {
70
+ if (offeringId) {
71
71
  contractQueryParams = {
72
- offer_id: offerId,
72
+ offering_id: offeringId,
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
- offerId={offerId}
97
+ offeringId={offeringId}
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
- offerId: undefined,
115
+ offeringId: undefined,
116
116
  nbContractsToSign: 1,
117
117
  expectedBadgeCount: 1,
118
118
  },
119
119
  {
120
120
  organizationId: faker.string.uuid(),
121
- offerId: faker.string.uuid(),
121
+ offeringId: faker.string.uuid(),
122
122
  nbContractsToSign: 1,
123
123
  expectedBadgeCount: 1,
124
124
  },
125
125
  {
126
126
  organizationId: undefined,
127
- offerId: faker.string.uuid(),
127
+ offeringId: faker.string.uuid(),
128
128
  nbContractsToSign: 1,
129
129
  expectedBadgeCount: undefined,
130
130
  },
131
131
  {
132
132
  organizationId: undefined,
133
- offerId: undefined,
133
+ offeringId: undefined,
134
134
  nbContractsToSign: 1,
135
135
  expectedBadgeCount: undefined,
136
136
  },
@@ -138,39 +138,39 @@ describe('<ContractNavLink />', () => {
138
138
  // with 0 contracts to sign
139
139
  {
140
140
  organizationId: faker.string.uuid(),
141
- offerId: undefined,
141
+ offeringId: undefined,
142
142
  nbContractsToSign: 0,
143
143
  expectedBadgeCount: undefined,
144
144
  },
145
145
  {
146
146
  organizationId: faker.string.uuid(),
147
- offerId: faker.string.uuid(),
147
+ offeringId: faker.string.uuid(),
148
148
  nbContractsToSign: 0,
149
149
  expectedBadgeCount: undefined,
150
150
  },
151
151
  {
152
152
  organizationId: undefined,
153
- offerId: faker.string.uuid(),
153
+ offeringId: faker.string.uuid(),
154
154
  nbContractsToSign: 0,
155
155
  expectedBadgeCount: undefined,
156
156
  },
157
157
  {
158
158
  organizationId: undefined,
159
- offerId: undefined,
159
+ offeringId: 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: $offerId',
165
- async ({ nbContractsToSign, organizationId, offerId, expectedBadgeCount }) => {
164
+ 'should render Badge (count: $expectedBadgeCount) for nb contracts to sign: $nbContractsToSign, organizationId: $organizationId and courseProductId: $offeringId',
165
+ async ({ nbContractsToSign, organizationId, offeringId, expectedBadgeCount }) => {
166
166
  let contractQueryParams: ContractResourceQuery = {
167
167
  signature_state: ContractState.LEARNER_SIGNED,
168
168
  page: 1,
169
169
  page_size: PER_PAGE.teacherContractList,
170
170
  };
171
- if (offerId) {
171
+ if (offeringId) {
172
172
  contractQueryParams = {
173
- offer_id: offerId,
173
+ offering_id: offeringId,
174
174
  ...contractQueryParams,
175
175
  };
176
176
  }
@@ -194,7 +194,7 @@ describe('<ContractNavLink />', () => {
194
194
  label: 'My contract navigation link',
195
195
  }}
196
196
  organizationId={organizationId}
197
- offerId={offerId}
197
+ offeringId={offeringId}
198
198
  />,
199
199
  );
200
200