diff --git a/apps/web/components/integrations/DisconnectIntegration.tsx b/apps/web/components/integrations/DisconnectIntegration.tsx index 4506c41a1f..c4aabc705c 100644 --- a/apps/web/components/integrations/DisconnectIntegration.tsx +++ b/apps/web/components/integrations/DisconnectIntegration.tsx @@ -6,6 +6,8 @@ import showToast from "@calcom/lib/notification"; import { ButtonBaseProps } from "@calcom/ui/Button"; import { Dialog } from "@calcom/ui/Dialog"; +import { trpc } from "@lib/trpc"; + import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; export default function DisconnectIntegration(props: { @@ -14,32 +16,23 @@ export default function DisconnectIntegration(props: { render: (renderProps: ButtonBaseProps) => JSX.Element; onOpenChange: (isOpen: boolean) => unknown | Promise; }) { + const { id } = props; const { t } = useLocale(); const [modalOpen, setModalOpen] = useState(false); - const mutation = useMutation( - async () => { - const res = await fetch("/api/integrations", { - method: "DELETE", - body: JSON.stringify({ id: props.id }), - headers: { - "Content-Type": "application/json", - }, - }); - if (!res.ok) { - throw new Error("Something went wrong"); - } - return res.json(); + + const mutation = trpc.useMutation("viewer.deleteCredential", { + onSettled: async () => { + await props.onOpenChange(modalOpen); }, - { - async onSettled() { - await props.onOpenChange(modalOpen); - }, - onSuccess(data) { - showToast(data.message, "success"); - setModalOpen(false); - }, - } - ); + onSuccess: () => { + showToast("Integration deleted successfully", "success"); + setModalOpen(false); + }, + onError: () => { + throw new Error("Something went wrong"); + }, + }); + return ( <> @@ -49,7 +42,7 @@ export default function DisconnectIntegration(props: { confirmBtnText={t("yes_remove_app")} cancelBtnText="Cancel" onConfirm={() => { - mutation.mutate(); + mutation.mutate({ id }); }}> {t("are_you_sure_you_want_to_remove_this_app")} diff --git a/apps/web/ee/lib/stripe/server.ts b/apps/web/ee/lib/stripe/server.ts index 8cc083ebb4..6796946bb0 100644 --- a/apps/web/ee/lib/stripe/server.ts +++ b/apps/web/ee/lib/stripe/server.ts @@ -151,6 +151,27 @@ export async function refund( } } +export const closePayments = async (paymentIntentId: string, stripeAccount: string) => { + try { + // Expire all current sessions + const sessions = await stripe.checkout.sessions.list( + { + payment_intent: paymentIntentId, + }, + { stripeAccount } + ); + for (const session of sessions.data) { + await stripe.checkout.sessions.expire(session.id, { stripeAccount }); + } + // Then cancel the payment intent + await stripe.paymentIntents.cancel(paymentIntentId, { stripeAccount }); + return; + } catch (e) { + console.error(e); + return; + } +}; + async function handleRefundError(opts: { event: CalendarEvent; reason: string; paymentId: string }) { console.error(`refund failed: ${opts.reason} for booking '${opts.event.uid}'`); await sendOrganizerPaymentRefundFailedEmail({ diff --git a/apps/web/pages/apps/installed.tsx b/apps/web/pages/apps/installed.tsx index 2aff1516a0..6976ea1d6d 100644 --- a/apps/web/pages/apps/installed.tsx +++ b/apps/web/pages/apps/installed.tsx @@ -21,7 +21,6 @@ import Shell, { ShellSubHeading } from "@components/Shell"; import SkeletonLoader from "@components/apps/SkeletonLoader"; import { CalendarListContainer } from "@components/integrations/CalendarListContainer"; import DisconnectIntegration from "@components/integrations/DisconnectIntegration"; -import DisconnectStripeIntegration from "@components/integrations/DisconnectStripeIntegration"; import IntegrationListItem from "@components/integrations/IntegrationListItem"; import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections"; @@ -42,7 +41,7 @@ function ConnectOrDisconnectIntegrationButton(props: { if (credentialId) { if (type === "stripe_payment") { return ( - (