diff --git a/src/components/client/donation-flow/DonationFlowForm.tsx b/src/components/client/donation-flow/DonationFlowForm.tsx index cce7eb4e5..764363aea 100644 --- a/src/components/client/donation-flow/DonationFlowForm.tsx +++ b/src/components/client/donation-flow/DonationFlowForm.tsx @@ -25,7 +25,7 @@ import CheckboxField from 'components/common/form/CheckboxField' import AcceptPrivacyPolicyField from 'components/common/form/AcceptPrivacyPolicyField' import ConfirmationDialog from 'components/common/ConfirmationDialog' import SubmitButton from 'components/common/form/SubmitButton' -import { useUpdateSetupIntent } from 'service/donation' +import { useCancelSetupIntent, useUpdateSetupIntent } from 'service/donation' import StepSplitter from './common/StepSplitter' import PaymentMethod from './steps/payment-method/PaymentMethod' @@ -134,6 +134,7 @@ export function DonationFlowForm() { const elements = useElements() const router = useRouter() const updateSetupIntentMutation = useUpdateSetupIntent() + const cancelSetupIntentMutation = useCancelSetupIntent() const paymentMethodSectionRef = React.useRef(null) const authenticationSectionRef = React.useRef(null) const [showCancelDialog, setShowCancelDialog] = React.useState(false) @@ -152,6 +153,7 @@ export function DonationFlowForm() { onSubmit={async (values, helpers) => { setSubmitPaymentLoading(true) if (values.payment === DonationFormPaymentMethod.BANK) { + cancelSetupIntentMutation.mutate({ id: setupIntent.id }) helpers.resetForm() sessionStorage.removeItem('donation-form') return router.push( @@ -240,7 +242,7 @@ export function DonationFlowForm() { { - // TODO: Cancel the setup intent + cancelSetupIntentMutation.mutate({ id: setupIntent.id }) router.push(routes.campaigns.viewCampaignBySlug(campaign.slug)) }} title={t('cancel-dialog.title')} diff --git a/src/gql/donations.d.ts b/src/gql/donations.d.ts index 53d14d17a..07741a7ee 100644 --- a/src/gql/donations.d.ts +++ b/src/gql/donations.d.ts @@ -36,6 +36,10 @@ export type UpdatePaymentIntentInput = { payload: Stripe.PaymentIntentUpdateParams } +export type CancelSetupIntentInput = { + id: string +} + export type UpdateSetupIntentInput = { id: string idempotencyKey: string diff --git a/src/service/apiEndpoints.ts b/src/service/apiEndpoints.ts index 6585d8c94..f578b03c6 100644 --- a/src/service/apiEndpoints.ts +++ b/src/service/apiEndpoints.ts @@ -168,6 +168,11 @@ export const endpoints = { url: `/stripe/setup-intent/${id}?idempotency-key=${idempotencyKey}`, method: 'POST', }, + cancelSetupIntent: (id: string) => + { + url: `/stripe/setup-intent/${id}/cancel`, + method: 'POST', + }, createBankDonation: { url: '/donation/create-bank-payment', method: 'POST' }, synchronizeWithPayment: (id: string) => { url: `/donation/${id}/sync-with-payment`, method: 'PATCH' }, diff --git a/src/service/donation.ts b/src/service/donation.ts index e082652e6..dcb2c2431 100644 --- a/src/service/donation.ts +++ b/src/service/donation.ts @@ -12,6 +12,7 @@ import { SubscriptionPaymentInput, UpdateSetupIntentInput, UserDonationInput, + CancelSetupIntentInput, } from 'gql/donations' import { apiClient } from 'service/apiClient' import { endpoints } from 'service/apiEndpoints' @@ -21,6 +22,7 @@ import { useMutation } from '@tanstack/react-query' import { FilterData } from 'gql/types' import { PaymentMode } from 'components/client/donation-flow/helpers/types' import { Session } from 'next-auth' +import { SetupIntent } from '@stripe/stripe-js' export const createCheckoutSession = async (data: CheckoutSessionInput) => { return await apiClient.post>( @@ -59,6 +61,16 @@ export function useUpdateSetupIntent() { }) } +export function useCancelSetupIntent() { + return useMutation, AxiosError, CancelSetupIntentInput>({ + mutationFn: async ({ id }) => { + return await apiClient.patch>( + endpoints.donation.cancelSetupIntent(id).url, + ) + }, + }) +} + export function useCreateSubscriptionPayment() { const { data: session } = useSession() return useMutation(async (data: SubscriptionPaymentInput) => {