@infosoftas/s4-orders-js-sdk 0.1.12 → 0.1.13
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/README.md +37 -10
- package/package.json +3 -3
- package/src/App.tsx +72 -1
- package/src/components/EHFForm/EHFForm.tsx +51 -4
- package/src/components/FormFields/FormFields.helper.ts +3 -2
- package/src/components/FormFields/FormFieldsMapper.ts +2 -0
- package/src/components/FormFields/TermsCheckbox.tsx +58 -0
- package/src/components/OIOForm/OIOForm.tsx +53 -6
- package/src/components/OrderDenialModal/OrderDenialModal.tsx +91 -0
- package/src/components/OrderDenialModal/orderDenialModal.scss +42 -0
- package/src/components/OrderForm/OrderForm.tsx +80 -6
- package/src/custom.d.ts +4 -0
- package/src/enums/general.ts +1 -0
- package/src/hooks/useOrderForm.tsx +133 -10
- package/src/types/general.ts +21 -4
- package/src/types/order.ts +1 -0
- package/src/utils/order.helper.ts +2 -2
- package/tsconfig.json +12 -15
package/README.md
CHANGED
|
@@ -39,17 +39,19 @@ enum PaymentMethodEnum {
|
|
|
39
39
|
OIO = 'OIO',
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
type
|
|
42
|
+
type OrderFormFieldType = {
|
|
43
43
|
name: string;
|
|
44
44
|
required?: boolean;
|
|
45
|
+
readOnly?: boolean;
|
|
46
|
+
label?: string;
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
type PaymentMethodOptionsType = {
|
|
48
50
|
[key in PaymentMethodEnum]: {
|
|
49
51
|
generateSubscriberContact?: boolean;
|
|
50
52
|
accountId?: string;
|
|
51
|
-
orderFormFields
|
|
52
|
-
paymentInvoiceFields?:
|
|
53
|
+
orderFormFields: OrderFormFieldType[];
|
|
54
|
+
paymentInvoiceFields?: OrderFormFieldType[] | never[] | null;
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -75,9 +77,10 @@ type ConfigType = {
|
|
|
75
77
|
moduleTitle?: string;
|
|
76
78
|
submitStartCallback?: (subscriberId: string) => void;
|
|
77
79
|
userActionCallback?: (action: UserActionEnum, args: object | null | undefined) => void;
|
|
78
|
-
setContactCallback?: (contactInfo:
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
setContactCallback?: (contactInfo: ContactRequestType) => void;
|
|
81
|
+
cancelVippsCallback?: () => void;
|
|
82
|
+
apiKey?: string;
|
|
83
|
+
apiUrl?: string;
|
|
81
84
|
templatePackageId: string;
|
|
82
85
|
subscriberId: string;
|
|
83
86
|
userId: string;
|
|
@@ -85,14 +88,31 @@ type ConfigType = {
|
|
|
85
88
|
organizationId: string;
|
|
86
89
|
redirectUrl?: string;
|
|
87
90
|
showIframe?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* The full list of payment methods displayed in the UI, each with a display label and value.
|
|
93
|
+
* Controls what the user sees in the payment method selector.
|
|
94
|
+
* @example [{ label: 'Credit Card', value: 'SwedbankPay' }, { label: 'Invoice', value: 'Invoice' }]
|
|
95
|
+
*/
|
|
88
96
|
availablePaymentMethods?: { label: string; value: PaymentMethodEnum }[];
|
|
97
|
+
/**
|
|
98
|
+
* Whitelist of payment methods the subscriber is permitted to use.
|
|
99
|
+
* If a method is in availablePaymentMethods but not here, it will be shown but blocked.
|
|
100
|
+
* @example ['SwedbankPay', 'Invoice']
|
|
101
|
+
*/
|
|
102
|
+
allowedPaymentMethods?: PaymentMethodEnum[];
|
|
103
|
+
/**
|
|
104
|
+
* Per-payment-method form field configuration.
|
|
105
|
+
* Controls which input fields are shown in the order form for each payment method.
|
|
106
|
+
* Use accountId on SwedbankPay to set your Swedbank Pay account ID.
|
|
107
|
+
*/
|
|
89
108
|
paymentMethodsOptions?: PaymentMethodOptionsType;
|
|
109
|
+
requireTermsAcceptance?: boolean;
|
|
90
110
|
language?: string;
|
|
91
111
|
merchantAgreementUrl?: string;
|
|
92
112
|
invoiceAddressSelection?: {
|
|
93
113
|
enabled?: boolean;
|
|
94
114
|
label?: string;
|
|
95
|
-
fields?:
|
|
115
|
+
fields?: OrderFormFieldType[];
|
|
96
116
|
};
|
|
97
117
|
settings?: {
|
|
98
118
|
successText?: string;
|
|
@@ -101,6 +121,7 @@ type ConfigType = {
|
|
|
101
121
|
backButtonText?: string;
|
|
102
122
|
verifyButtonText?: string;
|
|
103
123
|
organizationNumberLabel?: string;
|
|
124
|
+
cvrLabel?: string;
|
|
104
125
|
glnLabel?: string;
|
|
105
126
|
orderDefaultValues?: OrderFormInputsType;
|
|
106
127
|
paymentMethodLabel?: string;
|
|
@@ -110,6 +131,9 @@ type ConfigType = {
|
|
|
110
131
|
errorValidationTitleMsg?: string;
|
|
111
132
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
112
133
|
errorValidationBlockingOffersMsg?: string;
|
|
134
|
+
paymentMethodNotAllowedMsg?: string;
|
|
135
|
+
invoiceLookupNotFoundText?: string;
|
|
136
|
+
termsAndConditionsText?: string;
|
|
113
137
|
};
|
|
114
138
|
}
|
|
115
139
|
```
|
|
@@ -388,8 +412,11 @@ export default OrderPlace;
|
|
|
388
412
|
| redirectUrl | window.location.href | redirect url |
|
|
389
413
|
| showIframe | false | show credit card in iframe |
|
|
390
414
|
| userActionCallback | undefined | function for tracking user actions |
|
|
391
|
-
|
|
|
392
|
-
|
|
|
415
|
+
| cancelVippsCallback | undefined | callback invoked when a Vipps/MobilePay payment is cancelled |
|
|
416
|
+
| paymentMethodsOptions | orderFormFields: [{name: 'phoneNumber', required: false, readOnly: false, label: ''}] | default form fields |
|
|
417
|
+
| availablePaymentMethods | [] | available payment methods to display |
|
|
418
|
+
| allowedPaymentMethods | [] | list of payment methods the subscriber is allowed to use |
|
|
419
|
+
| requireTermsAcceptance | false | when true, the user must accept terms and conditions before submitting |
|
|
393
420
|
| language | 'en-US' | language |
|
|
394
421
|
| merchantAgreementUrl | '' | vipps and MobilePay property |
|
|
395
|
-
| settings | {successText: 'Order
|
|
422
|
+
| settings | {successText: 'Order completed successfully!', failureText: 'Something went wrong!', submitButtonText: 'Start', backButtonText: 'Back', verifyButtonText: 'Verify', organizationNumberLabel: 'Organization Number', cvrLabel: 'CVR', glnLabel: 'GLN', paymentMethodLabel: 'Select Payment Method', orderDefaultValues: 'Default order form values', errorReqMsg: '', errorInvalidEmailMsg: '', errorInvalidPhoneMsg: '', errorValidationTitleMsg: 'One or more validation errors occurred.', errorValidationDenialOrderBlockingMsg: '...', errorValidationBlockingOffersMsg: '...', paymentMethodNotAllowedMsg: 'This payment method not allowed!', invoiceLookupNotFoundText: 'There was no recipient found for the given information', termsAndConditionsText: '' } | label and text properties |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infosoftas/s4-orders-js-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "rimraf lib && webpack --mode production",
|
|
6
6
|
"release": "release-it"
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"copy-webpack-plugin": "^14.0.0",
|
|
28
28
|
"css-loader": "^7.1.2",
|
|
29
29
|
"mini-css-extract-plugin": "^2.9.4",
|
|
30
|
-
"release-it": "^
|
|
30
|
+
"release-it": "^20.0.0",
|
|
31
31
|
"rimraf": "^6.1.2",
|
|
32
32
|
"sass": "^1.94.2",
|
|
33
33
|
"sass-loader": "^16.0.6",
|
|
34
34
|
"style-loader": "^4.0.0",
|
|
35
35
|
"ts-loader": "^9.5.4",
|
|
36
|
-
"typescript": "^
|
|
36
|
+
"typescript": "^6.0.2",
|
|
37
37
|
"webpack": "^5.105.2",
|
|
38
38
|
"webpack-cli": "^6.0.1"
|
|
39
39
|
},
|
package/src/App.tsx
CHANGED
|
@@ -45,6 +45,7 @@ const App: FC<ConfigType> = ({
|
|
|
45
45
|
invoiceAddressSelection,
|
|
46
46
|
availablePaymentMethods = [],
|
|
47
47
|
allowedPaymentMethods,
|
|
48
|
+
requireTermsAcceptance,
|
|
48
49
|
language = 'en-US',
|
|
49
50
|
merchantAgreementUrl = '',
|
|
50
51
|
settings = {
|
|
@@ -67,9 +68,17 @@ const App: FC<ConfigType> = ({
|
|
|
67
68
|
'The order/subscription will not be created because the subscriber has a denial order blocking all.',
|
|
68
69
|
errorValidationBlockingOffersMsg:
|
|
69
70
|
'The order/subscription will not be created because the subscriber has a denial order blocking offers.',
|
|
71
|
+
orderDenialOfferBaseText:
|
|
72
|
+
'Hello again!\n\nLooks like you already tried this offer.',
|
|
73
|
+
orderDenialOfferWithFallbackText:
|
|
74
|
+
'Hello again!\n\nLooks like you already tried this offer, but we would like to keep you with us.\n\nTherefore we got a new great offer for you:',
|
|
75
|
+
orderDenialAmountText:
|
|
76
|
+
'We are sorry, but you do not meet the requirements for this offer. Please contact customer service for more information.',
|
|
77
|
+
orderDenialFallbackOffer: undefined,
|
|
70
78
|
paymentMethodNotAllowedMsg: '',
|
|
71
79
|
invoiceLookupNotFoundText:
|
|
72
80
|
'There was no recipient found for the given information',
|
|
81
|
+
termsAndConditionsText: '',
|
|
73
82
|
},
|
|
74
83
|
}) => {
|
|
75
84
|
const [loading, setLoading] = useState<boolean>(false);
|
|
@@ -342,6 +351,12 @@ const App: FC<ConfigType> = ({
|
|
|
342
351
|
callback={handleInvoiceForm}
|
|
343
352
|
backButtonText={settings?.backButtonText}
|
|
344
353
|
verifyButtonText={settings?.verifyButtonText}
|
|
354
|
+
orderDenialCloseButtonText={
|
|
355
|
+
settings?.orderDenialCloseButtonText
|
|
356
|
+
}
|
|
357
|
+
orderDenialContinueButtonText={
|
|
358
|
+
settings?.orderDenialContinueButtonText
|
|
359
|
+
}
|
|
345
360
|
organizationNumberLabel={settings?.cvrLabel}
|
|
346
361
|
glnLabel={settings?.glnLabel}
|
|
347
362
|
organizationNumber={
|
|
@@ -375,6 +390,18 @@ const App: FC<ConfigType> = ({
|
|
|
375
390
|
errorValidationBlockingOffersMsg={
|
|
376
391
|
settings?.errorValidationBlockingOffersMsg
|
|
377
392
|
}
|
|
393
|
+
orderDenialOfferBaseText={
|
|
394
|
+
settings?.orderDenialOfferBaseText
|
|
395
|
+
}
|
|
396
|
+
orderDenialOfferWithFallbackText={
|
|
397
|
+
settings?.orderDenialOfferWithFallbackText
|
|
398
|
+
}
|
|
399
|
+
orderDenialAmountText={
|
|
400
|
+
settings?.orderDenialAmountText
|
|
401
|
+
}
|
|
402
|
+
orderDenialFallbackOffer={
|
|
403
|
+
settings?.orderDenialFallbackOffer
|
|
404
|
+
}
|
|
378
405
|
/>
|
|
379
406
|
)}
|
|
380
407
|
{formType === FormTypeEnum.EHF && (
|
|
@@ -383,6 +410,12 @@ const App: FC<ConfigType> = ({
|
|
|
383
410
|
callback={handleInvoiceForm}
|
|
384
411
|
backButtonText={settings?.backButtonText}
|
|
385
412
|
verifyButtonText={settings?.verifyButtonText}
|
|
413
|
+
orderDenialCloseButtonText={
|
|
414
|
+
settings?.orderDenialCloseButtonText
|
|
415
|
+
}
|
|
416
|
+
orderDenialContinueButtonText={
|
|
417
|
+
settings?.orderDenialContinueButtonText
|
|
418
|
+
}
|
|
386
419
|
organizationNumberLabel={
|
|
387
420
|
settings?.organizationNumberLabel
|
|
388
421
|
}
|
|
@@ -417,6 +450,18 @@ const App: FC<ConfigType> = ({
|
|
|
417
450
|
errorValidationBlockingOffersMsg={
|
|
418
451
|
settings?.errorValidationBlockingOffersMsg
|
|
419
452
|
}
|
|
453
|
+
orderDenialOfferBaseText={
|
|
454
|
+
settings?.orderDenialOfferBaseText
|
|
455
|
+
}
|
|
456
|
+
orderDenialOfferWithFallbackText={
|
|
457
|
+
settings?.orderDenialOfferWithFallbackText
|
|
458
|
+
}
|
|
459
|
+
orderDenialAmountText={
|
|
460
|
+
settings?.orderDenialAmountText
|
|
461
|
+
}
|
|
462
|
+
orderDenialFallbackOffer={
|
|
463
|
+
settings?.orderDenialFallbackOffer
|
|
464
|
+
}
|
|
420
465
|
/>
|
|
421
466
|
)}
|
|
422
467
|
{formType !== FormTypeEnum.OIO &&
|
|
@@ -438,6 +483,12 @@ const App: FC<ConfigType> = ({
|
|
|
438
483
|
submitButtonText={
|
|
439
484
|
settings?.submitButtonText
|
|
440
485
|
}
|
|
486
|
+
orderDenialCloseButtonText={
|
|
487
|
+
settings?.orderDenialCloseButtonText
|
|
488
|
+
}
|
|
489
|
+
orderDenialContinueButtonText={
|
|
490
|
+
settings?.orderDenialContinueButtonText
|
|
491
|
+
}
|
|
441
492
|
paymentMethodLabel={
|
|
442
493
|
settings?.paymentMethodLabel
|
|
443
494
|
}
|
|
@@ -473,6 +524,24 @@ const App: FC<ConfigType> = ({
|
|
|
473
524
|
errorValidationBlockingOffersMsg={
|
|
474
525
|
settings?.errorValidationBlockingOffersMsg
|
|
475
526
|
}
|
|
527
|
+
orderDenialOfferBaseText={
|
|
528
|
+
settings?.orderDenialOfferBaseText
|
|
529
|
+
}
|
|
530
|
+
orderDenialOfferWithFallbackText={
|
|
531
|
+
settings?.orderDenialOfferWithFallbackText
|
|
532
|
+
}
|
|
533
|
+
orderDenialAmountText={
|
|
534
|
+
settings?.orderDenialAmountText
|
|
535
|
+
}
|
|
536
|
+
orderDenialFallbackOffer={
|
|
537
|
+
settings?.orderDenialFallbackOffer
|
|
538
|
+
}
|
|
539
|
+
termsAndConditionsText={
|
|
540
|
+
settings?.termsAndConditionsText
|
|
541
|
+
}
|
|
542
|
+
requireTermsAcceptance={
|
|
543
|
+
requireTermsAcceptance
|
|
544
|
+
}
|
|
476
545
|
/>
|
|
477
546
|
)}
|
|
478
547
|
</>
|
|
@@ -489,7 +558,9 @@ const App: FC<ConfigType> = ({
|
|
|
489
558
|
{isFailed && <Alert className="mt-2" msg={failedMsg} />}
|
|
490
559
|
{isFailed &&
|
|
491
560
|
errorsMsg?.length > 0 &&
|
|
492
|
-
errorsMsg.map((i) =>
|
|
561
|
+
errorsMsg.map((i, index) => (
|
|
562
|
+
<Alert key={`${i}-${index}`} className="mt-2" msg={i} />
|
|
563
|
+
))}
|
|
493
564
|
</div>
|
|
494
565
|
</ErrorBoundary>
|
|
495
566
|
);
|
|
@@ -3,12 +3,14 @@ import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
|
|
|
3
3
|
|
|
4
4
|
import Alert from '../Alert/Alert';
|
|
5
5
|
import Button from '../Button/Button';
|
|
6
|
+
import OrderDenialModal from '../OrderDenialModal/OrderDenialModal';
|
|
6
7
|
import InputField from '../FormFields/InputField';
|
|
7
8
|
import { PaymentMethodEnum, UserActionEnum } from '../../enums/general';
|
|
8
9
|
import {
|
|
9
|
-
|
|
10
|
+
OrderFormFieldType,
|
|
10
11
|
PaymentMethodOptionsType,
|
|
11
12
|
ContactRequestType,
|
|
13
|
+
OrderDenialFallbackOfferType,
|
|
12
14
|
} from '../../types/general';
|
|
13
15
|
import { OrderFormInputsType, OrderInfoType } from '../../types/order';
|
|
14
16
|
import { orderInvoiceContactFields } from '../../utils/order.helper';
|
|
@@ -27,6 +29,8 @@ type Props = {
|
|
|
27
29
|
className?: string;
|
|
28
30
|
backButtonText?: string;
|
|
29
31
|
verifyButtonText?: string;
|
|
32
|
+
orderDenialCloseButtonText?: string;
|
|
33
|
+
orderDenialContinueButtonText?: string;
|
|
30
34
|
organizationNumberLabel?: string;
|
|
31
35
|
organizationNumber?: string;
|
|
32
36
|
glnLabel?: string;
|
|
@@ -44,13 +48,17 @@ type Props = {
|
|
|
44
48
|
invoiceAddressSelection?: {
|
|
45
49
|
enabled?: boolean;
|
|
46
50
|
label?: string;
|
|
47
|
-
fields?:
|
|
51
|
+
fields?: OrderFormFieldType[];
|
|
48
52
|
paymentMethods?: PaymentMethodEnum[];
|
|
49
53
|
};
|
|
50
54
|
invoiceLookupNotFoundText?: string;
|
|
51
55
|
errorValidationTitleMsg?: string;
|
|
52
56
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
53
57
|
errorValidationBlockingOffersMsg?: string;
|
|
58
|
+
orderDenialOfferBaseText?: string;
|
|
59
|
+
orderDenialOfferWithFallbackText?: string;
|
|
60
|
+
orderDenialAmountText?: string;
|
|
61
|
+
orderDenialFallbackOffer?: OrderDenialFallbackOfferType;
|
|
54
62
|
};
|
|
55
63
|
|
|
56
64
|
type EHFFormInputsType = {
|
|
@@ -70,6 +78,8 @@ const EHFForm: FC<Props> = ({
|
|
|
70
78
|
className = '',
|
|
71
79
|
backButtonText = '',
|
|
72
80
|
verifyButtonText = '',
|
|
81
|
+
orderDenialCloseButtonText = 'Close',
|
|
82
|
+
orderDenialContinueButtonText = 'Continue',
|
|
73
83
|
organizationNumberLabel = '',
|
|
74
84
|
organizationNumber = '',
|
|
75
85
|
templatePackageId,
|
|
@@ -88,6 +98,10 @@ const EHFForm: FC<Props> = ({
|
|
|
88
98
|
errorValidationTitleMsg,
|
|
89
99
|
errorValidationDenialOrderBlockingMsg,
|
|
90
100
|
errorValidationBlockingOffersMsg,
|
|
101
|
+
orderDenialOfferBaseText,
|
|
102
|
+
orderDenialOfferWithFallbackText,
|
|
103
|
+
orderDenialAmountText,
|
|
104
|
+
orderDenialFallbackOffer,
|
|
91
105
|
}) => {
|
|
92
106
|
const methods = useForm<EHFFormInputsType>({
|
|
93
107
|
defaultValues: {
|
|
@@ -108,7 +122,16 @@ const EHFForm: FC<Props> = ({
|
|
|
108
122
|
paymentMethodsOptions?.[orderValues?.paymentMethod as PaymentMethodEnum]
|
|
109
123
|
?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
|
|
110
124
|
|
|
111
|
-
const {
|
|
125
|
+
const {
|
|
126
|
+
orderSubmit,
|
|
127
|
+
continueWithFallbackOffer,
|
|
128
|
+
loading,
|
|
129
|
+
apiErrorMsg,
|
|
130
|
+
errorsMsg,
|
|
131
|
+
orderDenialType,
|
|
132
|
+
orderDenialMessage,
|
|
133
|
+
dismissOrderDenial,
|
|
134
|
+
} = useOrderForm({
|
|
112
135
|
callback,
|
|
113
136
|
submitStartCallback,
|
|
114
137
|
userActionCallback,
|
|
@@ -130,6 +153,10 @@ const EHFForm: FC<Props> = ({
|
|
|
130
153
|
errorValidationTitleMsg,
|
|
131
154
|
errorValidationDenialOrderBlockingMsg,
|
|
132
155
|
errorValidationBlockingOffersMsg,
|
|
156
|
+
orderDenialOfferBaseText,
|
|
157
|
+
orderDenialOfferWithFallbackText,
|
|
158
|
+
orderDenialAmountText,
|
|
159
|
+
orderDenialFallbackOffer,
|
|
133
160
|
});
|
|
134
161
|
|
|
135
162
|
const onSubmit: SubmitHandler<EHFFormInputsType> = async (
|
|
@@ -178,7 +205,27 @@ const EHFForm: FC<Props> = ({
|
|
|
178
205
|
|
|
179
206
|
{apiErrorMsg && <Alert className="mt-2" msg={apiErrorMsg} />}
|
|
180
207
|
{errorsMsg?.length > 0 &&
|
|
181
|
-
errorsMsg.map((i) =>
|
|
208
|
+
errorsMsg.map((i, index) => (
|
|
209
|
+
<Alert key={index} className="mt-2" msg={i} />
|
|
210
|
+
))}
|
|
211
|
+
<OrderDenialModal
|
|
212
|
+
isOpen={!!orderDenialType}
|
|
213
|
+
message={orderDenialMessage}
|
|
214
|
+
closeButtonText={orderDenialCloseButtonText}
|
|
215
|
+
continueButtonText={orderDenialContinueButtonText}
|
|
216
|
+
canContinue={
|
|
217
|
+
orderDenialType === 'offer' &&
|
|
218
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
219
|
+
}
|
|
220
|
+
offer={
|
|
221
|
+
orderDenialType === 'offer' &&
|
|
222
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
223
|
+
? orderDenialFallbackOffer
|
|
224
|
+
: undefined
|
|
225
|
+
}
|
|
226
|
+
onClose={dismissOrderDenial}
|
|
227
|
+
onContinue={continueWithFallbackOffer}
|
|
228
|
+
/>
|
|
182
229
|
</form>
|
|
183
230
|
</FormProvider>
|
|
184
231
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OrderFormFieldType } from '../../types/general';
|
|
2
2
|
|
|
3
3
|
export const FIELD_TYPES = {
|
|
4
4
|
PHONE: 'phoneNumber',
|
|
@@ -21,9 +21,10 @@ export const FIELD_TYPES = {
|
|
|
21
21
|
INVOICE_EMAIL: 'invoiceEmail',
|
|
22
22
|
INVOICE_CARE_OF: 'invoiceCareOf',
|
|
23
23
|
INVOICE_BUYER_REFERENCE: 'invoiceBuyerReference',
|
|
24
|
+
TERMS_CHECKBOX: 'termsCheckbox',
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
export const DEFAULT_ORDER_FORM_FIELDS:
|
|
27
|
+
export const DEFAULT_ORDER_FORM_FIELDS: OrderFormFieldType[] = [
|
|
27
28
|
{
|
|
28
29
|
name: FIELD_TYPES.PHONE,
|
|
29
30
|
required: false,
|
|
@@ -3,6 +3,7 @@ import PhoneField from './PhoneField';
|
|
|
3
3
|
import NameField from './NameField';
|
|
4
4
|
import AddressField from './AddressField';
|
|
5
5
|
import InputField from './InputField';
|
|
6
|
+
import TermsCheckbox from './TermsCheckbox';
|
|
6
7
|
|
|
7
8
|
import { FIELD_TYPES } from './FormFields.helper';
|
|
8
9
|
|
|
@@ -27,6 +28,7 @@ const formFieldsMapper = {
|
|
|
27
28
|
[FIELD_TYPES.INVOICE_ZIP]: InputField,
|
|
28
29
|
[FIELD_TYPES.INVOICE_CARE_OF]: InputField,
|
|
29
30
|
[FIELD_TYPES.INVOICE_BUYER_REFERENCE]: InputField,
|
|
31
|
+
[FIELD_TYPES.TERMS_CHECKBOX]: TermsCheckbox,
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
export default formFieldsMapper;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
import { useFormContext } from 'react-hook-form';
|
|
3
|
+
|
|
4
|
+
import { uuidv4 } from '../../utils/helper';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
name: string;
|
|
8
|
+
required: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
label?: string | ReactNode;
|
|
11
|
+
errorReqMsg?: string;
|
|
12
|
+
errors?: {
|
|
13
|
+
[key: string]: {
|
|
14
|
+
message?: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const TermsCheckbox: FC<Props> = ({
|
|
20
|
+
name,
|
|
21
|
+
required = true,
|
|
22
|
+
disabled = false,
|
|
23
|
+
label = 'I accept the terms and conditions',
|
|
24
|
+
errorReqMsg = 'You must accept the terms and conditions to proceed.',
|
|
25
|
+
errors,
|
|
26
|
+
}) => {
|
|
27
|
+
const { register } = useFormContext();
|
|
28
|
+
const id = uuidv4();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="checkbox-wrapper" data-testid={`sdk-${name}-field-id`}>
|
|
32
|
+
<>
|
|
33
|
+
<input
|
|
34
|
+
id={id}
|
|
35
|
+
type="checkbox"
|
|
36
|
+
disabled={disabled}
|
|
37
|
+
className={`checkbox-control ${disabled ? 'disabled' : ''}`}
|
|
38
|
+
{...register(name, {
|
|
39
|
+
required: required ? errorReqMsg : false,
|
|
40
|
+
})}
|
|
41
|
+
/>
|
|
42
|
+
<label
|
|
43
|
+
className="checkbox-label"
|
|
44
|
+
htmlFor={id}
|
|
45
|
+
style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
|
|
46
|
+
>
|
|
47
|
+
{label} {required && <span className="text-error">*</span>}
|
|
48
|
+
</label>
|
|
49
|
+
</>
|
|
50
|
+
|
|
51
|
+
{errors && errors[name] && (
|
|
52
|
+
<div className="text-error caption">{errors[name].message}</div>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default TermsCheckbox;
|
|
@@ -3,14 +3,16 @@ import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
|
|
|
3
3
|
|
|
4
4
|
import Alert from '../Alert/Alert';
|
|
5
5
|
import Button from '../Button/Button';
|
|
6
|
+
import OrderDenialModal from '../OrderDenialModal/OrderDenialModal';
|
|
6
7
|
import InputField from '../FormFields/InputField';
|
|
7
8
|
import { DEFAULT_ORDER_FORM_FIELDS } from '../FormFields/FormFields.helper';
|
|
8
9
|
|
|
9
10
|
import { PaymentMethodEnum, UserActionEnum } from '../../enums/general';
|
|
10
11
|
import {
|
|
11
|
-
|
|
12
|
+
OrderFormFieldType,
|
|
12
13
|
PaymentMethodOptionsType,
|
|
13
14
|
ContactRequestType,
|
|
15
|
+
OrderDenialFallbackOfferType,
|
|
14
16
|
} from '../../types/general';
|
|
15
17
|
import useOrderForm from '../../hooks/useOrderForm';
|
|
16
18
|
import { orderInvoiceContactFields } from '../../utils/order.helper';
|
|
@@ -28,6 +30,8 @@ type Props = {
|
|
|
28
30
|
className?: string;
|
|
29
31
|
backButtonText?: string;
|
|
30
32
|
verifyButtonText?: string;
|
|
33
|
+
orderDenialCloseButtonText?: string;
|
|
34
|
+
orderDenialContinueButtonText?: string;
|
|
31
35
|
organizationNumberLabel?: string;
|
|
32
36
|
organizationNumber?: string;
|
|
33
37
|
glnLabel?: string;
|
|
@@ -45,13 +49,17 @@ type Props = {
|
|
|
45
49
|
invoiceAddressSelection?: {
|
|
46
50
|
enabled?: boolean;
|
|
47
51
|
label?: string;
|
|
48
|
-
fields?:
|
|
52
|
+
fields?: OrderFormFieldType[];
|
|
49
53
|
paymentMethods?: PaymentMethodEnum[];
|
|
50
54
|
};
|
|
51
55
|
invoiceLookupNotFoundText?: string;
|
|
52
56
|
errorValidationTitleMsg?: string;
|
|
53
57
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
54
58
|
errorValidationBlockingOffersMsg?: string;
|
|
59
|
+
orderDenialOfferBaseText?: string;
|
|
60
|
+
orderDenialOfferWithFallbackText?: string;
|
|
61
|
+
orderDenialAmountText?: string;
|
|
62
|
+
orderDenialFallbackOffer?: OrderDenialFallbackOfferType;
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
type OIOFormInputsType = {
|
|
@@ -64,7 +72,7 @@ const initialData = {
|
|
|
64
72
|
gln: '',
|
|
65
73
|
};
|
|
66
74
|
|
|
67
|
-
const
|
|
75
|
+
const OIOForm: FC<Props> = ({
|
|
68
76
|
callback,
|
|
69
77
|
onBack,
|
|
70
78
|
submitStartCallback,
|
|
@@ -73,6 +81,8 @@ const EHFForm: FC<Props> = ({
|
|
|
73
81
|
className = '',
|
|
74
82
|
backButtonText = '',
|
|
75
83
|
verifyButtonText = '',
|
|
84
|
+
orderDenialCloseButtonText = 'Close',
|
|
85
|
+
orderDenialContinueButtonText = 'Continue',
|
|
76
86
|
organizationNumberLabel = '',
|
|
77
87
|
organizationNumber = '',
|
|
78
88
|
glnLabel = '',
|
|
@@ -92,6 +102,10 @@ const EHFForm: FC<Props> = ({
|
|
|
92
102
|
errorValidationTitleMsg,
|
|
93
103
|
errorValidationDenialOrderBlockingMsg,
|
|
94
104
|
errorValidationBlockingOffersMsg,
|
|
105
|
+
orderDenialOfferBaseText,
|
|
106
|
+
orderDenialOfferWithFallbackText,
|
|
107
|
+
orderDenialAmountText,
|
|
108
|
+
orderDenialFallbackOffer,
|
|
95
109
|
}) => {
|
|
96
110
|
const methods = useForm<OIOFormInputsType>({
|
|
97
111
|
defaultValues: {
|
|
@@ -116,7 +130,16 @@ const EHFForm: FC<Props> = ({
|
|
|
116
130
|
paymentMethodsOptions?.[orderValues?.paymentMethod as PaymentMethodEnum]
|
|
117
131
|
?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
|
|
118
132
|
|
|
119
|
-
const {
|
|
133
|
+
const {
|
|
134
|
+
orderSubmit,
|
|
135
|
+
continueWithFallbackOffer,
|
|
136
|
+
loading,
|
|
137
|
+
apiErrorMsg,
|
|
138
|
+
errorsMsg,
|
|
139
|
+
orderDenialType,
|
|
140
|
+
orderDenialMessage,
|
|
141
|
+
dismissOrderDenial,
|
|
142
|
+
} = useOrderForm({
|
|
120
143
|
callback,
|
|
121
144
|
submitStartCallback,
|
|
122
145
|
userActionCallback,
|
|
@@ -138,6 +161,10 @@ const EHFForm: FC<Props> = ({
|
|
|
138
161
|
errorValidationTitleMsg,
|
|
139
162
|
errorValidationDenialOrderBlockingMsg,
|
|
140
163
|
errorValidationBlockingOffersMsg,
|
|
164
|
+
orderDenialOfferBaseText,
|
|
165
|
+
orderDenialOfferWithFallbackText,
|
|
166
|
+
orderDenialAmountText,
|
|
167
|
+
orderDenialFallbackOffer,
|
|
141
168
|
});
|
|
142
169
|
|
|
143
170
|
const onSubmit: SubmitHandler<OIOFormInputsType> = async (
|
|
@@ -189,10 +216,30 @@ const EHFForm: FC<Props> = ({
|
|
|
189
216
|
</div>
|
|
190
217
|
{apiErrorMsg && <Alert className="mt-2" msg={apiErrorMsg} />}
|
|
191
218
|
{errorsMsg?.length > 0 &&
|
|
192
|
-
errorsMsg.map((i) =>
|
|
219
|
+
errorsMsg.map((i, index) => (
|
|
220
|
+
<Alert key={`${i}-${index}`} className="mt-2" msg={i} />
|
|
221
|
+
))}
|
|
222
|
+
<OrderDenialModal
|
|
223
|
+
isOpen={!!orderDenialType}
|
|
224
|
+
message={orderDenialMessage}
|
|
225
|
+
closeButtonText={orderDenialCloseButtonText}
|
|
226
|
+
continueButtonText={orderDenialContinueButtonText}
|
|
227
|
+
canContinue={
|
|
228
|
+
orderDenialType === 'offer' &&
|
|
229
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
230
|
+
}
|
|
231
|
+
offer={
|
|
232
|
+
orderDenialType === 'offer' &&
|
|
233
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
234
|
+
? orderDenialFallbackOffer
|
|
235
|
+
: undefined
|
|
236
|
+
}
|
|
237
|
+
onClose={dismissOrderDenial}
|
|
238
|
+
onContinue={continueWithFallbackOffer}
|
|
239
|
+
/>
|
|
193
240
|
</form>
|
|
194
241
|
</FormProvider>
|
|
195
242
|
);
|
|
196
243
|
};
|
|
197
244
|
|
|
198
|
-
export default
|
|
245
|
+
export default OIOForm;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
|
|
4
|
+
import { OrderDenialFallbackOfferType } from '../../types/general';
|
|
5
|
+
import Button from '../Button/Button';
|
|
6
|
+
|
|
7
|
+
import './orderDenialModal.scss';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
isOpen: boolean;
|
|
11
|
+
message?: string;
|
|
12
|
+
offer?: OrderDenialFallbackOfferType;
|
|
13
|
+
canContinue?: boolean;
|
|
14
|
+
closeButtonText?: string;
|
|
15
|
+
continueButtonText?: string;
|
|
16
|
+
onContinue: () => void;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const OrderDenialModal: FC<Props> = ({
|
|
21
|
+
isOpen,
|
|
22
|
+
message,
|
|
23
|
+
offer,
|
|
24
|
+
canContinue = true,
|
|
25
|
+
closeButtonText = 'Close',
|
|
26
|
+
continueButtonText = 'Continue',
|
|
27
|
+
onContinue,
|
|
28
|
+
onClose,
|
|
29
|
+
}) => {
|
|
30
|
+
if (!isOpen || typeof document === 'undefined') {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return createPortal(
|
|
35
|
+
<div
|
|
36
|
+
className="sdk-order-denial-modal-overlay"
|
|
37
|
+
data-testid="sdk-order-denial-modal-overlay"
|
|
38
|
+
>
|
|
39
|
+
<div
|
|
40
|
+
className="sdk-order-denial-modal"
|
|
41
|
+
role="dialog"
|
|
42
|
+
aria-modal="true"
|
|
43
|
+
aria-label="Order denial modal"
|
|
44
|
+
>
|
|
45
|
+
<p className="sdk-order-denial-modal-text">
|
|
46
|
+
{message?.split('\\n').map((line, i, arr) => (
|
|
47
|
+
<span key={i}>
|
|
48
|
+
{line}
|
|
49
|
+
{i < arr.length - 1 && <br />}
|
|
50
|
+
</span>
|
|
51
|
+
))}
|
|
52
|
+
</p>
|
|
53
|
+
{offer?.title && offer?.templatePackageId && (
|
|
54
|
+
<div className="sdk-order-denial-offer-box">
|
|
55
|
+
<h4 className="sdk-order-denial-offer-title">
|
|
56
|
+
{offer.title}
|
|
57
|
+
</h4>
|
|
58
|
+
{offer.description && (
|
|
59
|
+
<p className="sdk-order-denial-offer-description">
|
|
60
|
+
{offer.description}
|
|
61
|
+
</p>
|
|
62
|
+
)}
|
|
63
|
+
{offer.price && (
|
|
64
|
+
<p className="sdk-order-denial-offer-meta">
|
|
65
|
+
{offer.price}
|
|
66
|
+
</p>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
<div className="sdk-order-denial-modal-actions">
|
|
71
|
+
<Button
|
|
72
|
+
type="button"
|
|
73
|
+
btnType="default"
|
|
74
|
+
buttonText={closeButtonText}
|
|
75
|
+
onClick={onClose}
|
|
76
|
+
/>
|
|
77
|
+
{canContinue && (
|
|
78
|
+
<Button
|
|
79
|
+
type="button"
|
|
80
|
+
buttonText={continueButtonText}
|
|
81
|
+
onClick={onContinue}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>,
|
|
87
|
+
document.body
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default OrderDenialModal;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.sdk-order-denial-modal-overlay {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
z-index: 9999;
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.sdk-order-denial-modal {
|
|
12
|
+
width: min(560px, 100%);
|
|
13
|
+
padding: 24px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sdk-order-denial-modal-text {
|
|
17
|
+
margin: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.sdk-order-denial-offer-box {
|
|
21
|
+
margin-top: 16px;
|
|
22
|
+
padding: 14px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.sdk-order-denial-offer-title {
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.sdk-order-denial-offer-description {
|
|
30
|
+
margin: 8px 0 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.sdk-order-denial-offer-meta {
|
|
34
|
+
margin: 8px 0 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sdk-order-denial-modal-actions {
|
|
38
|
+
margin-top: 20px;
|
|
39
|
+
display: flex;
|
|
40
|
+
justify-content: flex-end;
|
|
41
|
+
gap: 10px;
|
|
42
|
+
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
ChangeEvent,
|
|
4
|
+
ReactNode,
|
|
5
|
+
Suspense,
|
|
6
|
+
useState,
|
|
7
|
+
useMemo,
|
|
8
|
+
useEffect,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
|
|
3
11
|
|
|
4
12
|
import { PaymentMethodEnum, UserActionEnum } from '../../enums/general';
|
|
@@ -8,19 +16,22 @@ import {
|
|
|
8
16
|
} from '../../constants/index';
|
|
9
17
|
import Alert from '../Alert/Alert';
|
|
10
18
|
import Button from '../Button/Button';
|
|
19
|
+
import OrderDenialModal from '../OrderDenialModal/OrderDenialModal';
|
|
11
20
|
import ToggleField from '../FormFields/ToggleFiled';
|
|
12
21
|
import formFieldsMapper from '../FormFields/FormFieldsMapper';
|
|
13
22
|
import { DEFAULT_ORDER_FORM_FIELDS } from '../FormFields/FormFields.helper';
|
|
14
23
|
import { OrderFormInputsType, OrderInfoType } from '../../types/order';
|
|
15
24
|
import {
|
|
16
25
|
PaymentMethodOptionsType,
|
|
17
|
-
|
|
26
|
+
OrderFormFieldType,
|
|
18
27
|
ContactRequestType,
|
|
28
|
+
OrderDenialFallbackOfferType,
|
|
19
29
|
} from '../../types/general';
|
|
20
30
|
import { orderInvoiceContactFields } from '../../utils/order.helper';
|
|
21
31
|
import useOrderForm from '../../hooks/useOrderForm';
|
|
22
32
|
|
|
23
33
|
import './orderForm.scss';
|
|
34
|
+
import TermsCheckbox from '../FormFields/TermsCheckbox';
|
|
24
35
|
|
|
25
36
|
type Props = {
|
|
26
37
|
callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
|
|
@@ -45,6 +56,8 @@ type Props = {
|
|
|
45
56
|
paymentMethods?: { label: string; value: PaymentMethodEnum }[];
|
|
46
57
|
allowedPaymentMethods?: PaymentMethodEnum[];
|
|
47
58
|
submitButtonText?: string;
|
|
59
|
+
orderDenialCloseButtonText?: string;
|
|
60
|
+
orderDenialContinueButtonText?: string;
|
|
48
61
|
paymentMethodLabel?: string;
|
|
49
62
|
paymentMethodNotAllowedMsg?: string;
|
|
50
63
|
errorReqMsg?: string;
|
|
@@ -53,12 +66,18 @@ type Props = {
|
|
|
53
66
|
invoiceAddressSelection?: {
|
|
54
67
|
enabled?: boolean;
|
|
55
68
|
label?: string;
|
|
56
|
-
fields?:
|
|
69
|
+
fields?: OrderFormFieldType[];
|
|
57
70
|
paymentMethods?: PaymentMethodEnum[];
|
|
58
71
|
};
|
|
72
|
+
requireTermsAcceptance?: boolean;
|
|
59
73
|
errorValidationTitleMsg?: string;
|
|
60
74
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
61
75
|
errorValidationBlockingOffersMsg?: string;
|
|
76
|
+
orderDenialOfferBaseText?: string;
|
|
77
|
+
orderDenialOfferWithFallbackText?: string;
|
|
78
|
+
orderDenialAmountText?: string;
|
|
79
|
+
orderDenialFallbackOffer?: OrderDenialFallbackOfferType;
|
|
80
|
+
termsAndConditionsText?: string | ReactNode;
|
|
62
81
|
};
|
|
63
82
|
|
|
64
83
|
const initialData = {
|
|
@@ -95,6 +114,8 @@ const OrderForm: FC<Props> = ({
|
|
|
95
114
|
allowedPaymentMethods,
|
|
96
115
|
invoiceAddressSelection,
|
|
97
116
|
submitButtonText = 'Start',
|
|
117
|
+
orderDenialCloseButtonText = 'Close',
|
|
118
|
+
orderDenialContinueButtonText = 'Continue',
|
|
98
119
|
paymentMethodLabel = 'Select Payment Method',
|
|
99
120
|
paymentMethodNotAllowedMsg = 'This payment method not allowed!',
|
|
100
121
|
errorReqMsg = '',
|
|
@@ -103,6 +124,12 @@ const OrderForm: FC<Props> = ({
|
|
|
103
124
|
errorValidationTitleMsg,
|
|
104
125
|
errorValidationDenialOrderBlockingMsg,
|
|
105
126
|
errorValidationBlockingOffersMsg,
|
|
127
|
+
orderDenialOfferBaseText,
|
|
128
|
+
orderDenialOfferWithFallbackText,
|
|
129
|
+
orderDenialAmountText,
|
|
130
|
+
orderDenialFallbackOffer,
|
|
131
|
+
requireTermsAcceptance,
|
|
132
|
+
termsAndConditionsText,
|
|
106
133
|
}) => {
|
|
107
134
|
if (!templatePackageId) {
|
|
108
135
|
console.error('"templatePackageId" should be set');
|
|
@@ -127,7 +154,7 @@ const OrderForm: FC<Props> = ({
|
|
|
127
154
|
console.error('"identityProviderId" should be set');
|
|
128
155
|
}
|
|
129
156
|
|
|
130
|
-
const [orderFields, setOrderFields] = useState<
|
|
157
|
+
const [orderFields, setOrderFields] = useState<OrderFormFieldType[]>(
|
|
131
158
|
paymentMethodsOptions?.[
|
|
132
159
|
defaultValues?.paymentMethod || PAYMENT_METHOD_DEFAULT
|
|
133
160
|
]?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS
|
|
@@ -158,6 +185,7 @@ const OrderForm: FC<Props> = ({
|
|
|
158
185
|
|
|
159
186
|
const invoiceAddressToggle = watch('invoiceAddressSelection');
|
|
160
187
|
const paymentMethodInput = watch('paymentMethod');
|
|
188
|
+
const isTermsAccepted = watch('termsAccept', false);
|
|
161
189
|
|
|
162
190
|
const invoiceOrderFields =
|
|
163
191
|
paymentMethodsOptions?.[paymentMethodInput || PAYMENT_METHOD_DEFAULT]
|
|
@@ -169,7 +197,16 @@ const OrderForm: FC<Props> = ({
|
|
|
169
197
|
invoiceAddressSelection?.paymentMethods ||
|
|
170
198
|
INVOICE_ALLOWED_PAYMENT_METHODS;
|
|
171
199
|
|
|
172
|
-
const {
|
|
200
|
+
const {
|
|
201
|
+
orderSubmit,
|
|
202
|
+
continueWithFallbackOffer,
|
|
203
|
+
loading,
|
|
204
|
+
apiErrorMsg,
|
|
205
|
+
errorsMsg,
|
|
206
|
+
orderDenialType,
|
|
207
|
+
orderDenialMessage,
|
|
208
|
+
dismissOrderDenial,
|
|
209
|
+
} = useOrderForm({
|
|
173
210
|
callback,
|
|
174
211
|
submitStartCallback,
|
|
175
212
|
userActionCallback,
|
|
@@ -190,6 +227,10 @@ const OrderForm: FC<Props> = ({
|
|
|
190
227
|
errorValidationTitleMsg,
|
|
191
228
|
errorValidationDenialOrderBlockingMsg,
|
|
192
229
|
errorValidationBlockingOffersMsg,
|
|
230
|
+
orderDenialOfferBaseText,
|
|
231
|
+
orderDenialOfferWithFallbackText,
|
|
232
|
+
orderDenialAmountText,
|
|
233
|
+
orderDenialFallbackOffer,
|
|
193
234
|
});
|
|
194
235
|
|
|
195
236
|
const onSubmit: SubmitHandler<OrderFormInputsType> = async (
|
|
@@ -248,6 +289,10 @@ const OrderForm: FC<Props> = ({
|
|
|
248
289
|
allowPaymentMethod &&
|
|
249
290
|
invoicePaymentMethods.includes(paymentMethodInput as PaymentMethodEnum);
|
|
250
291
|
|
|
292
|
+
const isSubmitButtonDisabled = requireTermsAcceptance
|
|
293
|
+
? !isTermsAccepted
|
|
294
|
+
: false;
|
|
295
|
+
|
|
251
296
|
return (
|
|
252
297
|
<FormProvider {...methods}>
|
|
253
298
|
<form
|
|
@@ -344,11 +389,20 @@ const OrderForm: FC<Props> = ({
|
|
|
344
389
|
})}
|
|
345
390
|
</Suspense>
|
|
346
391
|
)}
|
|
392
|
+
{requireTermsAcceptance && (
|
|
393
|
+
<TermsCheckbox
|
|
394
|
+
name="termsAccept"
|
|
395
|
+
label={termsAndConditionsText}
|
|
396
|
+
required
|
|
397
|
+
errors={errors}
|
|
398
|
+
/>
|
|
399
|
+
)}
|
|
347
400
|
{allowPaymentMethod && (
|
|
348
401
|
<Button
|
|
349
402
|
type="submit"
|
|
350
403
|
loading={loading}
|
|
351
404
|
buttonText={submitButtonText}
|
|
405
|
+
disable={isSubmitButtonDisabled}
|
|
352
406
|
/>
|
|
353
407
|
)}
|
|
354
408
|
<Alert
|
|
@@ -361,7 +415,27 @@ const OrderForm: FC<Props> = ({
|
|
|
361
415
|
/>
|
|
362
416
|
{errorsMsg?.length > 0 &&
|
|
363
417
|
allowPaymentMethod &&
|
|
364
|
-
errorsMsg.map((i) =>
|
|
418
|
+
errorsMsg.map((i, index) => (
|
|
419
|
+
<Alert key={`${i}-${index}`} className="mt-2" msg={i} />
|
|
420
|
+
))}
|
|
421
|
+
<OrderDenialModal
|
|
422
|
+
isOpen={!!orderDenialType}
|
|
423
|
+
message={orderDenialMessage}
|
|
424
|
+
closeButtonText={orderDenialCloseButtonText}
|
|
425
|
+
continueButtonText={orderDenialContinueButtonText}
|
|
426
|
+
canContinue={
|
|
427
|
+
orderDenialType === 'offer' &&
|
|
428
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
429
|
+
}
|
|
430
|
+
offer={
|
|
431
|
+
orderDenialType === 'offer' &&
|
|
432
|
+
!!orderDenialFallbackOffer?.templatePackageId
|
|
433
|
+
? orderDenialFallbackOffer
|
|
434
|
+
: undefined
|
|
435
|
+
}
|
|
436
|
+
onClose={dismissOrderDenial}
|
|
437
|
+
onContinue={continueWithFallbackOffer}
|
|
438
|
+
/>
|
|
365
439
|
</form>
|
|
366
440
|
</FormProvider>
|
|
367
441
|
);
|
package/src/custom.d.ts
ADDED
package/src/enums/general.ts
CHANGED
|
@@ -32,6 +32,7 @@ export enum FormTypeEnum {
|
|
|
32
32
|
export enum UserActionEnum {
|
|
33
33
|
SELECT_FORM = 'selectForm',
|
|
34
34
|
SELECT_PAYMENT_METHOD = 'selectPaymentMethod',
|
|
35
|
+
SELECT_FALLBACK_OFFER = 'selectFallbackOffer',
|
|
35
36
|
RETURN_TO_MAIN = 'returnToMain',
|
|
36
37
|
TOGGLE_INVOICE_ADDRESS = 'toggleInvoiceAddress',
|
|
37
38
|
SEARCH_ORGANIZATION_NUMBER = 'searchOrganizationNumber',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
2
|
import { SubmitHandler } from 'react-hook-form';
|
|
3
3
|
|
|
4
4
|
import { createSubscriber } from '../api/SubscribeApi';
|
|
@@ -13,7 +13,8 @@ import { WRONG_MSG, PAYMENT_METHOD_DEFAULT } from '../constants/index';
|
|
|
13
13
|
import { OrderFormInputsType, OrderInfoType } from '../types/order';
|
|
14
14
|
import {
|
|
15
15
|
ErrorsMsg,
|
|
16
|
-
|
|
16
|
+
OrderFormFieldType,
|
|
17
|
+
OrderDenialFallbackOfferType,
|
|
17
18
|
PaymentMethodOptionsType,
|
|
18
19
|
ContactRequestType,
|
|
19
20
|
} from '../types/general';
|
|
@@ -35,9 +36,7 @@ type Props = {
|
|
|
35
36
|
action: UserActionEnum,
|
|
36
37
|
args: object | null | undefined
|
|
37
38
|
) => void;
|
|
38
|
-
setContactCallback?: (
|
|
39
|
-
contactInfo: ContactRequestType
|
|
40
|
-
) => void;
|
|
39
|
+
setContactCallback?: (contactInfo: ContactRequestType) => void;
|
|
41
40
|
templatePackageId: string;
|
|
42
41
|
subscriberId?: string;
|
|
43
42
|
userId?: string;
|
|
@@ -48,13 +47,59 @@ type Props = {
|
|
|
48
47
|
language: string;
|
|
49
48
|
merchantAgreementUrl: string;
|
|
50
49
|
paymentMethodsOptions?: PaymentMethodOptionsType;
|
|
51
|
-
orderFields:
|
|
50
|
+
orderFields: OrderFormFieldType[];
|
|
52
51
|
invoiceAddressToggle?: boolean;
|
|
53
|
-
invoiceOrderFields:
|
|
52
|
+
invoiceOrderFields: OrderFormFieldType[];
|
|
54
53
|
invoiceLookupNotFoundText?: string;
|
|
55
54
|
errorValidationTitleMsg?: string;
|
|
56
55
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
57
56
|
errorValidationBlockingOffersMsg?: string;
|
|
57
|
+
orderDenialOfferBaseText?: string;
|
|
58
|
+
orderDenialOfferWithFallbackText?: string;
|
|
59
|
+
orderDenialAmountText?: string;
|
|
60
|
+
orderDenialFallbackOffer?: OrderDenialFallbackOfferType;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type DenialErrorType = {
|
|
64
|
+
status?: number;
|
|
65
|
+
errors?: Record<string, string[] | undefined>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const OFFER_DENIAL_BASE_TEXT =
|
|
69
|
+
'Hello again!\n\nLooks like you already tried this offer.';
|
|
70
|
+
const OFFER_DENIAL_WITH_FALLBACK_TEXT =
|
|
71
|
+
'Hello again!\n\nLooks like you already tried this offer, but we would like to keep you with us.\n\nTherefore we got a new great offer for you:';
|
|
72
|
+
|
|
73
|
+
const getDenialErrorType = (
|
|
74
|
+
error: DenialErrorType
|
|
75
|
+
): 'offer' | 'amount' | null => {
|
|
76
|
+
if (error?.status !== 400 || !error?.errors) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const normalizedEntries = Object.entries(error.errors).map(
|
|
81
|
+
([key, value]) => [key.toLowerCase(), value] as const
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const hasOffer = normalizedEntries.some(
|
|
85
|
+
([key, value]) =>
|
|
86
|
+
key === 'offer' && Array.isArray(value) && value.length > 0
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (hasOffer) {
|
|
90
|
+
return 'offer';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const hasAmount = normalizedEntries.some(
|
|
94
|
+
([key, value]) =>
|
|
95
|
+
key === 'amount' && Array.isArray(value) && value.length > 0
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (hasAmount) {
|
|
99
|
+
return 'amount';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return null;
|
|
58
103
|
};
|
|
59
104
|
|
|
60
105
|
const useOrderForm = ({
|
|
@@ -79,17 +124,56 @@ const useOrderForm = ({
|
|
|
79
124
|
errorValidationTitleMsg,
|
|
80
125
|
errorValidationDenialOrderBlockingMsg,
|
|
81
126
|
errorValidationBlockingOffersMsg,
|
|
127
|
+
orderDenialOfferBaseText,
|
|
128
|
+
orderDenialOfferWithFallbackText,
|
|
129
|
+
orderDenialAmountText,
|
|
130
|
+
orderDenialFallbackOffer,
|
|
82
131
|
}: Props) => {
|
|
83
132
|
const [loading, setLoading] = useState<boolean>(false);
|
|
84
133
|
const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
|
|
85
134
|
const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
|
|
135
|
+
const [orderDenialType, setOrderDenialType] = useState<
|
|
136
|
+
'offer' | 'amount' | null
|
|
137
|
+
>(null);
|
|
138
|
+
const [submittedOrderData, setSubmittedOrderData] =
|
|
139
|
+
useState<OrderFormInputsType | null>(null);
|
|
140
|
+
const fallbackOfferTemplatePackageIdRef = useRef<string | null>(null);
|
|
141
|
+
|
|
142
|
+
const dismissOrderDenial = () => {
|
|
143
|
+
setOrderDenialType(null);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const getOrderDenialMessage = () => {
|
|
147
|
+
if (orderDenialType === 'offer') {
|
|
148
|
+
if (orderDenialFallbackOffer?.templatePackageId) {
|
|
149
|
+
return (
|
|
150
|
+
orderDenialOfferWithFallbackText ||
|
|
151
|
+
OFFER_DENIAL_WITH_FALLBACK_TEXT
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return orderDenialOfferBaseText || OFFER_DENIAL_BASE_TEXT;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (orderDenialType === 'amount') {
|
|
159
|
+
return (
|
|
160
|
+
orderDenialAmountText ||
|
|
161
|
+
errorValidationDenialOrderBlockingMsg ||
|
|
162
|
+
WRONG_MSG
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return '';
|
|
167
|
+
};
|
|
86
168
|
|
|
87
169
|
const orderSubmit: SubmitHandler<OrderFormInputsType> = async (
|
|
88
170
|
data
|
|
89
171
|
): Promise<void> => {
|
|
90
172
|
setApiErrorMsg('');
|
|
91
173
|
setErrorsMsg([]);
|
|
174
|
+
setOrderDenialType(null);
|
|
92
175
|
setLoading(true);
|
|
176
|
+
setSubmittedOrderData(data);
|
|
93
177
|
try {
|
|
94
178
|
let id: string | undefined = subscriberId;
|
|
95
179
|
let invoiceResponse = null;
|
|
@@ -152,8 +236,6 @@ const useOrderForm = ({
|
|
|
152
236
|
sessionStorage.setItem('subscriberId', id); // For avoiding attempt of creating subscriber again
|
|
153
237
|
}
|
|
154
238
|
|
|
155
|
-
console.log('Dette er en ny testversjon av OSDK');
|
|
156
|
-
|
|
157
239
|
if (setContactCallback) {
|
|
158
240
|
setContactCallback(contactModel);
|
|
159
241
|
}
|
|
@@ -163,6 +245,10 @@ const useOrderForm = ({
|
|
|
163
245
|
if (id) {
|
|
164
246
|
const paymentMethod =
|
|
165
247
|
data.paymentMethod || PAYMENT_METHOD_DEFAULT;
|
|
248
|
+
const selectedTemplateSubscriptionPlanId =
|
|
249
|
+
fallbackOfferTemplatePackageIdRef.current ||
|
|
250
|
+
templatePackageId;
|
|
251
|
+
fallbackOfferTemplatePackageIdRef.current = null;
|
|
166
252
|
|
|
167
253
|
const agreements = prepareAgreementModel({
|
|
168
254
|
paymentMethod,
|
|
@@ -188,7 +274,8 @@ const useOrderForm = ({
|
|
|
188
274
|
subscriberId: id,
|
|
189
275
|
subscriptionPlan: {
|
|
190
276
|
organizationId,
|
|
191
|
-
templateSubscriptionPlanId:
|
|
277
|
+
templateSubscriptionPlanId:
|
|
278
|
+
selectedTemplateSubscriptionPlanId,
|
|
192
279
|
},
|
|
193
280
|
paymentAgreement: { ...agreements },
|
|
194
281
|
invoiceContact: invoiceAddressToggle
|
|
@@ -218,6 +305,17 @@ const useOrderForm = ({
|
|
|
218
305
|
errorValidationDenialOrderBlockingMsg,
|
|
219
306
|
} as ErrorMessages;
|
|
220
307
|
|
|
308
|
+
const detectedDenialType = getDenialErrorType(
|
|
309
|
+
error as DenialErrorType
|
|
310
|
+
);
|
|
311
|
+
if (detectedDenialType) {
|
|
312
|
+
setApiErrorMsg('');
|
|
313
|
+
setErrorsMsg([]);
|
|
314
|
+
setOrderDenialType(detectedDenialType);
|
|
315
|
+
callback(null);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
221
319
|
console.error(error);
|
|
222
320
|
setApiErrorMsg(
|
|
223
321
|
prepareErrorMessage(error as Error, undefined, translations)
|
|
@@ -238,11 +336,36 @@ const useOrderForm = ({
|
|
|
238
336
|
}
|
|
239
337
|
};
|
|
240
338
|
|
|
339
|
+
const continueWithFallbackOffer = async () => {
|
|
340
|
+
if (orderDenialType !== 'offer' || !submittedOrderData) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const fallbackTemplatePackageId =
|
|
345
|
+
orderDenialFallbackOffer?.templatePackageId;
|
|
346
|
+
|
|
347
|
+
if (!fallbackTemplatePackageId) {
|
|
348
|
+
dismissOrderDenial();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
fallbackOfferTemplatePackageIdRef.current = fallbackTemplatePackageId;
|
|
353
|
+
userActionCallback?.(UserActionEnum.SELECT_FALLBACK_OFFER, {
|
|
354
|
+
templatePackageId: fallbackTemplatePackageId,
|
|
355
|
+
});
|
|
356
|
+
dismissOrderDenial();
|
|
357
|
+
await orderSubmit(submittedOrderData);
|
|
358
|
+
};
|
|
359
|
+
|
|
241
360
|
return {
|
|
242
361
|
orderSubmit,
|
|
362
|
+
continueWithFallbackOffer,
|
|
243
363
|
loading,
|
|
244
364
|
apiErrorMsg,
|
|
245
365
|
errorsMsg,
|
|
366
|
+
orderDenialType,
|
|
367
|
+
orderDenialMessage: getOrderDenialMessage(),
|
|
368
|
+
dismissOrderDenial,
|
|
246
369
|
};
|
|
247
370
|
};
|
|
248
371
|
|
package/src/types/general.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
1
3
|
import { PaymentMethodEnum, UserActionEnum } from '../enums/general';
|
|
2
4
|
import { OrderFormInputsType } from './order';
|
|
3
5
|
|
|
@@ -7,7 +9,7 @@ declare global {
|
|
|
7
9
|
}
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
export type
|
|
12
|
+
export type OrderFormFieldType = {
|
|
11
13
|
name: string;
|
|
12
14
|
required?: boolean;
|
|
13
15
|
readOnly?: boolean;
|
|
@@ -18,8 +20,8 @@ export type PaymentMethodOptionsType = {
|
|
|
18
20
|
[key in PaymentMethodEnum]: {
|
|
19
21
|
generateSubscriberContact?: boolean;
|
|
20
22
|
accountId?: string;
|
|
21
|
-
orderFormFields
|
|
22
|
-
paymentInvoiceFields?:
|
|
23
|
+
orderFormFields?: OrderFormFieldType[];
|
|
24
|
+
paymentInvoiceFields?: OrderFormFieldType[] | never[] | null;
|
|
23
25
|
};
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -34,6 +36,13 @@ export type ContactRequestType = {
|
|
|
34
36
|
careOf?: string;
|
|
35
37
|
};
|
|
36
38
|
|
|
39
|
+
export type OrderDenialFallbackOfferType = {
|
|
40
|
+
title?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
price?: string;
|
|
43
|
+
templatePackageId?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
37
46
|
export type ConfigType = {
|
|
38
47
|
submitStartCallback?: (subscriberId: string) => void;
|
|
39
48
|
userActionCallback?: (
|
|
@@ -56,12 +65,13 @@ export type ConfigType = {
|
|
|
56
65
|
availablePaymentMethods?: { label: string; value: PaymentMethodEnum }[];
|
|
57
66
|
allowedPaymentMethods?: PaymentMethodEnum[];
|
|
58
67
|
paymentMethodsOptions?: PaymentMethodOptionsType;
|
|
68
|
+
requireTermsAcceptance?: boolean;
|
|
59
69
|
language?: string;
|
|
60
70
|
merchantAgreementUrl?: string;
|
|
61
71
|
invoiceAddressSelection?: {
|
|
62
72
|
enabled?: boolean;
|
|
63
73
|
label?: string;
|
|
64
|
-
fields?:
|
|
74
|
+
fields?: OrderFormFieldType[];
|
|
65
75
|
};
|
|
66
76
|
settings?: {
|
|
67
77
|
successText?: string;
|
|
@@ -69,6 +79,8 @@ export type ConfigType = {
|
|
|
69
79
|
submitButtonText?: string;
|
|
70
80
|
backButtonText?: string;
|
|
71
81
|
verifyButtonText?: string;
|
|
82
|
+
orderDenialCloseButtonText?: string;
|
|
83
|
+
orderDenialContinueButtonText?: string;
|
|
72
84
|
organizationNumberLabel?: string;
|
|
73
85
|
cvrLabel?: string;
|
|
74
86
|
glnLabel?: string;
|
|
@@ -82,6 +94,11 @@ export type ConfigType = {
|
|
|
82
94
|
errorValidationTitleMsg?: string;
|
|
83
95
|
errorValidationDenialOrderBlockingMsg?: string;
|
|
84
96
|
errorValidationBlockingOffersMsg?: string;
|
|
97
|
+
orderDenialOfferBaseText?: string;
|
|
98
|
+
orderDenialOfferWithFallbackText?: string;
|
|
99
|
+
orderDenialAmountText?: string;
|
|
100
|
+
orderDenialFallbackOffer?: OrderDenialFallbackOfferType;
|
|
101
|
+
termsAndConditionsText?: string | ReactNode;
|
|
85
102
|
};
|
|
86
103
|
};
|
|
87
104
|
|
package/src/types/order.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MessageEventTypeEnum, PaymentMethodEnum } from '../enums/general';
|
|
2
2
|
import { AgreementsType, OrderFormInputsType } from '../types/order';
|
|
3
|
-
import {
|
|
3
|
+
import { OrderFormFieldType } from '../types/general';
|
|
4
4
|
import { FIELD_TYPES } from '../components/FormFields/FormFields.helper';
|
|
5
5
|
|
|
6
6
|
type AgreementModelType = {
|
|
@@ -105,7 +105,7 @@ export const prepareAgreementModel = ({
|
|
|
105
105
|
|
|
106
106
|
type ContactModelType = {
|
|
107
107
|
data: OrderFormInputsType;
|
|
108
|
-
orderFields:
|
|
108
|
+
orderFields: OrderFormFieldType[];
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
export const prepareContactModel = ({
|
package/tsconfig.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
3
|
+
"target": "es2020",
|
|
4
4
|
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
-
"downlevelIteration": true,
|
|
6
5
|
"allowJs": true,
|
|
7
6
|
"checkJs": false,
|
|
8
7
|
"skipLibCheck": true,
|
|
@@ -12,28 +11,26 @@
|
|
|
12
11
|
"forceConsistentCasingInFileNames": true,
|
|
13
12
|
"noFallthroughCasesInSwitch": true,
|
|
14
13
|
"module": "esnext",
|
|
15
|
-
"moduleResolution": "node",
|
|
16
14
|
"resolveJsonModule": true,
|
|
17
15
|
"isolatedModules": false,
|
|
18
16
|
"noEmit": false,
|
|
19
17
|
"noImplicitAny": true,
|
|
20
18
|
"jsx": "react-jsx",
|
|
21
|
-
"baseUrl": "src",
|
|
22
19
|
"sourceMap": true,
|
|
23
20
|
"inlineSources": true,
|
|
24
21
|
"sourceRoot": "/",
|
|
25
22
|
"paths": {
|
|
26
|
-
"*": ["
|
|
27
|
-
"API": ["api"],
|
|
28
|
-
"API/*": ["api/*"],
|
|
29
|
-
"Component/*": ["components/*"],
|
|
30
|
-
"Utils/*": ["utils/*"],
|
|
31
|
-
"Hooks/*": ["hooks/*"],
|
|
32
|
-
"Models/*": ["models/*"],
|
|
33
|
-
"Types/*": ["types/*"],
|
|
34
|
-
"Enums/*": ["enums/*"],
|
|
35
|
-
"Constants/*": ["constants/*"],
|
|
36
|
-
"Assets/*": ["assets/*"]
|
|
23
|
+
"*": ["./src/*"],
|
|
24
|
+
"API": ["./src/api"],
|
|
25
|
+
"API/*": ["./src/api/*"],
|
|
26
|
+
"Component/*": ["./src/components/*"],
|
|
27
|
+
"Utils/*": ["./src/utils/*"],
|
|
28
|
+
"Hooks/*": ["./src/hooks/*"],
|
|
29
|
+
"Models/*": ["./src/models/*"],
|
|
30
|
+
"Types/*": ["./src/types/*"],
|
|
31
|
+
"Enums/*": ["./src/enums/*"],
|
|
32
|
+
"Constants/*": ["./src/constants/*"],
|
|
33
|
+
"Assets/*": ["./src/assets/*"]
|
|
37
34
|
}
|
|
38
35
|
},
|
|
39
36
|
"include": ["src"],
|