richie-education 2.29.2 → 2.29.3-dev48

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 (127) hide show
  1. package/i18n/locales/ar-SA.json +193 -125
  2. package/i18n/locales/es-ES.json +193 -125
  3. package/i18n/locales/fa-IR.json +193 -125
  4. package/i18n/locales/fr-CA.json +193 -125
  5. package/i18n/locales/fr-FR.json +193 -125
  6. package/i18n/locales/ko-KR.json +193 -125
  7. package/i18n/locales/pt-PT.json +193 -125
  8. package/i18n/locales/ru-RU.json +193 -125
  9. package/i18n/locales/vi-VN.json +193 -125
  10. package/js/api/joanie.ts +42 -17
  11. package/js/api/lms/dummy.ts +1 -12
  12. package/js/components/ContractFrame/AbstractContractFrame.spec.tsx +16 -9
  13. package/js/components/ContractFrame/AbstractContractFrame.tsx +28 -23
  14. package/js/components/ContractFrame/LearnerContractFrame.tsx +2 -2
  15. package/js/components/ContractFrame/_styles.scss +6 -14
  16. package/js/components/ContractStatus/index.spec.tsx +1 -1
  17. package/js/components/ContractStatus/index.tsx +1 -1
  18. package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/index.spec.tsx +15 -45
  19. package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/index.tsx +19 -26
  20. package/js/components/DownloadContractButton/index.spec.tsx +1 -1
  21. package/js/components/Form/utils.ts +2 -1
  22. package/js/components/OpenEdxFullNameForm/index.spec.tsx +229 -0
  23. package/js/components/OpenEdxFullNameForm/index.tsx +7 -7
  24. package/js/components/PaymentInterfaces/LyraPopIn.tsx +2 -2
  25. package/js/components/PaymentInterfaces/PayplugLightbox.tsx +1 -1
  26. package/js/components/PaymentInterfaces/__mocks__/index.tsx +1 -4
  27. package/js/components/PaymentInterfaces/types.ts +5 -2
  28. package/js/components/PaymentScheduleGrid/_styles.scss +13 -0
  29. package/js/components/PaymentScheduleGrid/index.tsx +50 -70
  30. package/js/components/PurchaseButton/index.spec.tsx +84 -37
  31. package/js/components/PurchaseButton/index.tsx +9 -27
  32. package/js/components/SaleTunnel/AddressSelector/index.spec.tsx +2 -2
  33. package/js/components/SaleTunnel/CertificateSaleTunnel/index.tsx +2 -2
  34. package/js/components/SaleTunnel/CredentialSaleTunnel/index.tsx +6 -10
  35. package/js/components/SaleTunnel/GenericSaleTunnel.tsx +105 -48
  36. package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +16 -20
  37. package/js/components/SaleTunnel/SaleTunnelSavePaymentMethod/_styles.scss +12 -0
  38. package/js/components/SaleTunnel/SaleTunnelSavePaymentMethod/index.tsx +157 -0
  39. package/js/components/SaleTunnel/SaleTunnelSuccess/index.tsx +15 -29
  40. package/js/components/SaleTunnel/Sponsors/SaleTunnelSponsors.scss +4 -5
  41. package/js/components/SaleTunnel/Sponsors/SaleTunnelSponsors.tsx +39 -11
  42. package/js/components/SaleTunnel/SubscriptionButton/_styles.scss +7 -0
  43. package/js/components/SaleTunnel/SubscriptionButton/index.tsx +202 -0
  44. package/js/components/SaleTunnel/_styles.scss +16 -5
  45. package/js/components/SaleTunnel/hooks/useTerms.tsx +0 -77
  46. package/js/components/SaleTunnel/index.credential.spec.tsx +14 -25
  47. package/js/components/SaleTunnel/index.full-process.spec.tsx +114 -48
  48. package/js/components/SaleTunnel/index.spec.tsx +333 -717
  49. package/js/components/SaleTunnel/index.tsx +2 -1
  50. package/js/components/SignContractButton/index.omniscientOrders.spec.tsx +16 -11
  51. package/js/components/SignContractButton/index.spec.tsx +16 -20
  52. package/js/components/SignContractButton/index.tsx +3 -1
  53. package/js/hooks/useCreditCards/index.spec.tsx +70 -6
  54. package/js/hooks/useCreditCards/index.ts +49 -11
  55. package/js/hooks/useOrders/index.spec.tsx +322 -0
  56. package/js/hooks/{useOrders.ts → useOrders/index.ts} +40 -14
  57. package/js/hooks/usePaymentSchedule.tsx +23 -0
  58. package/js/hooks/useProductOrder/index.spec.tsx +77 -60
  59. package/js/hooks/useProductOrder/index.tsx +2 -2
  60. package/js/hooks/useResources/useResourcesRoot.ts +4 -3
  61. package/js/index.tsx +2 -0
  62. package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.spec.tsx +1 -1
  63. package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.tsx +4 -2
  64. package/js/pages/DashboardOrderLayout/index.spec.tsx +10 -1
  65. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +8 -5
  66. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +8 -9
  67. package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.spec.tsx +1 -1
  68. package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx +1 -6
  69. package/js/settings/settings.prod.ts +0 -2
  70. package/js/settings/settings.test.ts +16 -2
  71. package/js/translations/ar-SA.json +1 -1
  72. package/js/translations/es-ES.json +1 -1
  73. package/js/translations/fa-IR.json +1 -1
  74. package/js/translations/fr-CA.json +1 -1
  75. package/js/translations/fr-FR.json +1 -1
  76. package/js/translations/ko-KR.json +1 -1
  77. package/js/translations/pt-PT.json +1 -1
  78. package/js/translations/ru-RU.json +1 -1
  79. package/js/translations/vi-VN.json +1 -1
  80. package/js/types/Joanie.ts +81 -32
  81. package/js/utils/OrderHelper/index.ts +46 -38
  82. package/js/utils/PaymentScheduleHelper/index.spec.tsx +78 -0
  83. package/js/utils/PaymentScheduleHelper/index.ts +30 -0
  84. package/js/utils/ProductHelper/index.spec.ts +322 -166
  85. package/js/utils/ProductHelper/index.ts +32 -0
  86. package/js/utils/test/factories/joanie.ts +72 -69
  87. package/js/widgets/Dashboard/components/DashboardItem/Contract/index.spec.tsx +2 -2
  88. package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.tsx +8 -18
  89. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.spec.tsx +23 -0
  90. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.tsx +23 -1
  91. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +145 -34
  92. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.tsx +175 -37
  93. package/js/widgets/Dashboard/components/DashboardItem/Order/CertificateItem/index.tsx +51 -0
  94. package/js/widgets/Dashboard/components/DashboardItem/Order/ContractItem/index.tsx +52 -0
  95. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemNotResumable.spec.tsx +109 -0
  96. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.spec.tsx +219 -5
  97. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +111 -245
  98. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.spec.tsx +61 -8
  99. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +17 -7
  100. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemSavePaymentMethod.spec.tsx +116 -0
  101. package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +175 -0
  102. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/_styles.scss +7 -0
  103. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/index.tsx +127 -0
  104. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx +216 -0
  105. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.spec.tsx +18 -71
  106. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.tsx +40 -25
  107. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateMessage/index.tsx +28 -22
  108. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.spec.tsx +18 -73
  109. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.tsx +32 -16
  110. package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.tsx +150 -0
  111. package/js/widgets/Dashboard/components/DashboardOrderLoader/index.tsx +32 -14
  112. package/js/widgets/Dashboard/components/Signature/SignatureDummy.tsx +25 -3
  113. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/EnrollableCourseRunList.tsx +2 -6
  114. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/index.spec.tsx +7 -14
  115. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.spec.tsx +7 -5
  116. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.tsx +5 -7
  117. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +242 -332
  118. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +12 -13
  119. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +10 -21
  120. package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/index.joanie.spec.tsx +2 -2
  121. package/package.json +45 -44
  122. package/scss/components/_index.scss +4 -2
  123. package/js/components/PaymentButton/_styles.scss +0 -27
  124. package/js/components/SaleTunnel/GenericPaymentButton/index.tsx +0 -340
  125. package/js/components/SaleTunnel/SaleTunnelNotValidated/index.tsx +0 -70
  126. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/ProductSignatureHeader/index.tsx +0 -41
  127. /package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/_styles.scss +0 -0
