richie-education 3.1.3-dev15 → 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 +2 -2
  9. package/js/components/SaleTunnel/index.full-process.spec.tsx +3 -3
  10. package/js/components/SaleTunnel/index.spec.tsx +5 -5
  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 +21 -19
  52. package/js/utils/test/factories/joanie.ts +3 -3
  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 -10
  68. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +87 -63
  69. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +2 -2
  70. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +24 -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
package/js/api/joanie.ts CHANGED
@@ -127,8 +127,8 @@ export const getRoutes = () => {
127
127
  },
128
128
  organizations: {
129
129
  get: `${baseUrl}/organizations/:id/`,
130
- offers: {
131
- get: `${baseUrl}/organizations/:organization_id/offers/:id/`,
130
+ offerings: {
131
+ get: `${baseUrl}/organizations/:organization_id/offerings/:id/`,
132
132
  },
133
133
  courses: {
134
134
  get: `${baseUrl}/organizations/:organization_id/courses/:id/`,
@@ -156,8 +156,8 @@ export const getRoutes = () => {
156
156
  courseRuns: {
157
157
  get: `${baseUrl}/course-runs/:id/`,
158
158
  },
159
- offers: {
160
- get: `${baseUrl}/offers/:id/`,
159
+ offerings: {
160
+ get: `${baseUrl}/offerings/:id/`,
161
161
  },
162
162
  contractDefinitions: {
163
163
  previewTemplate: `${baseUrl}/contract_definitions/:id/preview_template/`,
@@ -470,12 +470,12 @@ const API = (): Joanie.API => {
470
470
  ).then(checkStatus);
471
471
  },
472
472
  },
473
- offers: {
474
- get: (filters?: Joanie.OfferQueryFilters) => {
473
+ offerings: {
474
+ get: (filters?: Joanie.OfferingQueryFilters) => {
475
475
  return fetchWithJWT(
476
476
  filters?.organization_id
477
- ? buildApiUrl(ROUTES.organizations.offers.get, filters)
478
- : buildApiUrl(ROUTES.offers.get, filters),
477
+ ? buildApiUrl(ROUTES.organizations.offerings.get, filters)
478
+ : buildApiUrl(ROUTES.offerings.get, filters),
479
479
  ).then(checkStatus);
480
480
  },
481
481
  },
@@ -6,10 +6,10 @@ import { IntlProvider } from 'react-intl';
6
6
  import fetchMock from 'fetch-mock';
7
7
  import { QueryStateFactory } from 'utils/test/factories/reactQuery';
8
8
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
9
- import { ContractFactory, OfferFactory, OrganizationFactory } from 'utils/test/factories/joanie';
9
+ import { ContractFactory, OfferingFactory, OrganizationFactory } from 'utils/test/factories/joanie';
10
10
  import { createTestQueryClient } from 'utils/test/createTestQueryClient';
11
11
  import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
12
- import { isOffer } from 'types/Joanie';
12
+ import { isOffering } from 'types/Joanie';
13
13
  import { Props } from './AbstractContractFrame';
14
14
  import { OrganizationContractFrame } from '.';
15
15
 
@@ -73,28 +73,29 @@ describe('OrganizationContractFrame', () => {
73
73
 
74
74
  it.each([
75
75
  {
76
- label: 'contractList: undefined, offer: undefined',
76
+ label: 'contractList: undefined, offering: undefined',
77
77
  contractList: undefined,
78
- offer: undefined,
78
+ offering: undefined,
79
79
  },
80
80
  {
81
- label: 'contractList: 2 Contract, offer: undefined',
81
+ label: 'contractList: 2 Contract, offering: undefined',
82
82
  contractList: ContractFactory().many(2),
83
- offer: undefined,
83
+ offering: undefined,
84
84
  },
85
85
  {
86
- label: 'contractList: undefined, offer: one Offer',
86
+ label: 'contractList: undefined, offering: one Offering',
87
87
  contractList: undefined,
88
- offer: OfferFactory().one(),
88
+ offering: OfferingFactory().one(),
89
89
  },
90
90
  ])(
91
91
  'should implement AbstractContractFrame for organization and $label',
92
- async ({ contractList, offer }) => {
92
+ async ({ contractList, offering }) => {
93
93
  const organization = OrganizationFactory().one();
94
94
  const contracts = contractList || ContractFactory().many(2);
95
95
  const isOpen = faker.datatype.boolean();
96
96
 
97
- const invitationLinkQueryString = offer && isOffer(offer) ? `?offer_ids=${offer.id}` : '';
97
+ const invitationLinkQueryString =
98
+ offering && isOffering(offering) ? `?offering_ids=${offering.id}` : '';
98
99
  const expectedUrls = {
99
100
  getInvitationLink: `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts-signature-link/${invitationLinkQueryString}`,
100
101
  checkSignature: `https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?id=${contracts[0].id}&id=${contracts[1].id}`,
@@ -126,7 +127,7 @@ describe('OrganizationContractFrame', () => {
126
127
  <Wrapper client={client}>
127
128
  <OrganizationContractFrame
128
129
  organizationId={organization.id}
129
- offerIds={offer ? [offer.id] : undefined}
130
+ offeringIds={offering ? [offering.id] : undefined}
130
131
  isOpen={isOpen}
131
132
  onDone={handleDone}
132
133
  onClose={handleClose}
@@ -4,17 +4,17 @@ import { useJoanieApi } from 'contexts/JoanieApiContext';
4
4
  import AbstractContractFrame, {
5
5
  AbstractProps,
6
6
  } from 'components/ContractFrame/AbstractContractFrame';
7
- import { Contract, Offer } from 'types/Joanie';
7
+ import { Contract, Offering } from 'types/Joanie';
8
8
 
9
9
  interface Props extends AbstractProps {
10
10
  contractIds?: Contract['id'][];
11
11
  organizationId: string;
12
- offerIds?: Offer['id'][];
12
+ offeringIds?: Offering['id'][];
13
13
  }
14
14
 
15
15
  const OrganizationContractFrame = ({
16
16
  organizationId,
17
- offerIds = [],
17
+ offeringIds = [],
18
18
  contractIds,
19
19
  onDone,
20
20
  ...props
@@ -29,7 +29,7 @@ const OrganizationContractFrame = ({
29
29
  be signed. We need to keep track of these ids to check if all contracts have been signed.
30
30
  */
31
31
  const response = await api.organizations.contracts.getSignatureLinks({
32
- offer_ids: offerIds,
32
+ offering_ids: offeringIds,
33
33
  organization_id: organizationId,
34
34
  contracts_ids: contractIds,
35
35
  });
@@ -6,18 +6,23 @@ import {
6
6
  Course as RichieCourse,
7
7
  isRichieCourse,
8
8
  } from 'types/Course';
9
- import { CourseListItem as JoanieCourse, OfferLight, isOffer, ProductType } from 'types/Joanie';
9
+ import {
10
+ CourseListItem as JoanieCourse,
11
+ OfferingLight,
12
+ isOffering,
13
+ ProductType,
14
+ } from 'types/Joanie';
10
15
  import { TeacherDashboardPaths } from 'widgets/Dashboard/utils/teacherDashboardPaths';
11
16
  import { CourseGlimpseCourse } from '.';
12
17
 
13
- const getCourseGlimpsePropsFromOffer = (
14
- offer: OfferLight,
18
+ const getCourseGlimpsePropsFromOffering = (
19
+ offering: OfferingLight,
15
20
  intl: IntlShape,
16
21
  organizationId?: string,
17
22
  ): CourseGlimpseCourse => {
18
23
  const courseRouteParams = {
19
- courseId: offer.course.id,
20
- offerId: offer.id,
24
+ courseId: offering.course.id,
25
+ offeringId: offering.id,
21
26
  };
22
27
  const courseRoute = organizationId
23
28
  ? generatePath(TeacherDashboardPaths.ORGANIZATION_PRODUCT, {
@@ -26,27 +31,28 @@ const getCourseGlimpsePropsFromOffer = (
26
31
  })
27
32
  : generatePath(TeacherDashboardPaths.COURSE_PRODUCT, courseRouteParams);
28
33
  return {
29
- id: offer.id,
30
- code: offer.course.code,
31
- title: offer.product.title,
32
- cover_image: offer.course.cover
34
+ id: offering.id,
35
+ code: offering.course.code,
36
+ title: offering.product.title,
37
+ cover_image: offering.course.cover
33
38
  ? {
34
- src: offer.course.cover.src,
39
+ src: offering.course.cover.src,
35
40
  }
36
41
  : null,
37
42
  organization: {
38
- title: offer.organizations[0].title,
39
- image: offer.organizations[0].logo || null,
43
+ title: offering.organizations[0].title,
44
+ image: offering.organizations[0].logo || null,
40
45
  },
41
- product_id: offer.product.id,
46
+ product_id: offering.product.id,
42
47
  course_route: courseRoute,
43
- state: offer.product.state,
48
+ state: offering.product.state,
44
49
  certificate_offer:
45
- offer.product.type === ProductType.CERTIFICATE ? CourseCertificateOffer.PAID : null,
46
- offer: offer.product.type === ProductType.CREDENTIAL ? CourseOffer.PAID : null,
47
- certificate_price: offer.product.type === ProductType.CERTIFICATE ? offer.product.price : null,
48
- price: offer.product.type === ProductType.CREDENTIAL ? offer.product.price : null,
49
- price_currency: offer.product.price_currency,
50
+ offering.product.type === ProductType.CERTIFICATE ? CourseCertificateOffer.PAID : null,
51
+ offer: offering.product.type === ProductType.CREDENTIAL ? CourseOffer.PAID : null,
52
+ certificate_price:
53
+ offering.product.type === ProductType.CERTIFICATE ? offering.product.price : null,
54
+ price: offering.product.type === ProductType.CREDENTIAL ? offering.product.price : null,
55
+ price_currency: offering.product.price_currency,
50
56
  };
51
57
  };
52
58
 
@@ -112,12 +118,12 @@ const getCourseGlimpsePropsFromJoanieCourse = (
112
118
  };
113
119
 
114
120
  export const getCourseGlimpseProps = (
115
- course: RichieCourse | (JoanieCourse | OfferLight),
121
+ course: RichieCourse | (JoanieCourse | OfferingLight),
116
122
  intl?: IntlShape,
117
123
  organizationId?: string,
118
124
  ): CourseGlimpseCourse => {
119
- if (isOffer(course)) {
120
- return getCourseGlimpsePropsFromOffer(course, intl!, organizationId);
125
+ if (isOffering(course)) {
126
+ return getCourseGlimpsePropsFromOffering(course, intl!, organizationId);
121
127
  }
122
128
 
123
129
  if (isRichieCourse(course)) {
@@ -1,10 +1,10 @@
1
1
  import { IntlShape } from 'react-intl';
2
- import { OfferLight, CourseListItem as JoanieCourse } from 'types/Joanie';
2
+ import { OfferingLight, CourseListItem as JoanieCourse } from 'types/Joanie';
3
3
  import { Course as RichieCourse } from 'types/Course';
4
4
  import { CourseGlimpseCourse, getCourseGlimpseProps } from 'components/CourseGlimpse';
5
5
 
6
6
  export const getCourseGlimpseListProps = (
7
- courses: RichieCourse[] | (JoanieCourse | OfferLight)[],
7
+ courses: RichieCourse[] | (JoanieCourse | OfferingLight)[],
8
8
  intl?: IntlShape,
9
9
  organizationId?: string,
10
10
  ): CourseGlimpseCourse[] => {
@@ -42,7 +42,7 @@ const messages = defineMessages({
42
42
 
43
43
  interface PurchaseButtonPropsBase {
44
44
  product: Joanie.CredentialProduct | Joanie.CertificateProduct;
45
- offer?: Joanie.Offer;
45
+ offering?: Joanie.Offering;
46
46
  isWithdrawable: boolean;
47
47
  disabled?: boolean;
48
48
  className?: string;
@@ -66,7 +66,7 @@ interface CertificatePurchaseButtonProps extends PurchaseButtonPropsBase {
66
66
  const PurchaseButton = ({
67
67
  product,
68
68
  course,
69
- offer,
69
+ offering,
70
70
  enrollment,
71
71
  isWithdrawable,
72
72
  organizations,
@@ -140,7 +140,7 @@ const PurchaseButton = ({
140
140
  {...saleTunnelModal}
141
141
  product={product}
142
142
  organizations={organizations}
143
- offer={offer}
143
+ offering={offering}
144
144
  enrollment={enrollment}
145
145
  course={course}
146
146
  isWithdrawable={isWithdrawable}
@@ -10,7 +10,7 @@ import {
10
10
  } from 'react';
11
11
  import { SaleTunnelSponsors } from 'components/SaleTunnel/Sponsors/SaleTunnelSponsors';
12
12
  import { SaleTunnelProps } from 'components/SaleTunnel/index';
13
- import { Address, Offer, CreditCard, Order, OrderState, Product } from 'types/Joanie';
13
+ import { Address, Offering, CreditCard, Order, OrderState, Product } from 'types/Joanie';
14
14
  import useProductOrder from 'hooks/useProductOrder';
15
15
  import { SaleTunnelSuccess } from 'components/SaleTunnel/SaleTunnelSuccess';
16
16
  import WebAnalyticsAPIHandler from 'api/web-analytics';
@@ -26,7 +26,7 @@ export interface SaleTunnelContextType {
26
26
  order?: Order;
27
27
  product: Product;
28
28
  webAnalyticsEventKey: string;
29
- offer?: Offer;
29
+ offering?: Offering;
30
30
 
31
31
  // internal
32
32
  step: SaleTunnelStep;
@@ -114,7 +114,7 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
114
114
  webAnalyticsEventKey: props.eventKey,
115
115
  order,
116
116
  product: props.product,
117
- offer: props.offer,
117
+ offering: props.offering,
118
118
  props,
119
119
  billingAddress,
120
120
  setBillingAddress,
@@ -101,7 +101,7 @@ const Email = () => {
101
101
  };
102
102
 
103
103
  const Total = () => {
104
- const { product, offer } = useSaleTunnelContext();
104
+ const { product, offering } = useSaleTunnelContext();
105
105
  return (
106
106
  <div className="sale-tunnel__total">
107
107
  <div className="sale-tunnel__total__amount mt-t" data-testid="sale-tunnel__total__amount">
@@ -110,7 +110,7 @@ const Total = () => {
110
110
  </div>
111
111
  <div className="block-title">
112
112
  <FormattedNumber
113
- value={offer?.rules.discounted_price || product.price}
113
+ value={offering?.rules.discounted_price || product.price}
114
114
  style="currency"
115
115
  currency={product.price_currency}
116
116
  />
@@ -15,7 +15,7 @@ import CourseProductItem from 'widgets/SyllabusCourseRunsList/components/CourseP
15
15
  import {
16
16
  AddressFactory,
17
17
  ContractFactory,
18
- OfferFactory,
18
+ OfferingFactory,
19
19
  CredentialOrderFactory,
20
20
  CreditCardFactory,
21
21
  PaymentFactory,
@@ -99,7 +99,7 @@ describe('SaleTunnel', () => {
99
99
  */
100
100
  const course = PacedCourseFactory().one();
101
101
  const product = ProductFactory().one();
102
- const offer = OfferFactory({
102
+ const offering = OfferingFactory({
103
103
  course,
104
104
  product,
105
105
  is_withdrawable: false,
@@ -108,7 +108,7 @@ describe('SaleTunnel', () => {
108
108
 
109
109
  fetchMock.get(
110
110
  `https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/`,
111
- offer,
111
+ offering,
112
112
  );
113
113
  fetchMock.get(
114
114
  `https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/payment-schedule/`,
@@ -15,7 +15,7 @@ import {
15
15
  AddressFactory,
16
16
  CertificateOrderFactory,
17
17
  CertificateProductFactory,
18
- OfferFactory,
18
+ OfferingFactory,
19
19
  CredentialOrderFactory,
20
20
  CredentialProductFactory,
21
21
  CreditCardFactory,
@@ -453,7 +453,7 @@ describe.each([
453
453
  const intl = createIntl({ locale: 'en' });
454
454
  const schedule = PaymentInstallmentFactory().many(2);
455
455
 
456
- const offer = OfferFactory({
456
+ const offering = OfferingFactory({
457
457
  product: ProductFactory({
458
458
  price: 840,
459
459
  price_currency: 'EUR',
@@ -463,7 +463,7 @@ describe.each([
463
463
  discount_rate: 0.3,
464
464
  },
465
465
  }).one();
466
- const { product } = offer;
466
+ const { product } = offering;
467
467
 
468
468
  fetchMock
469
469
  .get(
@@ -475,7 +475,7 @@ describe.each([
475
475
  schedule,
476
476
  );
477
477
 
478
- render(<Wrapper product={product} offer={offer} isWithdrawable={true} />, {
478
+ render(<Wrapper product={product} offering={offering} isWithdrawable={true} />, {
479
479
  queryOptions: { client: createTestQueryClient({ user: richieUser }) },
480
480
  });
481
481
 
@@ -515,7 +515,7 @@ describe.each([
515
515
  const $totalAmount = screen.getByTestId('sale-tunnel__total__amount');
516
516
  expect($totalAmount).toHaveTextContent(
517
517
  'Total' +
518
- formatPrice(offer!.rules.discounted_price!, product.price_currency).replace(
518
+ formatPrice(offering!.rules.discounted_price!, product.price_currency).replace(
519
519
  /(\u202F|\u00a0)/g,
520
520
  ' ',
521
521
  ),
@@ -2,7 +2,7 @@ import { ModalProps } from '@openfun/cunningham-react';
2
2
  import {
3
3
  CertificateProduct,
4
4
  CourseLight,
5
- Offer,
5
+ Offering,
6
6
  CredentialProduct,
7
7
  Enrollment,
8
8
  Order,
@@ -16,7 +16,7 @@ import { PacedCourse } from 'types';
16
16
 
17
17
  export interface SaleTunnelProps extends Pick<ModalProps, 'isOpen' | 'onClose'> {
18
18
  product: Product;
19
- offer?: Offer;
19
+ offering?: Offering;
20
20
  organizations?: Organization[];
21
21
  isWithdrawable: boolean;
22
22
  course?: PacedCourse | CourseLight;
@@ -1,7 +1,7 @@
1
1
  import { screen } from '@testing-library/react';
2
2
  import fetchMock from 'fetch-mock';
3
3
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
4
- import { CourseListItemFactory, OfferFactory } from 'utils/test/factories/joanie';
4
+ import { CourseListItemFactory, OfferingFactory } from 'utils/test/factories/joanie';
5
5
  import { render } from 'utils/test/render';
6
6
  import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
7
7
  import { expectNoSpinner, expectSpinner } from 'utils/test/expectSpinner';
@@ -35,7 +35,7 @@ describe('components/TeacherDashboardCourseList', () => {
35
35
  });
36
36
 
37
37
  it('should render loading more state', async () => {
38
- const trainings = OfferFactory().many(2);
38
+ const trainings = OfferingFactory().many(2);
39
39
  const courses = CourseListItemFactory().many(2);
40
40
  const courseAndProductList = [...courses, ...trainings];
41
41
 
@@ -60,7 +60,7 @@ describe('components/TeacherDashboardCourseList', () => {
60
60
  });
61
61
 
62
62
  it('should render courses and products list', async () => {
63
- const trainings = OfferFactory().many(2);
63
+ const trainings = OfferingFactory().many(2);
64
64
  const courses = CourseListItemFactory().many(2);
65
65
  const courseAndProductList = [...courses, ...trainings];
66
66
 
@@ -6,7 +6,7 @@ import { CourseGlimpseList, getCourseGlimpseListProps } from 'components/CourseG
6
6
  import { Spinner } from 'components/Spinner';
7
7
  import context from 'utils/context';
8
8
  import { useIntersectionObserver } from 'hooks/useIntersectionObserver';
9
- import { CourseListItem, OfferLight } from 'types/Joanie';
9
+ import { CourseListItem, OfferingLight } from 'types/Joanie';
10
10
  import Banner from 'components/Banner';
11
11
 
12
12
  const messages = defineMessages({
@@ -31,7 +31,7 @@ interface TeacherDashboardCourseListProps {
31
31
  titleTranslated?: string;
32
32
  organizationId?: string;
33
33
  loadMore: () => void;
34
- courseAndProductList?: (CourseListItem | OfferLight)[];
34
+ courseAndProductList?: (CourseListItem | OfferingLight)[];
35
35
  isLoadingMore?: boolean;
36
36
  hasMore?: boolean;
37
37
  isNewSearchLoading?: boolean;
@@ -1,5 +1,5 @@
1
1
  import { useJoanieApi } from 'contexts/JoanieApiContext';
2
- import { Offer, Organization } from 'types/Joanie';
2
+ import { Offering, Organization } from 'types/Joanie';
3
3
  import { browserDownloadFromBlob } from 'utils/download';
4
4
  import { HttpStatusCode } from 'utils/errors/HttpError';
5
5
  import { handle } from 'utils/errors/handle';
@@ -53,11 +53,11 @@ const useContractArchive = () => {
53
53
  },
54
54
  create: async (
55
55
  organizationId?: Organization['id'],
56
- offerId?: Offer['id'],
56
+ offeringId?: Offering['id'],
57
57
  ): Promise<string> => {
58
58
  const response = await api.user.contracts.zip_archive.create({
59
59
  organization_id: organizationId,
60
- offer_id: offerId,
60
+ offering_id: offeringId,
61
61
  });
62
62
 
63
63
  return extractArchiveId(response.url);
@@ -2,13 +2,13 @@ import { renderHook, waitFor } from '@testing-library/react';
2
2
  import { QueryClient } from '@tanstack/react-query';
3
3
  import fetchMock from 'fetch-mock';
4
4
  import { PropsWithChildren } from 'react';
5
- import { CourseListItem, Offer } from 'types/Joanie';
5
+ import { CourseListItem, Offering } from 'types/Joanie';
6
6
  import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
7
7
  import { createTestQueryClient } from 'utils/test/createTestQueryClient';
8
8
  import { SessionProvider } from 'contexts/SessionContext';
9
9
  import { getRoutes } from 'api/joanie';
10
10
  import { mockPaginatedResponse } from 'utils/test/mockPaginatedResponse';
11
- import { CourseListItemFactory, OfferFactory } from 'utils/test/factories/joanie';
11
+ import { CourseListItemFactory, OfferingFactory } from 'utils/test/factories/joanie';
12
12
  import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
13
13
  import { useCourseProductUnion } from '.';
14
14
 
@@ -41,12 +41,12 @@ const renderUseCourseProductUnion = ({ organizationId }: { organizationId?: stri
41
41
 
42
42
  describe('useCourseProductUnion', () => {
43
43
  let courseList: CourseListItem[];
44
- let offerList: Offer[];
44
+ let offeringList: Offering[];
45
45
  let nbApiCalls: number;
46
46
 
47
47
  beforeEach(() => {
48
48
  courseList = CourseListItemFactory().many(6);
49
- offerList = OfferFactory().many(6);
49
+ offeringList = OfferingFactory().many(6);
50
50
 
51
51
  fetchMock.get('https://joanie.endpoint/api/v1.0/orders/', [], { overwriteRoutes: true });
52
52
  fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', [], { overwriteRoutes: true });
@@ -59,38 +59,38 @@ describe('useCourseProductUnion', () => {
59
59
  fetchMock.restore();
60
60
  });
61
61
 
62
- it('should call courses and offer endpoints', async () => {
62
+ it('should call courses and offering endpoints', async () => {
63
63
  const ROUTES = getRoutes();
64
64
  const coursesUrl = ROUTES.courses.get.replace(':id/', '');
65
- const offersUrl = ROUTES.offers.get.replace(':id/', '');
65
+ const offeringsUrl = ROUTES.offerings.get.replace(':id/', '');
66
66
  fetchMock.get(
67
67
  `${coursesUrl}?has_listed_course_runs=true&page=1&page_size=${PER_PAGE}`,
68
68
  mockPaginatedResponse(courseList.slice(0, PER_PAGE), 0, false),
69
69
  );
70
70
  fetchMock.get(
71
- `${offersUrl}?page=1&page_size=${PER_PAGE}`,
72
- mockPaginatedResponse(offerList.slice(0, PER_PAGE), 0, false),
71
+ `${offeringsUrl}?page=1&page_size=${PER_PAGE}`,
72
+ mockPaginatedResponse(offeringList.slice(0, PER_PAGE), 0, false),
73
73
  );
74
74
  const { result } = renderUseCourseProductUnion();
75
75
  await waitFor(() => expect(result.current.isLoading).toBe(false));
76
76
  expect(result.current.data.length).toBe(PER_PAGE);
77
77
  nbApiCalls += 1; // courses page 1
78
- nbApiCalls += 1; // offers page 1
78
+ nbApiCalls += 1; // offerings page 1
79
79
  const calledUrls = fetchMock.calls().map((call) => call[0]);
80
80
  expect(calledUrls).toHaveLength(nbApiCalls);
81
81
  expect(calledUrls).toContain(
82
82
  `${coursesUrl}?has_listed_course_runs=true&page=1&page_size=${PER_PAGE}`,
83
83
  );
84
- expect(calledUrls).toContain(`${offersUrl}?page=1&page_size=${PER_PAGE}`);
84
+ expect(calledUrls).toContain(`${offeringsUrl}?page=1&page_size=${PER_PAGE}`);
85
85
  }, 25000);
86
86
 
87
- it('should call organization courses and organization offer endpoints', async () => {
87
+ it('should call organization courses and organization offering endpoints', async () => {
88
88
  const organizationId = 'DUMMY_ORGANIZATION_ID';
89
89
  const ROUTES = getRoutes();
90
90
  const organizationCoursesUrl = ROUTES.organizations.courses.get
91
91
  .replace(':organization_id', organizationId)
92
92
  .replace(':id/', '');
93
- const organizationOffersUrl = ROUTES.organizations.offers.get
93
+ const organizationOfferingsUrl = ROUTES.organizations.offerings.get
94
94
  .replace(':organization_id', organizationId)
95
95
  .replace(':id/', '');
96
96
  fetchMock.get(
@@ -98,19 +98,19 @@ describe('useCourseProductUnion', () => {
98
98
  mockPaginatedResponse(courseList.slice(0, PER_PAGE), 0, false),
99
99
  );
100
100
  fetchMock.get(
101
- `${organizationOffersUrl}?page=1&page_size=${PER_PAGE}`,
102
- mockPaginatedResponse(offerList.slice(0, PER_PAGE), 0, false),
101
+ `${organizationOfferingsUrl}?page=1&page_size=${PER_PAGE}`,
102
+ mockPaginatedResponse(offeringList.slice(0, PER_PAGE), 0, false),
103
103
  );
104
104
  const { result } = renderUseCourseProductUnion({ organizationId: 'DUMMY_ORGANIZATION_ID' });
105
105
  await waitFor(() => expect(result.current.isLoading).toBe(false));
106
106
  expect(result.current.data.length).toBe(PER_PAGE);
107
107
  nbApiCalls += 1; // courses page 1
108
- nbApiCalls += 1; // offers page 1
108
+ nbApiCalls += 1; // offerings page 1
109
109
  const calledUrls = fetchMock.calls().map((call) => call[0]);
110
110
  expect(calledUrls).toHaveLength(nbApiCalls);
111
111
  expect(calledUrls).toContain(
112
112
  `${organizationCoursesUrl}?has_listed_course_runs=true&page=1&page_size=${PER_PAGE}`,
113
113
  );
114
- expect(calledUrls).toContain(`${organizationOffersUrl}?page=1&page_size=${PER_PAGE}`);
114
+ expect(calledUrls).toContain(`${organizationOfferingsUrl}?page=1&page_size=${PER_PAGE}`);
115
115
  });
116
116
  });
@@ -3,11 +3,11 @@ import { useJoanieApi } from 'contexts/JoanieApiContext';
3
3
  import {
4
4
  CourseListItem,
5
5
  Product,
6
- Offer,
6
+ Offering,
7
7
  CourseQueryFilters,
8
- OfferQueryFilters,
8
+ OfferingQueryFilters,
9
9
  ProductType,
10
- OfferLight,
10
+ OfferingLight,
11
11
  } from 'types/Joanie';
12
12
  import useUnionResource, { ResourceUnionPaginationProps } from 'hooks/useUnionResource';
13
13
 
@@ -41,9 +41,9 @@ export const useCourseProductUnion = ({
41
41
  const api = useJoanieApi();
42
42
  return useUnionResource<
43
43
  CourseListItem,
44
- Offer | OfferLight,
44
+ Offering | OfferingLight,
45
45
  CourseQueryFilters,
46
- OfferQueryFilters
46
+ OfferingQueryFilters
47
47
  >({
48
48
  queryAConfig: {
49
49
  queryKey: ['user', 'courses'],
@@ -51,8 +51,8 @@ export const useCourseProductUnion = ({
51
51
  filters: { query, organization_id: organizationId, has_listed_course_runs: true },
52
52
  },
53
53
  queryBConfig: {
54
- queryKey: ['user', 'offers'],
55
- fn: api.offers.get,
54
+ queryKey: ['user', 'offerings'],
55
+ fn: api.offerings.get,
56
56
  filters: { query, organization_id: organizationId, product_type: productType },
57
57
  },
58
58
  perPage,
@@ -1,5 +1,5 @@
1
1
  import { defineMessages } from 'react-intl';
2
- import { API, CourseProductQueryFilters, Offer, Product } from 'types/Joanie';
2
+ import { API, CourseProductQueryFilters, Offering, Product } from 'types/Joanie';
3
3
  import { QueryOptions, useResourcesCustom, UseResourcesProps } from 'hooks/useResources';
4
4
  import { useJoanieApi } from 'contexts/JoanieApiContext';
5
5
 
@@ -19,7 +19,7 @@ export const messages = defineMessages({
19
19
  /**
20
20
  * Joanie Api hook to retrieve a product through its id and a course code.
21
21
  */
22
- const props: UseResourcesProps<Offer, CourseProductQueryFilters, API['courses']['products']> = {
22
+ const props: UseResourcesProps<Offering, CourseProductQueryFilters, API['courses']['products']> = {
23
23
  queryKey: ['courses-products'],
24
24
  apiInterface: () => useJoanieApi().courses.products,
25
25
  messages,
@@ -27,11 +27,11 @@ const props: UseResourcesProps<Offer, CourseProductQueryFilters, API['courses'][
27
27
 
28
28
  export const useCourseProduct = (
29
29
  filters: Omit<CourseProductQueryFilters, 'id'> & { product_id: Product['id'] },
30
- queryOptions?: QueryOptions<Offer>,
30
+ queryOptions?: QueryOptions<Offering>,
31
31
  ) => {
32
32
  const { product_id: productId, ...queryfilters } = filters;
33
33
  const enabled = !!productId && !!queryfilters.course_id;
34
- const resources = useResourcesCustom<Offer, CourseProductQueryFilters>({
34
+ const resources = useResourcesCustom<Offering, CourseProductQueryFilters>({
35
35
  ...props,
36
36
  filters: { id: productId, ...queryfilters },
37
37
  queryOptions: { ...queryOptions, enabled },