richie-education 2.28.2-dev26 → 2.28.2-dev53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/api/joanie.ts +42 -17
- package/js/api/lms/dummy.ts +1 -12
- package/js/components/ContractFrame/AbstractContractFrame.spec.tsx +16 -9
- package/js/components/ContractFrame/AbstractContractFrame.tsx +28 -23
- package/js/components/ContractFrame/LearnerContractFrame.tsx +2 -2
- package/js/components/ContractFrame/_styles.scss +6 -14
- package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/index.spec.tsx +15 -45
- package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/index.tsx +17 -24
- package/js/components/DownloadContractButton/index.spec.tsx +1 -1
- package/js/components/OpenEdxFullNameForm/index.spec.tsx +229 -0
- package/js/components/OpenEdxFullNameForm/index.tsx +7 -7
- package/js/components/PaymentInterfaces/LyraPopIn.tsx +2 -2
- package/js/components/PaymentInterfaces/PayplugLightbox.tsx +1 -1
- package/js/components/PaymentInterfaces/__mocks__/index.tsx +1 -4
- package/js/components/PaymentInterfaces/types.ts +5 -2
- package/js/components/PaymentScheduleGrid/_styles.scss +13 -0
- package/js/components/PaymentScheduleGrid/index.tsx +50 -70
- package/js/components/PurchaseButton/index.spec.tsx +84 -37
- package/js/components/SaleTunnel/AddressSelector/index.spec.tsx +2 -1
- package/js/components/SaleTunnel/CertificateSaleTunnel/index.tsx +2 -2
- package/js/components/SaleTunnel/CredentialSaleTunnel/index.tsx +6 -10
- package/js/components/SaleTunnel/GenericSaleTunnel.tsx +80 -27
- package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +16 -20
- package/js/components/SaleTunnel/SaleTunnelSavePaymentMethod/_styles.scss +12 -0
- package/js/components/SaleTunnel/SaleTunnelSavePaymentMethod/index.tsx +160 -0
- package/js/components/SaleTunnel/SaleTunnelSuccess/index.tsx +15 -29
- package/js/components/SaleTunnel/Sponsors/SaleTunnelSponsors.scss +4 -5
- package/js/components/SaleTunnel/Sponsors/SaleTunnelSponsors.tsx +39 -11
- package/js/components/SaleTunnel/SubscriptionButton/_styles.scss +7 -0
- package/js/components/SaleTunnel/SubscriptionButton/index.tsx +201 -0
- package/js/components/SaleTunnel/_styles.scss +16 -5
- package/js/components/SaleTunnel/hooks/useTerms.tsx +0 -77
- package/js/components/SaleTunnel/index.credential.spec.tsx +14 -25
- package/js/components/SaleTunnel/index.full-process.spec.tsx +116 -48
- package/js/components/SaleTunnel/index.spec.tsx +334 -717
- package/js/components/SignContractButton/index.omniscientOrders.spec.tsx +16 -11
- package/js/components/SignContractButton/index.spec.tsx +16 -20
- package/js/components/SignContractButton/index.tsx +3 -1
- package/js/hooks/useCreditCards/index.spec.tsx +70 -6
- package/js/hooks/useCreditCards/index.ts +49 -11
- package/js/hooks/useOrders/index.spec.tsx +322 -0
- package/js/hooks/{useOrders.ts → useOrders/index.ts} +40 -14
- package/js/hooks/usePaymentSchedule.tsx +23 -0
- package/js/hooks/useProductOrder/index.spec.tsx +77 -60
- package/js/hooks/useProductOrder/index.tsx +2 -2
- package/js/hooks/useResources/useResourcesRoot.ts +4 -3
- package/js/index.tsx +2 -0
- package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.spec.tsx +1 -1
- package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.tsx +4 -2
- package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +8 -5
- package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +8 -9
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.spec.tsx +1 -1
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx +1 -6
- package/js/settings/settings.test.ts +11 -2
- package/js/types/Joanie.ts +77 -31
- package/js/utils/OrderHelper/index.ts +47 -38
- package/js/utils/test/factories/joanie.ts +66 -68
- package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.tsx +8 -18
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +26 -32
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.tsx +11 -6
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.spec.tsx +114 -5
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +99 -12
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.spec.tsx +3 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +6 -7
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/_styles.scss +7 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/index.tsx +126 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx +209 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.spec.tsx +18 -71
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.tsx +40 -25
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateMessage/index.tsx +28 -22
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.spec.tsx +18 -73
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.tsx +32 -16
- package/js/widgets/Dashboard/components/DashboardOrderLoader/index.tsx +3 -11
- package/js/widgets/Dashboard/components/Signature/SignatureDummy.tsx +25 -3
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/EnrollableCourseRunList.tsx +2 -6
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/index.spec.tsx +7 -14
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.spec.tsx +7 -5
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.tsx +5 -7
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +242 -332
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +12 -13
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +10 -21
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/index.joanie.spec.tsx +2 -2
- package/package.json +2 -1
- package/scss/components/_index.scss +4 -2
- package/js/components/PaymentButton/_styles.scss +0 -27
- package/js/components/SaleTunnel/GenericPaymentButton/index.tsx +0 -338
- package/js/components/SaleTunnel/SaleTunnelNotValidated/index.tsx +0 -70
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/ProductSignatureHeader/index.tsx +0 -41
- /package/js/components/{SaleTunnel/CreditCardSelector → CreditCardSelector}/_styles.scss +0 -0
package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.spec.tsx
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
2
|
import { screen } from '@testing-library/react';
|
|
3
3
|
import { createIntl } from 'react-intl';
|
|
4
|
-
import {
|
|
5
|
-
ContractDefinitionFactory,
|
|
6
|
-
ContractFactory,
|
|
7
|
-
CredentialOrderFactory,
|
|
8
|
-
} from 'utils/test/factories/joanie';
|
|
4
|
+
import { ContractFactory, CredentialOrderFactory } from 'utils/test/factories/joanie';
|
|
9
5
|
import { OrderState } from 'types/Joanie';
|
|
10
6
|
import { render } from 'utils/test/render';
|
|
11
7
|
import { IntlWrapper } from 'utils/test/wrappers/IntlWrapper';
|
|
@@ -15,100 +11,49 @@ const intl = createIntl({ locale: 'en' });
|
|
|
15
11
|
|
|
16
12
|
describe('<OrderStateTeacherMessage/>', () => {
|
|
17
13
|
it.each([
|
|
18
|
-
[OrderState.
|
|
19
|
-
[OrderState.SUBMITTED, 'Pending'],
|
|
20
|
-
[OrderState.PENDING, 'Pending'],
|
|
14
|
+
[OrderState.ASSIGNED, 'Pending'],
|
|
21
15
|
[OrderState.CANCELED, 'Canceled'],
|
|
22
|
-
|
|
23
|
-
'should display message from order state: %s when order have no contract',
|
|
24
|
-
(state, expectedMessage) => {
|
|
25
|
-
const order = CredentialOrderFactory({ state }).one();
|
|
26
|
-
render(<OrderStateTeacherMessage order={order} />, {
|
|
27
|
-
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
28
|
-
});
|
|
29
|
-
expect(screen.getByText(expectedMessage)).toBeInTheDocument();
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
it.each([
|
|
16
|
+
[OrderState.COMPLETED, 'On going'],
|
|
34
17
|
[OrderState.DRAFT, 'Pending'],
|
|
35
|
-
[OrderState.
|
|
36
|
-
[OrderState.
|
|
37
|
-
[OrderState.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
render(
|
|
46
|
-
<OrderStateTeacherMessage
|
|
47
|
-
order={orderWithContract}
|
|
48
|
-
contractDefinition={ContractDefinitionFactory().one()}
|
|
49
|
-
/>,
|
|
50
|
-
{
|
|
51
|
-
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
52
|
-
},
|
|
53
|
-
);
|
|
54
|
-
expect(screen.getByText(expectedMessage)).toBeInTheDocument();
|
|
55
|
-
},
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
it('should display message for validated order that need learner signature', () => {
|
|
59
|
-
const order = CredentialOrderFactory({
|
|
60
|
-
state: OrderState.VALIDATED,
|
|
61
|
-
contract: null,
|
|
62
|
-
}).one();
|
|
63
|
-
|
|
64
|
-
const contractDefinition = ContractDefinitionFactory().one();
|
|
65
|
-
|
|
66
|
-
render(<OrderStateTeacherMessage order={order} contractDefinition={contractDefinition} />, {
|
|
18
|
+
[OrderState.FAILED_PAYMENT, 'Last direct debit has failed'],
|
|
19
|
+
[OrderState.NO_PAYMENT, 'First direct debit has failed'],
|
|
20
|
+
[OrderState.PENDING, 'Pending for the first direct debit'],
|
|
21
|
+
[OrderState.PENDING_PAYMENT, 'On going'],
|
|
22
|
+
[OrderState.SIGNING, "Pending for learner's signature"],
|
|
23
|
+
[OrderState.TO_SAVE_PAYMENT_METHOD, 'Payment method is missing'],
|
|
24
|
+
[OrderState.TO_SIGN, "Pending for learner's signature"],
|
|
25
|
+
])('should display message from order state: %s', (state, expectedMessage) => {
|
|
26
|
+
const order = CredentialOrderFactory({ state }).one();
|
|
27
|
+
render(<OrderStateTeacherMessage order={order} />, {
|
|
67
28
|
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
68
29
|
});
|
|
69
|
-
expect(screen.getByText(
|
|
30
|
+
expect(screen.getByText(expectedMessage)).toBeInTheDocument();
|
|
70
31
|
});
|
|
71
32
|
|
|
72
33
|
it('should display message for validated order that need organization signature', () => {
|
|
73
34
|
const order = CredentialOrderFactory({
|
|
74
|
-
state: OrderState.
|
|
35
|
+
state: OrderState.PENDING_PAYMENT,
|
|
75
36
|
contract: ContractFactory({
|
|
76
37
|
student_signed_on: new Date().toISOString(),
|
|
77
38
|
}).one(),
|
|
78
39
|
}).one();
|
|
79
|
-
const contractDefinition = ContractDefinitionFactory().one();
|
|
80
|
-
|
|
81
|
-
render(<OrderStateTeacherMessage order={order} contractDefinition={contractDefinition} />, {
|
|
82
|
-
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
83
|
-
});
|
|
84
|
-
expect(screen.getByText('To be signed')).toBeInTheDocument();
|
|
85
|
-
});
|
|
86
40
|
|
|
87
|
-
it("should display message for validated order that don't have a generated certificate", () => {
|
|
88
|
-
const order = CredentialOrderFactory({
|
|
89
|
-
state: OrderState.VALIDATED,
|
|
90
|
-
certificate_id: undefined,
|
|
91
|
-
}).one();
|
|
92
41
|
render(<OrderStateTeacherMessage order={order} />, {
|
|
93
42
|
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
94
43
|
});
|
|
95
|
-
expect(
|
|
96
|
-
screen.getByText(intl.formatMessage(messages.statusOnGoing), {
|
|
97
|
-
exact: false,
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
44
|
+
expect(screen.getByText('To be signed')).toBeInTheDocument();
|
|
100
45
|
});
|
|
101
46
|
|
|
102
47
|
it('should display message for validated order that have a generated certificate', () => {
|
|
103
48
|
const order = CredentialOrderFactory({
|
|
104
|
-
state: OrderState.
|
|
49
|
+
state: OrderState.COMPLETED,
|
|
105
50
|
certificate_id: 'FAKE_CERTIFICATE_ID',
|
|
106
51
|
}).one();
|
|
107
52
|
render(<OrderStateTeacherMessage order={order} />, {
|
|
108
53
|
wrapper: ({ children }: PropsWithChildren) => <IntlWrapper>{children}</IntlWrapper>,
|
|
109
54
|
});
|
|
110
55
|
expect(
|
|
111
|
-
screen.getByText(intl.formatMessage(messages.
|
|
56
|
+
screen.getByText(intl.formatMessage(messages.statusPassed), {
|
|
112
57
|
exact: false,
|
|
113
58
|
}),
|
|
114
59
|
);
|
package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.tsx
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
1
|
import { defineMessages } from 'react-intl';
|
|
2
|
-
import OrderStateMessage, { OrderStateMessageBaseProps } from '../OrderStateMessage';
|
|
2
|
+
import OrderStateMessage, { MessageKeys, OrderStateMessageBaseProps } from '../OrderStateMessage';
|
|
3
3
|
|
|
4
|
-
export const messages = defineMessages({
|
|
4
|
+
export const messages = defineMessages<MessageKeys>({
|
|
5
5
|
statusDraft: {
|
|
6
6
|
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusDraft',
|
|
7
7
|
description: 'Status shown on the dashboard order item when order is draft.',
|
|
8
8
|
defaultMessage: 'Pending',
|
|
9
9
|
},
|
|
10
|
-
|
|
11
|
-
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.
|
|
12
|
-
description: 'Status shown on the dashboard order item when order is
|
|
10
|
+
statusAssigned: {
|
|
11
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusAssigned',
|
|
12
|
+
description: 'Status shown on the dashboard order item when order is assigned.',
|
|
13
13
|
defaultMessage: 'Pending',
|
|
14
14
|
},
|
|
15
15
|
statusPending: {
|
|
16
16
|
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusPending',
|
|
17
17
|
description: 'Status shown on the dashboard order item when order is pending.',
|
|
18
|
-
defaultMessage: 'Pending',
|
|
18
|
+
defaultMessage: 'Pending for the first direct debit',
|
|
19
19
|
},
|
|
20
|
-
|
|
21
|
-
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.
|
|
20
|
+
statusPendingPayment: {
|
|
21
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusPendingPayment',
|
|
22
22
|
description:
|
|
23
23
|
'Status shown on the dashboard order item when order is validated with no certificate',
|
|
24
|
-
defaultMessage: '
|
|
24
|
+
defaultMessage: 'On going',
|
|
25
25
|
},
|
|
26
26
|
statusCompleted: {
|
|
27
27
|
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusCompleted',
|
|
28
|
-
description:
|
|
29
|
-
|
|
30
|
-
defaultMessage: 'Certified',
|
|
28
|
+
description: 'Status shown on the dashboard order item when order is completed',
|
|
29
|
+
defaultMessage: 'On going',
|
|
31
30
|
},
|
|
32
31
|
statusWaitingSignature: {
|
|
33
32
|
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusWaitingSignature',
|
|
@@ -35,6 +34,12 @@ export const messages = defineMessages({
|
|
|
35
34
|
"Status shown on the dashboard order item when order is validated with contract's learner signature missing.",
|
|
36
35
|
defaultMessage: "Pending for learner's signature",
|
|
37
36
|
},
|
|
37
|
+
statusWaitingPaymentMethod: {
|
|
38
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusWaitingPaymentMethod',
|
|
39
|
+
description:
|
|
40
|
+
'Status shown on the dashboard order item when order is in to_save_payment_method state.',
|
|
41
|
+
defaultMessage: 'Payment method is missing',
|
|
42
|
+
},
|
|
38
43
|
statusWaitingCounterSignature: {
|
|
39
44
|
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusWaitingCounterSignature',
|
|
40
45
|
description:
|
|
@@ -46,10 +51,21 @@ export const messages = defineMessages({
|
|
|
46
51
|
description: 'Status shown on the dashboard order item when order is canceled',
|
|
47
52
|
defaultMessage: 'Canceled',
|
|
48
53
|
},
|
|
49
|
-
|
|
50
|
-
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.
|
|
51
|
-
description: 'Status shown on the dashboard order item when order
|
|
52
|
-
defaultMessage: '
|
|
54
|
+
statusNoPayment: {
|
|
55
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusNoPayment',
|
|
56
|
+
description: 'Status shown on the dashboard order item when order is in no payment state',
|
|
57
|
+
defaultMessage: 'First direct debit has failed',
|
|
58
|
+
},
|
|
59
|
+
statusFailedPayment: {
|
|
60
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusFailedPayment',
|
|
61
|
+
description: 'Status shown on the dashboard order item when order is in failed payment state',
|
|
62
|
+
defaultMessage: 'Last direct debit has failed',
|
|
63
|
+
},
|
|
64
|
+
statusPassed: {
|
|
65
|
+
id: 'components.DashboardItem.Order.OrderStateTeacherMessage.statusPassed',
|
|
66
|
+
description:
|
|
67
|
+
'Status shown on the dashboard order item when order is completed with certificate',
|
|
68
|
+
defaultMessage: 'Certified',
|
|
53
69
|
},
|
|
54
70
|
});
|
|
55
71
|
|
|
@@ -4,7 +4,6 @@ import { useMemo } from 'react';
|
|
|
4
4
|
import { useOmniscientOrder } from 'hooks/useOrders';
|
|
5
5
|
import { Spinner } from 'components/Spinner';
|
|
6
6
|
import Banner, { BannerType } from 'components/Banner';
|
|
7
|
-
import { useCourseProduct } from 'hooks/useCourseProducts';
|
|
8
7
|
import { isCredentialOrder } from 'pages/DashboardCourses/useOrdersEnrollments';
|
|
9
8
|
import { handle } from 'utils/errors/handle';
|
|
10
9
|
import { OrderHelper } from 'utils/OrderHelper';
|
|
@@ -39,10 +38,6 @@ export const DashboardOrderLoader = () => {
|
|
|
39
38
|
item: order,
|
|
40
39
|
states: { fetching: fetchingOrder, error: errorOrder },
|
|
41
40
|
} = useOmniscientOrder(params.orderId);
|
|
42
|
-
const {
|
|
43
|
-
item: courseProduct,
|
|
44
|
-
states: { fetching: fetchingCourseProduct, error: errorCourseProduct },
|
|
45
|
-
} = useCourseProduct({ course_id: order?.course?.code, product_id: order?.product_id });
|
|
46
41
|
const intl = useIntl();
|
|
47
42
|
|
|
48
43
|
const credentialOrder = order && isCredentialOrder(order) ? order : undefined;
|
|
@@ -52,12 +47,9 @@ export const DashboardOrderLoader = () => {
|
|
|
52
47
|
return intl.formatMessage(messages.wrongLinkedProductError);
|
|
53
48
|
}
|
|
54
49
|
}, [credentialOrder]);
|
|
55
|
-
const error = errorOrder ||
|
|
56
|
-
const fetching = fetchingOrder
|
|
57
|
-
const needsSignature = OrderHelper.orderNeedsSignature(
|
|
58
|
-
order,
|
|
59
|
-
courseProduct?.product.contract_definition,
|
|
60
|
-
);
|
|
50
|
+
const error = errorOrder || wrongLinkedProductError;
|
|
51
|
+
const fetching = fetchingOrder;
|
|
52
|
+
const needsSignature = order ? OrderHelper.orderNeedsSignature(order) : false;
|
|
61
53
|
|
|
62
54
|
return (
|
|
63
55
|
<>
|
|
@@ -4,6 +4,7 @@ import { defineMessages, FormattedMessage } from 'react-intl';
|
|
|
4
4
|
import { SignatureProps } from 'components/ContractFrame';
|
|
5
5
|
import { DummyContractPlaceholder } from 'widgets/Dashboard/components/Signature/DummyContractPlaceholder';
|
|
6
6
|
import { CONTRACT_SETTINGS } from 'settings';
|
|
7
|
+
import { getAPIEndpoint } from 'api/joanie';
|
|
7
8
|
|
|
8
9
|
const messages = defineMessages({
|
|
9
10
|
button: {
|
|
@@ -23,12 +24,31 @@ enum SignatureDummySteps {
|
|
|
23
24
|
SIGNING_LOADING,
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export const SignatureDummy = ({ onDone }: SignatureProps) => {
|
|
27
|
+
export const SignatureDummy = ({ invitationLink, onDone }: SignatureProps) => {
|
|
27
28
|
const [step, setStep] = useState(SignatureDummySteps.SIGNING);
|
|
28
29
|
|
|
30
|
+
const baseUrl = getAPIEndpoint();
|
|
31
|
+
// eslint-disable-next-line compat/compat
|
|
32
|
+
const link = new URL(invitationLink);
|
|
33
|
+
const reference = link.searchParams.get('reference');
|
|
34
|
+
const event = link.searchParams.get('eventTarget');
|
|
35
|
+
const sendSignatureNotification = () => {
|
|
36
|
+
fetch(`${baseUrl}/signature/notifications/`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
event_type: event,
|
|
43
|
+
reference,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
29
48
|
const sign = () => {
|
|
30
49
|
setStep(SignatureDummySteps.SIGNING_LOADING);
|
|
31
50
|
setTimeout(() => {
|
|
51
|
+
sendSignatureNotification();
|
|
32
52
|
onDone();
|
|
33
53
|
}, CONTRACT_SETTINGS.dummySignatureSignTimeout);
|
|
34
54
|
};
|
|
@@ -44,11 +64,13 @@ export const SignatureDummy = ({ onDone }: SignatureProps) => {
|
|
|
44
64
|
</div>
|
|
45
65
|
)}
|
|
46
66
|
{step === SignatureDummySteps.SIGNING_LOADING && (
|
|
47
|
-
<div className="
|
|
67
|
+
<div className="ContractFrame__container">
|
|
48
68
|
<h3 className="ContractFrame__caption">
|
|
49
69
|
<FormattedMessage {...messages.signing} />
|
|
50
70
|
</h3>
|
|
51
|
-
<
|
|
71
|
+
<div className="ContractFrame__footer">
|
|
72
|
+
<Loader />
|
|
73
|
+
</div>
|
|
52
74
|
</div>
|
|
53
75
|
)}
|
|
54
76
|
</>
|
|
@@ -11,7 +11,6 @@ import useDateFormat from 'hooks/useDateFormat';
|
|
|
11
11
|
import { IntlHelper } from 'utils/IntlHelper';
|
|
12
12
|
import WebAnalyticsAPIHandler from 'api/web-analytics';
|
|
13
13
|
import EnrollmentDate from 'components/EnrollmentDate';
|
|
14
|
-
import { Product } from 'types/Joanie';
|
|
15
14
|
import { OrderHelper } from 'utils/OrderHelper';
|
|
16
15
|
import { messages as sharedMessages } from '../CourseRunItem';
|
|
17
16
|
import CourseRunSection, { messages as sectionMessages } from './CourseRunSection';
|
|
@@ -53,16 +52,13 @@ const messages = defineMessages({
|
|
|
53
52
|
interface Props {
|
|
54
53
|
courseRuns: Joanie.CourseRun[];
|
|
55
54
|
order: Joanie.Order;
|
|
56
|
-
product: Product;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
const EnrollableCourseRunList = ({ courseRuns, order
|
|
57
|
+
const EnrollableCourseRunList = ({ courseRuns, order }: Props) => {
|
|
60
58
|
const intl = useIntl();
|
|
61
59
|
const formatDate = useDateFormat();
|
|
62
60
|
const formRef = useRef<HTMLFormElement>(null);
|
|
63
|
-
const needsSignature = order
|
|
64
|
-
? OrderHelper.orderNeedsSignature(order, product.contract_definition)
|
|
65
|
-
: false;
|
|
61
|
+
const needsSignature = order ? OrderHelper.orderNeedsSignature(order) : false;
|
|
66
62
|
|
|
67
63
|
const [selectedCourseRun, setSelectedCourseRun] = useState<Maybe<Joanie.CourseRun>>();
|
|
68
64
|
const [submitted, setSubmitted] = useState(false);
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
CredentialOrderFactory,
|
|
12
12
|
ProductFactory,
|
|
13
13
|
} from 'utils/test/factories/joanie';
|
|
14
|
-
import
|
|
14
|
+
import { CourseLight, CourseRun, Enrollment, OrderState } from 'types/Joanie';
|
|
15
15
|
import { Deferred } from 'utils/test/deferred';
|
|
16
16
|
import { CourseStateTextEnum, Priority } from 'types';
|
|
17
17
|
import { IntlHelper } from 'utils/IntlHelper';
|
|
@@ -114,10 +114,9 @@ describe('CourseProductCourseRuns', () => {
|
|
|
114
114
|
|
|
115
115
|
it('renders a warning message when no course runs are provided', () => {
|
|
116
116
|
const order = CredentialOrderFactory().one();
|
|
117
|
-
const product = ProductFactory().one();
|
|
118
117
|
|
|
119
118
|
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
120
|
-
render(<EnrollableCourseRunList courseRuns={[]} order={order}
|
|
119
|
+
render(<EnrollableCourseRunList courseRuns={[]} order={order} />, {
|
|
121
120
|
wrapper: BaseJoanieAppWrapper,
|
|
122
121
|
});
|
|
123
122
|
|
|
@@ -127,12 +126,9 @@ describe('CourseProductCourseRuns', () => {
|
|
|
127
126
|
it('renders a list of course runs with a call to action to enroll', async () => {
|
|
128
127
|
const courseRuns: CourseRun[] = CourseRunFactory().many(2);
|
|
129
128
|
const order = CredentialOrderFactory().one();
|
|
130
|
-
const product = ProductFactory({
|
|
131
|
-
contract_definition: undefined,
|
|
132
|
-
}).one();
|
|
133
129
|
|
|
134
130
|
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
135
|
-
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order}
|
|
131
|
+
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order} />, {
|
|
136
132
|
wrapper: BaseJoanieAppWrapper,
|
|
137
133
|
});
|
|
138
134
|
|
|
@@ -247,7 +243,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
247
243
|
fetchMock.get(`https://joanie.endpoint/api/v1.0/courses/${course.code}/`, HttpStatusCode.OK);
|
|
248
244
|
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
249
245
|
|
|
250
|
-
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order}
|
|
246
|
+
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order} />, {
|
|
251
247
|
wrapper: BaseJoanieAppWrapper,
|
|
252
248
|
});
|
|
253
249
|
|
|
@@ -355,12 +351,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
355
351
|
text: CourseStateTextEnum.STARTING_ON,
|
|
356
352
|
},
|
|
357
353
|
}).one();
|
|
358
|
-
const product = ProductFactory().one();
|
|
359
|
-
product.contract_definition = undefined;
|
|
360
354
|
const order = CredentialOrderFactory().one();
|
|
361
355
|
|
|
362
356
|
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
363
|
-
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order}
|
|
357
|
+
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order} />, {
|
|
364
358
|
wrapper: BaseJoanieAppWrapper,
|
|
365
359
|
});
|
|
366
360
|
|
|
@@ -438,11 +432,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
438
432
|
text: CourseStateTextEnum.STARTING_ON,
|
|
439
433
|
},
|
|
440
434
|
}).one();
|
|
441
|
-
const
|
|
442
|
-
const order = CredentialOrderFactory().one();
|
|
435
|
+
const order = CredentialOrderFactory({ state: OrderState.TO_SIGN }).one();
|
|
443
436
|
|
|
444
437
|
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
445
|
-
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order}
|
|
438
|
+
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order} />, {
|
|
446
439
|
wrapper: BaseJoanieAppWrapper,
|
|
447
440
|
});
|
|
448
441
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
2
|
import { screen, getByText } from '@testing-library/react';
|
|
3
|
-
import { CredentialOrderFactory
|
|
3
|
+
import { CredentialOrderFactory } from 'utils/test/factories/joanie';
|
|
4
4
|
import type { CourseRun, CredentialOrder } from 'types/Joanie';
|
|
5
5
|
import { OrderState } from 'types/Joanie';
|
|
6
6
|
import { render } from 'utils/test/render';
|
|
@@ -15,14 +15,16 @@ jest.mock('../CourseProductCourseRuns', () => ({
|
|
|
15
15
|
describe('CourseRunItem', () => {
|
|
16
16
|
it('does not allow user which purchase the product to enroll to course if order state is not validated', async () => {
|
|
17
17
|
const order: CredentialOrder = CredentialOrderFactory({
|
|
18
|
-
state: faker.helpers.arrayElement([
|
|
18
|
+
state: faker.helpers.arrayElement([
|
|
19
|
+
OrderState.CANCELED,
|
|
20
|
+
OrderState.PENDING,
|
|
21
|
+
OrderState.NO_PAYMENT,
|
|
22
|
+
]),
|
|
19
23
|
}).one();
|
|
20
|
-
const product = ProductFactory().one();
|
|
21
|
-
product.contract_definition = undefined;
|
|
22
24
|
|
|
23
25
|
const targetCourse = order.target_courses[0];
|
|
24
26
|
|
|
25
|
-
render(<CourseRunItem targetCourse={targetCourse} order={order}
|
|
27
|
+
render(<CourseRunItem targetCourse={targetCourse} order={order} />, {
|
|
26
28
|
wrapper: null,
|
|
27
29
|
});
|
|
28
30
|
|
|
@@ -2,8 +2,8 @@ import { useEffect, useRef } from 'react';
|
|
|
2
2
|
import { defineMessages } from 'react-intl';
|
|
3
3
|
import { Priority } from 'types';
|
|
4
4
|
import type * as Joanie from 'types/Joanie';
|
|
5
|
-
import { OrderState, Product } from 'types/Joanie';
|
|
6
5
|
import { CoursesHelper } from 'utils/CoursesHelper';
|
|
6
|
+
import { OrderHelper } from 'utils/OrderHelper';
|
|
7
7
|
import {
|
|
8
8
|
CourseRunList,
|
|
9
9
|
EnrollableCourseRunList,
|
|
@@ -26,13 +26,12 @@ other {Languages:}
|
|
|
26
26
|
interface Props {
|
|
27
27
|
targetCourse: Joanie.TargetCourse;
|
|
28
28
|
order?: Joanie.CredentialOrder;
|
|
29
|
-
product: Product;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
const CourseRunItem = ({ targetCourse, order
|
|
33
|
-
const isEnrollable = order
|
|
31
|
+
const CourseRunItem = ({ targetCourse, order }: Props) => {
|
|
32
|
+
const isEnrollable = OrderHelper.allowEnrollment(order);
|
|
34
33
|
const courseRunEnrollment = isEnrollable
|
|
35
|
-
? CoursesHelper.findActiveCourseEnrollmentInOrder(targetCourse, order)
|
|
34
|
+
? CoursesHelper.findActiveCourseEnrollmentInOrder(targetCourse, order!)
|
|
36
35
|
: undefined;
|
|
37
36
|
const isEnrolled = !!courseRunEnrollment?.is_active;
|
|
38
37
|
|
|
@@ -92,8 +91,7 @@ const CourseRunItem = ({ targetCourse, order, product }: Props) => {
|
|
|
92
91
|
{isEnrollable && !isEnrolled && (
|
|
93
92
|
<EnrollableCourseRunList
|
|
94
93
|
courseRuns={targetCourse.course_runs.filter(isOpenedCourseRun)}
|
|
95
|
-
order={order}
|
|
96
|
-
product={product}
|
|
94
|
+
order={order!}
|
|
97
95
|
/>
|
|
98
96
|
)}
|
|
99
97
|
{isEnrollable && isEnrolled && <EnrolledCourseRun enrollment={courseRunEnrollment} />}
|