@infosoftas/s4-orders-js-sdk 0.1.20 → 0.1.21-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.
Files changed (56) hide show
  1. package/README.md +471 -444
  2. package/build/postcss-scope-tailwind.cjs +66 -0
  3. package/components.json +21 -0
  4. package/package.json +59 -50
  5. package/src/App.css +409 -0
  6. package/src/App.tsx +639 -594
  7. package/src/components/Alert/Alert.tsx +23 -22
  8. package/src/components/Button/Button.tsx +18 -22
  9. package/src/components/EHFForm/EHFForm.tsx +253 -235
  10. package/src/components/FormFields/AddressField.tsx +55 -62
  11. package/src/components/FormFields/EmailField.tsx +53 -58
  12. package/src/components/FormFields/InputField.tsx +52 -53
  13. package/src/components/FormFields/NameField.tsx +52 -53
  14. package/src/components/FormFields/PhoneField.tsx +53 -58
  15. package/src/components/FormFields/TermsCheckbox.tsx +70 -58
  16. package/src/components/FormFields/ToggleFiled.tsx +52 -63
  17. package/src/components/FormFields/fieldValidators.ts +71 -0
  18. package/src/components/OIOForm/OIOForm.tsx +130 -69
  19. package/src/components/OrderDenialModal/OrderDenialModal.tsx +102 -89
  20. package/src/components/OrderForm/ContactDetailsSection.tsx +71 -0
  21. package/src/components/OrderForm/OrderForm.tsx +173 -232
  22. package/src/components/OrderForm/PaymentMethodContent.tsx +62 -0
  23. package/src/components/OrderForm/PaymentMethodSection.tsx +79 -0
  24. package/src/components/OrderForm/SubmitConfirmationDialog.tsx +55 -0
  25. package/src/components/OrderForm/orderFormState.ts +171 -0
  26. package/src/components/OrderForm/useSlotElement.tsx +89 -0
  27. package/src/components/ui/alert-dialog.tsx +185 -0
  28. package/src/components/ui/alert.tsx +75 -0
  29. package/src/components/ui/button.tsx +55 -0
  30. package/src/components/ui/card.tsx +99 -0
  31. package/src/components/ui/checkbox.tsx +28 -0
  32. package/src/components/ui/field.tsx +238 -0
  33. package/src/components/ui/input.tsx +19 -0
  34. package/src/components/ui/label.tsx +19 -0
  35. package/src/components/ui/radio-group.tsx +37 -0
  36. package/src/components/ui/separator.tsx +24 -0
  37. package/src/components/ui/skeleton.tsx +13 -0
  38. package/src/components/ui/spinner.tsx +10 -0
  39. package/src/components/ui/switch.tsx +29 -0
  40. package/src/components/ui/textarea.tsx +17 -0
  41. package/src/constants/index.ts +0 -2
  42. package/src/custom.d.ts +4 -4
  43. package/src/index.tsx +2 -0
  44. package/src/lib/utils.ts +1 -0
  45. package/src/types/general.ts +136 -122
  46. package/tsconfig.json +37 -38
  47. package/src/App.scss +0 -23
  48. package/src/assets/styles/forms.scss +0 -164
  49. package/src/assets/styles/general.scss +0 -46
  50. package/src/assets/styles/variables.scss +0 -29
  51. package/src/components/Alert/alert.scss +0 -21
  52. package/src/components/Button/button.scss +0 -48
  53. package/src/components/Loader/Loader.tsx +0 -22
  54. package/src/components/Loader/loader.scss +0 -37
  55. package/src/components/OrderDenialModal/orderDenialModal.scss +0 -42
  56. package/src/components/OrderForm/orderForm.scss +0 -10
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  FC,
3
- ChangeEvent,
3
+ KeyboardEvent,
4
4
  ReactNode,
5
- Suspense,
6
- useState,
7
- useMemo,
8
5
  useEffect,
6
+ useRef,
7
+ useState,
9
8
  } from 'react';
