mirror of
https://github.com/valitydev/checkout.git
synced 2024-11-06 10:35:20 +00:00
Add failure state to create payment hook (#191)
This commit is contained in:
parent
98404b1f15
commit
50ad71282d
@ -9,12 +9,9 @@ function getFingerprintFromComponents(components: Fingerprint2.Component[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getClientInfoUrl = (): { url: string } | undefined => {
|
const getClientInfoUrl = (): { url: string } | undefined => {
|
||||||
const url = (document.referrer || '').slice(
|
if (document.referrer === '') return;
|
||||||
0,
|
const url = new URL(document.referrer);
|
||||||
// URL max length (API constraint)
|
return { url: url.origin };
|
||||||
599
|
|
||||||
);
|
|
||||||
return url ? { url } : undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createPaymentResource = (
|
export const createPaymentResource = (
|
||||||
|
@ -4,8 +4,8 @@ import { InjectedFormProps, reduxForm } from 'redux-form';
|
|||||||
|
|
||||||
import { FormGroup } from '../form-group';
|
import { FormGroup } from '../form-group';
|
||||||
import { CardHolder, CardNumber, ExpireDate, SecureCode } from './fields';
|
import { CardHolder, CardNumber, ExpireDate, SecureCode } from './fields';
|
||||||
import { CardFormInfo, CardFormValues, FormName, PaymentStatus } from 'checkout/state';
|
import { CardFormInfo, CardFormValues, FormName, PaymentStatus, ResultFormInfo, ResultType } from 'checkout/state';
|
||||||
import { pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
||||||
import { PayButton } from '../pay-button';
|
import { PayButton } from '../pay-button';
|
||||||
import { Header } from '../header/header';
|
import { Header } from '../header/header';
|
||||||
import { toAmountConfig, toCardHolderConfig } from '../fields-config';
|
import { toAmountConfig, toCardHolderConfig } from '../fields-config';
|
||||||
@ -14,7 +14,6 @@ import { useAppDispatch, useAppSelector } from 'checkout/configure-store';
|
|||||||
import { getActiveModalFormSelector } from 'checkout/selectors';
|
import { getActiveModalFormSelector } from 'checkout/selectors';
|
||||||
import { InitialContext } from '../../../../initial-context';
|
import { InitialContext } from '../../../../initial-context';
|
||||||
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
||||||
import isNil from 'checkout/utils/is-nil';
|
|
||||||
|
|
||||||
const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormProps) => {
|
const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormProps) => {
|
||||||
const {
|
const {
|
||||||
@ -22,7 +21,7 @@ const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormPro
|
|||||||
initConfig,
|
initConfig,
|
||||||
model: { invoiceTemplate }
|
model: { invoiceTemplate }
|
||||||
} = useContext(InitialContext);
|
} = useContext(InitialContext);
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const { paymentStatus } = useAppSelector<CardFormInfo>(getActiveModalFormSelector);
|
const { paymentStatus } = useAppSelector<CardFormInfo>(getActiveModalFormSelector);
|
||||||
const cardHolder = toCardHolderConfig(initConfig.requireCardHolder);
|
const cardHolder = toCardHolderConfig(initConfig.requireCardHolder);
|
||||||
const amount = toAmountConfig(initConfig, invoiceTemplate);
|
const amount = toAmountConfig(initConfig, invoiceTemplate);
|
||||||
@ -47,10 +46,13 @@ const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormPro
|
|||||||
if (submitFailed) {
|
if (submitFailed) {
|
||||||
dispatch(setViewInfoError(true));
|
dispatch(setViewInfoError(true));
|
||||||
}
|
}
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [submitFailed, paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [submitFailed, createPaymentState]);
|
||||||
|
|
||||||
const submit = (values: CardFormValues) => {
|
const submit = (values: CardFormValues) => {
|
||||||
dispatch(prepareToPay());
|
dispatch(prepareToPay());
|
||||||
|
@ -6,7 +6,9 @@ import {
|
|||||||
FormName,
|
FormName,
|
||||||
PaymentTerminalFormInfo,
|
PaymentTerminalFormInfo,
|
||||||
PaymentTerminalFormValues,
|
PaymentTerminalFormValues,
|
||||||
PaymentTerminalSelectorFormInfo
|
PaymentTerminalSelectorFormInfo,
|
||||||
|
ResultFormInfo,
|
||||||
|
ResultType
|
||||||
} from 'checkout/state';
|
} from 'checkout/state';
|
||||||
import { getMetadata, PaymentMethodItemContainer } from 'checkout/components/ui';
|
import { getMetadata, PaymentMethodItemContainer } from 'checkout/components/ui';
|
||||||
import { PaymentMethodName, ServiceProvider, ServiceProviderContactInfo } from 'checkout/backend';
|
import { PaymentMethodName, ServiceProvider, ServiceProviderContactInfo } from 'checkout/backend';
|
||||||
@ -45,7 +47,7 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP
|
|||||||
const emailPrefilled = !!initConfig.email;
|
const emailPrefilled = !!initConfig.email;
|
||||||
const phoneNumberPrefilled = !!initConfig.phoneNumber;
|
const phoneNumberPrefilled = !!initConfig.phoneNumber;
|
||||||
|
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
@ -69,10 +71,13 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [createPaymentState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaymentMethodItemContainer id={`${Math.floor(Math.random() * 100)}-payment-method-item`} onClick={onClick}>
|
<PaymentMethodItemContainer id={`${Math.floor(Math.random() * 100)}-payment-method-item`} onClick={onClick}>
|
||||||
|
@ -2,11 +2,11 @@ import * as React from 'react';
|
|||||||
import { useContext, useEffect } from 'react';
|
import { useContext, useEffect } from 'react';
|
||||||
import { InjectedFormProps, reduxForm } from 'redux-form';
|
import { InjectedFormProps, reduxForm } from 'redux-form';
|
||||||
|
|
||||||
import { FormName, PaymentTerminalFormValues } from 'checkout/state';
|
import { FormName, PaymentTerminalFormValues, ResultFormInfo, ResultType } from 'checkout/state';
|
||||||
import { Header } from '../header';
|
import { Header } from '../header';
|
||||||
import { useAppDispatch } from 'checkout/configure-store';
|
import { useAppDispatch } from 'checkout/configure-store';
|
||||||
import { ProviderSelectorField } from './provider-selector';
|
import { ProviderSelectorField } from './provider-selector';
|
||||||
import { pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
||||||
import { PayButton } from '../pay-button';
|
import { PayButton } from '../pay-button';
|
||||||
import { PaymentMethodName } from 'checkout/backend';
|
import { PaymentMethodName } from 'checkout/backend';
|
||||||
import styled from 'checkout/styled-components';
|
import styled from 'checkout/styled-components';
|
||||||
@ -14,7 +14,6 @@ import { toEmailConfig, toPhoneNumberConfig } from '../fields-config';
|
|||||||
import { FormGroup } from '../form-group';
|
import { FormGroup } from '../form-group';
|
||||||
import { Email, Phone } from '../common-fields';
|
import { Email, Phone } from '../common-fields';
|
||||||
import { getMetadata } from 'checkout/components';
|
import { getMetadata } from 'checkout/components';
|
||||||
import isNil from 'checkout/utils/is-nil';
|
|
||||||
|
|
||||||
import { InitialContext } from '../../../../initial-context';
|
import { InitialContext } from '../../../../initial-context';
|
||||||
import { getAvailableTerminalPaymentMethod } from '../get-available-terminal-payment-method';
|
import { getAvailableTerminalPaymentMethod } from '../get-available-terminal-payment-method';
|
||||||
@ -29,7 +28,7 @@ const ProviderSelectorDescription = styled.p`
|
|||||||
|
|
||||||
export const PaymentTerminalBankCardFormDef: React.FC<InjectedFormProps> = ({ submitFailed, handleSubmit }) => {
|
export const PaymentTerminalBankCardFormDef: React.FC<InjectedFormProps> = ({ submitFailed, handleSubmit }) => {
|
||||||
const { locale, initConfig, availablePaymentMethods } = useContext(InitialContext);
|
const { locale, initConfig, availablePaymentMethods } = useContext(InitialContext);
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const paymentMethod = getAvailableTerminalPaymentMethod(availablePaymentMethods, KnownProviderCategories.BankCard);
|
const paymentMethod = getAvailableTerminalPaymentMethod(availablePaymentMethods, KnownProviderCategories.BankCard);
|
||||||
const serviceProviders = paymentMethod?.serviceProviders;
|
const serviceProviders = paymentMethod?.serviceProviders;
|
||||||
const email = toEmailConfig(initConfig.email);
|
const email = toEmailConfig(initConfig.email);
|
||||||
@ -45,10 +44,13 @@ export const PaymentTerminalBankCardFormDef: React.FC<InjectedFormProps> = ({ su
|
|||||||
if (submitFailed) {
|
if (submitFailed) {
|
||||||
dispatch(setViewInfoError(true));
|
dispatch(setViewInfoError(true));
|
||||||
}
|
}
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [submitFailed, paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [submitFailed, createPaymentState]);
|
||||||
|
|
||||||
const submit = (values: PaymentTerminalFormValues) => {
|
const submit = (values: PaymentTerminalFormValues) => {
|
||||||
dispatch(prepareToPay());
|
dispatch(prepareToPay());
|
||||||
|
@ -5,8 +5,15 @@ import get from 'lodash-es/get';
|
|||||||
import styled from 'checkout/styled-components';
|
import styled from 'checkout/styled-components';
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector } from 'checkout/configure-store';
|
import { useAppDispatch, useAppSelector } from 'checkout/configure-store';
|
||||||
import { pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
||||||
import { FormName, PaymentStatus, PaymentTerminalFormValues, PaymentTerminalFormInfo } from 'checkout/state';
|
import {
|
||||||
|
FormName,
|
||||||
|
PaymentStatus,
|
||||||
|
PaymentTerminalFormValues,
|
||||||
|
PaymentTerminalFormInfo,
|
||||||
|
ResultFormInfo,
|
||||||
|
ResultType
|
||||||
|
} from 'checkout/state';
|
||||||
import { Header } from '../header';
|
import { Header } from '../header';
|
||||||
import { PayButton } from '../pay-button';
|
import { PayButton } from '../pay-button';
|
||||||
import { FormGroup } from '../form-group';
|
import { FormGroup } from '../form-group';
|
||||||
@ -26,7 +33,6 @@ import {
|
|||||||
} from './init-config-payment';
|
} from './init-config-payment';
|
||||||
import { MetadataSelect } from './metadata-select';
|
import { MetadataSelect } from './metadata-select';
|
||||||
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
||||||
import isNil from 'checkout/utils/is-nil';
|
|
||||||
import { InitialContext } from '../../../../initial-context';
|
import { InitialContext } from '../../../../initial-context';
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
@ -42,7 +48,7 @@ const PaymentTerminalFormRef: React.FC<InjectedFormProps> = ({ submitFailed, ini
|
|||||||
initConfig,
|
initConfig,
|
||||||
model: { serviceProviders, invoiceTemplate }
|
model: { serviceProviders, invoiceTemplate }
|
||||||
} = useContext(InitialContext);
|
} = useContext(InitialContext);
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const { providerID, paymentStatus } = useAppSelector<PaymentTerminalFormInfo>(getActiveModalFormSelector);
|
const { providerID, paymentStatus } = useAppSelector<PaymentTerminalFormInfo>(getActiveModalFormSelector);
|
||||||
const serviceProvider = serviceProviders.find((value) => value.id === providerID);
|
const serviceProvider = serviceProviders.find((value) => value.id === providerID);
|
||||||
const { form, contactInfo, logo, paymentSessionInfo, prefilledMetadataValues } = getMetadata(serviceProvider);
|
const { form, contactInfo, logo, paymentSessionInfo, prefilledMetadataValues } = getMetadata(serviceProvider);
|
||||||
@ -88,10 +94,13 @@ const PaymentTerminalFormRef: React.FC<InjectedFormProps> = ({ submitFailed, ini
|
|||||||
if (submitFailed) {
|
if (submitFailed) {
|
||||||
dispatch(setViewInfoError(true));
|
dispatch(setViewInfoError(true));
|
||||||
}
|
}
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [submitFailed, paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [submitFailed, createPaymentState]);
|
||||||
|
|
||||||
const submit = (values?: Partial<PaymentTerminalFormValues>) => {
|
const submit = (values?: Partial<PaymentTerminalFormValues>) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
|
@ -4,6 +4,7 @@ import { ResultFormContent } from './result-form-content';
|
|||||||
import { getFailedDescription } from './get-failed-description';
|
import { getFailedDescription } from './get-failed-description';
|
||||||
import { getLastChange } from 'checkout/utils';
|
import { getLastChange } from 'checkout/utils';
|
||||||
import { ResultFormType } from './result-form-content';
|
import { ResultFormType } from './result-form-content';
|
||||||
|
import isObject from 'checkout/utils/is-object';
|
||||||
|
|
||||||
export const refunded = (l: Locale): ResultFormContent => ({
|
export const refunded = (l: Locale): ResultFormContent => ({
|
||||||
hasActions: false,
|
hasActions: false,
|
||||||
@ -34,6 +35,23 @@ export const failed = (l: Locale, e: PaymentError | LogicError): ResultFormConte
|
|||||||
type: ResultFormType.ERROR
|
type: ResultFormType.ERROR
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getErrorDescription = (error: unknown): string => {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return `${error.name}: ${error.message}`;
|
||||||
|
} else if (isObject(error)) {
|
||||||
|
return JSON.stringify(error);
|
||||||
|
}
|
||||||
|
return 'Unknown error';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const failedHook = (l: Locale, error: unknown): ResultFormContent => ({
|
||||||
|
hasActions: true,
|
||||||
|
hasDone: false,
|
||||||
|
header: l['form.header.final.failed.label'],
|
||||||
|
description: getErrorDescription(error),
|
||||||
|
type: ResultFormType.ERROR
|
||||||
|
});
|
||||||
|
|
||||||
const processed = (l: Locale): ResultFormContent => ({
|
const processed = (l: Locale): ResultFormContent => ({
|
||||||
hasActions: false,
|
hasActions: false,
|
||||||
hasDone: true,
|
hasDone: true,
|
||||||
|
@ -5,6 +5,7 @@ import { FormName, ModalForms, ModalName, ResultFormInfo, ResultState, ResultTyp
|
|||||||
import { setResult } from 'checkout/actions';
|
import { setResult } from 'checkout/actions';
|
||||||
import { findNamed } from 'checkout/utils';
|
import { findNamed } from 'checkout/utils';
|
||||||
import { makeContentError, makeContentInvoice } from './make-content';
|
import { makeContentError, makeContentInvoice } from './make-content';
|
||||||
|
import { failedHook } from './make-content/make-from-payment-change';
|
||||||
import { ActionBlock } from './action-block';
|
import { ActionBlock } from './action-block';
|
||||||
import { ResultIcon } from './result-icons';
|
import { ResultIcon } from './result-icons';
|
||||||
import styled, { css } from 'checkout/styled-components';
|
import styled, { css } from 'checkout/styled-components';
|
||||||
@ -78,6 +79,8 @@ export const ResultForm = () => {
|
|||||||
switch (resultFormInfo.resultType) {
|
switch (resultFormInfo.resultType) {
|
||||||
case ResultType.error:
|
case ResultType.error:
|
||||||
return makeContentError(locale, error);
|
return makeContentError(locale, error);
|
||||||
|
case ResultType.hookError:
|
||||||
|
return failedHook(locale, resultFormInfo.hookError);
|
||||||
case ResultType.processed:
|
case ResultType.processed:
|
||||||
return makeContentInvoice(locale, events.events, events.status, error);
|
return makeContentInvoice(locale, events.events, events.status, error);
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,18 @@ import { InjectedFormProps, reduxForm } from 'redux-form';
|
|||||||
import get from 'lodash-es/get';
|
import get from 'lodash-es/get';
|
||||||
|
|
||||||
import { FormGroup } from '../form-group';
|
import { FormGroup } from '../form-group';
|
||||||
import { FormName, PaymentStatus, WalletFormInfo, WalletFormValues } from 'checkout/state';
|
import { FormName, PaymentStatus, ResultFormInfo, ResultType, WalletFormInfo, WalletFormValues } from 'checkout/state';
|
||||||
import { PayButton } from '../pay-button';
|
import { PayButton } from '../pay-button';
|
||||||
import { Header } from '../header';
|
import { Header } from '../header';
|
||||||
import { Amount } from '../common-fields';
|
import { Amount } from '../common-fields';
|
||||||
import { toFieldsConfig } from '../fields-config';
|
import { toFieldsConfig } from '../fields-config';
|
||||||
import { pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions';
|
||||||
import { SignUp } from './sign-up';
|
import { SignUp } from './sign-up';
|
||||||
import { getActiveModalFormSelector } from 'checkout/selectors';
|
import { getActiveModalFormSelector } from 'checkout/selectors';
|
||||||
import { useAppDispatch, useAppSelector } from 'checkout/configure-store';
|
import { useAppDispatch, useAppSelector } from 'checkout/configure-store';
|
||||||
import { getMetadata, MetadataField, MetadataLogo, obscurePassword, sortByIndex } from 'checkout/components/ui';
|
import { getMetadata, MetadataField, MetadataLogo, obscurePassword, sortByIndex } from 'checkout/components/ui';
|
||||||
import { LogoContainer } from './logo-container';
|
import { LogoContainer } from './logo-container';
|
||||||
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
|
||||||
import isNil from 'checkout/utils/is-nil';
|
|
||||||
|
|
||||||
import { InitialContext } from '../../../../initial-context';
|
import { InitialContext } from '../../../../initial-context';
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ const WalletFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormP
|
|||||||
initConfig,
|
initConfig,
|
||||||
model: { invoiceTemplate }
|
model: { invoiceTemplate }
|
||||||
} = useContext(InitialContext);
|
} = useContext(InitialContext);
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const { activeProvider, paymentStatus } = useAppSelector<WalletFormInfo>(getActiveModalFormSelector);
|
const { activeProvider, paymentStatus } = useAppSelector<WalletFormInfo>(getActiveModalFormSelector);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const formValues = useAppSelector((s) => get(s.form, 'walletForm.values'));
|
const formValues = useAppSelector((s) => get(s.form, 'walletForm.values'));
|
||||||
@ -60,10 +59,13 @@ const WalletFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormP
|
|||||||
if (submitFailed) {
|
if (submitFailed) {
|
||||||
dispatch(setViewInfoError(true));
|
dispatch(setViewInfoError(true));
|
||||||
}
|
}
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [submitFailed, paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [submitFailed, createPaymentState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="wallet-form" onSubmit={handleSubmit(submit)}>
|
<form id="wallet-form" onSubmit={handleSubmit(submit)}>
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { FormInfo, FormName, PaymentTerminalFormValues, WalletFormInfo } from 'checkout/state';
|
import {
|
||||||
|
FormInfo,
|
||||||
|
FormName,
|
||||||
|
PaymentTerminalFormValues,
|
||||||
|
ResultFormInfo,
|
||||||
|
ResultType,
|
||||||
|
WalletFormInfo
|
||||||
|
} from 'checkout/state';
|
||||||
import { getMetadata, MetadataLogo, PaymentMethodItemContainer } from 'checkout/components/ui';
|
import { getMetadata, MetadataLogo, PaymentMethodItemContainer } from 'checkout/components/ui';
|
||||||
import { PaymentMethodName, ServiceProvider } from 'checkout/backend';
|
import { PaymentMethodName, ServiceProvider } from 'checkout/backend';
|
||||||
import { PaymentRequestedPayload, goToFormInfo, pay, prepareToPay } from 'checkout/actions';
|
import { PaymentRequestedPayload, goToFormInfo, pay, prepareToPay } from 'checkout/actions';
|
||||||
@ -19,7 +26,7 @@ export interface WalletProviderPaymentMethodItemProps {
|
|||||||
export const WalletProviderPaymentMethodItem = ({ serviceProvider }: WalletProviderPaymentMethodItemProps) => {
|
export const WalletProviderPaymentMethodItem = ({ serviceProvider }: WalletProviderPaymentMethodItemProps) => {
|
||||||
const { logo, form } = getMetadata(serviceProvider);
|
const { logo, form } = getMetadata(serviceProvider);
|
||||||
|
|
||||||
const { paymentPayload, setFormData } = useCreatePayment();
|
const { createPaymentState, setFormData } = useCreatePayment();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
@ -37,10 +44,13 @@ export const WalletProviderPaymentMethodItem = ({ serviceProvider }: WalletProvi
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isNil(paymentPayload)) {
|
if (createPaymentState.status === 'SUCCESS') {
|
||||||
dispatch(pay(paymentPayload));
|
dispatch(pay(createPaymentState.data));
|
||||||
}
|
}
|
||||||
}, [paymentPayload]);
|
if (createPaymentState.status === 'FAILURE') {
|
||||||
|
dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error)));
|
||||||
|
}
|
||||||
|
}, [createPaymentState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaymentMethodItemContainer onClick={onClick}>
|
<PaymentMethodItemContainer onClick={onClick}>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useState, useCallback } from 'react';
|
import { useContext, useCallback, useReducer } from 'react';
|
||||||
|
|
||||||
import isNil from 'checkout/utils/is-nil';
|
import isNil from 'checkout/utils/is-nil';
|
||||||
import { PaymentRequestedPayload } from 'checkout/actions';
|
import { PaymentRequestedPayload } from 'checkout/actions';
|
||||||
@ -8,6 +8,32 @@ import { FormData } from './create-payment';
|
|||||||
import { InitialContext } from '../components/app/initial-context';
|
import { InitialContext } from '../components/app/initial-context';
|
||||||
import { PayableInvoiceContext } from '../components/app/modal-container/payable-invoice-context';
|
import { PayableInvoiceContext } from '../components/app/modal-container/payable-invoice-context';
|
||||||
|
|
||||||
|
type State =
|
||||||
|
| { status: 'PRISTINE' }
|
||||||
|
| { status: 'SUCCESS'; data: PaymentRequestedPayload }
|
||||||
|
| { status: 'FAILURE'; error: unknown };
|
||||||
|
|
||||||
|
type Action =
|
||||||
|
| { type: 'CREATE_PAYMENT_SUCCESS'; payload: PaymentRequestedPayload }
|
||||||
|
| { type: 'CREATE_PAYMENT_FAILURE'; error: unknown };
|
||||||
|
|
||||||
|
const dataReducer = (state: State, action: Action): State => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'CREATE_PAYMENT_SUCCESS':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
status: 'SUCCESS',
|
||||||
|
data: action.payload
|
||||||
|
};
|
||||||
|
case 'CREATE_PAYMENT_FAILURE':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
status: 'FAILURE',
|
||||||
|
error: action.error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const useCreatePayment = () => {
|
export const useCreatePayment = () => {
|
||||||
const {
|
const {
|
||||||
initConfig,
|
initConfig,
|
||||||
@ -18,51 +44,58 @@ export const useCreatePayment = () => {
|
|||||||
} = useContext(InitialContext);
|
} = useContext(InitialContext);
|
||||||
const { payableInvoiceData, setPayableInvoiceData } = useContext(PayableInvoiceContext);
|
const { payableInvoiceData, setPayableInvoiceData } = useContext(PayableInvoiceContext);
|
||||||
|
|
||||||
const [paymentPayload, setPaymentPayload] = useState<PaymentRequestedPayload>(null);
|
const [createPaymentState, dispatch] = useReducer(dataReducer, {
|
||||||
|
status: 'PRISTINE'
|
||||||
|
});
|
||||||
|
|
||||||
const setFormData = useCallback(
|
const setFormData = useCallback(
|
||||||
(formData: FormData) => {
|
(formData: FormData) => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
let data = payableInvoiceData;
|
try {
|
||||||
if (isNil(data)) {
|
let data = payableInvoiceData;
|
||||||
data = await createInvoiceWithTemplate({
|
if (isNil(data)) {
|
||||||
|
data = await createInvoiceWithTemplate({
|
||||||
|
capiEndpoint: appConfig.capiEndpoint,
|
||||||
|
invoiceTemplateAccessToken: initConfig.invoiceTemplateAccessToken,
|
||||||
|
invoiceTemplate,
|
||||||
|
amountInfo,
|
||||||
|
formAmount: formData.values?.amount
|
||||||
|
});
|
||||||
|
setPayableInvoiceData(data);
|
||||||
|
}
|
||||||
|
await createPayment({
|
||||||
capiEndpoint: appConfig.capiEndpoint,
|
capiEndpoint: appConfig.capiEndpoint,
|
||||||
invoiceTemplateAccessToken: initConfig.invoiceTemplateAccessToken,
|
urlShortenerEndpoint: appConfig.urlShortenerEndpoint,
|
||||||
invoiceTemplate,
|
origin,
|
||||||
amountInfo,
|
initConfig: {
|
||||||
formAmount: formData.values?.amount
|
redirectUrl: initConfig.redirectUrl,
|
||||||
|
email: initConfig.email,
|
||||||
|
phoneNumber: initConfig.phoneNumber,
|
||||||
|
paymentFlowHold: initConfig.paymentFlowHold,
|
||||||
|
holdExpiration: initConfig.holdExpiration,
|
||||||
|
recurring: initConfig.recurring,
|
||||||
|
metadata: initConfig.metadata,
|
||||||
|
isExternalIDIncluded: initConfig.isExternalIDIncluded
|
||||||
|
},
|
||||||
|
formData,
|
||||||
|
payableInvoice: data
|
||||||
});
|
});
|
||||||
setPayableInvoiceData(data);
|
const payload = {
|
||||||
|
capiEndpoint: appConfig.capiEndpoint,
|
||||||
|
invoiceID: data.invoice.id,
|
||||||
|
invoiceAccessToken: data.invoiceAccessToken,
|
||||||
|
serviceProviders
|
||||||
|
};
|
||||||
|
dispatch({ type: 'CREATE_PAYMENT_SUCCESS', payload });
|
||||||
|
} catch (error) {
|
||||||
|
dispatch({ type: 'CREATE_PAYMENT_FAILURE', error });
|
||||||
|
console.error('Create payment failure', error);
|
||||||
}
|
}
|
||||||
await createPayment({
|
|
||||||
capiEndpoint: appConfig.capiEndpoint,
|
|
||||||
urlShortenerEndpoint: appConfig.urlShortenerEndpoint,
|
|
||||||
origin,
|
|
||||||
initConfig: {
|
|
||||||
redirectUrl: initConfig.redirectUrl,
|
|
||||||
email: initConfig.email,
|
|
||||||
phoneNumber: initConfig.phoneNumber,
|
|
||||||
paymentFlowHold: initConfig.paymentFlowHold,
|
|
||||||
holdExpiration: initConfig.holdExpiration,
|
|
||||||
recurring: initConfig.recurring,
|
|
||||||
metadata: initConfig.metadata,
|
|
||||||
isExternalIDIncluded: initConfig.isExternalIDIncluded
|
|
||||||
},
|
|
||||||
formData,
|
|
||||||
payableInvoice: data
|
|
||||||
});
|
|
||||||
|
|
||||||
setPaymentPayload({
|
|
||||||
capiEndpoint: appConfig.capiEndpoint,
|
|
||||||
invoiceID: data.invoice.id,
|
|
||||||
invoiceAccessToken: data.invoiceAccessToken,
|
|
||||||
serviceProviders
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
},
|
},
|
||||||
[payableInvoiceData]
|
[payableInvoiceData]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { paymentPayload, setFormData };
|
return { createPaymentState, setFormData };
|
||||||
};
|
};
|
||||||
|
@ -2,16 +2,19 @@ import { FormInfo, FormName } from '../form-info';
|
|||||||
|
|
||||||
export enum ResultType {
|
export enum ResultType {
|
||||||
error = 'error',
|
error = 'error',
|
||||||
processed = 'processed'
|
processed = 'processed',
|
||||||
|
hookError = 'hookError'
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResultFormInfo extends FormInfo {
|
export class ResultFormInfo extends FormInfo {
|
||||||
resultType: ResultType;
|
resultType: ResultType;
|
||||||
|
hookError?: unknown;
|
||||||
|
|
||||||
constructor(resultType: ResultType) {
|
constructor(resultType: ResultType, hookError?: unknown) {
|
||||||
super();
|
super();
|
||||||
this.name = FormName.resultForm;
|
this.name = FormName.resultForm;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.active = true;
|
this.active = true;
|
||||||
|
this.hookError = hookError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user