richie-education 3.5.1-dev2 → 3.5.2-dev12

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 (49) hide show
  1. package/i18n/locales/ar-SA.json +4 -0
  2. package/i18n/locales/es-ES.json +4 -0
  3. package/i18n/locales/fa-IR.json +4 -0
  4. package/i18n/locales/fr-CA.json +4 -0
  5. package/i18n/locales/fr-FR.json +5 -1
  6. package/i18n/locales/ko-KR.json +4 -0
  7. package/i18n/locales/pt-PT.json +4 -0
  8. package/i18n/locales/ru-RU.json +4 -0
  9. package/i18n/locales/vi-VN.json +4 -0
  10. package/js/api/joanie.ts +15 -0
  11. package/js/api/lms/dummy.ts +1 -0
  12. package/js/api/lms/openedx-fonzie-keycloak.spec.ts +7 -10
  13. package/js/api/lms/openedx-fonzie-keycloak.ts +24 -21
  14. package/js/components/SaleTunnel/index.spec.tsx +31 -1
  15. package/js/hooks/useLearnerCoursesSearch/index.tsx +17 -4
  16. package/js/hooks/useProductOrder/index.spec.tsx +1 -0
  17. package/js/pages/DashboardCourses/index.spec.tsx +40 -8
  18. package/js/translations/ar-SA.json +1 -1
  19. package/js/translations/es-ES.json +1 -1
  20. package/js/translations/fa-IR.json +1 -1
  21. package/js/translations/fr-CA.json +1 -1
  22. package/js/translations/fr-FR.json +1 -1
  23. package/js/translations/ko-KR.json +1 -1
  24. package/js/translations/pt-PT.json +1 -1
  25. package/js/translations/ru-RU.json +1 -1
  26. package/js/translations/vi-VN.json +1 -1
  27. package/js/types/Joanie.ts +18 -1
  28. package/js/utils/OrderHelper/index.spec.ts +75 -0
  29. package/js/utils/OrderHelper/index.ts +14 -2
  30. package/js/utils/test/factories/joanie.ts +10 -0
  31. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +213 -1
  32. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.tsx +133 -31
  33. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.spec.tsx +22 -0
  34. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +29 -13
  35. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +0 -2
  36. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.spec.tsx +12 -0
  37. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.tsx +11 -0
  38. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateMessage/index.tsx +5 -1
  39. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.spec.tsx +12 -0
  40. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.tsx +11 -0
  41. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderWithdrawalModal/index.spec.tsx +167 -0
  42. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderWithdrawalModal/index.tsx +272 -0
  43. package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.spec.tsx +102 -0
  44. package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.tsx +84 -2
  45. package/js/widgets/Dashboard/components/DashboardItem/Order/_styles.scss +5 -0
  46. package/js/widgets/Dashboard/components/DashboardItem/_styles.scss +9 -1
  47. package/js/widgets/Dashboard/index.spec.tsx +0 -1
  48. package/package.json +1 -1
  49. package/scss/components/templates/courses/cms/_category_list.scss +5 -0
@@ -1,10 +1,12 @@
1
- import { defineMessages, FormattedMessage } from 'react-intl';
2
- import { Button } from '@openfun/cunningham-react';
1
+ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
2
+ import { Button, useModal } from '@openfun/cunningham-react';
3
3
  import { CredentialOrder, Product } from 'types/Joanie';
4
4
  import { AddressView } from 'components/Address';
5
5
  import { OrderHelper } from 'utils/OrderHelper';
6
+ import useDateFormat, { DATETIME_FORMAT } from 'hooks/useDateFormat';
6
7
  import ContractItem from '../ContractItem';
7
8
  import Installment from '../Installment';
9
+ import { OrderWithdrawalModal } from '../OrderWithdrawalModal';
8
10
 
