mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: Edit stripe payment integation drawer
This commit is contained in:
@@ -13,11 +13,11 @@ export class PaymentIntegration extends TenantModel {
|
|||||||
static get jsonSchema() {
|
static get jsonSchema() {
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['name', 'service', 'enable'],
|
required: ['name', 'service', 'active'],
|
||||||
properties: {
|
properties: {
|
||||||
id: { type: 'integer' },
|
id: { type: 'integer' },
|
||||||
service: { type: 'string' },
|
service: { type: 'string' },
|
||||||
enable: { type: 'boolean' },
|
active: { type: 'boolean' },
|
||||||
accountId: { type: 'string' },
|
accountId: { type: 'string' },
|
||||||
options: { type: 'object' },
|
options: { type: 'object' },
|
||||||
createdAt: { type: 'string', format: 'date-time' },
|
createdAt: { type: 'string', format: 'date-time' },
|
||||||
|
|||||||
@@ -79,4 +79,6 @@ export enum DialogsName {
|
|||||||
DisconnectBankAccountConfirmation = 'DisconnectBankAccountConfirmation',
|
DisconnectBankAccountConfirmation = 'DisconnectBankAccountConfirmation',
|
||||||
SharePaymentLink = 'SharePaymentLink',
|
SharePaymentLink = 'SharePaymentLink',
|
||||||
SelectPaymentMethod = 'SelectPaymentMethodsDialog',
|
SelectPaymentMethod = 'SelectPaymentMethodsDialog',
|
||||||
|
|
||||||
|
StripeSetup = 'StripeSetup'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,6 @@ export enum DRAWERS {
|
|||||||
CREDIT_NOTE_CUSTOMIZE = 'CREDIT_NOTE_CUSTOMIZE',
|
CREDIT_NOTE_CUSTOMIZE = 'CREDIT_NOTE_CUSTOMIZE',
|
||||||
PAYMENT_RECEIVED_CUSTOMIZE = 'PAYMENT_RECEIVED_CUSTOMIZE',
|
PAYMENT_RECEIVED_CUSTOMIZE = 'PAYMENT_RECEIVED_CUSTOMIZE',
|
||||||
BRANDING_TEMPLATES = 'BRANDING_TEMPLATES',
|
BRANDING_TEMPLATES = 'BRANDING_TEMPLATES',
|
||||||
PAYMENT_INVOICE_PREVIEW = 'PAYMENT_INVOICE_PREVIEW'
|
PAYMENT_INVOICE_PREVIEW = 'PAYMENT_INVOICE_PREVIEW',
|
||||||
|
STRIPE_PAYMENT_INTEGRATION_EDIT = 'STRIPE_PAYMENT_INTEGRATION_EDIT'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import React, { createContext, ReactNode, useContext } from 'react';
|
import { createContext, ReactNode, useContext } from 'react';
|
||||||
import { useGetPaymentServicesState } from '@/hooks/query/payment-services';
|
import {
|
||||||
|
GetPaymentServicesStateResponse,
|
||||||
|
useGetPaymentServicesState,
|
||||||
|
} from '@/hooks/query/payment-services';
|
||||||
|
|
||||||
type PaymentMethodsContextType = {
|
type PaymentMethodsContextType = {
|
||||||
isPaymentMethodsStateLoading: boolean;
|
isPaymentMethodsStateLoading: boolean;
|
||||||
paymentMethodsState: any;
|
paymentMethodsState: GetPaymentServicesStateResponse | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PaymentMethodsContext = createContext<PaymentMethodsContextType>(
|
const PaymentMethodsContext = createContext<PaymentMethodsContextType>(
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Button, Classes, Intent, Text } from '@blueprintjs/core';
|
import { Button, Classes, Intent, Text } from '@blueprintjs/core';
|
||||||
import { Box, Card, Group, Stack } from '@/components';
|
import { AppToaster, Box, Card, Group, Stack } from '@/components';
|
||||||
import { StripeLogo } from '@/icons/StripeLogo';
|
import { StripeLogo } from '@/icons/StripeLogo';
|
||||||
import { PaymentMethodsBoot } from './PreferencesPaymentMethodsBoot';
|
import {
|
||||||
|
PaymentMethodsBoot,
|
||||||
|
usePaymentMethodsBoot,
|
||||||
|
} from './PreferencesPaymentMethodsBoot';
|
||||||
|
import { StripePreSetupDialog } from './dialogs/StripePreSetupDialog/StripePreSetupDialog';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
import { useDialogActions, useDrawerActions } from '@/hooks/state';
|
||||||
|
import { useCreateStripeAccountLink } from '@/hooks/query/stripe-integration';
|
||||||
|
import { StripeIntegrationEditDrawer } from './drawers/StripeIntegrationEditDrawer';
|
||||||
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
|
|
||||||
export default function PreferencesPaymentMethodsPage() {
|
export default function PreferencesPaymentMethodsPage() {
|
||||||
return (
|
return (
|
||||||
@@ -18,19 +27,81 @@ export default function PreferencesPaymentMethodsPage() {
|
|||||||
<StripePaymentMethod />
|
<StripePaymentMethod />
|
||||||
</Stack>
|
</Stack>
|
||||||
</PaymentMethodsBoot>
|
</PaymentMethodsBoot>
|
||||||
|
|
||||||
|
<StripePreSetupDialog dialogName={DialogsName.StripeSetup} />
|
||||||
|
<StripeIntegrationEditDrawer
|
||||||
|
name={DRAWERS.STRIPE_PAYMENT_INTEGRATION_EDIT}
|
||||||
|
/>
|
||||||
</PaymentMethodsRoot>
|
</PaymentMethodsRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function StripePaymentMethod() {
|
function StripePaymentMethod() {
|
||||||
|
const { openDialog } = useDialogActions();
|
||||||
|
const { openDrawer } = useDrawerActions();
|
||||||
|
const { paymentMethodsState } = usePaymentMethodsBoot();
|
||||||
|
const stripeState = paymentMethodsState?.stripe;
|
||||||
|
|
||||||
|
const isAccountCreated = stripeState?.isStripeAccountCreated;
|
||||||
|
const isAccountActive = stripeState?.isStripePaymentActive;
|
||||||
|
const stripeAccountId = stripeState?.stripeAccountId;
|
||||||
|
|
||||||
|
const {
|
||||||
|
mutateAsync: createStripeAccountLink,
|
||||||
|
isLoading: isCreateStripeLinkLoading,
|
||||||
|
} = useCreateStripeAccountLink();
|
||||||
|
|
||||||
|
// Handle Stripe setup button click.
|
||||||
|
const handleSetUpBtnClick = () => {
|
||||||
|
openDialog(DialogsName.StripeSetup);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle complete Stripe setup button click.
|
||||||
|
const handleCompleteSetUpBtnClick = () => {
|
||||||
|
createStripeAccountLink({ stripeAccountId })
|
||||||
|
.then((res) => {
|
||||||
|
const { clientSecret } = res;
|
||||||
|
|
||||||
|
if (clientSecret.url) {
|
||||||
|
window.open(clientSecret.url, '_blank');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: 'Something went wrong.',
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditBtnClick = () => {
|
||||||
|
openDrawer(DRAWERS.STRIPE_PAYMENT_INTEGRATION_EDIT);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card style={{ margin: 0 }}>
|
<Card style={{ margin: 0 }}>
|
||||||
<Group position="apart">
|
<Group position="apart">
|
||||||
<StripeLogo />
|
<StripeLogo />
|
||||||
<Group>
|
<Group spacing={10}>
|
||||||
<Button intent={Intent.PRIMARY} small>
|
<Button small onClick={handleEditBtnClick}>
|
||||||
Set it Up
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{!isAccountCreated && (
|
||||||
|
<Button intent={Intent.PRIMARY} small onClick={handleSetUpBtnClick}>
|
||||||
|
Set it Up
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{isAccountCreated && !isAccountActive && (
|
||||||
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
small
|
||||||
|
onClick={handleCompleteSetUpBtnClick}
|
||||||
|
loading={isCreateStripeLinkLoading}
|
||||||
|
>
|
||||||
|
Complete Stripe Set Up
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import { Dialog, DialogSuspense } from '@/components';
|
||||||
|
import { compose } from '@/utils';
|
||||||
|
import withDialogRedux from '@/components/DialogReduxConnect';
|
||||||
|
import { StripePreSetupDialogContent } from './StripePreSetupDialogContent';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select payment methods dialogs.
|
||||||
|
*/
|
||||||
|
function StripePreSetupDialogRoot({ dialogName, payload, isOpen }) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
name={dialogName}
|
||||||
|
isOpen={isOpen}
|
||||||
|
payload={payload}
|
||||||
|
title={'Share Link'}
|
||||||
|
canEscapeJeyClose={true}
|
||||||
|
autoFocus={true}
|
||||||
|
style={{ width: 570 }}
|
||||||
|
>
|
||||||
|
<DialogSuspense>
|
||||||
|
<StripePreSetupDialogContent />
|
||||||
|
</DialogSuspense>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StripePreSetupDialog = compose(withDialogRedux())(
|
||||||
|
StripePreSetupDialogRoot,
|
||||||
|
);
|
||||||
|
|
||||||
|
StripePreSetupDialogRoot.displayName = 'StripePreSetupDialog';
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
useCreateStripeAccount,
|
||||||
|
useCreateStripeAccountLink,
|
||||||
|
} from '@/hooks/query/stripe-integration';
|
||||||
|
import { Button, DialogBody, DialogFooter, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
export function StripePreSetupDialogContent() {
|
||||||
|
const {
|
||||||
|
mutateAsync: createStripeAccount,
|
||||||
|
isLoading: isCreateStripeAccountLoading,
|
||||||
|
} = useCreateStripeAccount();
|
||||||
|
|
||||||
|
const {
|
||||||
|
mutateAsync: createStripeAccountLink,
|
||||||
|
isLoading: isCreateStripeLinkLoading,
|
||||||
|
} = useCreateStripeAccountLink();
|
||||||
|
|
||||||
|
const handleSetUpBtnClick = () => {
|
||||||
|
createStripeAccount({})
|
||||||
|
.then((response) => {
|
||||||
|
const { account_id: accountId } = response;
|
||||||
|
|
||||||
|
return createStripeAccountLink({ stripeAccountId: accountId });
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
const { clientSecret } = res;
|
||||||
|
|
||||||
|
if (clientSecret.url) {
|
||||||
|
window.location.href = clientSecret.url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLoading = isCreateStripeAccountLoading || isCreateStripeLinkLoading;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DialogBody>
|
||||||
|
|
||||||
|
|
||||||
|
</DialogBody>
|
||||||
|
<DialogFooter
|
||||||
|
actions={
|
||||||
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
onClick={handleSetUpBtnClick}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
Set It Up
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
></DialogFooter>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import React, { createContext, useContext } from 'react';
|
||||||
|
import { Spinner } from '@blueprintjs/core';
|
||||||
|
import { useAccounts } from '@/hooks/query';
|
||||||
|
|
||||||
|
interface StripeIntegrationEditContextType {
|
||||||
|
accounts: any;
|
||||||
|
isAccountsLoading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StripeIntegrationEditContext =
|
||||||
|
createContext<StripeIntegrationEditContextType>(
|
||||||
|
{} as StripeIntegrationEditContextType,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const useStripeIntegrationEditBoot = () => {
|
||||||
|
const context = useContext<StripeIntegrationEditContextType>(
|
||||||
|
StripeIntegrationEditContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'useStripeIntegrationEditContext must be used within a StripeIntegrationEditProvider',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StripeIntegrationEditBoot: React.FC = ({ children }) => {
|
||||||
|
const { data: accounts, isLoading: isAccountsLoading } = useAccounts({}, {});
|
||||||
|
const value = { accounts, isAccountsLoading };
|
||||||
|
const isLoading = isAccountsLoading;
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <Spinner size={20} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<StripeIntegrationEditContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</StripeIntegrationEditContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import { Classes } from '@blueprintjs/core';
|
||||||
|
import { DrawerBody, DrawerHeaderContent } from '@/components';
|
||||||
|
import { StripeIntegrationEditForm } from './StripeIntegrationEditForm';
|
||||||
|
import { StripeIntegrationEditBoot } from './StripeIntegrationEditBoot';
|
||||||
|
import {
|
||||||
|
StripeIntegrationEditFormContent,
|
||||||
|
StripeIntegrationEditFormFooter,
|
||||||
|
} from './StripeIntegrationEditFormContent';
|
||||||
|
|
||||||
|
export function StripeIntegrationEditContent() {
|
||||||
|
return (
|
||||||
|
<StripeIntegrationEditBoot>
|
||||||
|
<DrawerHeaderContent title={'Edit Stripe Integration'} />
|
||||||
|
<StripeIntegrationEditBoot>
|
||||||
|
<StripeIntegrationEditForm>
|
||||||
|
<DrawerBody>
|
||||||
|
<StripeIntegrationEditFormContent />
|
||||||
|
</DrawerBody>
|
||||||
|
|
||||||
|
<div className={Classes.DRAWER_FOOTER}>
|
||||||
|
<StripeIntegrationEditFormFooter />
|
||||||
|
</div>
|
||||||
|
</StripeIntegrationEditForm>
|
||||||
|
</StripeIntegrationEditBoot>
|
||||||
|
</StripeIntegrationEditBoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { Drawer, DrawerSuspense } from '@/components';
|
||||||
|
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||||
|
|
||||||
|
const StripeIntegrationEditContent = React.lazy(() =>
|
||||||
|
import('./StripeIntegrationEditContent').then((module) => ({
|
||||||
|
default: module.StripeIntegrationEditContent,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stripe integration edit drawer.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function StripeIntegrationEditDrawerRoot({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withDrawer
|
||||||
|
isOpen,
|
||||||
|
payload,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Drawer isOpen={isOpen} name={name} payload={payload} size={'600px'}>
|
||||||
|
<DrawerSuspense>
|
||||||
|
<StripeIntegrationEditContent />
|
||||||
|
</DrawerSuspense>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StripeIntegrationEditDrawer = R.compose(withDrawers())(
|
||||||
|
StripeIntegrationEditDrawerRoot,
|
||||||
|
);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
import { Formik, FormikHelpers } from 'formik';
|
||||||
|
|
||||||
|
interface StripeIntegrationFormValues {
|
||||||
|
paymentAccountId: string;
|
||||||
|
clearingAccountId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
paymentAccountId: '',
|
||||||
|
clearingAccountId: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
paymentAccountId: Yup.string().required('Payment Account is required'),
|
||||||
|
clearingAccountId: Yup.string().required('Clearing Account is required'),
|
||||||
|
});
|
||||||
|
|
||||||
|
interface StripeIntegrationEditFormProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StripeIntegrationEditForm({
|
||||||
|
children,
|
||||||
|
}: StripeIntegrationEditFormProps) {
|
||||||
|
const onSubmit = (
|
||||||
|
values: StripeIntegrationFormValues,
|
||||||
|
{ setSubmitting }: FormikHelpers<StripeIntegrationFormValues>,
|
||||||
|
) => {
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
>
|
||||||
|
<>{children}</>
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { AccountsSelect, FFormGroup, Group, Stack } from '@/components';
|
||||||
|
import { useStripeIntegrationEditBoot } from './StripeIntegrationEditBoot';
|
||||||
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
|
import { useDrawerActions } from '@/hooks/state';
|
||||||
|
|
||||||
|
export function StripeIntegrationEditFormContent() {
|
||||||
|
const { accounts } = useStripeIntegrationEditBoot();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack spacing={0} style={{ padding: 20 }}>
|
||||||
|
<FFormGroup
|
||||||
|
name={'paymentAccountId'}
|
||||||
|
label={'Payment Account'}
|
||||||
|
style={{ maxWidth: 300 }}
|
||||||
|
>
|
||||||
|
<AccountsSelect
|
||||||
|
name={'paymentAccountId'}
|
||||||
|
items={accounts}
|
||||||
|
fastField
|
||||||
|
fill
|
||||||
|
allowCreate
|
||||||
|
/>
|
||||||
|
</FFormGroup>
|
||||||
|
|
||||||
|
<FFormGroup
|
||||||
|
name={'clearingAccountId'}
|
||||||
|
label={'Clearing Account'}
|
||||||
|
style={{ maxWidth: 300 }}
|
||||||
|
>
|
||||||
|
<AccountsSelect
|
||||||
|
name={'clearingAccountId'}
|
||||||
|
items={accounts}
|
||||||
|
fastField
|
||||||
|
fill
|
||||||
|
allowCreate
|
||||||
|
/>
|
||||||
|
</FFormGroup>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StripeIntegrationEditFormFooter() {
|
||||||
|
const { name } = useDrawerContext();
|
||||||
|
const { closeDrawer } = useDrawerActions();
|
||||||
|
const { submitForm } = useFormikContext();
|
||||||
|
|
||||||
|
const handleSubmitBtnClick = () => {
|
||||||
|
submitForm();
|
||||||
|
};
|
||||||
|
const handleCancelBtnClick = () => {
|
||||||
|
closeDrawer(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Group spacing={10}>
|
||||||
|
<Button intent={Intent.PRIMARY} onClick={handleSubmitBtnClick}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleCancelBtnClick}>Cancel</Button>
|
||||||
|
</Group>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -33,7 +33,16 @@ export const useGetPaymentServices = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface GetPaymentServicesStateResponse {}
|
export interface GetPaymentServicesStateResponse {
|
||||||
|
stripe: {
|
||||||
|
isStripeAccountCreated: boolean;
|
||||||
|
isStripePaymentActive: boolean;
|
||||||
|
stripeAccountId: string;
|
||||||
|
stripeCurrencies: string[];
|
||||||
|
stripePublishableKey: string;
|
||||||
|
stripeRedirectUrl: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Retrieves the state of payment services.
|
* Retrieves the state of payment services.
|
||||||
* @param {UseQueryOptions<GetPaymentServicesStateResponse, Error>} options
|
* @param {UseQueryOptions<GetPaymentServicesStateResponse, Error>} options
|
||||||
@@ -52,7 +61,7 @@ export const useGetPaymentServicesState = (
|
|||||||
.then(
|
.then(
|
||||||
(response) =>
|
(response) =>
|
||||||
transformToCamelCase(
|
transformToCamelCase(
|
||||||
response.data?.paymentServicesState,
|
response.data?.data,
|
||||||
) as GetPaymentServicesStateResponse,
|
) as GetPaymentServicesStateResponse,
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user