10
- import { FormProvider, useForm, SubmitHandler } from 'react-hook-form';
9
+ import {
10
+ FormProvider,
11
+ useForm,
12
+ Resolver,
13
+ SubmitHandler,
14
+ } from 'react-hook-form';
15
+ import { zodResolver } from '@hookform/resolvers/zod';
11
16
 
12
17
  import { PaymentMethodEnum, UserActionEnum } from '../../enums/general';
13
- import {
14
- PAYMENT_METHOD_DEFAULT,
15
- INVOICE_ALLOWED_PAYMENT_METHODS,
16
- } from '../../constants/index';
18
+ import { PAYMENT_METHOD_DEFAULT } from '../../constants/index';
17
19
  import Alert from '../Alert/Alert';
18
20
  import Button from '../Button/Button';
19
21
  import OrderDenialModal from '../OrderDenialModal/OrderDenialModal';
20
- import ToggleField from '../FormFields/ToggleFiled';
21
- import formFieldsMapper from '../FormFields/FormFieldsMapper';
22
- import { DEFAULT_ORDER_FORM_FIELDS } from '../FormFields/FormFields.helper';
22
+ import TermsCheckbox from '../FormFields/TermsCheckbox';
23
23
  import { OrderFormInputsType, OrderInfoType } from '../../types/order';
