richie-education 3.3.2-dev6 → 3.4.1-dev13

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 (179) hide show
  1. package/.eslintrc.json +0 -3
  2. package/.storybook/main.js +11 -12
  3. package/.storybook/preview.tsx +49 -24
  4. package/cunningham.cjs +31 -0
  5. package/i18n/compile-translations.js +12 -10
  6. package/i18n/locales/ar-SA.json +20 -0
  7. package/i18n/locales/es-ES.json +20 -0
  8. package/i18n/locales/fa-IR.json +20 -0
  9. package/i18n/locales/fr-CA.json +20 -0
  10. package/i18n/locales/fr-FR.json +21 -1
  11. package/i18n/locales/ko-KR.json +20 -0
  12. package/i18n/locales/pt-PT.json +42 -22
  13. package/i18n/locales/ru-RU.json +20 -0
  14. package/i18n/locales/vi-VN.json +20 -0
  15. package/jest.config.js +5 -0
  16. package/js/api/joanie.ts +20 -0
  17. package/js/api/utils.ts +4 -3
  18. package/js/components/AddressesManagement/AddressForm/index.stories.tsx +1 -1
  19. package/js/components/AddressesManagement/AddressForm/index.tsx +4 -3
  20. package/js/components/AddressesManagement/index.stories.tsx +1 -1
  21. package/js/components/AddressesManagement/index.tsx +5 -3
  22. package/js/components/Badge/index.stories.tsx +1 -1
  23. package/js/components/Badge/index.tsx +1 -1
  24. package/js/components/Banner/index.stories.tsx +1 -1
  25. package/js/components/CourseGlimpse/index.stories.tsx +1 -1
  26. package/js/components/CourseGlimpseList/index.stories.tsx +1 -1
  27. package/js/components/CreditCardSelector/_styles.scss +2 -2
  28. package/js/components/CreditCardSelector/index.tsx +11 -3
  29. package/js/components/DownloadAgreementButton/index.tsx +51 -0
  30. package/js/components/DownloadBatchOrderSeatsButton/index.spec.tsx +46 -0
  31. package/js/components/DownloadBatchOrderSeatsButton/index.tsx +80 -0
  32. package/js/components/DownloadCertificateButton/index.tsx +2 -1
  33. package/js/components/DownloadContractButton/index.tsx +7 -1
  34. package/js/components/Form/Form/index.tsx +4 -2
  35. package/js/components/Icon/index.stories.tsx +2 -1
  36. package/js/components/Modal/index.stories.tsx +1 -1
  37. package/js/components/Modal/index.tsx +2 -1
  38. package/js/components/OpenEdxFullNameForm/index.stories.tsx +1 -1
  39. package/js/components/OpenEdxFullNameForm/index.tsx +2 -2
  40. package/js/components/PaymentScheduleGrid/_styles.scss +2 -2
  41. package/js/components/PurchaseButton/index.stories.tsx +1 -1
  42. package/js/components/RegisteredAddress/index.stories.tsx +1 -1
  43. package/js/components/RegisteredAddress/index.tsx +4 -2
  44. package/js/components/SaleTunnel/AddressSelector/CreateAddressFormModal.tsx +1 -1
  45. package/js/components/SaleTunnel/AddressSelector/EditAddressFormModal.tsx +1 -1
  46. package/js/components/SaleTunnel/AddressSelector/index.tsx +4 -2
  47. package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationGroup.tsx +5 -4
  48. package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationSingular.tsx +27 -5
  49. package/js/components/SaleTunnel/SaleTunnelSuccess/index.tsx +1 -1
  50. package/js/components/SaleTunnel/SubscriptionButton/index.tsx +9 -6
  51. package/js/components/SaleTunnel/_styles.scss +9 -8
  52. package/js/components/SaleTunnel/index.credential.spec.tsx +50 -1
  53. package/js/components/SaleTunnel/index.full-process-b2b.spec.tsx +5 -5
  54. package/js/components/SaleTunnel/index.full-process-b2c.spec.tsx +1 -1
  55. package/js/components/SaleTunnel/index.stories.tsx +1 -1
  56. package/js/components/Spinner/index.stories.tsx +1 -1
  57. package/js/components/Tabs/index.stories.tsx +1 -1
  58. package/js/components/Tabs/index.tsx +2 -1
  59. package/js/components/TeacherDashboardCourseList/index.tsx +2 -1
  60. package/js/hooks/useAddressesManagement.tsx +4 -2
  61. package/js/hooks/useBatchOrder/index.tsx +21 -1
  62. package/js/hooks/useCreditCards/index.ts +6 -4
  63. package/js/hooks/useDashboardAddressForm.tsx +3 -3
  64. package/js/hooks/useDownloadAgreement/index.spec.tsx +136 -0
  65. package/js/hooks/useDownloadAgreement/index.tsx +25 -0
  66. package/js/hooks/useDownloadBatchOrderSeats/index.spec.tsx +132 -0
  67. package/js/hooks/useDownloadBatchOrderSeats/index.tsx +24 -0
  68. package/js/hooks/useMatchMedia.ts +1 -1
  69. package/js/hooks/useResources/useResourcesRoot.ts +1 -1
  70. package/js/hooks/useUnionResource/index.ts +6 -2
  71. package/js/hooks/useUnionResource/utils/fetchEntity.ts +1 -0
  72. package/js/pages/DashboardAddressesManagement/DashboardAddressBox.tsx +3 -3
  73. package/js/pages/DashboardAddressesManagement/DashboardCreateAddress.stories.tsx +1 -1
  74. package/js/pages/DashboardAddressesManagement/DashboardCreateAddress.tsx +1 -1
  75. package/js/pages/DashboardAddressesManagement/DashboardEditAddress.stories.tsx +1 -1
  76. package/js/pages/DashboardAddressesManagement/DashboardEditAddress.tsx +3 -2
  77. package/js/pages/DashboardAddressesManagement/index.stories.tsx +1 -1
  78. package/js/pages/DashboardAddressesManagement/index.tsx +1 -1
  79. package/js/pages/DashboardBatchOrderLayout/index.spec.tsx +19 -2
  80. package/js/pages/DashboardCourses/index.tsx +2 -1
  81. package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.stories.tsx +1 -1
  82. package/js/pages/DashboardCreditCardsManagement/DashboardCreditCardBox.tsx +3 -3
  83. package/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.stories.tsx +1 -1
  84. package/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.tsx +3 -2
  85. package/js/pages/DashboardCreditCardsManagement/index.stories.tsx +1 -1
  86. package/js/pages/DashboardOpenEdxProfile/index.stories.tsx +1 -1
  87. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +4 -2
  88. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.tsx +2 -1
  89. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +4 -4
  90. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +8 -9
  91. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +14 -3
  92. package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx +6 -1
  93. package/js/pages/TeacherDashboardCourseLoader/CourseRunList/utils.tsx +2 -1
  94. package/js/pages/TeacherDashboardOrganizationAgreements/BulkAgreementContractButton.tsx +4 -2
  95. package/js/pages/TeacherDashboardOrganizationAgreements/SignOrganizationAgreementButton.tsx +2 -1
  96. package/js/pages/TeacherDashboardOrganizationQuotes/BatchOrderSeatInfoQuote.tsx +112 -0
  97. package/js/pages/TeacherDashboardOrganizationQuotes/_styles.scss +17 -0
  98. package/js/pages/TeacherDashboardOrganizationQuotes/index.full-process.spec.tsx +7 -4
  99. package/js/pages/TeacherDashboardOrganizationQuotes/index.spec.tsx +8 -4
  100. package/js/pages/TeacherDashboardOrganizationQuotes/index.tsx +39 -26
  101. package/js/translations/ar-SA.json +1 -1
  102. package/js/translations/es-ES.json +1 -1
  103. package/js/translations/fa-IR.json +1 -1
  104. package/js/translations/fr-CA.json +1 -1
  105. package/js/translations/fr-FR.json +1 -1
  106. package/js/translations/ko-KR.json +1 -1
  107. package/js/translations/pt-PT.json +1 -1
  108. package/js/translations/ru-RU.json +1 -1
  109. package/js/translations/vi-VN.json +1 -1
  110. package/js/types/Joanie.ts +22 -2
  111. package/js/utils/ProductHelper/index.spec.ts +1 -1
  112. package/js/utils/StorybookHelper/index.tsx +3 -6
  113. package/js/utils/cunningham-tokens.ts +1111 -142
  114. package/js/utils/download.ts +3 -1
  115. package/js/utils/errors/handle.spec.ts +3 -3
  116. package/js/utils/react-query/useSessionMutation/index.ts +8 -3
  117. package/js/utils/test/factories/joanie.ts +16 -2
  118. package/js/widgets/Dashboard/components/DashboardAvatar/index.stories.tsx +1 -1
  119. package/js/widgets/Dashboard/components/DashboardBox/index.stories.tsx +13 -5
  120. package/js/widgets/Dashboard/components/DashboardBreadcrumbs/index.stories.tsx +1 -1
  121. package/js/widgets/Dashboard/components/DashboardBreadcrumbs/index.tsx +3 -2
  122. package/js/widgets/Dashboard/components/DashboardCard/index.spec.tsx +13 -2
  123. package/js/widgets/Dashboard/components/DashboardCard/index.stories.tsx +12 -4
  124. package/js/widgets/Dashboard/components/DashboardCard/index.tsx +1 -1
  125. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderAgreementInfo.tsx +72 -0
  126. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/BatchOrderPaymentManager.tsx +1 -1
  127. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/index.tsx +2 -1
  128. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderSeatInfo.spec.tsx +114 -0
  129. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderSeatInfo.tsx +133 -0
  130. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/DashboardBatchOrderSubItems.tsx +17 -1
  131. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/batchOrderSeatInfoMessages.ts +24 -0
  132. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/index.tsx +16 -3
  133. package/js/widgets/Dashboard/components/DashboardItem/Certificate/index.stories.tsx +1 -1
  134. package/js/widgets/Dashboard/components/DashboardItem/Contract/index.stories.tsx +1 -1
  135. package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.stories.tsx +1 -1
  136. package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.tsx +8 -4
  137. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.stories.tsx +1 -1
  138. package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.tsx +1 -1
  139. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderReadonly.stories.tsx +1 -1
  140. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderWritable.stories.tsx +1 -1
  141. package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +1 -1
  142. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/_styles.scss +2 -2
  143. package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx +2 -1
  144. package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.tsx +6 -3
  145. package/js/widgets/Dashboard/components/DashboardItem/_styles.scss +6 -2
  146. package/js/widgets/Dashboard/components/DashboardItem/index.stories.tsx +1 -1
  147. package/js/widgets/Dashboard/components/DashboardItem/index.tsx +2 -1
  148. package/js/widgets/Dashboard/components/DashboardListAvatar/index.stories.tsx +1 -1
  149. package/js/widgets/Dashboard/components/DashboardSidebar/index.stories.tsx +1 -1
  150. package/js/widgets/Dashboard/components/LearnerDashboardSidebar/index.stories.tsx +1 -1
  151. package/js/widgets/Dashboard/components/ProtectedOutlet/AuthenticatedOutlet.spec.tsx +1 -1
  152. package/js/widgets/Dashboard/components/ProtectedOutlet/ProtectedOutlet.spec.tsx +1 -1
  153. package/js/widgets/Dashboard/components/SearchBar/index.tsx +2 -1
  154. package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.stories.tsx +1 -1
  155. package/js/widgets/Dashboard/components/TeacherDashboardProfileSidebar/index.stories.tsx +1 -1
  156. package/js/widgets/Dashboard/hooks/useRouteInfo/index.spec.tsx +2 -2
  157. package/js/widgets/Dashboard/index.spec.tsx +1 -1
  158. package/js/widgets/Dashboard/utils/teacherDashboardPaths.tsx +2 -2
  159. package/js/widgets/Search/components/SearchFilterValueParent/index.stories.tsx +1 -1
  160. package/js/widgets/Search/components/SearchFiltersPane/index.tsx +2 -1
  161. package/js/widgets/Slider/index.stories.tsx +1 -1
  162. package/js/widgets/Slider/index.tsx +7 -6
  163. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCertificateItem/index.stories.tsx +1 -1
  164. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.stories.tsx +1 -1
  165. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +1 -1
  166. package/js/widgets/SyllabusCourseRunsList/components/CourseWishButton/index.tsx +4 -2
  167. package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRun/index.stories.tsx +1 -1
  168. package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRunCompacted/index.stories.tsx +41 -0
  169. package/js/widgets/UserLogin/index.stories.tsx +1 -1
  170. package/package.json +76 -81
  171. package/scss/components/_subheader.scss +1 -1
  172. package/scss/components/templates/richie/slider/_slider.scss +1 -1
  173. package/scss/objects/_course_glimpses.scss +1 -0
  174. package/scss/objects/_dashboard.scss +77 -0
  175. package/scss/trumps/_bootstrap.scss +1 -0
  176. package/scss/vendors/css/cunningham-tokens.css +1259 -154
  177. package/scss/vendors/cunningham-tokens.scss +1479 -150
  178. package/tsconfig.json +1 -1
  179. package/webpack.config.js +8 -0
