feat: Hook up edit Stripe settings form

This commit is contained in:
Ahmed Bouhuolia
2024-09-22 17:25:27 +02:00
parent 3308133736
commit 9827a84857
8 changed files with 71 additions and 39 deletions

View File

@@ -26,15 +26,10 @@ export class PaymentServicesController extends BaseController {
'/:paymentMethodId', '/:paymentMethodId',
[ [
param('paymentMethodId').exists(), param('paymentMethodId').exists(),
body('name').optional().isString(), body('name').optional().isString(),
body('options.bankAccountId').optional().isNumeric(), body('options.bank_account_id').optional().isNumeric(),
body('options.clearingAccountId').optional().isNumeric(), body('options.clearing_account_id').optional().isNumeric(),
body('options.showVisa').optional().isBoolean(),
body('options.showMasterCard').optional().isBoolean(),
body('options.showDiscover').optional().isBoolean(),
body('options.showAmer').optional().isBoolean(),
body('options.showJcb').optional().isBoolean(),
body('options.showDiners').optional().isBoolean(),
], ],
this.validationResult, this.validationResult,
asyncMiddleware(this.updatePaymentMethod.bind(this)) asyncMiddleware(this.updatePaymentMethod.bind(this))

View File

@@ -1,4 +1,5 @@
import { createContext, ReactNode, useContext } from 'react'; import { createContext, ReactNode, useContext } from 'react';
import { Spinner } from '@blueprintjs/core';
import { import {
GetPaymentServicesStateResponse, GetPaymentServicesStateResponse,
useGetPaymentServicesState, useGetPaymentServicesState,
@@ -23,6 +24,9 @@ const PaymentMethodsBoot = ({ children }: PaymentMethodsProviderProps) => {
const value = { isPaymentMethodsStateLoading, paymentMethodsState }; const value = { isPaymentMethodsStateLoading, paymentMethodsState };
if (isPaymentMethodsStateLoading) {
return <Spinner size={20} />;
}
return ( return (
<PaymentMethodsContext.Provider value={value}> <PaymentMethodsContext.Provider value={value}>
{children} {children}

View File

@@ -1,4 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React, { useEffect } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { import {
Button, Button,
@@ -20,6 +21,7 @@ import { StripePreSetupDialog } from './dialogs/StripePreSetupDialog/StripePreSe
import { DialogsName } from '@/constants/dialogs'; import { DialogsName } from '@/constants/dialogs';
import { import {
useAlertActions, useAlertActions,
useChangePreferencesPageTitle,
useDialogActions, useDialogActions,
useDrawerActions, useDrawerActions,
} from '@/hooks/state'; } from '@/hooks/state';
@@ -29,6 +31,12 @@ import { DRAWERS } from '@/constants/drawers';
import { MoreIcon } from '@/icons/More'; import { MoreIcon } from '@/icons/More';
export default function PreferencesPaymentMethodsPage() { export default function PreferencesPaymentMethodsPage() {
const changePageTitle = useChangePreferencesPageTitle();
useEffect(() => {
changePageTitle('Payment Methods');
}, [changePageTitle]);
return ( return (
<PaymentMethodsRoot> <PaymentMethodsRoot>
<PaymentMethodsBoot> <PaymentMethodsBoot>

View File

@@ -11,20 +11,17 @@ import { useStripeIntegrationEditBoot } from './StripeIntegrationEditBoot';
import { transformToForm } from '@/utils'; import { transformToForm } from '@/utils';
interface StripeIntegrationFormValues { interface StripeIntegrationFormValues {
paymentAccountId: string; bankAccountId: string;
clearingAccountId: string; clearingAccountId: string;
} }
const initialValues = { const initialValues = {
paymentAccountId: '', bankAccountId: '',
clearingAccountId: '', clearingAccountId: '',
}; };
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
paymentAccountId: Yup.string().required('Payment Account is required'), bankAccountId: Yup.string().required('Bank Account is required'),
clearingAccountId: Yup.string().required('Clearing Account is required'), clearingAccountId: Yup.string().required('Clearing Account is required'),
}); });
interface StripeIntegrationEditFormProps { interface StripeIntegrationEditFormProps {
children: React.ReactNode; children: React.ReactNode;
} }
@@ -44,13 +41,14 @@ export function StripeIntegrationEditForm({
...initialValues, ...initialValues,
...transformToForm(paymentMethod?.options, initialValues), ...transformToForm(paymentMethod?.options, initialValues),
}; };
const onSubmit = ( const onSubmit = (
values: StripeIntegrationFormValues, values: StripeIntegrationFormValues,
{ setSubmitting }: FormikHelpers<StripeIntegrationFormValues>, { setSubmitting }: FormikHelpers<StripeIntegrationFormValues>,
) => { ) => {
const _values = { options: { ...values } };
setSubmitting(true); setSubmitting(true);
updatePaymentMethod({ paymentMethodId, values }) updatePaymentMethod({ paymentMethodId, values: _values })
.then(() => { .then(() => {
AppToaster.show({ AppToaster.show({
message: 'The Stripe settings have been updated.', message: 'The Stripe settings have been updated.',

View File

@@ -11,12 +11,13 @@ export function StripeIntegrationEditFormContent() {
return ( return (
<Stack spacing={0} style={{ padding: 20 }}> <Stack spacing={0} style={{ padding: 20 }}>
<FFormGroup <FFormGroup
name={'paymentAccountId'} name={'bankAccountId'}
label={'Payment Account'} label={'Bank Account'}
style={{ maxWidth: 300 }} style={{ maxWidth: 300 }}
helperText={'The bank account where the Stripe payout is deposited.'}
> >
<AccountsSelect <AccountsSelect
name={'paymentAccountId'} name={'bankAccountId'}
items={accounts} items={accounts}
fastField fastField
fill fill
@@ -27,6 +28,8 @@ export function StripeIntegrationEditFormContent() {
<FFormGroup <FFormGroup
name={'clearingAccountId'} name={'clearingAccountId'}
label={'Clearing Account'} label={'Clearing Account'}
subLabel='Liability Account'
helperText={'Clearing account tracks all payments collected through Stripe.'}
style={{ maxWidth: 300 }} style={{ maxWidth: 300 }}
> >
<AccountsSelect <AccountsSelect

View File

@@ -2,6 +2,7 @@
import { import {
useMutation, useMutation,
useQuery, useQuery,
useQueryClient,
UseQueryOptions, UseQueryOptions,
UseQueryResult, UseQueryResult,
} from 'react-query'; } from 'react-query';
@@ -9,6 +10,7 @@ import useApiRequest from '../useRequest';
import { transformToCamelCase, transfromToSnakeCase } from '@/utils'; import { transformToCamelCase, transfromToSnakeCase } from '@/utils';
const PaymentServicesQueryKey = 'PaymentServices'; const PaymentServicesQueryKey = 'PaymentServices';
const PaymentServicesStateQueryKey = 'PaymentServicesState';
export interface GetPaymentServicesResponse {} export interface GetPaymentServicesResponse {}
/** /**
@@ -60,7 +62,7 @@ export const useGetPaymentServicesState = (
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useQuery<GetPaymentServicesStateResponse, Error>( return useQuery<GetPaymentServicesStateResponse, Error>(
['PaymentServicesState'], [PaymentServicesStateQueryKey],
() => () =>
apiRequest apiRequest
.get('/payment-services/state') .get('/payment-services/state')
@@ -99,19 +101,27 @@ export const useUpdatePaymentMethod = (): UseMutationResult<
unknown unknown
> => { > => {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation< return useMutation<
UpdatePaymentMethodResponse, UpdatePaymentMethodResponse,
Error, Error,
UpdatePaymentMethodValues, UpdatePaymentMethodValues,
unknown unknown
>((data: UpdatePaymentMethodValues) => >(
apiRequest (data: UpdatePaymentMethodValues) =>
.post( apiRequest
`/payment-services/${data.paymentMethodId}`, .post(
transfromToSnakeCase(data.values), `/payment-services/${data.paymentMethodId}`,
) transfromToSnakeCase(data.values),
.then((response) => response.data), )
.then((response) => response.data),
{
onSuccess: () => {
queryClient.invalidateQueries(PaymentServicesStateQueryKey);
queryClient.invalidateQueries(PaymentServicesQueryKey);
},
},
); );
}; };
@@ -127,11 +137,13 @@ export const useGetPaymentMethod = (
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useQuery<GetPaymentMethodResponse, Error>( return useQuery<GetPaymentMethodResponse, Error>(
['paymentMethod', paymentMethodId], [PaymentServicesQueryKey, paymentMethodId],
() => apiRequest.get(`/payment-services/${paymentMethodId}`), () =>
{ apiRequest
select: (data) => .get(`/payment-services/${paymentMethodId}`)
transformToCamelCase(data.data) as GetPaymentMethodResponse, .then(
}, (res) =>
transformToCamelCase(res.data?.data) as GetPaymentMethodResponse,
),
); );
}; };

View File

@@ -14,6 +14,7 @@ import {
closeDrawer, closeDrawer,
openAlert, openAlert,
closeAlert, closeAlert,
changePreferencesPageTitle,
} from '@/store/dashboard/dashboard.actions'; } from '@/store/dashboard/dashboard.actions';
export const useDispatchAction = (action) => { export const useDispatchAction = (action) => {
@@ -95,3 +96,7 @@ export const useAlertActions = () => {
closeAlert: useDispatchAction(closeAlert), closeAlert: useDispatchAction(closeAlert),
}; };
}; };
export const useChangePreferencesPageTitle = () => {
return useDispatchAction(changePreferencesPageTitle);
};

View File

@@ -129,19 +129,26 @@ export function closeSidebarSubmenu() {
export function addAutofill(autofillRef: number, payload: any) { export function addAutofill(autofillRef: number, payload: any) {
return { return {
type: t.ADD_AUTOFILL_REF, type: t.ADD_AUTOFILL_REF,
payload: { ref: autofillRef, payload } payload: { ref: autofillRef, payload },
} };
} }
export function removeAutofill(autofillRef: number) { export function removeAutofill(autofillRef: number) {
return { return {
type: t.REMOVE_AUTOFILL_REF, type: t.REMOVE_AUTOFILL_REF,
payload: { ref: autofillRef} payload: { ref: autofillRef },
} };
} }
export function resetAutofill() { export function resetAutofill() {
return { return {
type: t.RESET_AUTOFILL_REF, type: t.RESET_AUTOFILL_REF,
} };
}
export function changePreferencesPageTitle(pageTitle: string) {
return {
type: 'CHANGE_PREFERENCES_PAGE_TITLE',
pageTitle,
};
} }