@@ -1,340 +0,0 @@
1
- import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
2
- import { useEffect, useMemo, useRef, useState } from 'react';
3
- import { Button } from '@openfun/cunningham-react';
4
- import { useJoanieApi } from 'contexts/JoanieApiContext';
5
- import { useSaleTunnelContext } from 'components/SaleTunnel/GenericSaleTunnel';
6
- import { useOrders } from 'hooks/useOrders';
7
- import { OrderCreationPayload, OrderState } from 'types/Joanie';
8
- import type { Maybe } from 'types/utils';
9
- import { useTerms } from 'components/SaleTunnel/hooks/useTerms';
10
- import WebAnalyticsAPIHandler from 'api/web-analytics';
11
- import { CourseProductEvent } from 'types/web-analytics';
12
- import { ObjectHelper } from 'utils/ObjectHelper';
13
- import { HttpError } from 'utils/errors/HttpError';
14
- import { PAYMENT_SETTINGS } from 'settings';
15
- import { Spinner } from 'components/Spinner';
16
- import PaymentInterface from 'components/PaymentInterfaces';
17
- import { useMatchMediaLg } from 'hooks/useMatchMedia';
18
- import { PaymentErrorMessageId, Payment, PaymentWithId } from 'components/PaymentInterfaces/types';
19
-
20
- const messages = defineMessages({
21
- errorAbort: {
22
- defaultMessage: 'You have aborted the payment.',
23
- description: 'Error message shown when user aborts the payment.',
24
- id: 'components.PaymentButton.errorAbort',
25
- },
26
- errorAborting: {
27
- defaultMessage: 'Aborting the payment...',
28
- description: 'Error message shown when user asks to abort the payment.',
29
- id: 'components.PaymentButton.errorAborting',
30
- },
31
- errorDefault: {
32
- defaultMessage: 'An error occurred during payment. Please retry later.',
33
- description: 'Error message shown when payment creation request failed.',
34
- id: 'components.PaymentButton.errorDefault',
35
- },
36
- errorFullProduct: {
37
- defaultMessage: 'There are no more places available for this product.',
38
- description:
39
- 'Error message shown when payment creation request failed because there is no remaining available seat for the product.',
40
- id: 'components.PaymentButton.errorFullProduct',
41
- },
42
- errorAddress: {
43
- defaultMessage: 'You must have a billing address.',
44
- description: "Error message shown when the user didn't select a billing address.",
45
- id: 'components.PaymentButton.errorAddress',
46
- },
47
- errorTerms: {
48
- defaultMessage: 'You must accept the terms.',
49
- description: "Error message shown when the user didn't check the terms checkbox.",
50
- id: 'components.PaymentButton.errorTerms',
51
- },
52
- pay: {
53
- defaultMessage: 'Pay {price}',
54
- description: 'CTA label to proceed to the payment of the product',
55
- id: 'components.PaymentButton.pay',
56
- },
57
- payInOneClick: {
58
- defaultMessage: 'Pay in one click {price}',
59
- description: 'CTA label to proceed to the one click payment of the product',
60
- id: 'components.PaymentButton.payInOneClick',
61
- },
62
- paymentInProgress: {
63
- defaultMessage: 'Payment in progress',
64
- description: 'Label for screen reader when a payment is in progress.',
65
- id: 'components.PaymentButton.paymentInProgress',
66
- },
67
- });
68
-
69
- type PaymentInfo = Payment & { order_id: string };
70
-
71
- enum ComponentStates {
72
- IDLE = 'idle',
73
- LOADING = 'loading',
74
- ERROR = 'error',
75
- }
76
-
77
- interface Props {
78
- buildOrderPayload: (
79
- payload: Pick<OrderCreationPayload, 'product_id' | 'has_consent_to_terms'>,
80
- ) => OrderCreationPayload;
81
- }
82
-
83
- export const GenericPaymentButton = ({ buildOrderPayload }: Props) => {
84
- const intl = useIntl();
85
- const API = useJoanieApi();
86
- const timeoutRef = useRef<NodeJS.Timeout>();
87
- const {
88
- webAnalyticsEventKey,
89
- order,
90
- billingAddress,
91
- creditCard,
92
- product,
93
- onPaymentSuccess,
94
- props: saleTunnelProps,
95
- runSubmitCallbacks,
96
- } = useSaleTunnelContext();
97
- const { methods: orderMethods } = useOrders(undefined, { enabled: false });
98
- const [payment, setPayment] = useState<PaymentInfo>();
99
- const [state, setState] = useState<ComponentStates>(ComponentStates.IDLE);
100
- const [error, setError] = useState<PaymentErrorMessageId | string>();
101
- const hasPaymentId = (p: Maybe<Payment>): p is Extract<Payment, PaymentWithId> => {
102
- return Boolean(p?.hasOwnProperty('payment_id'));
103
- };
104
- const paymentId = hasPaymentId(payment) ? payment.payment_id : undefined;
105
- const isMobile = useMatchMediaLg();
106
-
107
- // This pattern is ugly but I couldn't find a better way to achieve it in a nicer way.
108
- // Without this, when we call onPaymentSuccess() directly from the after polling function,
109
- // it is not the latest version of the function, so the value of `order` inside the context function (defined in GenericSaleTunnel.tsx)
110
- // will be undefined, then calling onFinish(order) with an undefined order.
111
- const onPaymentSuccessRef = useRef(onPaymentSuccess);
112
- onPaymentSuccessRef.current = onPaymentSuccess;
113
-
114
- const { validateTerms, termsAccepted, renderTermsCheckbox } = useTerms({
115
- product,
116
- error,
117
- onError: (e) => {
118
- handleError(e);
119
- },
120
- });
121
-
122
- const isReadyToPay = useMemo(() => {
123
- return (
124
- (saleTunnelProps.course || saleTunnelProps.enrollment) &&
125
- product &&
126
- billingAddress &&
127
- termsAccepted
128
- );
129
- }, [product, saleTunnelProps.course, saleTunnelProps.enrollment, billingAddress, termsAccepted]);
130
-
131
- const isBusy = useMemo(() => {
132
- return (
133
- state === ComponentStates.LOADING ||
134
- (state === ComponentStates.ERROR && error === PaymentErrorMessageId.ERROR_ABORTING)
135
- );
136
- }, [state, error]);
137
-
138
- /**
139
- * Use Joanie API to retrieve an order and check if it's state is validated
140
- *
141
- * @param {string} id - Order id
142
- * @returns {Promise<boolean>} - Promise resolving to true if order is validated
143
- */
144
- const isOrderValidated = async (id: string): Promise<Boolean> => {
145
- const orderToCheck = await API.user.orders.get({ id });
146
- return orderToCheck?.state === OrderState.VALIDATED;
147
- };
148
-
149
- const createPayment = async (orderId: string) => {
150
- WebAnalyticsAPIHandler()?.sendCourseProductEvent(
151
- CourseProductEvent.PAYMENT_CREATION,
152
- webAnalyticsEventKey,
153
- );
154
-
155
- if (!billingAddress) {
156
- handleError(PaymentErrorMessageId.ERROR_ADDRESS);
157
- }
158
-
159
- validateTerms();
160
-
161
- if (isReadyToPay) {
162
- setState(ComponentStates.LOADING);
163
- setError(undefined);
164
-
165
- if (!payment) {
166
- const billingAddressPayload = ObjectHelper.omit(billingAddress!, 'id', 'is_main');
167
-
168
- orderMethods.submit(
169
- {
170
- id: orderId,
171
- billing_address: billingAddressPayload,
172
- ...(creditCard && { credit_card_id: creditCard.id }),
173
- },
174
- {
175
- onSuccess: (orderPayment) => {
176
- const paymentInfos = {
177
- ...orderPayment.payment_info,
178
- order_id: orderId,
179
- };
180
- setPayment(paymentInfos);
181
- },
182
- onError: async (createPaymentError: HttpError) => {
183
- if (createPaymentError.responseBody) {
184
- const responseErrors = await createPaymentError.responseBody;
185
- if ('max_validated_orders' in responseErrors) {
186
- handleError(PaymentErrorMessageId.ERROR_FULL_PRODUCT);
187
- }
188
- }
189
- handleError();
190
- },
191
- },
192
- );
193
- }
194
- }
195
- };
196
-
197
- const createOrder = async () => {
198
- setState(ComponentStates.LOADING);
199
-
200
- try {
201
- await runSubmitCallbacks();
202
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
203
- } catch (_error) {
204
- // Example: full name failed saving to OpenEDX.
205
- setState(ComponentStates.IDLE);
206
- return;
207
- }
208
-
209
- if (!billingAddress) {
210
- handleError(PaymentErrorMessageId.ERROR_ADDRESS);
211
- }
212
-
213
- validateTerms();
214
-
215
- if (!isReadyToPay) {
216
- return;
217
- }
218
-
219
- if (order) {
220
- createPayment(order.id);
221
- } else {
222
- const payload = buildOrderPayload({
223
- product_id: product.id,
224
- has_consent_to_terms: termsAccepted,
225
- });
226
- orderMethods.create(payload, {
227
- onSuccess: (newOrder) => {
228
- createPayment(newOrder.id);
229
- },
230
- onError: async () => {
231
- handleError();
232
- },
233
- });
234
- }
235
- };
236
-
237
- const handleSuccess = () => {
238
- let round = 0;
239
-
240
- const checkOrderValidity = async () => {
241
- if (round >= PAYMENT_SETTINGS.pollLimit) {
242
- timeoutRef.current = undefined;
243
- onPaymentSuccessRef.current(false);
244
- } else {
245
- const isValidated = await isOrderValidated(payment!.order_id);
246
- if (isValidated) {
247
- setState(ComponentStates.IDLE);
248
- timeoutRef.current = undefined;
249
- onPaymentSuccessRef.current();
250
- } else {
251
- round++;
252
- timeoutRef.current = setTimeout(checkOrderValidity, PAYMENT_SETTINGS.pollInterval);
253
- }
254
- }
255
- };
256
-
257
- checkOrderValidity();
258
- };
259
-
260
- const handleError = (
261
- messageId: PaymentErrorMessageId | string = PaymentErrorMessageId.ERROR_DEFAULT,
262
- ) => {
263
- setState(ComponentStates.ERROR);
264
- setError(messageId);
265
- };
266
-
267
- useEffect(() => {
268
- if (error === PaymentErrorMessageId.ERROR_ABORTING) {
269
- orderMethods
270
- .abort({
271
- id: payment!.order_id,
272
- payment_id: paymentId,
273
- })
274
- .then(() => {
275
- handleError(PaymentErrorMessageId.ERROR_ABORT);
276
- })
277
- .catch(() => {
278
- handleError();
279
- });
280
- } else if (error && !messages.hasOwnProperty(error)) {
281
- orderMethods.invalidate();
282
- }
283
- if (state === ComponentStates.ERROR) {
284
- setPayment(undefined);
285
- }
286
- }, [error]);
287
-
288
- useEffect(() => {
289
- if (state === ComponentStates.ERROR) {
290
- document.querySelector<HTMLElement>('#sale-tunnel-payment-error')?.focus();
291
- }
292
- }, [state]);
293
-
294
- return (
295
- <>
296
- {renderTermsCheckbox()}
297
- <Button
298
- disabled={isBusy}
299
- onClick={createOrder}
300
- data-testid={order && 'payment-button-order-loaded'}
301
- fullWidth={isMobile}
302
- {...(state === ComponentStates.ERROR && {
303
- 'aria-describedby': 'sale-tunnel-payment-error',
304
- })}
305
- >
306
- {isBusy ? (
307
- <Spinner theme="light" aria-labelledby="payment-in-progress">
308
- <span id="payment-in-progress">
309
- <FormattedMessage {...messages.paymentInProgress} />
310
- </span>
311
- </Spinner>
312
- ) : (
313
- <FormattedMessage
314
- {...(creditCard ? messages.payInOneClick : messages.pay)}
315
- values={{
316
- price: intl.formatNumber(product.price, {
317
- style: 'currency',
318
- currency: product.price_currency,
319
- }),
320
- }}
321
- />
322
- )}
323
- </Button>
324
- {state === ComponentStates.LOADING && payment && (
325
- <PaymentInterface {...payment} onError={handleError} onSuccess={handleSuccess} />
326
- )}
327
- {state === ComponentStates.ERROR && (
328
- <p className="payment-button__error" id="sale-tunnel-payment-error" tabIndex={-1}>
329
- {!error || messages.hasOwnProperty(error) ? (
330
- <FormattedMessage
331
- {...messages[(error as PaymentErrorMessageId) || PaymentErrorMessageId.ERROR_DEFAULT]}
332
- />
333
- ) : (
334
- error
335
- )}
336
- </p>
337
- )}
338
- </>
339
- );
340
- };
@@ -1,70 +0,0 @@
1
- import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
2
- import { Button } from '@openfun/cunningham-react';
3
- import { generatePath } from 'react-router-dom';
4
- import WarningIcon from 'components/WarningIcon';
5
- import { getDashboardBasename } from 'widgets/Dashboard/hooks/useDashboardRouter/getDashboardBasename';
6
- import { useSaleTunnelContext } from 'components/SaleTunnel/GenericSaleTunnel';
7
- import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRoutesPaths';
8
- import { ProductType } from 'types/Joanie';
9
-
10
- const messages = defineMessages({
11
- apology: {
12
- defaultMessage: "Sorry, you'll have to wait a little longer!",
13
- description: 'Text displayed to thank user for his order',
14
- id: 'components.SaleTunnelSuccessNotValidated.apology',
15
- },
16
- title: {
17
- defaultMessage: 'It takes too long to validate your order.',
18
- description: 'Message to confirm that order has been created',
19
- id: 'components.SaleTunnelSuccessNotValidated.title',
20
- },
21
- description: {
22
- defaultMessage:
23
- 'Your payment has succeeded but your order validation is taking too long, you can close this dialog and come back later. You will receive your invoice by email in a few moments.',
24
- description: "Text to remind that order's invoice will be send by email soon",
25
- id: 'components.SaleTunnelSuccessNotValidated.description',
26
- },
27
- cta: {
28
- defaultMessage: 'Close',
29
- description: 'Label to the call to action to close sale tunnel',
30
- id: 'components.SaleTunnelSuccessNotValidated.cta',
31
- },
32
- });
33
-
34
- const SaleTunnelNotValidated = ({ closeModal }: { closeModal: () => void }) => {
35
- const intl = useIntl();
36
- const { order, product } = useSaleTunnelContext();
37
- return (
38
- <section className="sale-tunnel-end" data-testid="generic-sale-tunnel-not-validated-step">
39
- <header className="sale-tunnel-end__header">
40
- <WarningIcon />
41
- <h3 className="sale-tunnel-end__title">
42
- <FormattedMessage {...messages.apology} />
43
- </h3>
44
- </header>
45
- <p className="sale-tunnel-end__content">
46
- <FormattedMessage {...messages.title} />
47
- <br />
48
- <FormattedMessage {...messages.description} />
49
- </p>
50
- <footer className="sale-tunnel-end__footer">
51
- {product.type === ProductType.CREDENTIAL ? (
52
- <Button
53
- href={
54
- getDashboardBasename(intl.locale) +
55
- generatePath(LearnerDashboardPaths.ORDER, { orderId: order!.id })
56
- }
57
- >
58
- <FormattedMessage {...messages.cta} />
59
- </Button>
60
- ) : (
61
- <Button onClick={closeModal}>
62
- <FormattedMessage {...messages.cta} />
63
- </Button>
64
- )}
65
- </footer>
66
- </section>
67
- );
68
- };
69
-
70
- export default SaleTunnelNotValidated;
@@ -1,41 +0,0 @@
1
- import { Button } from '@openfun/cunningham-react';
2
- import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
3
- import { generatePath } from 'react-router-dom';
4
- import Banner, { BannerType } from 'components/Banner';
5
- import { getDashboardBasename } from 'widgets/Dashboard/hooks/useDashboardRouter/getDashboardBasename';
6
- import { Order } from 'types/Joanie';
7
-
8
- import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRoutesPaths';
9
-
10
- const messages = defineMessages({
11
- signatureNeeded: {
12
- defaultMessage: 'You need to sign your training contract before enrolling to course runs',
13
- description: 'Banner displayed when the contract is not signed on the syllabus',
14
- id: 'components.CourseProductItem.signatureNeeded',
15
- },
16
- contractSignActionLabel: {
17
- id: 'components.CourseProductItem.contractSignActionLabel',
18
- description: 'Label of "sign contract" action on the syllabus.',
19
- defaultMessage: 'Sign your training contract',
20
- },
21
- });
22
-
23
- export const ProductSignatureHeader = ({ order }: { order?: Order }) => {
24
- const intl = useIntl();
25
- return (
26
- <>
27
- <Banner message={intl.formatMessage(messages.signatureNeeded)} type={BannerType.ERROR} />
28
- <Button
29
- fullWidth={true}
30
- className="mb-s"
31
- size="small"
32
- href={
33
- getDashboardBasename(intl.locale) +
34
- generatePath(LearnerDashboardPaths.ORDER, { orderId: order!.id })
35
- }
36
- >
37
- <FormattedMessage {...messages.contractSignActionLabel} />
38
- </Button>
39
- </>
40
- );
41
- };