@@ -0,0 +1,112 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { FormattedMessage, useIntl } from 'react-intl';
3
+ import { Button, Input } from '@openfun/cunningham-react';
4
+ import { Icon, IconTypeEnum } from 'components/Icon';
5
+ import Banner, { BannerType } from 'components/Banner';
6
+ import { useBatchOrderSeats } from 'hooks/useBatchOrder';
7
+ import { BatchOrderQuote, BatchOrderSeat } from 'types/Joanie';
8
+ import { batchOrderSeatInfoMessages } from 'widgets/Dashboard/components/DashboardItem/BatchOrder/batchOrderSeatInfoMessages';
9
+
10
+ const ITEMS_PER_PAGE = 10;
11
+
12
+ export const BatchOrderSeatInfoQuote = ({ batchOrder }: { batchOrder: BatchOrderQuote }) => {
13
+ const intl = useIntl();
14
+ const [query, setQuery] = useState('');
15
+ const [page, setPage] = useState(1);
16
+ const [allSeats, setAllSeats] = useState<BatchOrderSeat[]>([]);
17
+
18
+ const seatsOwnedCount = batchOrder.seats_owned ?? 0;
19
+
20
+ const {
21
+ items: seats,
22
+ meta,
23
+ states,
24
+ } = useBatchOrderSeats(
25
+ {
26
+ batch_order_id: batchOrder.id,
27
+ query: query || undefined,
28
+ page,
29
+ page_size: ITEMS_PER_PAGE,
30
+ },
31
+ { enabled: !!batchOrder.id },
32
+ );
33
+
34
+ useEffect(() => {
35
+ if (page === 1) {
36
+ setAllSeats(seats);
37
+ } else if (seats.length > 0) {
38
+ setAllSeats((prev) => [...prev, ...seats]);
39
+ }
40
+ }, [seats]);
41
+
42
+ useEffect(() => {
43
+ setPage(1);
44
+ }, [query]);
45
+
46
+ const totalCount = meta?.pagination?.count ?? 0;
47
+ const remainingCount = Math.min(ITEMS_PER_PAGE, totalCount - allSeats.length);
48
+
49
+ if (
50
+ !batchOrder.nb_seats ||
51
+ batchOrder.seats_owned === undefined ||
52
+ batchOrder.seats_to_own === undefined
53
+ ) {
54
+ return null;
55
+ }
56
+
57
+ return (
58
+ <div className="dashboard__quote__enrollment">
59
+ <div className="content">
60
+ <div className="enrollment-progress">
61
+ <span className="dashboard-item__label">
62
+ {intl.formatMessage(batchOrderSeatInfoMessages.enrolledParticipants, {
63
+ seats_owned: seatsOwnedCount,
64
+ nb_seats: batchOrder.nb_seats,
65
+ })}
66
+ </span>
67
+ <div className="enrollment-progress__bar">
68
+ <div
69
+ className="enrollment-progress__bar__fill"
70
+ style={{ width: `${(seatsOwnedCount / batchOrder.nb_seats) * 100}%` }}
71
+ />
72
+ </div>
73
+ </div>
74
+ {states.error && <Banner message={states.error} type={BannerType.ERROR} />}
75
+ <div className="enrollment-nested-section__content">
76
+ <Input
77
+ className="enrollment-search"
78
+ label={intl.formatMessage(batchOrderSeatInfoMessages.searchPlaceholder)}
79
+ value={query}
80
+ onChange={(e) => setQuery(e.target.value)}
81
+ rightIcon={<Icon name={IconTypeEnum.MAGNIFYING_GLASS} size="small" />}
82
+ />
83
+ {allSeats.length === 0 && query ? (
84
+ <FormattedMessage {...batchOrderSeatInfoMessages.noResults} />
85
+ ) : (
86
+ <>
87
+ <ul className="enrollment-list">
88
+ {allSeats.map((seat) => (
89
+ <li key={seat.id}>{seat.owner_name ?? seat.voucher}</li>
90
+ ))}
91
+ </ul>
92
+ {remainingCount > 0 && (
93
+ <Button
94
+ className="enrollment-load-more"
95
+ color="brand"
96
+ variant="secondary"
97
+ size="small"
98
+ onClick={() => setPage((p) => p + 1)}
99
+ disabled={states.fetching}
100
+ >
101
+ {intl.formatMessage(batchOrderSeatInfoMessages.loadMore, {
102
+ count: remainingCount,
103
+ })}
104
+ </Button>
105
+ )}
106
+ </>
107
+ )}
108
+ </div>
109
+ </div>
110
+ </div>
111
+ );
112
+ };
@@ -38,3 +38,20 @@
38
38
  display: flex;
