richie-education 3.2.1-dev9 → 3.2.2-dev26

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 (98) hide show
  1. package/i18n/locales/ar-SA.json +29 -1
  2. package/i18n/locales/es-ES.json +29 -1
  3. package/i18n/locales/fa-IR.json +29 -1
  4. package/i18n/locales/fr-CA.json +29 -1
  5. package/i18n/locales/fr-FR.json +29 -1
  6. package/i18n/locales/ko-KR.json +29 -1
  7. package/i18n/locales/pt-PT.json +29 -1
  8. package/i18n/locales/ru-RU.json +29 -1
  9. package/i18n/locales/vi-VN.json +29 -1
  10. package/js/api/joanie.ts +144 -0
  11. package/js/components/PaymentInterfaces/types.ts +7 -0
  12. package/js/components/PaymentScheduleGrid/index.tsx +4 -2
  13. package/js/components/SaleTunnel/AddressSelector/index.spec.tsx +9 -2
  14. package/js/components/SaleTunnel/GenericSaleTunnel.tsx +33 -0
  15. package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationGroup.tsx +253 -0
  16. package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationSingular.tsx +314 -0
  17. package/js/components/SaleTunnel/SaleTunnelInformation/StepContent.tsx +528 -0
  18. package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +47 -261
  19. package/js/components/SaleTunnel/SaleTunnelSuccess/index.tsx +25 -11
  20. package/js/components/SaleTunnel/SubscriptionButton/index.tsx +54 -6
  21. package/js/components/SaleTunnel/_styles.scss +55 -0
  22. package/js/components/SaleTunnel/index.full-process-b2b.spec.tsx +356 -0
  23. package/js/components/SaleTunnel/{index.full-process.spec.tsx → index.full-process-b2c.spec.tsx} +4 -1
  24. package/js/components/SaleTunnel/index.spec.tsx +130 -1
  25. package/js/hooks/useBatchOrder/index.tsx +36 -0
  26. package/js/hooks/useContractArchive/index.ts +2 -0
  27. package/js/hooks/useOfferingOrganizations/index.tsx +38 -0
  28. package/js/hooks/useOrganizationAgreements.tsx/index.tsx +66 -0
  29. package/js/hooks/useOrganizationQuotes/index.tsx +56 -0
  30. package/js/hooks/usePaymentPlan.tsx +2 -1
  31. package/js/hooks/useTeacherPendingAgreementsCount/index.ts +34 -0
  32. package/js/pages/DashboardBatchOrderLayout/_styles.scss +5 -0
  33. package/js/pages/DashboardBatchOrderLayout/index.spec.tsx +78 -0
  34. package/js/pages/DashboardBatchOrderLayout/index.tsx +45 -0
  35. package/js/pages/DashboardBatchOrders/index.spec.tsx +237 -0
  36. package/js/pages/DashboardBatchOrders/index.tsx +84 -0
  37. package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardCourseContractsLayout/index.tsx +0 -1
  38. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +3 -1
  39. package/js/pages/TeacherDashboardOrganizationAgreements/AgreementActionsBar.tsx +49 -0
  40. package/js/pages/TeacherDashboardOrganizationAgreements/BulkAgreementContractButton.tsx +79 -0
  41. package/js/pages/TeacherDashboardOrganizationAgreements/OrganizationAgreementFrame.tsx +71 -0
  42. package/js/pages/TeacherDashboardOrganizationAgreements/SignOrganizationAgreementButton.tsx +60 -0
  43. package/js/pages/TeacherDashboardOrganizationAgreements/hooks/useAgreementsAbilities.tsx +8 -0
  44. package/js/pages/TeacherDashboardOrganizationAgreements/hooks/useHasAgreementToDownload.tsx +27 -0
  45. package/js/pages/TeacherDashboardOrganizationAgreements/hooks/useTeacherAgreementsToSign.tsx +32 -0
  46. package/js/pages/TeacherDashboardOrganizationAgreements/index.spec.tsx +433 -0
  47. package/js/pages/TeacherDashboardOrganizationAgreements/index.tsx +130 -0
  48. package/js/pages/TeacherDashboardOrganizationAgreementsLayout/index.tsx +25 -0
  49. package/js/pages/TeacherDashboardOrganizationCourseLoader/index.spec.tsx +9 -0
  50. package/js/pages/TeacherDashboardOrganizationQuotes/_styles.scss +40 -0
  51. package/js/pages/TeacherDashboardOrganizationQuotes/index.full-process.spec.tsx +194 -0
  52. package/js/pages/TeacherDashboardOrganizationQuotes/index.spec.tsx +144 -0
  53. package/js/pages/TeacherDashboardOrganizationQuotes/index.tsx +521 -0
  54. package/js/pages/TeacherDashboardOrganizationQuotesLayout/index.tsx +26 -0
  55. package/js/translations/ar-SA.json +1 -1
  56. package/js/translations/es-ES.json +1 -1
  57. package/js/translations/fa-IR.json +1 -1
  58. package/js/translations/fr-CA.json +1 -1
  59. package/js/translations/fr-FR.json +1 -1
  60. package/js/translations/ko-KR.json +1 -1
  61. package/js/translations/pt-PT.json +1 -1
  62. package/js/translations/ru-RU.json +1 -1
  63. package/js/translations/vi-VN.json +1 -1
  64. package/js/types/Joanie.ts +216 -1
  65. package/js/utils/AbilitiesHelper/agreementAbilities.ts +14 -0
  66. package/js/utils/AbilitiesHelper/index.ts +7 -0
  67. package/js/utils/AbilitiesHelper/types.ts +12 -3
  68. package/js/utils/ObjectHelper/index.ts +20 -0
  69. package/js/utils/OrderHelper/index.ts +10 -0
  70. package/js/utils/errors/HttpError.ts +1 -0
  71. package/js/utils/test/factories/joanie.ts +156 -1
  72. package/js/widgets/Dashboard/components/DashboardBatchOrderLoader/_styles.scss +14 -0
  73. package/js/widgets/Dashboard/components/DashboardBatchOrderLoader/index.tsx +32 -0
  74. package/js/widgets/Dashboard/components/DashboardCard/index.spec.tsx +18 -0
  75. package/js/widgets/Dashboard/components/DashboardCard/index.stories.tsx +25 -2
  76. package/js/widgets/Dashboard/components/DashboardCard/index.tsx +4 -2
  77. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/BatchOrderPaymentManager.tsx +88 -0
  78. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/index.tsx +216 -0
  79. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/DashboardBatchOrderSubItems.tsx +316 -0
  80. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/index.spec.tsx +27 -0
  81. package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/index.tsx +175 -0
  82. package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +5 -2
  83. package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.tsx +4 -1
  84. package/js/widgets/Dashboard/components/DashboardItem/Order/_styles.scss +5 -0
  85. package/js/widgets/Dashboard/components/DashboardItem/_styles.scss +43 -0
  86. package/js/widgets/Dashboard/components/DashboardSidebar/components/AgreementNavLink/index.spec.tsx +214 -0
  87. package/js/widgets/Dashboard/components/DashboardSidebar/components/AgreementNavLink/index.tsx +47 -0
  88. package/js/widgets/Dashboard/components/LearnerDashboardSidebar/index.tsx +1 -0
  89. package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.spec.tsx +21 -3
  90. package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.tsx +9 -0
  91. package/js/widgets/Dashboard/utils/learnerRoutes.tsx +30 -0
  92. package/js/widgets/Dashboard/utils/learnerRoutesPaths.tsx +12 -0
  93. package/js/widgets/Dashboard/utils/teacherDashboardPaths.tsx +12 -0
  94. package/js/widgets/Dashboard/utils/teacherRoutes.tsx +17 -0
  95. package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +8 -2
  96. package/package.json +4 -1
  97. package/scss/colors/_theme.scss +1 -1
  98. package/scss/components/_index.scss +1 -0