24
24
  import {
25
25
  PaymentMethodSettingsType,
@@ -27,12 +27,18 @@ import {
27
27
  OrderFormFieldType,
28
28
  ContactRequestType,
29
29
  OrderDenialFallbackOfferType,
30
+ SubmitConfirmationType,
30
31
  } from '../../types/general';
31
- import { orderInvoiceContactFields } from '../../utils/order.helper';
32
32
  import useOrderForm from '../../hooks/useOrderForm';
33
-
34
- import './orderForm.scss';
35
- import TermsCheckbox from '../FormFields/TermsCheckbox';
33
+ import { useSlotElement, renderInSlot } from './useSlotElement';
34
+ import {
35
+ deriveOrderFormState,
36
+ buildOrderFormSchema,
37
+ OrderFormConfig,
38
+ } from './orderFormState';
39
+ import PaymentMethodSection from './PaymentMethodSection';
40
+ import ContactDetailsSection from './ContactDetailsSection';
41
+ import SubmitConfirmationDialog from './SubmitConfirmationDialog';
36
42
 
37
43
  type Props = {
38
44
  callback: (url: string | null, orderInfo?: OrderInfoType | null) => void;
@@ -60,10 +66,14 @@ type Props = {
60
66
  orderDenialCloseButtonText?: string;
61
67
  orderDenialContinueButtonText?: string;
62
68
  paymentMethodLabel?: string;
69
+ contactDetailsLabel?: string;
70
+ paymentMethodElementId?: string;
71
+ contactDetailsElementId?: string;
63
72
  paymentMethodNotAllowedMsg?: string;
64
73
  errorReqMsg?: string;
65
74
  errorInvalidEmailMsg?: string;
66
75
  errorInvalidPhoneMsg?: string;
76
+ errorTermsMsg?: string;
67
77
  invoiceAddressSelection?: {
68
78
  enabled?: boolean;
69
79
  label?: string;
@@ -81,6 +91,7 @@ type Props = {
81
91
  organizationId: string
82
92
  ) => Promise<OrderDenialFallbackOfferType | undefined>;
83
93
  termsAndConditionsText?: string | ReactNode;
94
+ submitConfirmation?: SubmitConfirmationType;
84
95
  };
85
96
 
86
97
  const initialData = {
@@ -119,11 +130,15 @@ const OrderForm: FC<Props> = ({
119
130
  submitButtonText = 'Start',
120
131
  orderDenialCloseButtonText = 'Close',
121
132
  orderDenialContinueButtonText = 'Continue',
122
- paymentMethodLabel = 'Select Payment Method',
133
+ paymentMethodLabel = 'Select payment method',
134
+ contactDetailsLabel,
135
+ paymentMethodElementId,
136
+ contactDetailsElementId,
123
137
  paymentMethodNotAllowedMsg = 'This payment method not allowed!',
124
138
  errorReqMsg = '',
125
139
  errorInvalidEmailMsg = '',
126
140
  errorInvalidPhoneMsg = '',
141
+ errorTermsMsg = '',
127
142
  errorValidationTitleMsg,
128
143
  errorValidationDenialOrderBlockingMsg,
129
144
  errorValidationBlockingOffersMsg,
@@ -133,52 +148,68 @@ const OrderForm: FC<Props> = ({
133
148
  fetchDenialFallbackOffer,
134
149
  requireTermsAcceptance,
135
150
  termsAndConditionsText,
151
+ submitConfirmation,
136
152
  }) => {
137
- if (!templatePackageId) {
138
- console.error('"templatePackageId" should be set');
139
- }
153
+ const subscriberIdValue =
154
+ subscriberId || sessionStorage.getItem('subscriberId') || undefined;
140
155
 
141
- if (!organizationId) {
142
- console.error('"organizationId" should be set');
143
- }
156
+ useEffect(() => {
157
+ if (!templatePackageId)
158
+ console.error('"templatePackageId" should be set');
159
+ if (!organizationId) console.error('"organizationId" should be set');
160
+ if (!userId) console.error('"userId" should be set');
161
+ if (!identityProviderId)
162
+ console.error('"identityProviderId" should be set');
163
+ }, [templatePackageId, organizationId, userId, identityProviderId]);
144
164
 
145
- if (!subscriberId) {
146
- const sessionSubscriberId = sessionStorage.getItem('subscriberId');
147
- if (sessionSubscriberId) {
148
- subscriberId = sessionSubscriberId;
149
- }
150
- }
165
+ const config: OrderFormConfig = {
166
+ paymentMethods,
167
+ paymentMethodsOptions,
168
+ allowedPaymentMethods,
169
+ invoiceAddressSelection,
170
+ };
151
171
 
152
- if (!userId) {
153
- console.error('"userId" should be set');
154
- }
172
+ const messages = {
173
+ errorReqMsg,
174
+ errorInvalidEmailMsg,
175
+ errorInvalidPhoneMsg,
176
+ errorTermsMsg,
177
+ };
155
178
 
156
- if (!identityProviderId) {
157
- console.error('"identityProviderId" should be set');
158
- }
179
+ const configuredPaymentMethods = paymentMethods.map((m) => m.value);
180
+ const initialPaymentMethod = configuredPaymentMethods.length
181
+ ? ([defaultValues?.paymentMethod, PAYMENT_METHOD_DEFAULT].find(
182
+ (m) => m && configuredPaymentMethods.includes(m)
183
+ ) ?? configuredPaymentMethods[0])
184
+ : defaultValues?.paymentMethod || PAYMENT_METHOD_DEFAULT;
159
185
 
160
- const [orderFields, setOrderFields] = useState<OrderFormFieldType[]>(
161
- paymentMethodsOptions?.[
162
- defaultValues?.paymentMethod || PAYMENT_METHOD_DEFAULT
163
- ]?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS
164
- );
186
+ const resolver: Resolver<OrderFormInputsType> = (values, ctx, options) => {
187
+ const schema = buildOrderFormSchema(
188
+ deriveOrderFormState(values, config),
189
+ requireTermsAcceptance,
190
+ messages
191
+ );
192
+ return zodResolver(schema)(values, ctx, options);
193
+ };
165
194
 
166
195
  const methods = useForm<OrderFormInputsType>({
196
+ resolver,
167
197
  defaultValues: {
168
198
  ...initialData,
169
199
  ...(defaultValues ?? {}),
170
- paymentMethod:
171
- defaultValues?.paymentMethod || PAYMENT_METHOD_DEFAULT,
200
+ paymentMethod: initialPaymentMethod,
172
201
  },
173
202
  });
174
203
 
175
- const {
176
- register,
177
- handleSubmit,
178
- setValue,
179
- watch,
180
- formState: { errors },
181
- } = methods;
204
+ const { control, handleSubmit, setValue, watch } = methods;
205
+
206
+ const derived = deriveOrderFormState(
207
+ {
208
+ paymentMethod: watch('paymentMethod'),
209
+ invoiceAddressSelection: watch('invoiceAddressSelection'),
210
+ },
211
+ config
212
+ );
182
213
 
183
214
  useEffect(() => {
184
215
  userActionCallback?.(UserActionEnum.SELECT_PAYMENT_METHOD, {
@@ -186,20 +217,6 @@ const OrderForm: FC<Props> = ({
186
217
  });
187
218
  }, []);
188
219
 
189
- const invoiceAddressToggle = watch('invoiceAddressSelection');
190
- const paymentMethodInput = watch('paymentMethod');
191
- const isTermsAccepted = watch('termsAccept', false);
192
-
193
- const invoiceOrderFields =
194
- paymentMethodsOptions?.[paymentMethodInput || PAYMENT_METHOD_DEFAULT]
195
- ?.paymentInvoiceFields ||
196
- invoiceAddressSelection?.fields ||
197
- orderInvoiceContactFields;
198
-
199
- const invoicePaymentMethods =
200
- invoiceAddressSelection?.paymentMethods ||
201
- INVOICE_ALLOWED_PAYMENT_METHODS;
202
-
203
220
  const {
204
221
  orderSubmit,
205
222
  continueWithFallbackOffer,
@@ -216,18 +233,18 @@ const OrderForm: FC<Props> = ({
216
233
  userActionCallback,
217
234
  setContactCallback,
218
235
  organizationId,
219
- subscriberId,
236
+ subscriberId: subscriberIdValue,
220
237
  userId,
221
238
  identityProviderId,
222
- orderFields,
239
+ orderFields: derived.orderFields,
223
240
  redirectUrl,
224
241
  showIframe,
225
242
  language,
226
243
  merchantAgreementUrl,
227
244
  paymentMethodsOptions,
228
245
  templatePackageId,
229
- invoiceAddressToggle,
230
- invoiceOrderFields,
246
+ invoiceAddressToggle: watch('invoiceAddressSelection'),
247
+ invoiceOrderFields: derived.invoiceOrderFields,
231
248
  errorValidationTitleMsg,
232
249
  errorValidationDenialOrderBlockingMsg,
233
250
  errorValidationBlockingOffersMsg,
@@ -237,221 +254,145 @@ const OrderForm: FC<Props> = ({
237
254
  fetchDenialFallbackOffer,
238
255
  });
239
256
 
240
- const onSubmit: SubmitHandler<OrderFormInputsType> = async (
241
- data
242
- ): Promise<void> => {
257
+ const [pendingSubmit, setPendingSubmit] =
258
+ useState<OrderFormInputsType | null>(null);
259
+
260
+ const submitOrder = async (data: OrderFormInputsType): Promise<void> => {
243
261
  if (
244
- paymentMethodInput === PaymentMethodEnum.EHF ||
245
- paymentMethodInput === PaymentMethodEnum.OIO
262
+ derived.paymentMethod === PaymentMethodEnum.EHF ||
263
+ derived.paymentMethod === PaymentMethodEnum.OIO
246
264
  ) {
247
- updateFormData(data);
265
+ updateFormData?.(data);
248
266
  return;
249
267
  }
250
268
  await orderSubmit(data);
251
269
  };
252
270
 
253
- const handlePaymentChange = (e: ChangeEvent<HTMLInputElement>) => {
254
- setValue('paymentMethod', e.target.value as PaymentMethodEnum);
255
- const orderFieldsLocal =
256
- paymentMethodsOptions?.[e.target.value as PaymentMethodEnum]
257
- ?.orderFormFields ?? DEFAULT_ORDER_FORM_FIELDS;
258
- setOrderFields(orderFieldsLocal);
259
- if (
260
- !invoicePaymentMethods.includes(e.target.value as PaymentMethodEnum)
261
- ) {
271
+ const onSubmit: SubmitHandler<OrderFormInputsType> = async (data) => {
272
+ if (submitConfirmation) {
273
+ setPendingSubmit(data);
274
+ return;
275
+ }
276
+ await submitOrder(data);
277
+ };
278
+
279
+ const confirmSubmit = () => {
280
+ const data = pendingSubmit;
281
+ setPendingSubmit(null);
282
+ if (data) submitOrder(data);
283
+ };
284
+
285
+ const handlePaymentChange = (paymentMethod: PaymentMethodEnum) => {
286
+ setValue('paymentMethod', paymentMethod, { shouldValidate: true });
287
+ if (!derived.invoicePaymentMethods.includes(paymentMethod)) {
262
288
  setValue('invoiceAddressSelection', false);
263
289
  }
264
290
 
265
291
  userActionCallback?.(UserActionEnum.SELECT_PAYMENT_METHOD, {
266
- paymentMethod: e.target.value,
292
+ paymentMethod,
267
293
  });
268
294
  };
269
295
 
270
- const allowPaymentMethod = useMemo(() => {
271
- if (!allowedPaymentMethods || allowedPaymentMethods?.length === 0) {
272
- return true;
273
- }
296
+ const paymentMethodSlot = useSlotElement(paymentMethodElementId);
297
+ const contactDetailsSlot = useSlotElement(contactDetailsElementId);
298
+ const formRef = useRef<HTMLFormElement>(null);
274
299
 
275
- if (
276
- allowedPaymentMethods.includes(
277
- paymentMethodInput as PaymentMethodEnum
278
- )
279
- ) {
280
- return true;
281
- }
300
+ const handleSlotKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
301
+ if (event.key !== 'Enter' || event.defaultPrevented) return;
302
+ if (!derived.allowPaymentMethod || loading) return;
282
303
 
283
- return false;
284
- }, [allowedPaymentMethods, paymentMethodInput]);
304
+ const target = event.target as HTMLElement;
305
+ if (target.tagName !== 'INPUT') return;
285
306
 
286
- const showInvoiceFields =
287
- invoiceAddressToggle &&
288
- invoiceOrderFields?.length > 0 &&
289
- allowPaymentMethod;
307
+ const { type } = target as HTMLInputElement;
308
+ if (type === 'button' || type === 'submit' || type === 'reset') return;
290
309
 
291
- const showInvoiceToggle =
292
- invoiceAddressSelection?.enabled &&
293
- allowPaymentMethod &&
294
- invoicePaymentMethods.includes(paymentMethodInput as PaymentMethodEnum);
310
+ event.preventDefault();
311
+ formRef.current?.requestSubmit();
312
+ };
313
+
314
+ const paymentMethodSection = derived.showPaymentMethodSelection ? (
315
+ <PaymentMethodSection
316
+ control={control}
317
+ paymentMethods={paymentMethods}
318
+ label={paymentMethodLabel}
319
+ onChange={handlePaymentChange}
320
+ />
321
+ ) : null;
295
322
 
296
- const isSubmitButtonDisabled = requireTermsAcceptance
297
- ? !isTermsAccepted
298
- : false;
323
+ const contactDetailsSection = derived.showContactDetails ? (
324
+ <ContactDetailsSection
325
+ label={contactDetailsLabel}
326
+ orderFields={derived.orderFields}
327
+ invoiceOrderFields={derived.invoiceOrderFields}
328
+ showOrderFields={derived.showOrderFields}
329
+ showInvoiceToggle={derived.showInvoiceToggle}
330
+ showInvoiceFields={derived.showInvoiceFields}
331
+ invoiceToggleLabel={invoiceAddressSelection?.label}
332
+ onInvoiceToggle={(value) =>
333
+ userActionCallback?.(UserActionEnum.TOGGLE_INVOICE_ADDRESS, {
334
+ value,
335
+ })
336
+ }
337
+ />
338
+ ) : null;
299
339
 
300
340
  return (
301
341
  <FormProvider {...methods}>
302
342
  <form
303
- className="sdk-order-form"
343
+ ref={formRef}
344
+ className="sdk-order-form flex w-full flex-col gap-6"
345
+ noValidate
304
346
  onSubmit={handleSubmit(onSubmit)}
305
347
  data-testid="sdk-order-form-id"
306
348
  >
307
- {paymentMethods?.length > 0 && (
308
- <div className="sdk-payment-method-section">
309
- <div className="field-wrapper radio-button-group">
310
- <div className="field-label">
311
- {paymentMethodLabel}
312
- </div>
313
- {paymentMethods.map((item) => (
314
- <div
315
- className="radio-button-control"
316
- key={item.value}
317
- >
318
- <label className="radio-badge">
319
- <input
320
- {...register('paymentMethod', {
321
- required: true,
322
- })}
323
- onChange={handlePaymentChange}
324
- type="radio"
325
- value={item.value}
326
- />
327
- <span className="value-block">
328
- {item.icons &&
329
- item.icons.length > 0 ? (
330
- <span className="prefix-icon">
331
- {item.icons.map((icon) => (
332
- <img
333
- key={icon.src}
334
- src={icon.src}
335
- alt={icon.alt}
336
- />
337
- ))}
338
- </span>
339
- ) : null}
340
- <span className="text-block">
341
- {item.label}
342
- </span>
343
- </span>
344
- </label>
345
- </div>
346
- ))}
347
- {errors.paymentMethod && (
348
- <div className="text-error caption">
349
- {errors.paymentMethod.message}
350
- </div>
351
- )}
352
- </div>
353
- </div>
349
+ {renderInSlot(
350
+ paymentMethodSection,
351
+ paymentMethodSlot,
352
+ handleSlotKeyDown
354
353
  )}
355
- <div className="sdk-order-details-section">
356
- {orderFields?.length > 0 && allowPaymentMethod && (
357
- <Suspense fallback={null}>
358
- {orderFields.map((field) => {
359
- const Component = formFieldsMapper[field.name];
360
-
361
- return Component ? (
362
- <Component
363
- key={field.name}
364
- name={field.name}
365
- label={field.label}
366
- required={field.required || false}
367
- readOnly={field.readOnly || false}
368
- errors={errors}
369
- errorReqMsg={errorReqMsg}
370
- errorInvalidEmailMsg={
371
- errorInvalidEmailMsg
372
- }
373
- errorInvalidPhoneMsg={
374
- errorInvalidPhoneMsg
375
- }
376
- />
377
- ) : null;
378
- })}
379
- </Suspense>
380
- )}
381
- {showInvoiceToggle && (
382
- <ToggleField
383
- name="invoiceAddressSelection"
384
- label={
385
- invoiceAddressSelection?.label ??
386
- 'Invoice Address'
387
- }
388
- toggleCallback={(e) =>
389
- userActionCallback?.(
390
- UserActionEnum.TOGGLE_INVOICE_ADDRESS,
391
- { value: e }
392
- )
393
- }
394
- />
395
- )}
396
- {showInvoiceFields && (
397
- <Suspense fallback={null}>
398
- {invoiceOrderFields.map((field) => {
399
- const Component = formFieldsMapper[field.name];
400
-
401
- return Component ? (
402
- <Component
403
- key={field.name}
404
- name={field.name}
405
- label={field.label}
406
- required={field.required || false}
407
- readOnly={field.readOnly || false}
408
- errors={errors}
409
- errorReqMsg={errorReqMsg}
410
- errorInvalidEmailMsg={
411
- errorInvalidEmailMsg
412
- }
413
- errorInvalidPhoneMsg={
414
- errorInvalidPhoneMsg
415
- }
416
- />
417
- ) : null;
418
- })}
419
- </Suspense>
420
- )}
354
+ {renderInSlot(
355
+ contactDetailsSection,
356
+ contactDetailsSlot,
357
+ handleSlotKeyDown
358
+ )}
359
+ <div className="sdk-order-actions-section flex flex-col gap-4">
421
360
  {requireTermsAcceptance && (
422
361
  <TermsCheckbox
423
362
  name="termsAccept"
424
363
  label={termsAndConditionsText}
425
364
  required
426
- errors={errors}
427
365
  />
428
366
  )}
429
- {allowPaymentMethod && (
367
+ {derived.allowPaymentMethod && (
430
368
  <Button
431
369
  type="submit"
432
370
  loading={loading}
433
371
  buttonText={submitButtonText}
434
- disable={isSubmitButtonDisabled}
372
+ className="w-full"
435
373
  />
436
374
  )}
437
375
  <Alert
438
- className="mt-2"
439
376
  msg={
440
- allowPaymentMethod
377
+ derived.allowPaymentMethod
441
378
  ? apiErrorMsg
442
379
  : paymentMethodNotAllowedMsg
443
380
  }
444
381
  />
445
382
  {errorsMsg?.length > 0 &&
446
- allowPaymentMethod &&
383
+ derived.allowPaymentMethod &&
447
384
  errorsMsg.map((i, index) => (
448
- <Alert
449
- key={`${i}-${index}`}
450
- className="mt-2"
451
- msg={i}
452
- />
385
+ <Alert key={`${i}-${index}`} msg={i} />
453
386
  ))}
454
387
  </div>
388
+ {submitConfirmation && (
389
+ <SubmitConfirmationDialog
390
+ isOpen={!!pendingSubmit}
391
+ confirmation={submitConfirmation}
392
+ onConfirm={confirmSubmit}
393
+ onCancel={() => setPendingSubmit(null)}
394
+ />
395
+ )}
455
396
  <OrderDenialModal
456
397
  isOpen={!!orderDenialType}
457
398
  message={orderDenialMessage}
@@ -0,0 +1,62 @@
1
+ import { FC } from 'react';
2
+ import { cn } from 'cn';
3
+
4
+ import { PaymentMethodOptionType } from '../../types/general';
5
+ import { FieldDescription, FieldTitle } from '../ui/field';
6
+
7
+ type Props = {
8
+ method: PaymentMethodOptionType;
9
+ };
10
+
11
+ const PaymentMethodContent: FC<Props> = ({ method }) => {
12
+ const hasIcons = !!method.icons?.length;
13
+
14
+ if (!hasIcons) {
15
+ return (
16
+ <div className="flex flex-1 flex-col gap-0.5">
17
+ <FieldTitle className="sdk-payment-method-label">
18
+ {method.label}
19
+ </FieldTitle>
20
+ {method.description && (
21
+ <FieldDescription className="sdk-payment-method-description">
22
+ {method.description}
23
+ </FieldDescription>
24
+ )}
25
+ </div>
26
+ );
27
+ }
28
+
29
+ return (
30
+ <div className="flex flex-1 flex-col gap-0.5">
31
+ <FieldTitle className="sdk-payment-method-icons min-h-5 flex-wrap items-center gap-1.5">
32
+ {method.description && (
33
+ <span className="sdk-payment-method-label sr-only">
34
+ {method.label}
35
+ </span>
36
+ )}
37
+ {method.icons?.map((icon) => (
38
+ <img
39
+ key={icon.src}
40
+ src={icon.src}
41
+ alt={icon.alt ?? ''}
42
+ className={cn(
43
+ 'h-5 w-auto object-contain',
44
+ icon.className
45
+ )}
46
+ />
47
+ ))}
48
+ </FieldTitle>
49
+ {method.description ? (
50
+ <FieldDescription className="sdk-payment-method-description">
51
+ {method.description}
52
+ </FieldDescription>
53
+ ) : (
54
+ <FieldDescription className="sdk-payment-method-label">
55
+ {method.label}
56
+ </FieldDescription>
57
+ )}
58
+ </div>
59
+ );
60
+ };
61
+
62
+ export default PaymentMethodContent;