39
39
  justify-content: center;
40
40
  }
41
+
42
+ .dashboard__quote__enrollment {
43
+ margin-top: 1rem;
44
+ padding-top: 1rem;
45
+ border-top: 1px solid r-theme-val(dashboard-card, base-color);
46
+
47
+ &__title {
48
+ margin: 0 0 0.5rem;
49
+ }
50
+
51
+ .content {
52
+ font-size: 0.8rem;
53
+ display: flex;
54
+ flex-direction: column;
55
+ gap: 0.5rem;
56
+ }
57
+ }
@@ -37,7 +37,7 @@ describe('full process for the organization quotes dashboard', () => {
37
37
 
38
38
  const organization = OrganizationFactory({
39
39
  abilities: {
40
- can_submit_for_signature_batch_order: true,
40
+ can_manage_batch_order_agreement: true,
41
41
  confirm_bank_transfer: true,
42
42
  confirm_quote: true,
43
43
  download_quote: true,
@@ -50,7 +50,7 @@ describe('full process for the organization quotes dashboard', () => {
50
50
  batch_order: {
51
51
  state: BatchOrderState.QUOTED,
52
52
  payment_method: PaymentMethod.CARD_PAYMENT,
53
- available_actions: { next_action: 'confirm_quote' },
53
+ available_actions: { next_action: 'confirm_quote', download_quote: true },
54
54
  },
55
55
  organization_signed_on: undefined,
56
56
  }).one();
@@ -206,7 +206,7 @@ describe('full process for the organization quotes dashboard', () => {
206
206
  fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/`, []);
207
207
  const organization = OrganizationFactory({
208
208
  abilities: {
209
- can_submit_for_signature_batch_order: true,
209
+ can_manage_batch_order_agreement: true,
210
210
  confirm_bank_transfer: true,
211
211
  confirm_quote: true,
212
212
  download_quote: true,
@@ -214,7 +214,6 @@ describe('full process for the organization quotes dashboard', () => {
214
214
  },
215
215
  }).one();
216
216
  fetchMock.get('https://joanie.endpoint/api/v1.0/organizations/1/', organization);
217
-
218
217
  const quoteQuoted = OrganizationQuoteFactory({
219
218
  batch_order: {
220
219
  state: BatchOrderState.QUOTED,
@@ -272,6 +271,10 @@ describe('full process for the organization quotes dashboard', () => {
272
271
  `https://joanie.endpoint/api/v1.0/organizations/1/submit-for-signature-batch-order/`,
273
272
  200,
274
273
  );
274
+ fetchMock.get(
275
+ `https://joanie.endpoint/api/v1.0/batch-orders/${quoteCompleted.batch_order.id}/seats/?page=1&page_size=10`,
276
+ { results: [], count: 0, previous: null, next: null },
277
+ );
275
278
 
276
279
  render(<TeacherDashboardOrganizationQuotes />, {
277
280
  routerOptions: {
@@ -28,7 +28,9 @@ describe('pages/TeacherDashboardOrganizationQuotes', () => {
28
28
  });
29
29
 
30
30
  it('should render a list of quotes for an organization', async () => {
31
- const quoteList = OrganizationQuoteFactory().many(1);
31
+ const quoteList = OrganizationQuoteFactory({
32
+ batch_order: { state: BatchOrderState.QUOTED },
33
+ }).many(1);
32
34
  fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/`, []);
33
35
 
34
36
  fetchMock.get('https://joanie.endpoint/api/v1.0/organizations/1/', []);
@@ -85,7 +87,9 @@ describe('pages/TeacherDashboardOrganizationQuotes', () => {
85
87
  });
86
88
 
87
89
  it('should paginate', async () => {
88
- const quoteList = OrganizationQuoteFactory().many(30);
90
+ const quoteList = OrganizationQuoteFactory({
91
+ batch_order: { state: BatchOrderState.QUOTED },
92
+ }).many(30);
89
93
  fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/`, []);
90
94
 
91
95
  fetchMock.get('https://joanie.endpoint/api/v1.0/organizations/1/', []);
@@ -158,14 +162,14 @@ describe('pages/TeacherDashboardOrganizationQuotes', () => {
158
162
  const quoteQuoted = OrganizationQuoteFactory({
159
163
  batch_order: {
160
164
  state: BatchOrderState.QUOTED,
161
- available_actions: { next_action: 'confirm_quote' },
165
+ available_actions: { next_action: 'confirm_quote', download_quote: true },
162
166
  },
163
167
  }).one();
164
168
  fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/`, []);
165
169
 
166
170
  const organization = OrganizationFactory({
167
171
  abilities: {
168
- can_submit_for_signature_batch_order: false,
172
+ can_manage_batch_order_agreement: false,
169
173
  confirm_bank_transfer: false,
170
174
  confirm_quote: false,
171
175
  download_quote: true,
@@ -14,6 +14,7 @@ import Badge from 'components/Badge';
14
14
  import { Icon, IconTypeEnum } from 'components/Icon';
15
15
  import { browserDownloadFromBlob } from 'utils/download';
16
16
  import { Spinner } from 'components/Spinner';
17
+ import { BatchOrderSeatInfoQuote } from './BatchOrderSeatInfoQuote';
17
18
 
18
19
  const messages = defineMessages({
19
20
  loading: {
@@ -360,34 +361,40 @@ const TeacherDashboardOrganizationQuotes = () => {
360
361
  );
361
362
  };
362
363
 
364
+ const renderDownloadButton = (quote: OrganizationQuote) => {
365
+ const batchOrder = quote.batch_order;
366
+
367
+ return (
368
+ <Button
369
+ size="small"
370
+ color="brand"
371
+ variant="secondary"
372
+ className="mr-2"
373
+ onClick={() => handleDownloadQuote(quote.id)}
374
+ icon={<span className="material-icons">download</span>}
375
+ disabled={!abilities?.download_quote || !batchOrder.available_actions.download_quote}
376
+ >
377
+ {intl.formatMessage(messages.downloadQuote)}
378
+ </Button>
379
+ );
380
+ };
381
+
363
382
  const renderActionButton = (quote: OrganizationQuote) => {
364
383
  const batchOrder = quote.batch_order;
365
384
  const state = batchOrder?.state;
366
385
  const paymentMethod = batchOrder?.payment_method;
367
386
 
368
- if (!batchOrder || !state || !paymentMethod || state === BatchOrderState.COMPLETED) return null;
369
-
370
- const confirmQuoteButtons = (
371
- <div>
372
- <Button
373
- size="small"
374
- color="secondary"
375
- className="mr-2"
376
- onClick={() => handleDownloadQuote(quote.id)}
377
- icon={<span className="material-icons">download</span>}
378
- disabled={!abilities?.download_quote}
379
- >
380
- {intl.formatMessage(messages.downloadQuote)}
381
- </Button>
382
- <Button
383
- size="small"
384
- onClick={() => handleOpenConfirm(quote.id)}
385
- icon={<span className="material-icons">check_circle</span>}
386
- disabled={!abilities?.confirm_quote}
387
- >
388
- {intl.formatMessage(messages.confirmQuote)}
389
- </Button>
390
- </div>
387
+ if (!batchOrder || !state || !paymentMethod) return null;
388
+
389
+ const confirmQuoteButton = (
390
+ <Button
391
+ size="small"
392
+ onClick={() => handleOpenConfirm(quote.id)}
393
+ icon={<span className="material-icons">check_circle</span>}
394
+ disabled={!abilities?.confirm_quote}
395
+ >
396
+ {intl.formatMessage(messages.confirmQuote)}
397
+ </Button>
391
398
  );
392
399
 
393
400
  const confirmPurchaseOrderButton = (
@@ -415,7 +422,7 @@ const TeacherDashboardOrganizationQuotes = () => {
415
422
  const submitForSignatureButton = (
416
423
  <Button
417
424
  size="small"
418
- disabled={batchOrder.contract_submitted || !abilities?.can_submit_for_signature_batch_order}
425
+ disabled={batchOrder.contract_submitted || !abilities?.can_manage_batch_order_agreement}
419
426
  onClick={() =>
420
427
  !batchOrder.contract_submitted && handleSubmitForSignature(quote.batch_order.id)
421
428
  }
@@ -429,7 +436,7 @@ const TeacherDashboardOrganizationQuotes = () => {
429
436
 
430
437
  switch (batchOrder.available_actions?.next_action) {
431
438
  case 'confirm_quote':
432
- return confirmQuoteButtons;
439
+ return confirmQuoteButton;
433
440
  case 'confirm_purchase_order':
434
441
  return confirmPurchaseOrderButton;
435
442
  case 'confirm_bank_transfer':
@@ -484,7 +491,10 @@ const TeacherDashboardOrganizationQuotes = () => {
484
491
  </Badge>
485
492
  )}
486
493
  </div>
487
- <div className="dashboard__quote__header__action">{renderActionButton(quote)}</div>
494
+ <div className="dashboard__quote__header__action">
495
+ {renderDownloadButton(quote)}
496
+ {renderActionButton(quote)}
497
+ </div>
488
498
  </div>
489
499
  }
490
500
  defaultExpanded={false}
@@ -533,6 +543,9 @@ const TeacherDashboardOrganizationQuotes = () => {
533
543
  </div>
534
544
  )}
535
545
  </div>
546
+ {quote.batch_order.state === BatchOrderState.COMPLETED && (
547
+ <BatchOrderSeatInfoQuote batchOrder={quote.batch_order} />
548
+ )}
536
549
  </DashboardCard>
537
550
  ))}
538
551
  <Pagination {...pagination} />