@infosoftas/s4-orders-js-sdk 0.0.1-alpha2c.3 → 0.0.1-beta1.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infosoftas/s4-orders-js-sdk",
3
- "version": "0.0.1-alpha2c.3",
3
+ "version": "0.0.1-beta1.0",
4
4
  "scripts": {
5
5
  "build": "rimraf lib && webpack --env mode=production",
6
6
  "release": "release-it"
package/src/App.tsx CHANGED
@@ -40,6 +40,7 @@ const App: FC<ConfigType> = ({
40
40
  paymentMethodsOptions,
41
41
  invoiceAddressSelection,
42
42
  availablePaymentMethods = [],
43
+ allowedPaymentMethods,
43
44
  language = 'en-US',
44
45
  merchantAgreementUrl = '',
45
46
  settings = {
@@ -49,10 +50,15 @@ const App: FC<ConfigType> = ({
49
50
  submitButtonText: 'Start',
50
51
  backButtonText: 'Back',
51
52
  verifyButtonText: 'Verify',
52
- organizationNumberLabel: 'CVR',
53
+ organizationNumberLabel: 'Organization Number',
53
54
  paymentMethodLabel: '',
54
55
  glnLabel: 'GLN',
56
+ cvrLabel: 'CVR',
55
57
  orderDefaultValues: undefined,
58
+ errorReqMsg: '',
59
+ errorInvalidEmailMsg: '',
60
+ errorInvalidPhoneMsg: '',
61
+ paymentMethodNotAllowedMsg: '',
56
62
  },
57
63
  }) => {
58
64
  const [loading, setLoading] = useState<boolean>(false);
@@ -249,11 +255,19 @@ const App: FC<ConfigType> = ({
249
255
  setFormType(FormTypeEnum.ORDER);
250
256
  };
251
257
 
252
- const handleInvoiceForm = async () => {
258
+ const updateFormData = (data: OrderFormInputsType) => {
259
+ setOrderFormValues(data);
260
+ setFormType(data.paymentMethod as unknown as FormTypeEnum);
261
+ };
262
+
263
+ const handleInvoiceForm = async (
264
+ _: string | null,
265
+ data?: OrderInfoType | null
266
+ ) => {
253
267
  await messageCallback({
254
- orderId: orderId || '',
268
+ orderId: data?.orderId || orderId || '',
255
269
  agreementId: '',
256
- orderInfo: orderInfo || null,
270
+ orderInfo: data || orderInfo || null,
257
271
  });
258
272
  };
259
273
 
@@ -283,10 +297,25 @@ const App: FC<ConfigType> = ({
283
297
  callback={handleInvoiceForm}
284
298
  backButtonText={settings?.backButtonText}
285
299
  verifyButtonText={settings?.verifyButtonText}
286
- organizationNumberLabel={
287
- settings?.organizationNumberLabel
288
- }
300
+ organizationNumberLabel={settings?.cvrLabel}
289
301
  glnLabel={settings?.glnLabel}
302
+ organizationNumber={
303
+ orderFormValues?.organizationNumber
304
+ }
305
+ orderValues={orderFormValues}
306
+ templatePackageId={templatePackageId}
307
+ subscriberId={subscriberId}
308
+ userId={userId}
309
+ identityProviderId={identityProviderId}
310
+ organizationId={organizationId}
311
+ redirectUrl={redirectUrl}
312
+ showIframe={showIframe}
313
+ paymentMethodsOptions={paymentMethodsOptions}
314
+ language={language}
315
+ merchantAgreementUrl={merchantAgreementUrl}
316
+ invoiceAddressSelection={
317
+ invoiceAddressSelection
318
+ }
290
319
  />
291
320
  )}
292
321
  {formType === FormTypeEnum.EHF && (
@@ -298,12 +327,30 @@ const App: FC<ConfigType> = ({
298
327
  organizationNumberLabel={
299
328
  settings?.organizationNumberLabel
300
329
  }
330
+ organizationNumber={
331
+ orderFormValues?.organizationNumber
332
+ }
333
+ orderValues={orderFormValues}
334
+ templatePackageId={templatePackageId}
335
+ subscriberId={subscriberId}
336
+ userId={userId}
337
+ identityProviderId={identityProviderId}
338
+ organizationId={organizationId}
339
+ redirectUrl={redirectUrl}
340
+ showIframe={showIframe}
341
+ paymentMethodsOptions={paymentMethodsOptions}
342
+ language={language}
343
+ merchantAgreementUrl={merchantAgreementUrl}
344
+ invoiceAddressSelection={
345
+ invoiceAddressSelection
346
+ }
301
347
  />
302
348
  )}
303
349
  {formType !== FormTypeEnum.OIO &&
304
350
  formType !== FormTypeEnum.EHF && (
305
351
  <OrderForm
306
352
  callback={handleForm}
353
+ updateFormData={updateFormData}
307
354
  submitStartCallback={submitStartCallback}
308
355
  templatePackageId={templatePackageId}
309
356
  subscriberId={subscriberId}
@@ -311,12 +358,18 @@ const App: FC<ConfigType> = ({
311
358
  identityProviderId={identityProviderId}
312
359
  organizationId={organizationId}
313
360
  paymentMethods={availablePaymentMethods}
361
+ allowedPaymentMethods={
362
+ allowedPaymentMethods
363
+ }
314
364
  submitButtonText={
315
365
  settings?.submitButtonText
316
366
  }
317
367
  paymentMethodLabel={
318
368
  settings?.paymentMethodLabel
319
369
  }
370
+ paymentMethodNotAllowedMsg={
371
+ settings?.paymentMethodNotAllowedMsg
372
+ }
320
373
  errorReqMsg={settings?.errorReqMsg}
321
374
  errorInvalidEmailMsg={
322
375
  settings?.errorInvalidEmailMsg
@@ -1,24 +1,46 @@
1
- import { FC, useState } from 'react';
1
+ import { FC } from 'react';
2
2
  import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
3
3
 
4
- import { invoiceLookup } from '../../api/InvoiceApi';
5
4
  import Alert from '../Alert/Alert';
6
5
  import Button from '../Button/Button';
7
6
  import InputField from '../FormFields/InputField';
7
+ import { PaymentMethodEnum } from '../../enums/general';
8
8
  import {
9
- prepareErrorMessage,
10
- prepareErrorsArrayMessage,
11
- } from '../../utils/helper';
12
- import { InvoiceLookupNetworkEnum } from '../../enums/general';
13
- import { ErrorsMsg } from '../../types/general';
9
+ OrderFormFiledType,
10
+ PaymentMethodOptionsType,
11
+ } from '../../types/general';
12
+ import { OrderFormInputsType, OrderInfoType } from '../../types/order';
13
+ import { orderInvoiceContactFields } from '../../utils/order.helper';
14
+ import useOrderForm from '../../hooks/useOrderForm';
15
+ import { DEFAULT_ORDER_FORM_FIELDS } from '../FormFields/FormFields.helper';
14
16
 
15
17
  type Props = {
16
- callback: (value: string) => void;
18
+ callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
17
19
  onBack: () => void;
20
+ submitStartCallback?: (id: string) => void;
21
+ className?: string;
18
22
  backButtonText?: string;
19
23
  verifyButtonText?: string;
20
24
  organizationNumberLabel?: string;
21
- className?: string;
25
+ organizationNumber?: string;
26
+ glnLabel?: string;
27
+ templatePackageId: string;
28
+ subscriberId?: string;
29
+ userId?: string;
30
+ identityProviderId?: string;
31
+ organizationId: string;
32
+ redirectUrl?: string;
33
+ showIframe?: boolean;
34
+ language: string;
35
+ merchantAgreementUrl: string;
36
+ orderValues?: OrderFormInputsType;
37
+ paymentMethodsOptions?: PaymentMethodOptionsType;
38
+ invoiceAddressSelection?: {
39
+ enabled?: boolean;
40
+ label?: string;
41
+ fields?: OrderFormFiledType[];
42
+ paymentMethods?: PaymentMethodEnum[];
43
+ };
22
44
  };
23
45
 
24
46
  type EHFFormInputsType = {
@@ -32,18 +54,29 @@ const initialData = {
32
54
  const EHFForm: FC<Props> = ({
33
55
  callback,
34
56
  onBack,
57
+ submitStartCallback,
58
+ className = '',
35
59
  backButtonText = '',
36
60
  verifyButtonText = '',
37
61
  organizationNumberLabel = '',
38
- className = '',
62
+ organizationNumber = '',
63
+ templatePackageId,
64
+ subscriberId,
65
+ userId,
66
+ identityProviderId,
67
+ organizationId,
68
+ redirectUrl,
69
+ showIframe,
70
+ language,
71
+ merchantAgreementUrl,
72
+ orderValues,
73
+ paymentMethodsOptions,
74
+ invoiceAddressSelection,
39
75
  }) => {
40
- const [loading, setLoading] = useState<boolean>(false);
41
- const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
42
- const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
43
-
44
76
  const methods = useForm<EHFFormInputsType>({
45
77
  defaultValues: {
46
78
  ...initialData,
79
+ organizationNumber,
47
80
  },
48
81
  });
49
82
 
@@ -52,32 +85,38 @@ const EHFForm: FC<Props> = ({
52
85
  formState: { errors },
53
86
  } = methods;
54
87
 
88
+ const invoiceOrderFields =
89
+ invoiceAddressSelection?.fields || orderInvoiceContactFields;
90
+
91
+ const orderFields =
92
+ paymentMethodsOptions?.[orderValues?.paymentMethod as PaymentMethodEnum]
93
+ ?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
94
+
95
+ const { orderSubmit, loading, apiErrorMsg, errorsMsg } = useOrderForm({
96
+ callback,
97
+ submitStartCallback,
98
+ organizationId,
99
+ subscriberId,
100
+ userId,
101
+ identityProviderId,
102
+ orderFields,
103
+ redirectUrl,
104
+ showIframe,
105
+ language,
106
+ merchantAgreementUrl,
107
+ paymentMethodsOptions,
108
+ templatePackageId,
109
+ invoiceAddressToggle: orderValues?.invoiceAddressSelection,
110
+ invoiceOrderFields,
111
+ });
112
+
55
113
  const onSubmit: SubmitHandler<EHFFormInputsType> = async (
56
114
  data
57
115
  ): Promise<void> => {
58
- setApiErrorMsg('');
59
- setErrorsMsg([]);
60
- setLoading(true);
61
- try {
62
- await invoiceLookup({
63
- network: InvoiceLookupNetworkEnum.EHF,
64
- value: data.organizationNumber,
65
- });
66
- callback(data.organizationNumber);
67
- } catch (error) {
68
- setApiErrorMsg(prepareErrorMessage(error as Error));
69
- setErrorsMsg(
70
- prepareErrorsArrayMessage(
71
- (
72
- error as {
73
- errors: ErrorsMsg;
74
- }
75
- )?.errors
76
- )
77
- );
78
- } finally {
79
- setLoading(false);
80
- }
116
+ orderSubmit({
117
+ ...orderValues,
118
+ organizationNumber: data.organizationNumber,
119
+ });
81
120
  };
82
121
 
83
122
  const handleBack = () => {
@@ -27,7 +27,7 @@ const AddressField: FC<Props> = ({
27
27
  const { register } = useFormContext();
28
28
  const id = uuidv4();
29
29
  return (
30
- <div className="field-wrapper" data-testid="sdk-address-field-id">
30
+ <div className="field-wrapper" data-testid={`sdk-${name}-field-id`}>
31
31
  <textarea
32
32
  id={id}
33
33
  autoComplete="address"
@@ -29,7 +29,7 @@ const EmailField: FC<Props> = ({
29
29
  const { register } = useFormContext();
30
30
  const id = uuidv4();
31
31
  return (
32
- <div className="field-wrapper" data-testid="sdk-email-field-id">
32
+ <div className="field-wrapper" data-testid={`sdk-${name}-field-id`}>
33
33
  <input
34
34
  id={id}
35
35
  autoComplete="email"
@@ -27,7 +27,7 @@ const NameField: FC<Props> = ({
27
27
  const { register } = useFormContext();
28
28
  const id = uuidv4();
29
29
  return (
30
- <div className="field-wrapper" data-testid="sdk-name-field-id">
30
+ <div className="field-wrapper" data-testid={`sdk-${name}-field-id`}>
31
31
  <input
32
32
  id={id}
33
33
  autoComplete="name"
@@ -29,7 +29,7 @@ const PhoneFiled: FC<Props> = ({
29
29
  const { register } = useFormContext();
30
30
  const id = uuidv4();
31
31
  return (
32
- <div className="field-wrapper" data-testid="sdk-phone-field-id">
32
+ <div className="field-wrapper" data-testid={`sdk-${name}-field-id`}>
33
33
  <input
34
34
  id={id}
35
35
  autoComplete="tel"
@@ -1,25 +1,47 @@
1
- import { FC, useState } from 'react';
1
+ import { FC } from 'react';
2
2
  import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
3
3
 
4
- import { invoiceLookup } from '../../api/InvoiceApi';
5
4
  import Alert from '../Alert/Alert';
6
5
  import Button from '../Button/Button';
7
6
  import InputField from '../FormFields/InputField';
7
+ import { DEFAULT_ORDER_FORM_FIELDS } from '../FormFields/FormFields.helper';
8
+
9
+ import { PaymentMethodEnum } from '../../enums/general';
8
10
  import {
9
- prepareErrorMessage,
10
- prepareErrorsArrayMessage,
11
- } from '../../utils/helper';
12
- import { InvoiceLookupNetworkEnum } from '../../enums/general';
13
- import { ErrorsMsg } from '../../types/general';
11
+ OrderFormFiledType,
12
+ PaymentMethodOptionsType,
13
+ } from '../../types/general';
14
+ import useOrderForm from '../../hooks/useOrderForm';
15
+ import { orderInvoiceContactFields } from '../../utils/order.helper';
16
+ import { OrderFormInputsType, OrderInfoType } from '../../types/order';
14
17
 
15
18
  type Props = {
16
- callback: (value: string) => void;
19
+ callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
17
20
  onBack: () => void;
21
+ submitStartCallback?: (id: string) => void;
22
+ className?: string;
18
23
  backButtonText?: string;
19
24
  verifyButtonText?: string;
20
25
  organizationNumberLabel?: string;
26
+ organizationNumber?: string;
21
27
  glnLabel?: string;
22
- className?: string;
28
+ templatePackageId: string;
29
+ subscriberId?: string;
30
+ userId?: string;
31
+ identityProviderId?: string;
32
+ organizationId: string;
33
+ redirectUrl?: string;
34
+ showIframe?: boolean;
35
+ language: string;
36
+ merchantAgreementUrl: string;
37
+ orderValues?: OrderFormInputsType;
38
+ paymentMethodsOptions?: PaymentMethodOptionsType;
39
+ invoiceAddressSelection?: {
40
+ enabled?: boolean;
41
+ label?: string;
42
+ fields?: OrderFormFiledType[];
43
+ paymentMethods?: PaymentMethodEnum[];
44
+ };
23
45
  };
24
46
 
25
47
  type OIOFormInputsType = {
@@ -35,19 +57,30 @@ const initialData = {
35
57
  const EHFForm: FC<Props> = ({
36
58
  callback,
37
59
  onBack,
60
+ submitStartCallback,
61
+ className = '',
38
62
  backButtonText = '',
39
63
  verifyButtonText = '',
40
64
  organizationNumberLabel = '',
65
+ organizationNumber = '',
41
66
  glnLabel = '',
42
- className = '',
67
+ templatePackageId,
68
+ subscriberId,
69
+ userId,
70
+ identityProviderId,
71
+ organizationId,
72
+ redirectUrl,
73
+ showIframe,
74
+ language,
75
+ merchantAgreementUrl,
76
+ orderValues,
77
+ paymentMethodsOptions,
78
+ invoiceAddressSelection,
43
79
  }) => {
44
- const [loading, setLoading] = useState<boolean>(false);
45
- const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
46
- const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
47
-
48
80
  const methods = useForm<OIOFormInputsType>({
49
81
  defaultValues: {
50
82
  ...initialData,
83
+ cvr: organizationNumber,
51
84
  },
52
85
  });
53
86
 
@@ -60,34 +93,35 @@ const EHFForm: FC<Props> = ({
60
93
  const cvr = watch('cvr');
61
94
  const gln = watch('gln');
62
95
 
96
+ const invoiceOrderFields =
97
+ invoiceAddressSelection?.fields || orderInvoiceContactFields;
98
+
99
+ const orderFields =
100
+ paymentMethodsOptions?.[orderValues?.paymentMethod as PaymentMethodEnum]
101
+ ?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
102
+
103
+ const { orderSubmit, loading, apiErrorMsg, errorsMsg } = useOrderForm({
104
+ callback,
105
+ submitStartCallback,
106
+ organizationId,
107
+ subscriberId,
108
+ userId,
109
+ identityProviderId,
110
+ orderFields,
111
+ redirectUrl,
112
+ showIframe,
113
+ language,
114
+ merchantAgreementUrl,
115
+ paymentMethodsOptions,
116
+ templatePackageId,
117
+ invoiceAddressToggle: orderValues?.invoiceAddressSelection,
118
+ invoiceOrderFields,
119
+ });
120
+
63
121
  const onSubmit: SubmitHandler<OIOFormInputsType> = async (
64
122
  data
65
123
  ): Promise<void> => {
66
- setApiErrorMsg('');
67
- setErrorsMsg([]);
68
- setLoading(true);
69
- try {
70
- await invoiceLookup({
71
- network: data.gln
72
- ? InvoiceLookupNetworkEnum.OIO_GLN
73
- : InvoiceLookupNetworkEnum.OIO_Danish_CVR,
74
- value: data.gln || data.cvr,
75
- });
76
- callback(data.gln || data.cvr);
77
- } catch (error) {
78
- setApiErrorMsg(prepareErrorMessage(error as Error));
79
- setErrorsMsg(
80
- prepareErrorsArrayMessage(
81
- (
82
- error as {
83
- errors: ErrorsMsg;
84
- }
85
- )?.errors
86
- )
87
- );
88
- } finally {
89
- setLoading(false);
90
- }
124
+ orderSubmit({ ...orderValues, gln: data.gln, cvr: data.cvr });
91
125
  };
92
126
 
93
127
  const handleBack = () => {
@@ -1,10 +1,11 @@
1
- import { FC, ChangeEvent, Suspense, useState } from 'react';
1
+ import { FC, ChangeEvent, Suspense, useState, useMemo } from 'react';
2
2
  import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
3
3
 
4
- import { createSubscriber, mapSubscriberToUser } from '../../api/SubscribeApi';
5
- import { orderStart } from '../../api/OrdersApi';
6
4
  import { PaymentMethodEnum } from '../../enums/general';
7
- import { WRONG_MSG, PAYMENT_METHOD_DEFAULT } from '../../constants/index';
5
+ import {
6
+ PAYMENT_METHOD_DEFAULT,
7
+ INVOICE_ALLOWED_PAYMENT_METHODS,
8
+ } from '../../constants/index';
8
9
  import Alert from '../Alert/Alert';
9
10
  import Button from '../Button/Button';
10
11
  import ToggleField from '../FormFields/ToggleFiled';
@@ -14,23 +15,15 @@ import { OrderFormInputsType, OrderInfoType } from '../../types/order';
14
15
  import {
15
16
  PaymentMethodOptionsType,
16
17
  OrderFormFiledType,
17
- ErrorsMsg,
18
18
  } from '../../types/general';
19
- import {
20
- orderInvoiceContactFields,
21
- prepareAgreementModel,
22
- prepareContactModel,
23
- prepareInvoiceModel,
24
- } from '../../utils/order.helper';
25
- import {
26
- prepareErrorMessage,
27
- prepareErrorsArrayMessage,
28
- } from '../../utils/helper';
19
+ import { orderInvoiceContactFields } from '../../utils/order.helper';
20
+ import useOrderForm from '../../hooks/useOrderForm';
29
21
 
30
22
  import './orderForm.scss';
31
23
 
32
24
  type Props = {
33
25
  callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
26
+ updateFormData: (data: OrderFormInputsType) => void;
34
27
  submitStartCallback?: (id: string) => void;
35
28
  templatePackageId: string;
36
29
  subscriberId?: string;
@@ -44,8 +37,10 @@ type Props = {
44
37
  paymentMethodsOptions?: PaymentMethodOptionsType;
45
38
  defaultValues?: OrderFormInputsType;
46
39
  paymentMethods?: { label: string; value: PaymentMethodEnum }[];
40
+ allowedPaymentMethods?: PaymentMethodEnum[];
47
41
  submitButtonText?: string;
48
42
  paymentMethodLabel?: string;
43
+ paymentMethodNotAllowedMsg?: string;
49
44
  errorReqMsg?: string;
50
45
  errorInvalidEmailMsg?: string;
51
46
  errorInvalidPhoneMsg?: string;
@@ -53,6 +48,7 @@ type Props = {
53
48
  enabled?: boolean;
54
49
  label?: string;
55
50
  fields?: OrderFormFiledType[];
51
+ paymentMethods?: PaymentMethodEnum[];
56
52
  };
57
53
  };
58
54
 
@@ -71,6 +67,7 @@ const initialData = {
71
67
 
72
68
  const OrderForm: FC<Props> = ({
73
69
  callback,
70
+ updateFormData,
74
71
  submitStartCallback,
75
72
  templatePackageId,
76
73
  subscriberId,
@@ -84,16 +81,15 @@ const OrderForm: FC<Props> = ({
84
81
  language,
85
82
  merchantAgreementUrl,
86
83
  paymentMethods = [],
84
+ allowedPaymentMethods,
87
85
  invoiceAddressSelection,
88
86
  submitButtonText = 'Start',
89
87
  paymentMethodLabel = 'Select Payment Method',
88
+ paymentMethodNotAllowedMsg = 'This payment method not allowed!',
90
89
  errorReqMsg = '',
91
90
  errorInvalidEmailMsg = '',
92
91
  errorInvalidPhoneMsg = '',
93
92
  }) => {
94
- const [loading, setLoading] = useState<boolean>(false);
95
- const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
96
- const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
97
93
  const [orderFields, setOrderFields] = useState<OrderFormFiledType[]>(
98
94
  paymentMethodsOptions?.[
99
95
  defaultValues?.paymentMethod || PAYMENT_METHOD_DEFAULT
@@ -111,6 +107,10 @@ const OrderForm: FC<Props> = ({
111
107
  const invoiceOrderFields =
112
108
  invoiceAddressSelection?.fields || orderInvoiceContactFields;
113
109
 
110
+ const invoicePaymentMethods =
111
+ invoiceAddressSelection?.paymentMethods ||
112
+ INVOICE_ALLOWED_PAYMENT_METHODS;
113
+
114
114
  const {
115
115
  register,
116
116
  handleSubmit,
@@ -120,99 +120,37 @@ const OrderForm: FC<Props> = ({
120
120
  } = methods;
121
121
 
122
122
  const invoiceAddressToggle = watch('invoiceAddressSelection');
123
+ const paymentMethodInput = watch('paymentMethod');
124
+
125
+ const { orderSubmit, loading, apiErrorMsg, errorsMsg } = useOrderForm({
126
+ callback,
127
+ submitStartCallback,
128
+ organizationId,
129
+ subscriberId,
130
+ userId,
131
+ identityProviderId,
132
+ orderFields,
133
+ redirectUrl,
134
+ showIframe,
135
+ language,
136
+ merchantAgreementUrl,
137
+ paymentMethodsOptions,
138
+ templatePackageId,
139
+ invoiceAddressToggle,
140
+ invoiceOrderFields,
141
+ });
123
142
 
124
143
  const onSubmit: SubmitHandler<OrderFormInputsType> = async (
125
144
  data
126
145
  ): Promise<void> => {
127
- setApiErrorMsg('');
128
- setErrorsMsg([]);
129
-
130
- setLoading(true);
131
- try {
132
- let id: string | undefined = subscriberId;
133
- const contactModel = prepareContactModel({ data, orderFields });
134
- if (!subscriberId) {
135
- const response = await createSubscriber({
136
- ...contactModel,
137
- });
138
- id = response.id;
139
-
140
- if (userId && identityProviderId) {
141
- await mapSubscriberToUser(id, {
142
- userId: userId,
143
- identityProviderId: identityProviderId,
144
- });
145
- }
146
- }
147
-
148
- submitStartCallback?.(id as string);
149
-
150
- if (id) {
151
- const paymentMethod =
152
- data.paymentMethod || PAYMENT_METHOD_DEFAULT;
153
-
154
- const agreements = prepareAgreementModel({
155
- paymentMethod,
156
- redirectUrl,
157
- showIframe,
158
- phoneNumber: orderFields.find(
159
- (i) => i.name === 'phoneNumber'
160
- )
161
- ? data.phoneNumber?.trim() || undefined
162
- : undefined,
163
- language,
164
- merchantAgreementUrl,
165
- generateSubscriberContact:
166
- paymentMethodsOptions?.[
167
- data.paymentMethod as PaymentMethodEnum
168
- ]?.generateSubscriberContact || false,
169
- accountId:
170
- paymentMethodsOptions?.[
171
- data.paymentMethod as PaymentMethodEnum
172
- ]?.accountId,
173
- });
174
- const responseOrder = await orderStart({
175
- subscriberId: id,
176
- subscriptionPlan: {
177
- organizationId,
178
- templateSubscriptionPlanId: templatePackageId,
179
- },
180
- paymentAgreement: { ...agreements },
181
- invoiceContact: invoiceAddressToggle
182
- ? prepareInvoiceModel({
183
- data,
184
- orderFields: invoiceOrderFields,
185
- })
186
- : undefined,
187
- orderReference: data.orderReference || undefined,
188
- });
189
- callback(responseOrder.terminalRedirectUrl, {
190
- ...(data || {}),
191
- orderId: responseOrder.id,
192
- subscriberId: id,
193
- paymentMethod: paymentMethod,
194
- });
195
- return;
196
- }
197
- callback(null);
198
- setApiErrorMsg(WRONG_MSG);
199
- setErrorsMsg([]);
200
- } catch (error) {
201
- console.error(error);
202
- setApiErrorMsg(prepareErrorMessage(error as Error));
203
- setErrorsMsg(
204
- prepareErrorsArrayMessage(
205
- (
206
- error as {
207
- errors: ErrorsMsg;
208
- }
209
- )?.errors
210
- )
211
- );
212
- callback(null);
213
- } finally {
214
- setLoading(false);
146
+ if (
147
+ paymentMethodInput === PaymentMethodEnum.EHF ||
148
+ paymentMethodInput === PaymentMethodEnum.OIO
149
+ ) {
150
+ updateFormData(data);
151
+ return;
215
152
  }
153
+ await orderSubmit(data);
216
154
  };
217
155
 
218
156
  const handlePaymentChange = (e: ChangeEvent<HTMLInputElement>) => {
@@ -221,8 +159,39 @@ const OrderForm: FC<Props> = ({
221
159
  paymentMethodsOptions?.[e.target.value as PaymentMethodEnum]
222
160
  ?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
223
161
  setOrderFields(orderFieldsLocal);
162
+ if (
163
+ !invoicePaymentMethods.includes(e.target.value as PaymentMethodEnum)
164
+ ) {
165
+ setValue('invoiceAddressSelection', false);
166
+ }
224
167
  };
225
168
 
169
+ const allowPaymentMethod = useMemo(() => {
170
+ if (!allowedPaymentMethods || allowedPaymentMethods?.length === 0) {
171
+ return true;
172
+ }
173
+
174
+ if (
175
+ allowedPaymentMethods.includes(
176
+ paymentMethodInput as PaymentMethodEnum
177
+ )
178
+ ) {
179
+ return true;
180
+ }
181
+
182
+ return false;
183
+ }, [allowedPaymentMethods, paymentMethodInput]);
184
+
185
+ const showInvoiceFields =
186
+ invoiceAddressToggle &&
187
+ invoiceOrderFields?.length > 0 &&
188
+ allowPaymentMethod;
189
+
190
+ const showInvoiceToggle =
191
+ invoiceAddressSelection?.enabled &&
192
+ allowPaymentMethod &&
193
+ invoicePaymentMethods.includes(paymentMethodInput as PaymentMethodEnum);
194
+
226
195
  return (
227
196
  <FormProvider {...methods}>
228
197
  <form
@@ -263,7 +232,7 @@ const OrderForm: FC<Props> = ({
263
232
  )}
264
233
  </div>
265
234
  )}
266
- {orderFields?.length > 0 && (
235
+ {orderFields?.length > 0 && allowPaymentMethod && (
267
236
  <Suspense fallback={null}>
268
237
  {orderFields.map((field) => {
269
238
  const Component = formFieldsMapper[field.name];
@@ -284,7 +253,7 @@ const OrderForm: FC<Props> = ({
284
253
  })}
285
254
  </Suspense>
286
255
  )}
287
- {invoiceAddressSelection?.enabled && (
256
+ {showInvoiceToggle && (
288
257
  <ToggleField
289
258
  name="invoiceAddressSelection"
290
259
  label={
@@ -292,7 +261,7 @@ const OrderForm: FC<Props> = ({
292
261
  }
293
262
  />
294
263
  )}
295
- {invoiceAddressToggle && invoiceOrderFields?.length > 0 && (
264
+ {showInvoiceFields && (
296
265
  <Suspense fallback={null}>
297
266
  {invoiceOrderFields.map((field) => {
298
267
  const Component = formFieldsMapper[field.name];
@@ -313,13 +282,23 @@ const OrderForm: FC<Props> = ({
313
282
  })}
314
283
  </Suspense>
315
284
  )}
316
- <Button
317
- type="submit"
318
- loading={loading}
319
- buttonText={submitButtonText}
285
+ {allowPaymentMethod && (
286
+ <Button
287
+ type="submit"
288
+ loading={loading}
289
+ buttonText={submitButtonText}
290
+ />
291
+ )}
292
+ <Alert
293
+ className="mt-2"
294
+ msg={
295
+ allowPaymentMethod
296
+ ? apiErrorMsg
297
+ : paymentMethodNotAllowedMsg
298
+ }
320
299
  />
321
- <Alert className="mt-2" msg={apiErrorMsg} />
322
300
  {errorsMsg?.length > 0 &&
301
+ allowPaymentMethod &&
323
302
  errorsMsg.map((i) => <Alert className="mt-2" msg={i} />)}
324
303
  </form>
325
304
  </FormProvider>
@@ -6,3 +6,8 @@ export const WRONG_MSG = 'Something went wrong!';
6
6
 
7
7
  export const PAYMENT_METHOD_DEFAULT: PaymentMethodEnum =
8
8
  PaymentMethodEnum.Vipps;
9
+
10
+ export const INVOICE_ALLOWED_PAYMENT_METHODS = [
11
+ PaymentMethodEnum.Email,
12
+ PaymentMethodEnum.Invoice,
13
+ ];
@@ -0,0 +1,184 @@
1
+ import { useState } from 'react';
2
+ import { SubmitHandler } from 'react-hook-form';
3
+
4
+ import { createSubscriber, mapSubscriberToUser } from '../api/SubscribeApi';
5
+ import { orderStart } from '../api/OrdersApi';
6
+ import { invoiceLookup } from '../api/InvoiceApi';
7
+ import { InvoiceLookupNetworkEnum, PaymentMethodEnum } from '../enums/general';
8
+ import { WRONG_MSG, PAYMENT_METHOD_DEFAULT } from '../constants/index';
9
+ import { OrderFormInputsType, OrderInfoType } from '../types/order';
10
+ import {
11
+ ErrorsMsg,
12
+ OrderFormFiledType,
13
+ PaymentMethodOptionsType,
14
+ } from '../types/general';
15
+ import {
16
+ prepareAgreementModel,
17
+ prepareContactModel,
18
+ prepareInvoiceModel,
19
+ } from '../utils/order.helper';
20
+ import {
21
+ prepareErrorMessage,
22
+ prepareErrorsArrayMessage,
23
+ } from '../utils/helper';
24
+
25
+ type Props = {
26
+ callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
27
+ submitStartCallback?: (id: string) => void;
28
+ templatePackageId: string;
29
+ subscriberId?: string;
30
+ userId?: string;
31
+ identityProviderId?: string;
32
+ organizationId: string;
33
+ redirectUrl?: string;
34
+ showIframe?: boolean;
35
+ language: string;
36
+ merchantAgreementUrl: string;
37
+ paymentMethodsOptions?: PaymentMethodOptionsType;
38
+ orderFields: OrderFormFiledType[];
39
+ invoiceAddressToggle?: boolean;
40
+ invoiceOrderFields: OrderFormFiledType[];
41
+ };
42
+
43
+ const useOrderForm = ({
44
+ callback,
45
+ submitStartCallback,
46
+ organizationId,
47
+ subscriberId,
48
+ userId,
49
+ identityProviderId,
50
+ orderFields,
51
+ redirectUrl,
52
+ showIframe,
53
+ language,
54
+ merchantAgreementUrl,
55
+ paymentMethodsOptions,
56
+ templatePackageId,
57
+ invoiceAddressToggle,
58
+ invoiceOrderFields,
59
+ }: Props) => {
60
+ const [loading, setLoading] = useState<boolean>(false);
61
+ const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
62
+ const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
63
+
64
+ const orderSubmit: SubmitHandler<OrderFormInputsType> = async (
65
+ data
66
+ ): Promise<void> => {
67
+ setApiErrorMsg('');
68
+ setErrorsMsg([]);
69
+ setLoading(true);
70
+ try {
71
+ let id: string | undefined = subscriberId;
72
+ const contactModel = prepareContactModel({ data, orderFields });
73
+ if (!subscriberId) {
74
+ const response = await createSubscriber({
75
+ ...contactModel,
76
+ gln: data?.gln,
77
+ organizationNumber:
78
+ data.paymentMethod === PaymentMethodEnum.OIO
79
+ ? data?.cvr
80
+ : data.organizationNumber || undefined,
81
+ });
82
+ id = response.id;
83
+
84
+ if (userId && identityProviderId) {
85
+ await mapSubscriberToUser(id, {
86
+ userId: userId,
87
+ identityProviderId: identityProviderId,
88
+ });
89
+ }
90
+ }
91
+
92
+ submitStartCallback?.(id as string);
93
+
94
+ if (id) {
95
+ const paymentMethod =
96
+ data.paymentMethod || PAYMENT_METHOD_DEFAULT;
97
+
98
+ const agreements = prepareAgreementModel({
99
+ paymentMethod,
100
+ redirectUrl,
101
+ showIframe,
102
+ phoneNumber: orderFields.find(
103
+ (i) => i.name === 'phoneNumber'
104
+ )
105
+ ? data.phoneNumber?.trim() || undefined
106
+ : undefined,
107
+ language,
108
+ merchantAgreementUrl,
109
+ generateSubscriberContact:
110
+ paymentMethodsOptions?.[
111
+ data.paymentMethod as PaymentMethodEnum
112
+ ]?.generateSubscriberContact || false,
113
+ accountId:
114
+ paymentMethodsOptions?.[
115
+ data.paymentMethod as PaymentMethodEnum
116
+ ]?.accountId,
117
+ });
118
+ const responseOrder = await orderStart({
119
+ subscriberId: id,
120
+ subscriptionPlan: {
121
+ organizationId,
122
+ templateSubscriptionPlanId: templatePackageId,
123
+ },
124
+ paymentAgreement: { ...agreements },
125
+ invoiceContact: invoiceAddressToggle
126
+ ? prepareInvoiceModel({
127
+ data,
128
+ orderFields: invoiceOrderFields,
129
+ })
130
+ : undefined,
131
+ orderReference: data.orderReference || undefined,
132
+ });
133
+ if (data.paymentMethod === PaymentMethodEnum.OIO) {
134
+ await invoiceLookup({
135
+ network: data.gln
136
+ ? InvoiceLookupNetworkEnum.OIO_GLN
137
+ : InvoiceLookupNetworkEnum.OIO_Danish_CVR,
138
+ value: data.gln || data.cvr || '',
139
+ });
140
+ }
141
+ if (data.paymentMethod === PaymentMethodEnum.EHF) {
142
+ await invoiceLookup({
143
+ network: InvoiceLookupNetworkEnum.EHF,
144
+ value: data.organizationNumber || '',
145
+ });
146
+ }
147
+ callback(responseOrder.terminalRedirectUrl, {
148
+ ...(data || {}),
149
+ orderId: responseOrder.id,
150
+ subscriberId: id,
151
+ paymentMethod: paymentMethod,
152
+ });
153
+ return;
154
+ }
155
+ callback(null);
156
+ setApiErrorMsg(WRONG_MSG);
157
+ setErrorsMsg([]);
158
+ } catch (error) {
159
+ console.error(error);
160
+ setApiErrorMsg(prepareErrorMessage(error as Error));
161
+ setErrorsMsg(
162
+ prepareErrorsArrayMessage(
163
+ (
164
+ error as {
165
+ errors: ErrorsMsg;
166
+ }
167
+ )?.errors
168
+ )
169
+ );
170
+ callback(null);
171
+ } finally {
172
+ setLoading(false);
173
+ }
174
+ };
175
+
176
+ return {
177
+ orderSubmit,
178
+ loading,
179
+ apiErrorMsg,
180
+ errorsMsg,
181
+ };
182
+ };
183
+
184
+ export default useOrderForm;
package/src/types/api.ts CHANGED
@@ -21,4 +21,6 @@ export type CreateSubscriberRequestType = {
21
21
  zip?: string;
22
22
  careOf?: string;
23
23
  buyerReference?: string;
24
+ gln?: string;
25
+ organizationNumber?: string;
24
26
  };
@@ -36,6 +36,7 @@ export type ConfigType = {
36
36
  redirectUrl?: string;
37
37
  showIframe?: boolean;
38
38
  availablePaymentMethods?: { label: string; value: PaymentMethodEnum }[];
39
+ allowedPaymentMethods?: PaymentMethodEnum[];
39
40
  paymentMethodsOptions?: PaymentMethodOptionsType;
40
41
  language?: string;
41
42
  merchantAgreementUrl?: string;
@@ -51,12 +52,14 @@ export type ConfigType = {
51
52
  backButtonText?: string;
52
53
  verifyButtonText?: string;
53
54
  organizationNumberLabel?: string;
55
+ cvrLabel?: string;
54
56
  glnLabel?: string;
55
57
  orderDefaultValues?: OrderFormInputsType;
56
58
  paymentMethodLabel?: string;
57
59
  errorReqMsg?: string;
58
60
  errorInvalidEmailMsg?: string;
59
61
  errorInvalidPhoneMsg?: string;
62
+ paymentMethodNotAllowedMsg?: string;
60
63
  };
61
64
  };
62
65
 
@@ -10,6 +10,7 @@ export type OrderFormInputsType = {
10
10
  address?: string;
11
11
  zip?: string;
12
12
  careOf?: string;
13
+ organizationNumber?: string;
13
14
  invoiceAddressSelection?: boolean;
14
15
  orderReference?: string;
15
16
  invoiceName?: string;
@@ -21,6 +22,8 @@ export type OrderFormInputsType = {
21
22
  invoiceZip?: string;
22
23
  invoiceCareOf?: string;
23
24
  invoiceBuyerReference?: string;
25
+ gln?: string;
26
+ cvr?: string;
24
27
  };
25
28
 
26
29
  export type VippsMobilePay = {