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
@@ -10,7 +10,7 @@ import {
10
10
  SaleTunnelContext,
11
11
  SaleTunnelContextType,
12
12
  } from 'components/SaleTunnel/GenericSaleTunnel';
13
- import { Address } from 'types/Joanie';
13
+ import { Address, PaymentSchedule } from 'types/Joanie';
14
14
  import {
15
15
  AddressFactory,
16
16
  CredentialOrderFactory,
@@ -50,6 +50,7 @@ describe('AddressSelector', () => {
50
50
  const Wrapper = () => {
51
51
  const [billingAddress, setBillingAddress] = useState<Address>();
52
52
  const [voucherCode, setVoucherCode] = useState<string>();
53
+ const [schedule, setSchedule] = useState<PaymentSchedule>();
53
54
  const context: SaleTunnelContextType = useMemo(
54
55
  () => ({
55
56
  webAnalyticsEventKey: 'eventKey',
@@ -58,6 +59,9 @@ describe('AddressSelector', () => {
58
59
  props: {} as SaleTunnelProps,
59
60
  billingAddress,
60
61
  setBillingAddress,
62
+ setBatchOrder: jest.fn(),
63
+ setBatchOrderFormMethods: jest.fn(),
64
+ validateBatchOrder: jest.fn(),
61
65
  setCreditCard: jest.fn(),
62
66
  step: SaleTunnelStep.IDLE,
63
67
  registerSubmitCallback: jest.fn(),
@@ -67,8 +71,11 @@ describe('AddressSelector', () => {
67
71
  hasWaivedWithdrawalRight: false,
68
72
  setHasWaivedWithdrawalRight: jest.fn(),
69
73
  setVoucherCode,
74
+ setSchedule,
75
+ needsPayment: false,
76
+ setNeedsPayment: jest.fn(),
70
77
  }),
71
- [billingAddress, voucherCode],
78
+ [billingAddress, voucherCode, schedule],
72
79
  );
73
80
  contextRef.current = context;
74
81
 
@@ -8,6 +8,7 @@ import {
8
8
  useState,
9
9
  useCallback,
10
10
  } from 'react';
11
+ import { UseFormReturn } from 'react-hook-form';
11
12
  import { SaleTunnelSponsors } from 'components/SaleTunnel/Sponsors/SaleTunnelSponsors';
12
13
  import { SaleTunnelProps } from 'components/SaleTunnel/index';
13
14
  import {
@@ -18,6 +19,8 @@ import {
18
19
  Order,
19
20
  OrderState,
20
21
  Product,
22
+ BatchOrder,
23
+ PaymentSchedule,
21
24
  } from 'types/Joanie';
22
25
  import useProductOrder from 'hooks/useProductOrder';
23
26
  import { SaleTunnelSuccess } from 'components/SaleTunnel/SaleTunnelSuccess';
@@ -43,6 +46,11 @@ export interface SaleTunnelContextType {
43
46
  // meta
44
47
  billingAddress?: Address;
45
48
  setBillingAddress: (address?: Address) => void;
49
+ batchOrder?: BatchOrder;
50
+ setBatchOrder: (batchOrder?: BatchOrder) => void;
51
+ batchOrderFormMethods?: UseFormReturn<BatchOrder>;
52
+ setBatchOrderFormMethods: (methods?: UseFormReturn<BatchOrder>) => void;
53
+ validateBatchOrder: () => void;
46
54
  creditCard?: CreditCard;
47
55
  setCreditCard: (creditCard?: CreditCard) => void;
48
56
  hasWaivedWithdrawalRight: boolean;
@@ -53,6 +61,10 @@ export interface SaleTunnelContextType {
53
61
  nextStep: () => void;
54
62
  voucherCode?: string;
55
63
  setVoucherCode: (code?: string) => void;
64
+ schedule?: PaymentSchedule;
65
+ setSchedule: (schedule?: PaymentSchedule) => void;
66
+ needsPayment: boolean;
67
+ setNeedsPayment: (needsPayment: boolean) => void;
56
68
  }
57
69
 
58
70
  export const SaleTunnelContext = createContext<SaleTunnelContextType>({} as any);
@@ -89,6 +101,8 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
89
101
  productId: props.product.id,
90
102
  });
91
103
  const [billingAddress, setBillingAddress] = useState<Address>();
104
+ const [batchOrder, setBatchOrder] = useState<BatchOrder>();
105
+ const [batchOrderFormMethods, setBatchOrderFormMethods] = useState<UseFormReturn<BatchOrder>>();
92
106
  const [creditCard, setCreditCard] = useState<CreditCard>();
93
107
  const [hasWaivedWithdrawalRight, setHasWaivedWithdrawalRight] = useState(false);
94
108
  const [step, setStep] = useState<SaleTunnelStep>(SaleTunnelStep.IDLE);
@@ -96,6 +110,7 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
96
110
  new Map(),
97
111
  );
98
112
  const [voucherCode, setVoucherCode] = useState<string>();
113
+ const [needsPayment, setNeedsPayment] = useState(true);
99
114
 
100
115
  const nextStep = useCallback(() => {
101
116
  if (order)
@@ -123,6 +138,12 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
123
138
  }
124
139
  }, [order, step]);
125
140
 
141
+ const validateBatchOrder = useCallback(() => {
142
+ if (batchOrder && step === SaleTunnelStep.IDLE) setStep(SaleTunnelStep.SUCCESS);
143
+ }, [batchOrder]);
144
+
145
+ const [schedule, setSchedule] = useState<PaymentSchedule | undefined>(undefined);
146
+
126
147
  const context: SaleTunnelContextType = useMemo(
127
148
  () => ({
128
149
  webAnalyticsEventKey: props.eventKey,
@@ -133,6 +154,11 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
133
154
  props,
134
155
  billingAddress,
135
156
  setBillingAddress,
157
+ batchOrder,
158
+ setBatchOrder,
159
+ batchOrderFormMethods,
160
+ setBatchOrderFormMethods,
161
+ validateBatchOrder,
136
162
  creditCard,
137
163
  setCreditCard,
138
164
  hasWaivedWithdrawalRight,
@@ -154,16 +180,23 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
154
180
  },
155
181
  voucherCode,
156
182
  setVoucherCode,
183
+ schedule,
184
+ setSchedule,
185
+ needsPayment,
186
+ setNeedsPayment,
157
187
  }),
158
188
  [
159
189
  props,
160
190
  order,
161
191
  billingAddress,
192
+ batchOrder,
193
+ batchOrderFormMethods,
162
194
  creditCard,
163
195
  step,
164
196
  submitCallbacks,
165
197
  hasWaivedWithdrawalRight,
166
198
  voucherCode,
199
+ needsPayment,
167
200
  ],
168
201
  );
169
202
 
@@ -0,0 +1,253 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
3
+ import { FormProvider, useForm } from 'react-hook-form';
4
+ import { yupResolver } from '@hookform/resolvers/yup';
5
+ import * as Yup from 'yup';
6
+ import { Step, StepLabel, Stepper } from '@mui/material';
7
+ import { Button } from '@openfun/cunningham-react';
8
+ import { BatchOrder } from 'types/Joanie';
9
+ import Form from 'components/Form';
10
+ import { useSaleTunnelContext } from 'components/SaleTunnel/GenericSaleTunnel';
11
+ import { ObjectHelper } from 'utils/ObjectHelper';
12
+ import { PaymentMethod } from 'components/PaymentInterfaces/types';
13
+ import { StepContent } from 'components/SaleTunnel/SaleTunnelInformation/StepContent';
14
+
15
+ const messages = defineMessages({
16
+ title: {
17
+ id: 'components.SaleTunnel.Information.title',
18
+ description: 'Title for the section containing purchase/billing information',
19
+ defaultMessage: 'Information',
20
+ },
21
+ description: {
22
+ id: 'components.SaleTunnel.Information.description',
23
+ description: 'Helper text explaining that the information will be used for billing',
24
+ defaultMessage: 'Those information will be used for billing',
25
+ },
26
+ purchaseTypeTitle: {
27
+ id: 'components.SaleTunnel.Information.purchaseTypeTitle',
28
+ description: 'Title of the section where the user selects the purchase type',
29
+ defaultMessage: 'Select purchase type',
30
+ },
31
+ purchaseTypeSelect: {
32
+ id: 'components.SaleTunnel.Information.purchaseTypeSelect',
33
+ description: 'Label for the select field used to choose the purchase type',
34
+ defaultMessage: 'Purchase type',
35
+ },
36
+ purchaseTypeOptionSingle: {
37
+ id: 'components.SaleTunnel.Information.purchaseTypeOptionSingle',
38
+ description: 'Option label for selecting a single purchase (B2C)',
39
+ defaultMessage: 'Single purchase (B2C)',
40
+ },
41
+ purchaseTypeOptionGroup: {
42
+ id: 'components.SaleTunnel.Information.purchaseTypeOptionGroup',
43
+ description: 'Option label for selecting a group purchase (B2B)',
44
+ defaultMessage: 'Group purchase (B2B)',
45
+ },
46
+ stepCompany: {
47
+ id: 'components.SaleTunnel.BatchOrderForm.stepCompany',
48
+ description: 'Step label for company information in the batch order form',
49
+ defaultMessage: 'Organization',
50
+ },
51
+ stepAdmin: {
52
+ id: 'components.SaleTunnel.BatchOrderForm.stepAdmin',
53
+ description: 'Step label for administrative follow-up in the batch order form',
54
+ defaultMessage: 'Follow-up',
55
+ },
56
+ stepSignatory: {
57
+ id: 'components.SaleTunnel.BatchOrderForm.stepSignatory',
58
+ description: 'Step label for signatory person in the batch order form',
59
+ defaultMessage: 'Signatory',
60
+ },
61
+ stepParticipants: {
62
+ id: 'components.SaleTunnel.BatchOrderForm.stepParticipants',
63
+ description: 'Step label for participants information in the batch order form',
64
+ defaultMessage: 'Participants',
65
+ },
66
+ stepFinancing: {
67
+ id: 'components.SaleTunnel.BatchOrderForm.stepFinancing',
68
+ description: 'Step label for financing/payment in the batch order form',
69
+ defaultMessage: 'Financing',
70
+ },
71
+ });
72
+
73
+ export const SaleTunnelInformationGroup = () => {
74
+ return (
75
+ <>
76
+ <div>
77
+ <h3 className="block-title mb-t">
78
+ <FormattedMessage {...messages.title} />
79
+ </h3>
80
+ <div className="description mb-s">
81
+ <FormattedMessage {...messages.description} />
82
+ </div>
83
+ </div>
84
+ <BatchOrderForm />
85
+ </>
86
+ );
87
+ };
88
+
89
+ export const validationSchema = Yup.object().shape({
90
+ offering_id: Yup.string().required(),
91
+ company_name: Yup.string().required(),
92
+ identification_number: Yup.string().required(),
93
+ vat_registration: Yup.string().optional(),
94
+ address: Yup.string().required(),
95
+ postcode: Yup.string().required(),
96
+ city: Yup.string().required(),
97
+ country: Yup.string().required(),
98
+ administrative_lastname: Yup.string().required(),
99
+ administrative_firstname: Yup.string().required(),
100
+ administrative_profession: Yup.string().required(),
101
+ administrative_email: Yup.string().email().required(),
102
+ administrative_telephone: Yup.string().required(),
103
+ signatory_lastname: Yup.string().required(),
104
+ signatory_firstname: Yup.string().required(),
105
+ signatory_profession: Yup.string().required(),
106
+ signatory_email: Yup.string().email().required(),
107
+ signatory_telephone: Yup.string().required(),
108
+ billing_address: Yup.object().optional().shape({
109
+ company_name: Yup.string().optional(),
110
+ identification_number: Yup.string().optional(),
111
+ contact_name: Yup.string().optional(),
112
+ contact_email: Yup.string().email().optional(),
113
+ address: Yup.string().optional(),
114
+ postcode: Yup.string().optional(),
115
+ city: Yup.string().optional(),
116
+ country: Yup.string().optional(),
117
+ }),
118
+ nb_seats: Yup.number().required().min(1),
119
+ payment_method: Yup.mixed<PaymentMethod>().oneOf(Object.values(PaymentMethod)).required(),
120
+ funding_entity: Yup.string().optional(),
121
+ funding_amount: Yup.number().optional(),
122
+ organization_id: Yup.string().optional(),
123
+ });
124
+
125
+ const requiredFieldsByStep: (keyof BatchOrder)[][] = [
126
+ ['company_name', 'identification_number', 'address', 'postcode', 'city', 'country'],
127
+ [
128
+ 'administrative_lastname',
129
+ 'administrative_firstname',
130
+ 'administrative_profession',
131
+ 'administrative_email',
132
+ 'administrative_telephone',
133
+ ],
134
+ [
135
+ 'signatory_lastname',
136
+ 'signatory_firstname',
137
+ 'signatory_profession',
138
+ 'signatory_email',
139
+ 'signatory_telephone',
140
+ ],
141
+ ['nb_seats'],
142
+ ['payment_method'],
143
+ ];
144
+
145
+ const BatchOrderForm = () => {
146
+ const intl = useIntl();
147
+ const { offering, batchOrder, setBatchOrder, setBatchOrderFormMethods } = useSaleTunnelContext();
148
+ const [isCurrentStepValid, setIsCurrentStepValid] = useState(false);
149
+ const defaultValues: BatchOrder = {
150
+ offering_id: offering?.id ?? '',
151
+ company_name: '',
152
+ identification_number: '',
153
+ address: '',
154
+ postcode: '',
155
+ city: '',
156
+ country: '',
157
+ administrative_lastname: '',
158
+ administrative_firstname: '',
159
+ administrative_profession: '',
160
+ administrative_email: '',
161
+ administrative_telephone: '',
162
+ signatory_lastname: '',
163
+ signatory_firstname: '',
164
+ signatory_profession: '',
165
+ signatory_email: '',
166
+ signatory_telephone: '',
167
+ nb_seats: 0,
168
+ payment_method: PaymentMethod.PURCHASE_ORDER,
169
+ funding_amount: 0,
170
+ };
171
+
172
+ const [activeStep, setActiveStep] = useState(0);
173
+ const steps = [
174
+ intl.formatMessage(messages.stepCompany),
175
+ intl.formatMessage(messages.stepAdmin),
176
+ intl.formatMessage(messages.stepSignatory),
177
+ intl.formatMessage(messages.stepParticipants),
178
+ intl.formatMessage(messages.stepFinancing),
179
+ ];
180
+
181
+ const form = useForm<BatchOrder>({
182
+ defaultValues: batchOrder || defaultValues,
183
+ mode: 'onBlur',
184
+ resolver: yupResolver(validationSchema),
185
+ });
186
+ const { watch } = form;
187
+ const values = watch();
188
+
189
+ useEffect(() => {
190
+ setBatchOrderFormMethods(form);
191
+ }, [form]);
192
+
193
+ useEffect(() => {
194
+ const cleanedValues = ObjectHelper.removeEmptyFields(values);
195
+ if (JSON.stringify(cleanedValues) !== JSON.stringify(batchOrder)) {
196
+ setBatchOrder(cleanedValues);
197
+ }
198
+ }, [values, batchOrder, setBatchOrder]);
199
+
200
+ useEffect(() => {
201
+ const requiredRules = requiredFieldsByStep[activeStep];
202
+ const isStepValid = requiredRules.every((field) => !!batchOrder?.[field]);
203
+ setIsCurrentStepValid(isStepValid);
204
+ }, [activeStep, batchOrder]);
205
+
206
+ return (
207
+ <FormProvider {...form}>
208
+ <Form noValidate>
209
+ <Stepper activeStep={activeStep} alternativeLabel className="stepper">
210
+ {steps.map((label, index) => (
211
+ <Step key={label}>
212
+ <StepLabel
213
+ onClick={() => {
214
+ if (index < activeStep) {
215
+ setActiveStep(index);
216
+ }
217
+ }}
218
+ style={{ cursor: index < activeStep ? 'pointer' : 'default' }}
219
+ >
220
+ {label}
221
+ </StepLabel>
222
+ </Step>
223
+ ))}
224
+ </Stepper>
225
+ <StepContent activeStep={activeStep} form={form} />
226
+ </Form>
227
+ <div className="navigationButton">
228
+ <Button
229
+ onClick={() => {
230
+ if (activeStep > 0) {
231
+ setActiveStep(activeStep - 1);
232
+ }
233
+ }}
234
+ hidden={activeStep === 0}
235
+ color="secondary"
236
+ >
237
+ Previous
238
+ </Button>
239
+ <Button
240
+ onClick={() => {
241
+ if (activeStep < steps.length - 1) {
242
+ setActiveStep(activeStep + 1);
243
+ }
244
+ }}
245
+ disabled={!isCurrentStepValid}
246
+ hidden={activeStep === steps.length - 1}
247
+ >
248
+ Next
249
+ </Button>
250
+ </div>
251
+ </FormProvider>
252
+ );
253
+ };