richie-education 2.30.1-dev22 → 2.30.1-dev25
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/lms/openedx-fonzie.spec.ts +1 -1
- package/js/api/lms/openedx-hawthorn.spec.ts +1 -1
- package/js/components/SaleTunnel/WithdrawRightCheckbox/index.tsx +56 -10
- package/js/components/SaleTunnel/index.full-process.spec.tsx +3 -1
- package/js/components/SaleTunnel/index.spec.tsx +37 -0
- package/js/contexts/SessionContext/index.spec.tsx +2 -2
- package/js/utils/test/factories/factories.spec.ts +1 -1
- package/js/utils/test/factories/joanie.ts +5 -5
- package/js/utils/test/factories/openEdx.tsx +1 -1
- package/js/utils/test/factories/richie.ts +1 -1
- package/package.json +1 -1
- package/scss/colors/_theme.scss +4 -0
- package/scss/components/_index.scss +1 -0
- package/scss/components/templates/richie/simpletext/_simpletext.scss +43 -0
|
@@ -22,7 +22,7 @@ describe('Fonzie API', () => {
|
|
|
22
22
|
|
|
23
23
|
it('uses its own route to get user information', async () => {
|
|
24
24
|
const user = {
|
|
25
|
-
username: faker.internet.
|
|
25
|
+
username: faker.internet.username(),
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
fetchMock.get('https://demo.endpoint.api/api/v1.0/user/me', user);
|
|
@@ -48,7 +48,7 @@ describe('OpenEdX Hawthorn API', () => {
|
|
|
48
48
|
describe('enrollment', () => {
|
|
49
49
|
beforeEach(() => {
|
|
50
50
|
courseId = faker.string.uuid();
|
|
51
|
-
username = faker.internet.
|
|
51
|
+
username = faker.internet.username();
|
|
52
52
|
fetchMock.restore();
|
|
53
53
|
mockHandle.mockRestore();
|
|
54
54
|
});
|
|
@@ -1,30 +1,72 @@
|
|
|
1
1
|
import { Alert, Checkbox, VariantType } from '@openfun/cunningham-react';
|
|
2
2
|
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
-
import { defineMessages, FormattedMessage } from 'react-intl
|
|
3
|
+
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|
4
4
|
import { useSaleTunnelContext } from 'components/SaleTunnel/GenericSaleTunnel';
|
|
5
|
+
import { ProductType } from 'types/Joanie';
|
|
5
6
|
|
|
6
7
|
const messages = defineMessages({
|
|
8
|
+
waiveCheckboxLabel: {
|
|
9
|
+
defaultMessage: 'By checking this box:',
|
|
10
|
+
description: 'Label of the checkbox to waive the withdrawal right.',
|
|
11
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.waiveCheckboxLabel',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const credentialProductMessages = defineMessages({
|
|
7
16
|
waiveCheckboxExplanation: {
|
|
8
17
|
defaultMessage:
|
|
9
|
-
'
|
|
18
|
+
'The training program you wish to enroll in begins before the end of the 14-day withdrawal period mentioned in Article L221-18 of the French Consumer Code. You must check the box below to proceed with your registration.',
|
|
10
19
|
description: 'Text to explain why the user has to waive to its withdrawal right.',
|
|
11
|
-
id: 'components.SaleTunnel.WithdrawRightCheckbox.waiverLabel',
|
|
20
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.credential.waiverLabel',
|
|
12
21
|
},
|
|
13
|
-
|
|
14
|
-
defaultMessage:
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
waiveCheckboxHelperClause1: {
|
|
23
|
+
defaultMessage:
|
|
24
|
+
'I acknowledge that I have expressly requested to begin the training before the expiration date of the withdrawal period.',
|
|
25
|
+
description: 'First clause item for the waiver checkbox.',
|
|
26
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.credential.waiveCheckboxHelperClause1',
|
|
27
|
+
},
|
|
28
|
+
waiveCheckboxHelperClause2: {
|
|
29
|
+
defaultMessage:
|
|
30
|
+
'I expressly waive my right of withdrawal in order to begin the training before the expiration of the withdrawal period.',
|
|
31
|
+
description: 'Second clause item for the waiver checkbox.',
|
|
32
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.credential.waiveCheckboxHelperClause2',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const certificateProductMessages = defineMessages({
|
|
37
|
+
waiveCheckboxExplanation: {
|
|
38
|
+
defaultMessage:
|
|
39
|
+
'If the examination period begins before the end of the 14-day withdrawal period mentioned in Article L221-18 of the French Consumer Code, you must check the box below to proceed with your registration.',
|
|
40
|
+
description: 'Text to explain why the user has to waive to its withdrawal right.',
|
|
41
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.certificate.waiverLabel',
|
|
42
|
+
},
|
|
43
|
+
waiveCheckboxHelperClause1: {
|
|
44
|
+
defaultMessage:
|
|
45
|
+
'I acknowledge that I have expressly requested my registration for the examination before the expiration date of the withdrawal period.',
|
|
46
|
+
description: 'First clause item for the waiver checkbox.',
|
|
47
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.certificate.waiveCheckboxHelperClause1',
|
|
48
|
+
},
|
|
49
|
+
waiveCheckboxHelperClause2: {
|
|
50
|
+
defaultMessage:
|
|
51
|
+
'I expressly waive my right of withdrawal in order to register for the examination before the expiration of the withdrawal period.',
|
|
52
|
+
description: 'Second clause item for the waiver checkbox.',
|
|
53
|
+
id: 'components.SaleTunnel.WithdrawRightCheckbox.certificate.waiveCheckboxHelperClause2',
|
|
17
54
|
},
|
|
18
55
|
});
|
|
19
56
|
|
|
20
57
|
const WithdrawRightCheckbox = () => {
|
|
21
58
|
const {
|
|
22
|
-
props: { isWithdrawable },
|
|
59
|
+
props: { isWithdrawable, product },
|
|
23
60
|
registerSubmitCallback,
|
|
24
61
|
unregisterSubmitCallback,
|
|
25
62
|
hasWaivedWithdrawalRight,
|
|
26
63
|
setHasWaivedWithdrawalRight,
|
|
27
64
|
} = useSaleTunnelContext();
|
|
65
|
+
const intl = useIntl();
|
|
66
|
+
const clauseMessages =
|
|
67
|
+
product.type === ProductType.CERTIFICATE
|
|
68
|
+
? certificateProductMessages
|
|
69
|
+
: credentialProductMessages;
|
|
28
70
|
const [hasErrorState, setHasError] = useState(false);
|
|
29
71
|
const setError = useCallback(async () => {
|
|
30
72
|
setHasError(!isWithdrawable && !hasWaivedWithdrawalRight);
|
|
@@ -44,13 +86,17 @@ const WithdrawRightCheckbox = () => {
|
|
|
44
86
|
data-testid="withdraw-right-checkbox"
|
|
45
87
|
>
|
|
46
88
|
<Alert type={hasErrorState ? VariantType.ERROR : VariantType.WARNING} className="mb-s">
|
|
47
|
-
<FormattedMessage {...
|
|
89
|
+
<FormattedMessage {...clauseMessages.waiveCheckboxExplanation} />
|
|
48
90
|
</Alert>
|
|
49
91
|
<Checkbox
|
|
50
92
|
className="waiveCheckbox__input"
|
|
51
|
-
label={
|
|
93
|
+
label={intl.formatMessage(messages.waiveCheckboxLabel)}
|
|
52
94
|
checked={hasWaivedWithdrawalRight}
|
|
53
95
|
onChange={(e) => setHasWaivedWithdrawalRight(e.target.checked)}
|
|
96
|
+
textItems={[
|
|
97
|
+
intl.formatMessage(clauseMessages.waiveCheckboxHelperClause1),
|
|
98
|
+
intl.formatMessage(clauseMessages.waiveCheckboxHelperClause2),
|
|
99
|
+
]}
|
|
54
100
|
/>
|
|
55
101
|
</section>
|
|
56
102
|
);
|
|
@@ -273,7 +273,9 @@ describe('SaleTunnel', () => {
|
|
|
273
273
|
/**
|
|
274
274
|
* Make sure the checkbox to waive withdrawal right is displayed
|
|
275
275
|
*/
|
|
276
|
-
const $waiveCheckbox = screen.
|
|
276
|
+
const $waiveCheckbox = within(screen.getByTestId('withdraw-right-checkbox')).getByRole(
|
|
277
|
+
'checkbox',
|
|
278
|
+
);
|
|
277
279
|
|
|
278
280
|
/**
|
|
279
281
|
* Subscribe
|
|
@@ -493,4 +493,41 @@ describe.each([
|
|
|
493
493
|
|
|
494
494
|
expect(screen.queryByTestId('withdraw-right-checkbox')).toBeNull();
|
|
495
495
|
});
|
|
496
|
+
|
|
497
|
+
it('should show a specific checkbox to waive withdrawal right according to the product type', async () => {
|
|
498
|
+
const product = ProductFactory().one();
|
|
499
|
+
const schedule = PaymentInstallmentFactory().many(2);
|
|
500
|
+
fetchMock
|
|
501
|
+
.get(
|
|
502
|
+
`https://joanie.endpoint/api/v1.0/orders/?${queryString.stringify(getFetchOrderQueryParams(product))}`,
|
|
503
|
+
[],
|
|
504
|
+
)
|
|
505
|
+
.get(
|
|
506
|
+
`https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/payment-schedule/`,
|
|
507
|
+
schedule,
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
render(<Wrapper product={product} isWithdrawable={false} />, {
|
|
511
|
+
queryOptions: { client: createTestQueryClient({ user: richieUser }) },
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
screen.getByTestId('withdraw-right-checkbox');
|
|
515
|
+
|
|
516
|
+
const expectedMessages =
|
|
517
|
+
productType === ProductType.CERTIFICATE
|
|
518
|
+
? [
|
|
519
|
+
'If the examination period begins before the end of the 14-day withdrawal period mentioned in Article L221-18 of the French Consumer Code, you must check the box below to proceed with your registration.',
|
|
520
|
+
'I acknowledge that I have expressly requested my registration for the examination before the expiration date of the withdrawal period.',
|
|
521
|
+
'I expressly waive my right of withdrawal in order to register for the examination before the expiration of the withdrawal period.',
|
|
522
|
+
]
|
|
523
|
+
: [
|
|
524
|
+
'The training program you wish to enroll in begins before the end of the 14-day withdrawal period mentioned in Article L221-18 of the French Consumer Code. You must check the box below to proceed with your registration.',
|
|
525
|
+
'I acknowledge that I have expressly requested to begin the training before the expiration date of the withdrawal period.',
|
|
526
|
+
'I expressly waive my right of withdrawal in order to begin the training before the expiration of the withdrawal period.',
|
|
527
|
+
];
|
|
528
|
+
|
|
529
|
+
expectedMessages.forEach((message) => {
|
|
530
|
+
screen.getByText(message);
|
|
531
|
+
});
|
|
532
|
+
});
|
|
496
533
|
});
|
|
@@ -119,7 +119,7 @@ describe('SessionProvider', () => {
|
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
it('provides user infos if user is authenticated then stores in cache', async () => {
|
|
122
|
-
const username = faker.internet.
|
|
122
|
+
const username = faker.internet.username();
|
|
123
123
|
const userDeferred = new Deferred();
|
|
124
124
|
fetchMock.get('https://endpoint.test/api/user/v1/me', userDeferred.promise);
|
|
125
125
|
const { result } = renderHook(useSession, {
|
|
@@ -146,7 +146,7 @@ describe('SessionProvider', () => {
|
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
it('destroy session then logout', async () => {
|
|
149
|
-
const username = faker.internet.
|
|
149
|
+
const username = faker.internet.username();
|
|
150
150
|
const userDeferred = new Deferred();
|
|
151
151
|
|
|
152
152
|
fetchMock.get('https://endpoint.test/api/user/v1/me', userDeferred.promise);
|
|
@@ -38,7 +38,7 @@ describe('factory', () => {
|
|
|
38
38
|
}
|
|
39
39
|
return {
|
|
40
40
|
fullname,
|
|
41
|
-
username: faker.internet.
|
|
41
|
+
username: faker.internet.username(),
|
|
42
42
|
mainAddress: DemoAddressFactory().one(),
|
|
43
43
|
addresses: DemoAddressFactory().many(3),
|
|
44
44
|
favoriteColors: Array(2).fill(faker.color.human()),
|
|
@@ -51,7 +51,7 @@ import { factory } from './factories';
|
|
|
51
51
|
export const UserLightFactory = factory((): UserLight => {
|
|
52
52
|
return {
|
|
53
53
|
id: faker.string.uuid(),
|
|
54
|
-
username: faker.internet.
|
|
54
|
+
username: faker.internet.username(),
|
|
55
55
|
full_name: faker.person.fullName(),
|
|
56
56
|
email: faker.internet.email(),
|
|
57
57
|
};
|
|
@@ -59,7 +59,7 @@ export const UserLightFactory = factory((): UserLight => {
|
|
|
59
59
|
export const JoanieUserProfileFactory = factory((): JoanieUserProfile => {
|
|
60
60
|
return {
|
|
61
61
|
id: faker.string.uuid(),
|
|
62
|
-
username: faker.internet.
|
|
62
|
+
username: faker.internet.username(),
|
|
63
63
|
full_name: faker.person.fullName(),
|
|
64
64
|
is_superuser: false,
|
|
65
65
|
is_staff: false,
|
|
@@ -394,7 +394,7 @@ export const NestedCertificateOrderFactory = factory((): NestedCertificateOrder
|
|
|
394
394
|
enrollment: EnrollmentLightFactory().one(),
|
|
395
395
|
organization: OrganizationFactory().one(),
|
|
396
396
|
product_title: FactoryHelper.unique(faker.lorem.words, { args: [1] }),
|
|
397
|
-
owner_name: faker.internet.
|
|
397
|
+
owner_name: faker.internet.username(),
|
|
398
398
|
state: OrderState.COMPLETED,
|
|
399
399
|
};
|
|
400
400
|
});
|
|
@@ -406,7 +406,7 @@ export const NestedCredentialOrderFactory = factory((): NestedCredentialOrder =>
|
|
|
406
406
|
enrollment: null,
|
|
407
407
|
organization: OrganizationFactory().one(),
|
|
408
408
|
product_title: FactoryHelper.unique(faker.lorem.words, { args: [1] }),
|
|
409
|
-
owner_name: faker.internet.
|
|
409
|
+
owner_name: faker.internet.username(),
|
|
410
410
|
state: OrderState.COMPLETED,
|
|
411
411
|
};
|
|
412
412
|
});
|
|
@@ -415,7 +415,7 @@ const AbstractOrderFactory = factory((): Order => {
|
|
|
415
415
|
return {
|
|
416
416
|
id: faker.string.uuid(),
|
|
417
417
|
created_on: faker.date.past({ years: 1 }).toISOString(),
|
|
418
|
-
owner: faker.internet.
|
|
418
|
+
owner: faker.internet.username(),
|
|
419
419
|
total: faker.number.int(),
|
|
420
420
|
total_currency: faker.finance.currencyCode(),
|
|
421
421
|
main_invoice_reference: faker.string.uuid(),
|
|
@@ -9,7 +9,7 @@ import { factory } from './factories';
|
|
|
9
9
|
|
|
10
10
|
export const OpenEdxApiProfileFactory = factory((): OpenEdxApiProfile => {
|
|
11
11
|
return {
|
|
12
|
-
username: faker.internet.
|
|
12
|
+
username: faker.internet.username(),
|
|
13
13
|
name: faker.person.fullName(),
|
|
14
14
|
country: faker.location.countryCode(),
|
|
15
15
|
year_of_birth: faker.date.past().toISOString(),
|
|
@@ -154,7 +154,7 @@ export const UserFactory = factory<User>(() => ({
|
|
|
154
154
|
access_token: faker.lorem.word(12),
|
|
155
155
|
full_name: faker.person.fullName(),
|
|
156
156
|
email: faker.internet.email(),
|
|
157
|
-
username: faker.internet.
|
|
157
|
+
username: faker.internet.username(),
|
|
158
158
|
}));
|
|
159
159
|
|
|
160
160
|
export const FonzieUserFactory = factory<User>(() => ({
|
package/package.json
CHANGED
package/scss/colors/_theme.scss
CHANGED
|
@@ -147,6 +147,10 @@ $r-theme: (
|
|
|
147
147
|
content-color: r-color('slate-grey'),
|
|
148
148
|
description-color: r-color('slate-grey'),
|
|
149
149
|
),
|
|
150
|
+
simpletext-variant-box: (
|
|
151
|
+
primary-color: r-color('denim'),
|
|
152
|
+
secondary-color: r-color('white'),
|
|
153
|
+
),
|
|
150
154
|
blogpost-glimpse: (
|
|
151
155
|
card-background: r-color('white'),
|
|
152
156
|
title-color: r-color('black'),
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
@import './templates/courses/plugins/category_plugin';
|
|
61
61
|
@import './templates/courses/plugins/licence_plugin';
|
|
62
|
+
@import './templates/richie/simpletext/simpletext';
|
|
62
63
|
@import './templates/richie/section/section';
|
|
63
64
|
@import './templates/richie/large_banner/large_banner';
|
|
64
65
|
@import './templates/richie/large_banner/compacted_banner';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// CKEditor 'simple text' plugin
|
|
2
|
+
//
|
|
3
|
+
// This aims to only adjust every possible plugins so they correctly fit since they
|
|
4
|
+
// were done for 100% size only. No colour, font or anything else should be changed
|
|
5
|
+
// here.
|
|
6
|
+
//
|
|
7
|
+
$r-simpletext-margin-bottom: 0.5rem !default;
|
|
8
|
+
$r-simpletext-variant-padding: 1rem !default;
|
|
9
|
+
$r-simpletext-variant-radius: 0.75rem !default;
|
|
10
|
+
|
|
11
|
+
.simple-text {
|
|
12
|
+
margin-bottom: $r-simpletext-margin-bottom;
|
|
13
|
+
|
|
14
|
+
& > *:last-child {
|
|
15
|
+
margin-bottom: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&__variant-round-box {
|
|
19
|
+
padding: $r-simpletext-variant-padding;
|
|
20
|
+
border: 1px solid transparent;
|
|
21
|
+
border-radius: $r-simpletext-variant-radius;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&__variant-stroked {
|
|
25
|
+
border-color: r-theme-val(simpletext-variant-box, primary-color);
|
|
26
|
+
background: r-theme-val(simpletext-variant-box, secondary-color);
|
|
27
|
+
|
|
28
|
+
h1,
|
|
29
|
+
h2,
|
|
30
|
+
h3,
|
|
31
|
+
h4,
|
|
32
|
+
h5,
|
|
33
|
+
h6 {
|
|
34
|
+
color: r-theme-val(simpletext-variant-box, primary-color);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__variant-fulfilled {
|
|
39
|
+
color: r-theme-val(simpletext-variant-box, secondary-color);
|
|
40
|
+
border-color: r-theme-val(simpletext-variant-box, primary-color);
|
|
41
|
+
background: r-theme-val(simpletext-variant-box, primary-color);
|
|
42
|
+
}
|
|
43
|
+
}
|