From 50ad71282dd413a2a2818da312ed137ef58f2f48 Mon Sep 17 00:00:00 2001 From: Ildar Galeev Date: Wed, 24 May 2023 19:31:44 +0300 Subject: [PATCH] Add failure state to create payment hook (#191) --- src/app/backend/create-payment-resource.ts | 9 +- .../form-container/card-form/card-form.tsx | 16 +-- .../payment-terminal-method-item.tsx | 15 ++- .../payment-terminal-bank-card-form.tsx | 16 +-- .../payment-terminal-form.tsx | 23 ++-- .../make-content/make-from-payment-change.tsx | 18 +++ .../result-form/result-form.tsx | 3 + .../wallet-form/wallet-form.tsx | 16 +-- .../wallet-provider-payment-method-item.tsx | 20 +++- src/app/hooks/use-create-payment.ts | 103 ++++++++++++------ .../state/modal/form-info/result-form-info.ts | 7 +- 11 files changed, 165 insertions(+), 81 deletions(-) diff --git a/src/app/backend/create-payment-resource.ts b/src/app/backend/create-payment-resource.ts index b79e5a79..a445c500 100644 --- a/src/app/backend/create-payment-resource.ts +++ b/src/app/backend/create-payment-resource.ts @@ -9,12 +9,9 @@ function getFingerprintFromComponents(components: Fingerprint2.Component[]) { } const getClientInfoUrl = (): { url: string } | undefined => { - const url = (document.referrer || '').slice( - 0, - // URL max length (API constraint) - 599 - ); - return url ? { url } : undefined; + if (document.referrer === '') return; + const url = new URL(document.referrer); + return { url: url.origin }; }; export const createPaymentResource = ( diff --git a/src/app/components/app/modal-container/modal/form-container/card-form/card-form.tsx b/src/app/components/app/modal-container/modal/form-container/card-form/card-form.tsx index 404879ea..95563371 100644 --- a/src/app/components/app/modal-container/modal/form-container/card-form/card-form.tsx +++ b/src/app/components/app/modal-container/modal/form-container/card-form/card-form.tsx @@ -4,8 +4,8 @@ import { InjectedFormProps, reduxForm } from 'redux-form'; import { FormGroup } from '../form-group'; import { CardHolder, CardNumber, ExpireDate, SecureCode } from './fields'; -import { CardFormInfo, CardFormValues, FormName, PaymentStatus } from 'checkout/state'; -import { pay, prepareToPay, setViewInfoError } from 'checkout/actions'; +import { CardFormInfo, CardFormValues, FormName, PaymentStatus, ResultFormInfo, ResultType } from 'checkout/state'; +import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions'; import { PayButton } from '../pay-button'; import { Header } from '../header/header'; import { toAmountConfig, toCardHolderConfig } from '../fields-config'; @@ -14,7 +14,6 @@ import { useAppDispatch, useAppSelector } from 'checkout/configure-store'; import { getActiveModalFormSelector } from 'checkout/selectors'; import { InitialContext } from '../../../../initial-context'; import { PaymentMethodName, useCreatePayment } from 'checkout/hooks'; -import isNil from 'checkout/utils/is-nil'; const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormProps) => { const { @@ -22,7 +21,7 @@ const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormPro initConfig, model: { invoiceTemplate } } = useContext(InitialContext); - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const { paymentStatus } = useAppSelector(getActiveModalFormSelector); const cardHolder = toCardHolderConfig(initConfig.requireCardHolder); const amount = toAmountConfig(initConfig, invoiceTemplate); @@ -47,10 +46,13 @@ const CardFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormPro if (submitFailed) { dispatch(setViewInfoError(true)); } - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [submitFailed, paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [submitFailed, createPaymentState]); const submit = (values: CardFormValues) => { dispatch(prepareToPay()); diff --git a/src/app/components/app/modal-container/modal/form-container/payment-methods/methods/payment-terminal-method-items/payment-terminal-method-item.tsx b/src/app/components/app/modal-container/modal/form-container/payment-methods/methods/payment-terminal-method-items/payment-terminal-method-item.tsx index bfcb47d1..916a317f 100644 --- a/src/app/components/app/modal-container/modal/form-container/payment-methods/methods/payment-terminal-method-items/payment-terminal-method-item.tsx +++ b/src/app/components/app/modal-container/modal/form-container/payment-methods/methods/payment-terminal-method-items/payment-terminal-method-item.tsx @@ -6,7 +6,9 @@ import { FormName, PaymentTerminalFormInfo, PaymentTerminalFormValues, - PaymentTerminalSelectorFormInfo + PaymentTerminalSelectorFormInfo, + ResultFormInfo, + ResultType } from 'checkout/state'; import { getMetadata, PaymentMethodItemContainer } from 'checkout/components/ui'; import { PaymentMethodName, ServiceProvider, ServiceProviderContactInfo } from 'checkout/backend'; @@ -45,7 +47,7 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP const emailPrefilled = !!initConfig.email; const phoneNumberPrefilled = !!initConfig.phoneNumber; - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const dispatch = useAppDispatch(); const onClick = () => { @@ -69,10 +71,13 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP }; useEffect(() => { - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [createPaymentState]); return ( diff --git a/src/app/components/app/modal-container/modal/form-container/payment-terminal-bank-card-form/payment-terminal-bank-card-form.tsx b/src/app/components/app/modal-container/modal/form-container/payment-terminal-bank-card-form/payment-terminal-bank-card-form.tsx index 3af7cf8a..08b1a36c 100644 --- a/src/app/components/app/modal-container/modal/form-container/payment-terminal-bank-card-form/payment-terminal-bank-card-form.tsx +++ b/src/app/components/app/modal-container/modal/form-container/payment-terminal-bank-card-form/payment-terminal-bank-card-form.tsx @@ -2,11 +2,11 @@ import * as React from 'react'; import { useContext, useEffect } from 'react'; 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 { useAppDispatch } from 'checkout/configure-store'; 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 { PaymentMethodName } from 'checkout/backend'; import styled from 'checkout/styled-components'; @@ -14,7 +14,6 @@ import { toEmailConfig, toPhoneNumberConfig } from '../fields-config'; import { FormGroup } from '../form-group'; import { Email, Phone } from '../common-fields'; import { getMetadata } from 'checkout/components'; -import isNil from 'checkout/utils/is-nil'; import { InitialContext } from '../../../../initial-context'; import { getAvailableTerminalPaymentMethod } from '../get-available-terminal-payment-method'; @@ -29,7 +28,7 @@ const ProviderSelectorDescription = styled.p` export const PaymentTerminalBankCardFormDef: React.FC = ({ submitFailed, handleSubmit }) => { const { locale, initConfig, availablePaymentMethods } = useContext(InitialContext); - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const paymentMethod = getAvailableTerminalPaymentMethod(availablePaymentMethods, KnownProviderCategories.BankCard); const serviceProviders = paymentMethod?.serviceProviders; const email = toEmailConfig(initConfig.email); @@ -45,10 +44,13 @@ export const PaymentTerminalBankCardFormDef: React.FC = ({ su if (submitFailed) { dispatch(setViewInfoError(true)); } - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [submitFailed, paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [submitFailed, createPaymentState]); const submit = (values: PaymentTerminalFormValues) => { dispatch(prepareToPay()); diff --git a/src/app/components/app/modal-container/modal/form-container/payment-terminal-form/payment-terminal-form.tsx b/src/app/components/app/modal-container/modal/form-container/payment-terminal-form/payment-terminal-form.tsx index be965a73..eca7265f 100644 --- a/src/app/components/app/modal-container/modal/form-container/payment-terminal-form/payment-terminal-form.tsx +++ b/src/app/components/app/modal-container/modal/form-container/payment-terminal-form/payment-terminal-form.tsx @@ -5,8 +5,15 @@ import get from 'lodash-es/get'; import styled from 'checkout/styled-components'; import { useAppDispatch, useAppSelector } from 'checkout/configure-store'; -import { pay, prepareToPay, setViewInfoError } from 'checkout/actions'; -import { FormName, PaymentStatus, PaymentTerminalFormValues, PaymentTerminalFormInfo } from 'checkout/state'; +import { goToFormInfo, pay, prepareToPay, setViewInfoError } from 'checkout/actions'; +import { + FormName, + PaymentStatus, + PaymentTerminalFormValues, + PaymentTerminalFormInfo, + ResultFormInfo, + ResultType +} from 'checkout/state'; import { Header } from '../header'; import { PayButton } from '../pay-button'; import { FormGroup } from '../form-group'; @@ -26,7 +33,6 @@ import { } from './init-config-payment'; import { MetadataSelect } from './metadata-select'; import { PaymentMethodName, useCreatePayment } from 'checkout/hooks'; -import isNil from 'checkout/utils/is-nil'; import { InitialContext } from '../../../../initial-context'; const Container = styled.div` @@ -42,7 +48,7 @@ const PaymentTerminalFormRef: React.FC = ({ submitFailed, ini initConfig, model: { serviceProviders, invoiceTemplate } } = useContext(InitialContext); - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const { providerID, paymentStatus } = useAppSelector(getActiveModalFormSelector); const serviceProvider = serviceProviders.find((value) => value.id === providerID); const { form, contactInfo, logo, paymentSessionInfo, prefilledMetadataValues } = getMetadata(serviceProvider); @@ -88,10 +94,13 @@ const PaymentTerminalFormRef: React.FC = ({ submitFailed, ini if (submitFailed) { dispatch(setViewInfoError(true)); } - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [submitFailed, paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [submitFailed, createPaymentState]); const submit = (values?: Partial) => { const payload = { diff --git a/src/app/components/app/modal-container/modal/form-container/result-form/make-content/make-from-payment-change.tsx b/src/app/components/app/modal-container/modal/form-container/result-form/make-content/make-from-payment-change.tsx index ac255ecd..68eb926f 100644 --- a/src/app/components/app/modal-container/modal/form-container/result-form/make-content/make-from-payment-change.tsx +++ b/src/app/components/app/modal-container/modal/form-container/result-form/make-content/make-from-payment-change.tsx @@ -4,6 +4,7 @@ import { ResultFormContent } from './result-form-content'; import { getFailedDescription } from './get-failed-description'; import { getLastChange } from 'checkout/utils'; import { ResultFormType } from './result-form-content'; +import isObject from 'checkout/utils/is-object'; export const refunded = (l: Locale): ResultFormContent => ({ hasActions: false, @@ -34,6 +35,23 @@ export const failed = (l: Locale, e: PaymentError | LogicError): ResultFormConte 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 => ({ hasActions: false, hasDone: true, diff --git a/src/app/components/app/modal-container/modal/form-container/result-form/result-form.tsx b/src/app/components/app/modal-container/modal/form-container/result-form/result-form.tsx index a95818f6..99ebc80b 100644 --- a/src/app/components/app/modal-container/modal/form-container/result-form/result-form.tsx +++ b/src/app/components/app/modal-container/modal/form-container/result-form/result-form.tsx @@ -5,6 +5,7 @@ import { FormName, ModalForms, ModalName, ResultFormInfo, ResultState, ResultTyp import { setResult } from 'checkout/actions'; import { findNamed } from 'checkout/utils'; import { makeContentError, makeContentInvoice } from './make-content'; +import { failedHook } from './make-content/make-from-payment-change'; import { ActionBlock } from './action-block'; import { ResultIcon } from './result-icons'; import styled, { css } from 'checkout/styled-components'; @@ -78,6 +79,8 @@ export const ResultForm = () => { switch (resultFormInfo.resultType) { case ResultType.error: return makeContentError(locale, error); + case ResultType.hookError: + return failedHook(locale, resultFormInfo.hookError); case ResultType.processed: return makeContentInvoice(locale, events.events, events.status, error); } diff --git a/src/app/components/app/modal-container/modal/form-container/wallet-form/wallet-form.tsx b/src/app/components/app/modal-container/modal/form-container/wallet-form/wallet-form.tsx index c041b3c1..b976f493 100644 --- a/src/app/components/app/modal-container/modal/form-container/wallet-form/wallet-form.tsx +++ b/src/app/components/app/modal-container/modal/form-container/wallet-form/wallet-form.tsx @@ -4,19 +4,18 @@ import { InjectedFormProps, reduxForm } from 'redux-form'; import get from 'lodash-es/get'; 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 { Header } from '../header'; import { Amount } from '../common-fields'; 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 { getActiveModalFormSelector } from 'checkout/selectors'; import { useAppDispatch, useAppSelector } from 'checkout/configure-store'; import { getMetadata, MetadataField, MetadataLogo, obscurePassword, sortByIndex } from 'checkout/components/ui'; import { LogoContainer } from './logo-container'; import { PaymentMethodName, useCreatePayment } from 'checkout/hooks'; -import isNil from 'checkout/utils/is-nil'; import { InitialContext } from '../../../../initial-context'; @@ -26,7 +25,7 @@ const WalletFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormP initConfig, model: { invoiceTemplate } } = useContext(InitialContext); - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const { activeProvider, paymentStatus } = useAppSelector(getActiveModalFormSelector); const dispatch = useAppDispatch(); const formValues = useAppSelector((s) => get(s.form, 'walletForm.values')); @@ -60,10 +59,13 @@ const WalletFormDef = ({ submitFailed, initialize, handleSubmit }: InjectedFormP if (submitFailed) { dispatch(setViewInfoError(true)); } - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [submitFailed, paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [submitFailed, createPaymentState]); return (
diff --git a/src/app/components/app/modal-container/modal/form-container/wallet-provider-payment-method-item/wallet-provider-payment-method-item.tsx b/src/app/components/app/modal-container/modal/form-container/wallet-provider-payment-method-item/wallet-provider-payment-method-item.tsx index ce3512da..bd8ec8bd 100644 --- a/src/app/components/app/modal-container/modal/form-container/wallet-provider-payment-method-item/wallet-provider-payment-method-item.tsx +++ b/src/app/components/app/modal-container/modal/form-container/wallet-provider-payment-method-item/wallet-provider-payment-method-item.tsx @@ -1,7 +1,14 @@ import * as React 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 { PaymentMethodName, ServiceProvider } from 'checkout/backend'; import { PaymentRequestedPayload, goToFormInfo, pay, prepareToPay } from 'checkout/actions'; @@ -19,7 +26,7 @@ export interface WalletProviderPaymentMethodItemProps { export const WalletProviderPaymentMethodItem = ({ serviceProvider }: WalletProviderPaymentMethodItemProps) => { const { logo, form } = getMetadata(serviceProvider); - const { paymentPayload, setFormData } = useCreatePayment(); + const { createPaymentState, setFormData } = useCreatePayment(); const dispatch = useAppDispatch(); const onClick = () => { @@ -37,10 +44,13 @@ export const WalletProviderPaymentMethodItem = ({ serviceProvider }: WalletProvi }; useEffect(() => { - if (!isNil(paymentPayload)) { - dispatch(pay(paymentPayload)); + if (createPaymentState.status === 'SUCCESS') { + dispatch(pay(createPaymentState.data)); } - }, [paymentPayload]); + if (createPaymentState.status === 'FAILURE') { + dispatch(goToFormInfo(new ResultFormInfo(ResultType.hookError, createPaymentState.error))); + } + }, [createPaymentState]); return ( diff --git a/src/app/hooks/use-create-payment.ts b/src/app/hooks/use-create-payment.ts index 4ad17cb8..ccdec67e 100644 --- a/src/app/hooks/use-create-payment.ts +++ b/src/app/hooks/use-create-payment.ts @@ -1,4 +1,4 @@ -import { useContext, useState, useCallback } from 'react'; +import { useContext, useCallback, useReducer } from 'react'; import isNil from 'checkout/utils/is-nil'; import { PaymentRequestedPayload } from 'checkout/actions'; @@ -8,6 +8,32 @@ import { FormData } from './create-payment'; import { InitialContext } from '../components/app/initial-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 = () => { const { initConfig, @@ -18,51 +44,58 @@ export const useCreatePayment = () => { } = useContext(InitialContext); const { payableInvoiceData, setPayableInvoiceData } = useContext(PayableInvoiceContext); - const [paymentPayload, setPaymentPayload] = useState(null); + const [createPaymentState, dispatch] = useReducer(dataReducer, { + status: 'PRISTINE' + }); const setFormData = useCallback( (formData: FormData) => { const fetchData = async () => { - let data = payableInvoiceData; - if (isNil(data)) { - data = await createInvoiceWithTemplate({ + try { + let data = payableInvoiceData; + 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, - invoiceTemplateAccessToken: initConfig.invoiceTemplateAccessToken, - invoiceTemplate, - amountInfo, - formAmount: formData.values?.amount + 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 }); - 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(); }, [payableInvoiceData] ); - return { paymentPayload, setFormData }; + return { createPaymentState, setFormData }; }; diff --git a/src/app/state/modal/form-info/result-form-info.ts b/src/app/state/modal/form-info/result-form-info.ts index 610799ad..ad0c00fe 100644 --- a/src/app/state/modal/form-info/result-form-info.ts +++ b/src/app/state/modal/form-info/result-form-info.ts @@ -2,16 +2,19 @@ import { FormInfo, FormName } from '../form-info'; export enum ResultType { error = 'error', - processed = 'processed' + processed = 'processed', + hookError = 'hookError' } export class ResultFormInfo extends FormInfo { resultType: ResultType; + hookError?: unknown; - constructor(resultType: ResultType) { + constructor(resultType: ResultType, hookError?: unknown) { super(); this.name = FormName.resultForm; this.resultType = resultType; this.active = true; + this.hookError = hookError; } }