@@ -0,0 +1,521 @@
1
+ import { defineMessages, FormattedMessage, FormattedNumber, useIntl } from 'react-intl';
2
+ import { Button, Input, Modal, ModalSize } from '@openfun/cunningham-react';
3
+ import { useEffect, useState } from 'react';
4
+ import { useParams } from 'react-router';
5
+ import Banner, { BannerType } from 'components/Banner';
6
+ import { useOrganizationsQuotes } from 'hooks/useOrganizationQuotes';
7
+ import { TeacherDashboardContractsParams } from 'pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters';
8
+ import { BatchOrderState, OrganizationQuote } from 'types/Joanie';
9
+ import { PaymentMethod } from 'components/PaymentInterfaces/types';
10
+ import { DashboardCard } from 'widgets/Dashboard/components/DashboardCard';
11
+ import { Pagination, usePagination } from 'components/Pagination';
12
+ import Badge from 'components/Badge';
13
+ import { Icon, IconTypeEnum } from 'components/Icon';
14
+ import { browserDownloadFromBlob } from 'utils/download';
15
+ import { Spinner } from 'components/Spinner';
16
+
17
+ const messages = defineMessages({
18
+ loading: {
19
+ defaultMessage: 'Loading organization quotes...',
20
+ description: 'Message displayed while loading organization quotes',
21
+ id: 'components.OrganizationQuotesTable.loading',
22
+ },
23
+ columnTitle: {
24
+ defaultMessage: 'Title',
25
+ id: 'components.OrganizationQuotesTable.columnTitle',
26
+ description: 'Title column in the quotes table',
27
+ },
28
+ columnCompany: {
29
+ defaultMessage: 'Company',
30
+ id: 'components.OrganizationQuotesTable.columnCompany',
31
+ description: 'Company column in the quotes table',
32
+ },
33
+ columnOwner: {
34
+ defaultMessage: 'Owner',
35
+ id: 'components.OrganizationQuotesTable.columnOwner',
36
+ description: 'Owner column in the quotes table',
37
+ },
38
+ columnState: {
39
+ defaultMessage: 'State',
40
+ id: 'components.OrganizationQuotesTable.columnState',
41
+ description: 'State column in the quotes table',
42
+ },
43
+ columnSignedOn: {
44
+ defaultMessage: 'Signed on',
45
+ id: 'components.OrganizationQuotesTable.columnSignedOn',
46
+ description: 'Signed on date column in the quotes table',
47
+ },
48
+ columnPayment: {
49
+ defaultMessage: 'Payment method',
50
+ id: 'components.OrganizationQuotesTable.payment',
51
+ description: 'Payment method column in the quotes table',
52
+ },
53
+ columnActions: {
54
+ defaultMessage: 'Actions',
55
+ id: 'components.OrganizationQuotesTable.columnActions',
56
+ description: 'Actions column in the quotes table',
57
+ },
58
+ confirmQuote: {
59
+ defaultMessage: 'Confirm quote',
60
+ id: 'components.OrganizationQuotesTable.confirmQuote',
61
+ description: 'Label for the action to confirm a quote',
62
+ },
63
+ confirmPurchaseOrder: {
64
+ defaultMessage: 'Confirm receipt of purchase order',
65
+ id: 'components.OrganizationQuotesTable.confirmPurchaseOrder',
66
+ description: 'Label for confirming receipt of a purchase order',
67
+ },
68
+ confirmBank: {
69
+ defaultMessage: 'Confirm bank transfer',
70
+ id: 'components.OrganizationQuotesTable.confirmBank',
71
+ description: 'Label for confirming a bank transfer',
72
+ },
73
+ sendForSignature: {
74
+ defaultMessage: 'Send quote for signature',
75
+ id: 'components.OrganizationQuotesTable.sendForSignature',
76
+ description: 'Action label to send a quote for signature',
77
+ },
78
+ waitingSignature: {
79
+ defaultMessage: 'Waiting signature',
80
+ id: 'components.OrganizationQuotesTable.waitingSignature',
81
+ description: 'Label for a quote waiting for signature',
82
+ },
83
+ waitingPayment: {
84
+ defaultMessage: 'Waiting payment',
85
+ id: 'components.OrganizationQuotesTable.waitingPayment',
86
+ description: 'Label for a quote waiting for payment',
87
+ },
88
+ processingPayment: {
89
+ defaultMessage: 'Processing payment',
90
+ id: 'components.OrganizationQuotesTable.processingPayment',
91
+ description: 'Label when Lyra is processing for payment',
92
+ },
93
+ payAmount: {
94
+ defaultMessage: 'Waiting for payment',
95
+ id: 'components.OrganizationQuotesTable.payAmount',
96
+ description: 'Label indicating the amount is pending payment',
97
+ },
98
+ downloadQuote: {
99
+ defaultMessage: 'Download quote',
100
+ id: 'components.OrganizationQuotesTable.downloadQuote',
101
+ description: 'Action label to download the quote',
102
+ },
103
+ modalTitle: {
104
+ defaultMessage: 'Confirm quote',
105
+ id: 'components.OrganizationQuotesTable.modalTitle',
106
+ description: 'Title of the confirm quote modal',
107
+ },
108
+ modalAmountLabel: {
109
+ defaultMessage: 'Total amount',
110
+ id: 'components.OrganizationQuotesTable.modalAmountLabel',
111
+ description: 'Label for the total amount in the modal',
112
+ },
113
+ modalCancel: {
114
+ defaultMessage: 'Cancel',
115
+ id: 'components.OrganizationQuotesTable.modalCancel',
116
+ description: 'Cancel button text in modal',
117
+ },
118
+ noQuotes: {
119
+ defaultMessage: 'No quotes found for this organization.',
120
+ id: 'components.OrganizationQuotesTable.noQuotes',
121
+ description: 'Message displayed when no quotes exist for the organization',
122
+ },
123
+ paymentCard: {
124
+ defaultMessage: 'Credit card',
125
+ id: 'components.OrganizationQuotesTable.paymentCard',
126
+ description: 'Payment method: credit card',
127
+ },
128
+ paymentPurchaseOrder: {
129
+ defaultMessage: 'Purchase order',
130
+ id: 'components.OrganizationQuotesTable.paymentPurchaseOrder',
131
+ description: 'Payment method: purchase order',
132
+ },
133
+ paymentBankTransfer: {
134
+ defaultMessage: 'Bank transfer',
135
+ id: 'components.OrganizationQuotesTable.paymentBankTransfer',
136
+ description: 'Payment method: bank transfer',
137
+ },
138
+ [BatchOrderState.QUOTED]: {
139
+ id: 'components.OrganizationQuotesTable.state.quoted',
140
+ defaultMessage: 'Quoted',
141
+ description: 'Batch order state: quoted',
142
+ },
143
+ [BatchOrderState.TO_SIGN]: {
144
+ id: 'components.OrganizationQuotesTable.state.toSign',
145
+ defaultMessage: 'To sign',
146
+ description: 'Batch order state: to be signed',
147
+ },
148
+ [BatchOrderState.SIGNING]: {
149
+ id: 'components.OrganizationQuotesTable.state.signing',
150
+ defaultMessage: 'Signing',
151
+ description: 'Batch order state: currently being signed',
152
+ },
153
+ [BatchOrderState.PROCESS_PAYMENT]: {
154
+ id: 'batchOrder.status.processPayment',
155
+ description: 'Status label for a process payment batch order',
156
+ defaultMessage: 'Process payment',
157
+ },
158
+ [BatchOrderState.COMPLETED]: {
159
+ id: 'components.OrganizationQuotesTable.state.completed',
160
+ defaultMessage: 'Completed',
161
+ description: 'Batch order state: completed',
162
+ },
163
+ [BatchOrderState.DRAFT]: {
164
+ id: 'components.OrganizationQuotesTable.state.draft.',
165
+ defaultMessage: 'Draft',
166
+ description: 'Batch order state: draft',
167
+ },
168
+ [BatchOrderState.ASSIGNED]: {
169
+ id: 'components.OrganizationQuotesTable.state.assigned.',
170
+ defaultMessage: 'Assigned',
171
+ description: 'Batch order state: assigned',
172
+ },
173
+ [BatchOrderState.PENDING]: {
174
+ id: 'components.OrganizationQuotesTable.state.pending.',
175
+ defaultMessage: 'Pending',
176
+ description: 'Batch order state: pending',
177
+ },
178
+ [BatchOrderState.FAILED_PAYMENT]: {
179
+ id: 'components.OrganizationQuotesTable.state.failedPayment.',
180
+ defaultMessage: 'Failed payment',
181
+ description: 'Batch order state: failed payment',
182
+ },
183
+ [BatchOrderState.CANCELED]: {
184
+ id: 'components.OrganizationQuotesTable.state.canceled',
185
+ defaultMessage: 'Canceled',
186
+ description: 'Batch order state: canceled',
187
+ },
188
+ [PaymentMethod.CARD_PAYMENT]: {
189
+ id: 'components.OrganizationQuotesTable.payment.card',
190
+ defaultMessage: 'Card payment',
191
+ description: 'Payment method: card payment',
192
+ },
193
+ [PaymentMethod.PURCHASE_ORDER]: {
194
+ id: 'components.OrganizationQuotesTable.payment.purchaseOrder',
195
+ defaultMessage: 'Purchase order',
196
+ description: 'Payment method: purchase order',
197
+ },
198
+ [PaymentMethod.BANK_TRANSFER]: {
199
+ id: 'components.OrganizationQuotesTable.payment.bankTransfer',
200
+ defaultMessage: 'Bank transfer',
201
+ description: 'Payment method: bank transfer',
202
+ },
203
+ batchOrderId: {
204
+ id: 'components.OrganizationQuotesTable.batchOrderId',
205
+ defaultMessage: 'Batch order id: {id}',
206
+ description: 'Label for the batch order reference (id)',
207
+ },
208
+ seats: {
209
+ id: 'batchOrder.seats',
210
+ defaultMessage: '{seats} {seats, plural, one {seat} other {seats}}',
211
+ description: 'Text displayed for seats value in batch order',
212
+ },
213
+ });
214
+
215
+ const TeacherDashboardOrganizationQuotes = () => {
216
+ const intl = useIntl();
217
+ const { organizationId: routeOrganizationId } = useParams<TeacherDashboardContractsParams>();
218
+ const pagination = usePagination({ itemsPerPage: 10 });
219
+
220
+ const {
221
+ quotes,
222
+ confirmQuote,
223
+ confirmPurchaseOrder,
224
+ confirmBankTransfer,
225
+ submitForSignature,
226
+ downloadQuote,
227
+ } = useOrganizationsQuotes();
228
+
229
+ const {
230
+ items: quotesList,
231
+ states: { error, isPending },
232
+ meta,
233
+ methods: { invalidate },
234
+ } = quotes({
235
+ organization_id: routeOrganizationId,
236
+ page: pagination.currentPage,
237
+ page_size: pagination.itemsPerPage,
238
+ });
239
+
240
+ const [selectedQuote, setSelectedQuote] = useState<OrganizationQuote | null>(null);
241
+ const [amount, setAmount] = useState('');
242
+ const [isModalOpen, setIsModalOpen] = useState(false);
243
+
244
+ useEffect(() => {
245
+ if (meta?.pagination?.count) {
246
+ pagination.setItemsCount(meta.pagination.count);
247
+ }
248
+ }, [meta?.pagination?.count]);
249
+
250
+ if (error) return <Banner message={error} type={BannerType.ERROR} rounded />;
251
+
252
+ if (isPending)
253
+ return (
254
+ <Spinner size="large">
255
+ <span id="loading-contract-data">
256
+ <FormattedMessage {...messages.loading} />
257
+ </span>
258
+ </Spinner>
259
+ );
260
+
261
+ if (!isPending && !error && quotesList.length === 0)
262
+ return (
263
+ <Banner type={BannerType.INFO} rounded message={intl.formatMessage(messages.noQuotes)} />
264
+ );
265
+
266
+ const handleOpenConfirm = (id: string) => {
267
+ const quote = quotesList.find((q) => q.id === id);
268
+ if (!quote) return;
269
+ setSelectedQuote(quote);
270
+ setIsModalOpen(true);
271
+ };
272
+
273
+ const handleCancel = () => {
274
+ setIsModalOpen(false);
275
+ setAmount('');
276
+ setSelectedQuote(null);
277
+ };
278
+
279
+ const handleConfirmQuote = async () => {
280
+ if (!selectedQuote) return;
281
+ await confirmQuote({
282
+ organization_id: routeOrganizationId,
283
+ payload: { total: amount, quote_id: selectedQuote.id },
284
+ });
285
+ handleCancel();
286
+ await invalidate();
287
+ };
288
+
289
+ const handleConfirmPurchaseOrder = async (id: string) => {
290
+ await confirmPurchaseOrder({
291
+ organization_id: routeOrganizationId,
292
+ payload: { quote_id: id },
293
+ });
294
+ await invalidate();
295
+ };
296
+
297
+ const handleConfirmBankTransfer = async (id: string) => {
298
+ await confirmBankTransfer({
299
+ organization_id: routeOrganizationId,
300
+ payload: { batch_order_id: id },
301
+ });
302
+ await invalidate();
303
+ };
304
+
305
+ const handleSubmitForSignature = async (id: string) => {
306
+ await submitForSignature({
307
+ organization_id: routeOrganizationId,
308
+ payload: { batch_order_id: id },
309
+ });
310
+ await invalidate();
311
+ };
312
+
313
+ const handleDownloadQuote = async (id: string) => {
314
+ await browserDownloadFromBlob(
315
+ () =>
316
+ downloadQuote({
317
+ organization_id: routeOrganizationId,
318
+ quote_id: id,
319
+ }),
320
+ true,
321
+ );
322
+ };
323
+
324
+ const renderActionButton = (quote: OrganizationQuote) => {
325
+ const batchOrder = quote.batch_order;
326
+ const state = batchOrder?.state;
327
+ const paymentMethod = batchOrder?.payment_method;
328
+
329
+ if (!batchOrder || !state || !paymentMethod || state === BatchOrderState.COMPLETED) return null;
330
+
331
+ const confirmQuoteButtons = (
332
+ <div>
333
+ <Button
334
+ size="small"
335
+ color="secondary"
336
+ className="mr-2"
337
+ onClick={() => handleDownloadQuote(quote.id)}
338
+ icon={<span className="material-icons">download</span>}
339
+ >
340
+ {intl.formatMessage(messages.downloadQuote)}
341
+ </Button>
342
+ <Button
343
+ size="small"
344
+ onClick={() => handleOpenConfirm(quote.id)}
345
+ icon={<span className="material-icons">check_circle</span>}
346
+ >
347
+ {intl.formatMessage(messages.confirmQuote)}
348
+ </Button>
349
+ </div>
350
+ );
351
+
352
+ const confirmPurchaseOrderButton = (
353
+ <Button
354
+ size="small"
355
+ className="ml-2"
356
+ onClick={() => handleConfirmPurchaseOrder(quote.id)}
357
+ icon={<span className="material-icons">description</span>}
358
+ >
359
+ {intl.formatMessage(messages.confirmPurchaseOrder)}
360
+ </Button>
361
+ );
362
+
363
+ const confirmBankTransferButton = (
364
+ <Button
365
+ size="small"
366
+ onClick={() => handleConfirmBankTransfer(quote.batch_order.id)}
367
+ icon={<span className="material-icons">account_balance</span>}
368
+ >
369
+ {intl.formatMessage(messages.confirmBank)}
370
+ </Button>
371
+ );
372
+
373
+ const submitForSignatureButton = (
374
+ <Button
375
+ size="small"
376
+ disabled={batchOrder.contract_submitted}
377
+ onClick={() =>
378
+ !batchOrder.contract_submitted && handleSubmitForSignature(quote.batch_order.id)
379
+ }
380
+ icon={<span className="material-icons">send</span>}
381
+ >
382
+ {batchOrder.contract_submitted
383
+ ? intl.formatMessage(messages.waitingSignature)
384
+ : intl.formatMessage(messages.sendForSignature)}
385
+ </Button>
386
+ );
387
+
388
+ switch (batchOrder.available_actions?.next_action) {
389
+ case 'confirm_quote':
390
+ return confirmQuoteButtons;
391
+ case 'confirm_purchase_order':
392
+ return confirmPurchaseOrderButton;
393
+ case 'confirm_bank_transfer':
394
+ return confirmBankTransferButton;
395
+ case 'submit_for_signature':
396
+ return submitForSignatureButton;
397
+ }
398
+
399
+ switch (paymentMethod) {
400
+ case PaymentMethod.CARD_PAYMENT:
401
+ switch (state) {
402
+ case BatchOrderState.PENDING:
403
+ return (
404
+ <Button
405
+ size="small"
406
+ disabled
407
+ icon={<span className="material-icons">hourglass_empty</span>}
408
+ >
409
+ {intl.formatMessage(messages.waitingPayment)}
410
+ </Button>
411
+ );
412
+ case BatchOrderState.PROCESS_PAYMENT:
413
+ return (
414
+ <Button size="small" disabled icon={<span className="material-icons">sync</span>}>
415
+ {intl.formatMessage(messages.processingPayment)}
416
+ </Button>
417
+ );
418
+ }
419
+ break;
420
+ }
421
+
422
+ switch (state) {
423
+ case BatchOrderState.TO_SIGN:
424
+ return submitForSignatureButton;
425
+ }
426
+
427
+ return null;
428
+ };
429
+
430
+ return (
431
+ <div className="dashboard__quotes">
432
+ {quotesList.map((quote) => (
433
+ <DashboardCard
434
+ key={quote.id}
435
+ header={
436
+ <div className="dashboard__quote__header">
437
+ <div className="dashboard__quote__header__main">
438
+ <span>{quote.batch_order.relation.product.title}</span>
439
+ {quote.batch_order.state && (
440
+ <Badge color="secondary">
441
+ <FormattedMessage {...messages[quote.batch_order.state]} />
442
+ </Badge>
443
+ )}
444
+ </div>
445
+ <div className="dashboard__quote__header__action">{renderActionButton(quote)}</div>
446
+ </div>
447
+ }
448
+ defaultExpanded={false}
449
+ >
450
+ <div className="dashboard__quote__informations">
451
+ <div className="dashboard__quote__reference">
452
+ <Icon name={IconTypeEnum.BARCODE} size="small" />
453
+ <span>
454
+ {intl.formatMessage(messages.batchOrderId, {
455
+ id: quote.batch_order.id,
456
+ })}
457
+ </span>
458
+ </div>
459
+ {quote.batch_order.owner_name && (
460
+ <div className="dashboard__quote__information">
461
+ <Icon name={IconTypeEnum.LOGIN} size="small" />
462
+ <span>{quote.batch_order.owner_name}</span>
463
+ </div>
464
+ )}
465
+ {quote.batch_order.company_name && (
466
+ <div className="dashboard__quote__information">
467
+ <Icon name={IconTypeEnum.ORG} size="small" />
468
+ <span>{quote.batch_order.company_name}</span>
469
+ </div>
470
+ )}
471
+ {quote.batch_order.nb_seats && (
472
+ <div className="dashboard__quote__information">
473
+ <Icon name={IconTypeEnum.GROUPS} size="small" />
474
+ <div>
475
+ <span>
476
+ {intl.formatMessage(messages.seats, { seats: quote.batch_order.nb_seats })}
477
+ </span>
478
+ </div>
479
+ </div>
480
+ )}
481
+ {quote.total && (
482
+ <div className="dashboard__quote__information">
483
+ <Icon name={IconTypeEnum.MONEY} size="small" />
484
+ <FormattedNumber value={quote.total} currency="EUR" style="currency" />
485
+ </div>
486
+ )}
487
+ {quote.batch_order.payment_method && (
488
+ <div className="dashboard__quote__information">
489
+ <Icon name={IconTypeEnum.OFFER_SUBSCRIPTION} size="small" />
490
+ <FormattedMessage {...messages[quote.batch_order.payment_method]} />
491
+ </div>
492
+ )}
493
+ </div>
494
+ </DashboardCard>
495
+ ))}
496
+ <Pagination {...pagination} />
497
+ <Modal
498
+ isOpen={isModalOpen}
499
+ onClose={handleCancel}
500
+ title={intl.formatMessage(messages.modalTitle)}
501
+ size={ModalSize.MEDIUM}
502
+ actions={
503
+ <Button size="small" onClick={handleConfirmQuote}>
504
+ {intl.formatMessage(messages.confirmQuote)}
505
+ </Button>
506
+ }
507
+ >
508
+ <div className="dashboard__quote__modal">
509
+ <Input
510
+ type="number"
511
+ label={intl.formatMessage(messages.modalAmountLabel)}
512
+ onChange={(e) => setAmount(e.target.value)}
513
+ value={amount}
514
+ />
515
+ </div>
516
+ </Modal>
517
+ </div>
518
+ );
519
+ };
520
+
521
+ export default TeacherDashboardOrganizationQuotes;
@@ -0,0 +1,26 @@
1
+ import { defineMessages, FormattedMessage } from 'react-intl';
2
+ import TeacherDashboardOrganizationQuotes from 'pages/TeacherDashboardOrganizationQuotes';
3
+
4
+ import { DashboardLayout } from 'widgets/Dashboard/components/DashboardLayout';
5
+ import { TeacherDashboardOrganizationSidebar } from 'widgets/Dashboard/components/TeacherDashboardOrganizationSidebar';
6
+
7
+ const messages = defineMessages({
8
+ pageTitle: {
9
+ defaultMessage: 'Quotes',
10
+ description: 'Use for the page title of the organization quotes',
11
+ id: 'pages.TeacherDashboardOrganizationQuotesLayout.pageTitle',
12
+ },
13
+ });
14
+
15
+ export const TeacherDashboardOrganizationQuotesLayout = () => {
16
+ return (
17
+ <DashboardLayout sidebar={<TeacherDashboardOrganizationSidebar />}>
18
+ <div className="dashboard__page_title_container">
19
+ <h1 className="dashboard__page_title">
20
+ <FormattedMessage {...messages.pageTitle} />
21
+ </h1>
22
+ </div>
23
+ <TeacherDashboardOrganizationQuotes />
24
+ </DashboardLayout>
25
+ );
26
+ };