9
11
  const messages = defineMessages({
10
12
  contactDescription: {
@@ -52,6 +54,31 @@ const messages = defineMessages({
52
54
  description: 'Subtitle for the organization contacts section',
53
55
  defaultMessage: 'Contacts',
54
56
  },
57
+ withdrawalTitle: {
58
+ id: 'components.DashboardItemOrder.OrganizationBlock.withdrawalTitle',
59
+ description: 'Title of the withdrawal block',
60
+ defaultMessage: 'Withdrawal',
61
+ },
62
+ withdrawalDescription: {
63
+ id: 'components.DashboardItemOrder.OrganizationBlock.withdrawalDescription',
64
+ description: 'Description of the withdrawal block',
65
+ defaultMessage: 'You can withdraw from your contract until {date}.',
66
+ },
67
+ withdrawalButton: {
68
+ id: 'components.DashboardItemOrder.OrganizationBlock.withdrawalButton',
69
+ description: 'Button label of the withdrawal block',
70
+ defaultMessage: 'Withdraw',
71
+ },
72
+ withdrawnTitle: {
73
+ id: 'components.DashboardItemOrder.OrganizationBlock.withdrawnTitle',
74
+ description: 'Title of the withdrawal block once the withdrawal is confirmed',
75
+ defaultMessage: 'Withdrawn',
76
+ },
77
+ withdrawnDescription: {
78
+ id: 'components.DashboardItemOrder.OrganizationBlock.withdrawnDescription',
79
+ description: 'Description shown once the withdrawal is confirmed',
80
+ defaultMessage: 'You withdrew from this order on {date}.',
81
+ },
55
82
  });
56
83
 
57
84
  type Props = {
@@ -148,7 +175,62 @@ const OrganizationBlock = ({ order, product }: Props) => {
148
175
  </div>
149
176
  )}
150
177
  {!hidePaymentBlock && <Installment order={order} />}
178
+ {order.eligible_to_withdraw && <Withdrawal order={order} product={product} />}
179
+ {OrderHelper.isWithdrawn(order) && <WithdrawnStatus order={order} />}
180
+ </div>
181
+ </div>
182
+ );
183
+ };
184
+
185
+ const Withdrawal = ({ order, product }: Props) => {
186
+ const intl = useIntl();
187
+ const formatDate = useDateFormat(DATETIME_FORMAT);
188
+ const modal = useModal();
189
+
190
+ return (
191
+ <div data-testid="dashboard-item-withdrawal" className="dashboard-splitted-card__item">
192
+ <div className="dashboard-splitted-card__item__title">
193
+ <span>
194
+ <FormattedMessage {...messages.withdrawalTitle} />
195
+ </span>
196
+ </div>
197
+ <p className="dashboard-splitted-card__item__description">
198
+ <FormattedMessage
199
+ {...messages.withdrawalDescription}
200
+ values={{ date: formatDate(order.withdrawal_date_limit) }}
201
+ />
202
+ </p>
203
+ <div className="dashboard-splitted-card__item__actions">
204
+ <Button size="small" color="brand" variant="secondary" onClick={modal.open}>
205
+ {intl.formatMessage(messages.withdrawalButton)}
206
+ </Button>
207
+ </div>
208
+ <OrderWithdrawalModal
209
+ {...modal}
210
+ order={order}
211
+ productTitle={product.title}
212
+ reference={order.course.code}
213
+ />
214
+ </div>
215
+ );
216
+ };
217
+
218
+ const WithdrawnStatus = ({ order }: { order: CredentialOrder }) => {
219
+ const formatDate = useDateFormat(DATETIME_FORMAT);
220
+
221
+ return (
222
+ <div data-testid="dashboard-item-withdrawn" className="dashboard-splitted-card__item">
223
+ <div className="dashboard-splitted-card__item__title">
224
+ <span>
225
+ <FormattedMessage {...messages.withdrawnTitle} />
226
+ </span>
151
227
  </div>
228
+ <p className="dashboard-splitted-card__item__description">
229
+ <FormattedMessage
230
+ {...messages.withdrawnDescription}
231
+ values={{ date: formatDate(order.withdrawn_confirmation_at) }}
232
+ />
233
+ </p>
152
234
  </div>
153
235
  );
154
236
  };
@@ -157,6 +157,11 @@
157
157
  }
158
158
  }
159
159
 
160
+ .order-withdrawal-modal__account-link {
161
+ color: inherit;
162
+ text-decoration: underline;
163
+ }
164
+
160
165
  .order-organization {
161
166
  &__caption {
162
167
  order: 3;
@@ -56,7 +56,9 @@
56
56
 
57
57
  &__status {
58
58
  display: flex;
59
- align-items: center;
59
+ // flex-start (not center) so the icon stays aligned with the first line
60
+ // of text when the text wraps onto several lines.
61
+ align-items: flex-start;
60
62
  gap: 0.5rem;
61
63
 
62
64
  @include media-breakpoint-down(sm) {
@@ -179,6 +181,7 @@
179
181
  justify-content: space-between;
180
182
  padding: 0.5rem 1rem;
181
183
  min-height: 3.75rem;
184
+ border-top: $onepixel solid r-theme-val(dashboard-item, base-border);
182
185
 
183
186
  &:first-child {
184
187
  border-top: 0;
@@ -201,6 +204,11 @@
201
204
  p {
202
205
  margin: 0;
203
206
  }
207
+
208
+ &__withdrawal__button {
209
+ text-decoration: underline;
210
+ white-space: nowrap;
211
+ }
204
212
  }
205
213
 
206
214
  &__runs {
@@ -52,7 +52,6 @@ describe('<Dashboard />', () => {
52
52
  fetchMock.get(
53
53
  'https://joanie.endpoint/api/v1.0/orders/' +
54
54
  '?product_type=credential' +
55
- '&state_exclude=canceled' +
56
55
  '&state_exclude=refunding' +
57
56
  '&state_exclude=refunded' +
58
57
  '&page=1' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "richie-education",
3
- "version": "3.5.1-dev2",
3
+ "version": "3.5.2-dev12",
4
4
  "description": "A CMS to build learning portals for Open Education",
5
5
  "main": "sandbox/manage.py",
6
6
  "scripts": {
@@ -8,4 +8,9 @@
8
8
  @if $body-padding-fix {
9
9
  @include content-padding-fix($gutter: 2rem);
10
10
  }
11
+
12
+ &__maincontent {
13
+ width: 100%;
14
+ padding: 0 $grid-gutter-width 1rem;
15
+ }
11
16
  }