@infosoftas/s4-orders-js-sdk 0.0.1-alpha2a → 0.0.1-alpha2b

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-alpha2a",
3
+ "version": "0.0.1-alpha2b",
4
4
  "scripts": {
5
5
  "build": "rimraf lib && webpack --env mode=production"
6
6
  },
package/src/App.tsx CHANGED
@@ -1,8 +1,14 @@
1
1
  import { FC, useEffect, useState } from 'react';
2
2
 
3
- import { MessageEventTypeEnum, PaymentMethodEnum } from './enums/general';
3
+ import {
4
+ FormTypeEnum,
5
+ MessageEventTypeEnum,
6
+ PaymentMethodEnum,
7
+ } from './enums/general';
4
8
  import useMessageEvent from './hooks/useMessageEvent';
5
9
  import OrderForm from './components/OrderForm/OrderForm';
10
+ import OIOForm from './components/OIOForm/OIOForm';
11
+ import EHFForm from './components/EHFForm/EHFForm';
6
12
  import Loader from './components/Loader/Loader';
7
13
  import MainIframe from './components/MainIframe/MainIframe';
8
14
  import Alert from './components/Alert/Alert';
@@ -35,6 +41,11 @@ const App: FC<ConfigType> = ({
35
41
  successText: 'Order successful completed!',
36
42
  failureText: 'Something went wrong!',
37
43
  buttonText: 'Start',
44
+ submitButtonText: 'Start',
45
+ backButtonText: 'Back',
46
+ verifyButtonText: 'Verify',
47
+ organizationNumberLabel: 'CVR',
48
+ glnLabel: 'GLN',
38
49
  },
39
50
  }) => {
40
51
  const [loading, setLoading] = useState<boolean>(false);
@@ -46,6 +57,7 @@ const App: FC<ConfigType> = ({
46
57
  const [failedMsg, setFailedMsg] = useState<string>('');
47
58
  const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
48
59
  const [orderInfo, setOrderInfo] = useState<OrderInfoType | null>(null);
60
+ const [formType, setFormType] = useState(FormTypeEnum.ORDER);
49
61
 
50
62
  useEffect(() => {
51
63
  if (apiKey) {
@@ -108,6 +120,7 @@ const App: FC<ConfigType> = ({
108
120
  setIsFailed(true);
109
121
  setLoading(false);
110
122
  setShowOrderForm(true);
123
+ setFormType(FormTypeEnum.ORDER);
111
124
  }
112
125
  };
113
126
 
@@ -191,18 +204,15 @@ const App: FC<ConfigType> = ({
191
204
  data?.paymentMethod === PaymentMethodEnum.Email ||
192
205
  data?.paymentMethod === PaymentMethodEnum.Invoice
193
206
  ) {
194
- if (window === top) {
195
- setIsConfirmed(true);
196
- setLoading(false);
197
- top.postMessage(
198
- {
199
- type: MessageEventTypeEnum.ORDER_FLOW_COMPLETE,
200
- isCompleted: true,
201
- orderInfo: data || null,
202
- },
203
- top?.location?.origin || '*'
204
- );
205
- }
207
+ messageCallback({
208
+ orderId: data.orderId || orderId || '',
209
+ agreementId: '',
210
+ orderInfo: data || orderInfo || null,
211
+ });
212
+ } else if (data?.paymentMethod === PaymentMethodEnum.EHF) {
213
+ setFormType(FormTypeEnum.EHF);
214
+ } else if (data?.paymentMethod === PaymentMethodEnum.OIO) {
215
+ setFormType(FormTypeEnum.OIO);
206
216
  } else if (url) {
207
217
  if (
208
218
  showIframe &&
@@ -219,6 +229,18 @@ const App: FC<ConfigType> = ({
219
229
  setIframeSrc(null);
220
230
  };
221
231
 
232
+ const handleInvoiceBack = () => {
233
+ setFormType(FormTypeEnum.ORDER);
234
+ };
235
+
236
+ const handleInvoiceForm = async () => {
237
+ await messageCallback({
238
+ orderId: orderId || '',
239
+ agreementId: '',
240
+ orderInfo: orderInfo || null,
241
+ });
242
+ };
243
+
222
244
  if (window !== top) {
223
245
  return null;
224
246
  }
@@ -238,27 +260,67 @@ const App: FC<ConfigType> = ({
238
260
  </div>
239
261
  )}
240
262
  {!iframeSrc && showOrderForm && (
241
- <OrderForm
242
- callback={handleForm}
243
- templatePackageId={templatePackageId}
244
- subscriberId={subscriberId}
245
- userId={userId}
246
- identityProviderId={identityProviderId}
247
- organizationId={organizationId}
248
- paymentMethods={availablePaymentMethods}
249
- buttonText={settings?.buttonText}
250
- paymentMethodLabel={settings?.paymentMethodLabel}
251
- errorReqMsg={settings?.errorReqMsg}
252
- errorInvalidEmailMsg={settings?.errorInvalidEmailMsg}
253
- errorInvalidPhoneMsg={settings?.errorInvalidPhoneMsg}
254
- defaultValues={settings?.orderDefaultValues}
255
- redirectUrl={redirectUrl}
256
- showIframe={showIframe}
257
- paymentMethodsOptions={paymentMethodsOptions}
258
- language={language}
259
- merchantAgreementUrl={merchantAgreementUrl}
260
- invoiceAddressSelection={invoiceAddressSelection}
261
- />
263
+ <>
264
+ {formType === FormTypeEnum.OIO && (
265
+ <OIOForm
266
+ onBack={handleInvoiceBack}
267
+ callback={handleInvoiceForm}
268
+ backButtonText={settings?.backButtonText}
269
+ verifyButtonText={settings?.verifyButtonText}
270
+ organizationNumberLabel={
271
+ settings?.organizationNumberLabel
272
+ }
273
+ glnLabel={settings?.glnLabel}
274
+ />
275
+ )}
276
+ {formType === FormTypeEnum.EHF && (
277
+ <EHFForm
278
+ onBack={handleInvoiceBack}
279
+ callback={handleInvoiceForm}
280
+ backButtonText={settings?.backButtonText}
281
+ verifyButtonText={settings?.verifyButtonText}
282
+ organizationNumberLabel={
283
+ settings?.organizationNumberLabel
284
+ }
285
+ />
286
+ )}
287
+ {formType !== FormTypeEnum.OIO &&
288
+ formType !== FormTypeEnum.EHF && (
289
+ <OrderForm
290
+ callback={handleForm}
291
+ templatePackageId={templatePackageId}
292
+ subscriberId={subscriberId}
293
+ userId={userId}
294
+ identityProviderId={identityProviderId}
295
+ organizationId={organizationId}
296
+ paymentMethods={availablePaymentMethods}
297
+ submitButtonText={
298
+ settings?.submitButtonText
299
+ }
300
+ paymentMethodLabel={
301
+ settings?.paymentMethodLabel
302
+ }
303
+ errorReqMsg={settings?.errorReqMsg}
304
+ errorInvalidEmailMsg={
305
+ settings?.errorInvalidEmailMsg
306
+ }
307
+ errorInvalidPhoneMsg={
308
+ settings?.errorInvalidPhoneMsg
309
+ }
310
+ defaultValues={settings?.orderDefaultValues}
311
+ redirectUrl={redirectUrl}
312
+ showIframe={showIframe}
313
+ paymentMethodsOptions={
314
+ paymentMethodsOptions
315
+ }
316
+ language={language}
317
+ merchantAgreementUrl={merchantAgreementUrl}
318
+ invoiceAddressSelection={
319
+ invoiceAddressSelection
320
+ }
321
+ />
322
+ )}
323
+ </>
262
324
  )}
263
325
  {showIframe && <MainIframe iframeSrc={iframeSrc} />}
264
326
  {isConfirmed && (
@@ -0,0 +1,25 @@
1
+ import fetcher from '../utils/fetcher';
2
+
3
+ type RequestInvoiceLookupType = {
4
+ network: string;
5
+ value: string;
6
+ };
7
+
8
+ type InvoiceLookupResponseType = {
9
+ recievesInvoice: boolean;
10
+ };
11
+
12
+ export const invoiceLookup = (
13
+ body: RequestInvoiceLookupType
14
+ ): Promise<InvoiceLookupResponseType> =>
15
+ fetcher<InvoiceLookupResponseType, RequestInvoiceLookupType>({
16
+ method: 'POST',
17
+ url: '/invoicelookup',
18
+ headers: {
19
+ 'S4-ORDERS-API-KEY':
20
+ sessionStorage.getItem('sdk_api_key') ||
21
+ process.env.API_KEY ||
22
+ '',
23
+ },
24
+ body,
25
+ }) as Promise<InvoiceLookupResponseType>;
@@ -17,6 +17,10 @@
17
17
  align-items: center;
18
18
  }
19
19
 
20
+ .gap-2 {
21
+ gap: 0.5rem
22
+ }
23
+
20
24
  .mt-2 {
21
25
  margin-top: 0.5rem;
22
26
  }
@@ -7,7 +7,7 @@ import './button.scss';
7
7
  type Props = {
8
8
  onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
9
9
  type?: 'button' | 'submit' | 'reset';
10
- btnType?: 'primary';
10
+ btnType?: 'primary' | 'default';
11
11
  buttonText?: string;
12
12
  loading?: boolean;
13
13
  disable?: boolean;
@@ -0,0 +1,125 @@
1
+ import { FC, useState } from 'react';
2
+ import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
3
+
4
+ import { invoiceLookup } from '../../api/InvoiceApi';
5
+ import Alert from '../Alert/Alert';
6
+ import Button from '../Button/Button';
7
+ import InputField from '../FormFields/InputField';
8
+ import {
9
+ prepareErrorMessage,
10
+ prepareErrorsArrayMessage,
11
+ } from '../../utils/helper';
12
+ import { InvoiceLookupNetworkEnum } from '../../enums/general';
13
+ import { ErrorsMsg } from '../../types/general';
14
+
15
+ type Props = {
16
+ callback: (value: string) => void;
17
+ onBack: () => void;
18
+ backButtonText?: string;
19
+ verifyButtonText?: string;
20
+ organizationNumberLabel?: string;
21
+ className?: string;
22
+ };
23
+
24
+ type EHFFormInputsType = {
25
+ organizationNumber: string;
26
+ };
27
+
28
+ const initialData = {
29
+ organizationNumber: '',
30
+ };
31
+
32
+ const EHFForm: FC<Props> = ({
33
+ callback,
34
+ onBack,
35
+ backButtonText = '',
36
+ verifyButtonText = '',
37
+ organizationNumberLabel = '',
38
+ className = '',
39
+ }) => {
40
+ const [loading, setLoading] = useState<boolean>(false);
41
+ const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
42
+ const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
43
+
44
+ const methods = useForm<EHFFormInputsType>({
45
+ defaultValues: {
46
+ ...initialData,
47
+ },
48
+ });
49
+
50
+ const {
51
+ handleSubmit,
52
+ formState: { errors },
53
+ } = methods;
54
+
55
+ const onSubmit: SubmitHandler<EHFFormInputsType> = async (
56
+ data
57
+ ): 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
+ }
81
+ };
82
+
83
+ const handleBack = () => {
84
+ onBack?.();
85
+ };
86
+
87
+ return (
88
+ <FormProvider {...methods}>
89
+ <form
90
+ className={`${className}`}
91
+ onSubmit={handleSubmit(onSubmit)}
92
+ data-testid="ehf-form-id"
93
+ >
94
+ <InputField
95
+ name="organizationNumber"
96
+ label={organizationNumberLabel}
97
+ required
98
+ readOnly={false}
99
+ errors={errors}
100
+ />
101
+ <div className="d-flex justify-center flex-wrap gap-2">
102
+ <Button
103
+ type="button"
104
+ btnType="default"
105
+ disable={loading}
106
+ buttonText={backButtonText}
107
+ onClick={handleBack}
108
+ />
109
+
110
+ <Button
111
+ type="submit"
112
+ loading={loading}
113
+ buttonText={verifyButtonText}
114
+ />
115
+ </div>
116
+
117
+ {apiErrorMsg && <Alert className="mt-2" msg={apiErrorMsg} />}
118
+ {errorsMsg?.length > 0 &&
119
+ errorsMsg.map((i) => <Alert className="mt-2" msg={i} />)}
120
+ </form>
121
+ </FormProvider>
122
+ );
123
+ };
124
+
125
+ export default EHFForm;
@@ -0,0 +1,141 @@
1
+ import { FC, useState } from 'react';
2
+ import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
3
+
4
+ import { invoiceLookup } from '../../api/InvoiceApi';
5
+ import Alert from '../Alert/Alert';
6
+ import Button from '../Button/Button';
7
+ import InputField from '../FormFields/InputField';
8
+ import {
9
+ prepareErrorMessage,
10
+ prepareErrorsArrayMessage,
11
+ } from '../../utils/helper';
12
+ import { InvoiceLookupNetworkEnum } from '../../enums/general';
13
+ import { ErrorsMsg } from '../../types/general';
14
+
15
+ type Props = {
16
+ callback: (value: string) => void;
17
+ onBack: () => void;
18
+ backButtonText?: string;
19
+ verifyButtonText?: string;
20
+ organizationNumberLabel?: string;
21
+ glnLabel?: string;
22
+ className?: string;
23
+ };
24
+
25
+ type OIOFormInputsType = {
26
+ cvr: string;
27
+ gln: string;
28
+ };
29
+
30
+ const initialData = {
31
+ cvr: '',
32
+ gln: '',
33
+ };
34
+
35
+ const EHFForm: FC<Props> = ({
36
+ callback,
37
+ onBack,
38
+ backButtonText = '',
39
+ verifyButtonText = '',
40
+ organizationNumberLabel = '',
41
+ glnLabel = '',
42
+ className = '',
43
+ }) => {
44
+ const [loading, setLoading] = useState<boolean>(false);
45
+ const [apiErrorMsg, setApiErrorMsg] = useState<string>('');
46
+ const [errorsMsg, setErrorsMsg] = useState<string[]>([]);
47
+
48
+ const methods = useForm<OIOFormInputsType>({
49
+ defaultValues: {
50
+ ...initialData,
51
+ },
52
+ });
53
+
54
+ const {
55
+ handleSubmit,
56
+ watch,
57
+ formState: { errors },
58
+ } = methods;
59
+
60
+ const cvr = watch('cvr');
61
+ const gln = watch('gln');
62
+
63
+ const onSubmit: SubmitHandler<OIOFormInputsType> = async (
64
+ data
65
+ ): 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
+ }
91
+ };
92
+
93
+ const handleBack = () => {
94
+ onBack?.();
95
+ };
96
+
97
+ return (
98
+ <FormProvider {...methods}>
99
+ <form
100
+ className={`${className}`}
101
+ onSubmit={handleSubmit(onSubmit)}
102
+ data-testid="oio-form-id"
103
+ >
104
+ <InputField
105
+ name="cvr"
106
+ label={organizationNumberLabel}
107
+ required={!gln}
108
+ readOnly={false}
109
+ errors={errors}
110
+ />
111
+ <InputField
112
+ name="gln"
113
+ label={glnLabel}
114
+ required={!cvr}
115
+ readOnly={false}
116
+ errors={errors}
117
+ />
118
+ <div className="d-flex justify-center flex-wrap gap-2">
119
+ <Button
120
+ type="button"
121
+ btnType="default"
122
+ disable={loading}
123
+ buttonText={backButtonText}
124
+ onClick={handleBack}
125
+ />
126
+
127
+ <Button
128
+ type="submit"
129
+ loading={loading}
130
+ buttonText={verifyButtonText}
131
+ />
132
+ </div>
133
+ {apiErrorMsg && <Alert className="mt-2" msg={apiErrorMsg} />}
134
+ {errorsMsg?.length > 0 &&
135
+ errorsMsg.map((i) => <Alert className="mt-2" msg={i} />)}
136
+ </form>
137
+ </FormProvider>
138
+ );
139
+ };
140
+
141
+ export default EHFForm;
@@ -43,7 +43,7 @@ type Props = {
43
43
  paymentMethodsOptions?: PaymentMethodOptionsType;
44
44
  defaultValues?: OrderFormInputsType;
45
45
  paymentMethods?: { label: string; value: PaymentMethodEnum }[];
46
- buttonText?: string;
46
+ submitButtonText?: string;
47
47
  paymentMethodLabel?: string;
48
48
  errorReqMsg?: string;
49
49
  errorInvalidEmailMsg?: string;
@@ -83,7 +83,7 @@ const OrderForm: FC<Props> = ({
83
83
  merchantAgreementUrl,
84
84
  paymentMethods = [],
85
85
  invoiceAddressSelection,
86
- buttonText = 'Start',
86
+ submitButtonText = 'Start',
87
87
  paymentMethodLabel = 'Select Payment Method',
88
88
  errorReqMsg = '',
89
89
  errorInvalidEmailMsg = '',
@@ -311,7 +311,7 @@ const OrderForm: FC<Props> = ({
311
311
  <Button
312
312
  type="submit"
313
313
  loading={loading}
314
- buttonText={buttonText}
314
+ buttonText={submitButtonText}
315
315
  />
316
316
  <Alert className="mt-2" msg={apiErrorMsg} />
317
317
  {errorsMsg?.length > 0 &&
@@ -16,3 +16,15 @@ export enum MessageEventTypeEnum {
16
16
  CANCEL = 'cancel',
17
17
  COMPLETE = 'complete',
18
18
  }
19
+
20
+ export enum InvoiceLookupNetworkEnum {
21
+ EHF = '0192',
22
+ OIO_GLN = '0088',
23
+ OIO_Danish_CVR = '0096',
24
+ }
25
+
26
+ export enum FormTypeEnum {
27
+ ORDER = 'order',
28
+ EHF = 'EHF',
29
+ OIO = 'OIO',
30
+ }
@@ -46,7 +46,11 @@ export type ConfigType = {
46
46
  settings?: {
47
47
  successText?: string;
48
48
  failureText?: string;
49
- buttonText?: string;
49
+ submitButtonText?: string;
50
+ backButtonText?: string;
51
+ verifyButtonText?: string;
52
+ organizationNumberLabel?: string;
53
+ glnLabel?: string;
50
54
  orderDefaultValues?: OrderFormInputsType;
51
55
  paymentMethodLabel?: string;
52
56
  errorReqMsg?: string;