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.
@@ -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.userName(),
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.userName();
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/lib';
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
- 'This training will start before the end of your withdrawal period. You must waive it to subscribe.',
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
- waiveCheckboxLabel: {
14
- defaultMessage: 'I waive my right of withdrawal',
15
- description: 'Label of the checkbox to waive the withdrawal right.',
16
- id: 'components.SaleTunnel.WithdrawRightCheckbox.waiveCheckboxLabel',
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 {...messages.waiveCheckboxExplanation} />
89
+ <FormattedMessage {...clauseMessages.waiveCheckboxExplanation} />
48
90
  </Alert>
49
91
  <Checkbox
50
92
  className="waiveCheckbox__input"
51
- label={<FormattedMessage {...messages.waiveCheckboxLabel} />}
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.getByLabelText('I waive my right of withdrawal');
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.userName();
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.userName();
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.userName(),
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.userName(),
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.userName(),
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.userName(),
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.userName(),
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.userName(),
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.userName(),
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.userName(),
157
+ username: faker.internet.username(),
158
158
  }));
159
159
 
160
160
  export const FonzieUserFactory = factory<User>(() => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "richie-education",
3
- "version": "2.30.1-dev22",
3
+ "version": "2.30.1-dev25",
4
4
  "description": "A CMS to build learning portals for Open Education",
5
5
  "main": "sandbox/manage.py",
6
6
  "scripts": {
@@ -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
+ }