mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
feat: delete user from db and unsubscribe from stripe
This commit is contained in:
@ -10,7 +10,13 @@
|
||||
"ghcr.io/devcontainers/features/node:1": {}
|
||||
},
|
||||
"onCreateCommand": "./.devcontainer/on-create.sh",
|
||||
"forwardPorts": [3000, 54320, 9000, 2500, 1100],
|
||||
"forwardPorts": [
|
||||
3000,
|
||||
54320,
|
||||
9000,
|
||||
2500,
|
||||
1100
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
@ -25,8 +31,8 @@
|
||||
"GitHub.copilot",
|
||||
"GitHub.vscode-pull-request-github",
|
||||
"Prisma.prisma",
|
||||
"VisualStudioExptTeam.vscodeintellicode",
|
||||
"VisualStudioExptTeam.vscodeintellicode"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { signOut } from 'next-auth/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
@ -65,6 +66,7 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
|
||||
const isSubmitting = form.formState.isSubmitting;
|
||||
|
||||
const { mutateAsync: updateProfile } = trpc.profile.updateProfile.useMutation();
|
||||
const { mutateAsync: deleteAccount } = trpc.profile.deleteAccount.useMutation();
|
||||
|
||||
const onFormSubmit = async ({ name, signature }: TProfileFormSchema) => {
|
||||
try {
|
||||
@ -98,6 +100,39 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onDeleteAccount = async () => {
|
||||
try {
|
||||
await deleteAccount();
|
||||
|
||||
await signOut({ callbackUrl: '/' });
|
||||
|
||||
toast({
|
||||
title: 'Account deleted',
|
||||
description: 'Your account has been deleted successfully.',
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
// logout after deleting account
|
||||
|
||||
router.push('/');
|
||||
} catch (err) {
|
||||
if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') {
|
||||
toast({
|
||||
title: 'An error occurred',
|
||||
description: err.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: 'An unknown error occurred',
|
||||
variant: 'destructive',
|
||||
description:
|
||||
'We encountered an unknown error while attempting to delete your account. Please try again later.',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
@ -171,12 +206,19 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
|
||||
<span className="font-semibold">all of your documents</span>, along with all of
|
||||
your completed documents, signatures, and all other resources belonging to your
|
||||
Account.
|
||||
<AlertDestructive />
|
||||
<Alert variant="destructive" className="mt-5">
|
||||
<AlertDescription className="selection:bg-red-100">
|
||||
This action is not reversible. Please be certain.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
||||
<AlertDialogAction
|
||||
onClick={onDeleteAccount}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
Delete Account
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
@ -189,12 +231,6 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export function AlertDestructive() {
|
||||
return (
|
||||
<Alert variant="destructive" className="mt-5">
|
||||
<AlertDescription className="selection:bg-red-100">
|
||||
This action is not reversible. Please be certain.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
// Cal.com Delete User TRPC = https://github.com/calcom/cal.com/blob/main/packages/trpc/server/routers/loggedInViewer/deleteMe.handler.ts#L11
|
||||
// https://github.com/calcom/cal.com/blob/main/packages/features/users/lib/userDeletionService.ts#L7
|
||||
// delete stripe: https://github.com/calcom/cal.com/blob/main/packages/app-store/stripepayment/lib/customer.ts#L72
|
||||
|
||||
10
packages/ee/server-only/stripe/delete-customer.ts
Normal file
10
packages/ee/server-only/stripe/delete-customer.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { stripe } from '@documenso/lib/server-only/stripe';
|
||||
import type { User } from '@documenso/prisma/client';
|
||||
|
||||
export const deleteStripeCustomer = async (user: User) => {
|
||||
if (!user.customerId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await stripe.customers.del(user.customerId);
|
||||
};
|
||||
@ -9,7 +9,7 @@ import SuperJSON from 'superjson';
|
||||
|
||||
import { getBaseUrl } from '@documenso/lib/universal/get-base-url';
|
||||
|
||||
import { AppRouter } from '../server/router';
|
||||
import type { AppRouter } from '../server/router';
|
||||
|
||||
export const trpc = createTRPCReact<AppRouter>({
|
||||
unstable_overrides: {
|
||||
|
||||
@ -10,3 +10,9 @@ export const ZSignUpMutationSchema = z.object({
|
||||
export type TSignUpMutationSchema = z.infer<typeof ZSignUpMutationSchema>;
|
||||
|
||||
export const ZVerifyPasswordMutationSchema = ZSignUpMutationSchema.pick({ password: true });
|
||||
|
||||
export const ZDeleteAccountMutationSchema = z.object({
|
||||
email: z.string().email(),
|
||||
});
|
||||
|
||||
export type TDeleteAccountMutationSchema = z.infer<typeof ZDeleteAccountMutationSchema>;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
|
||||
import { deleteStripeCustomer } from '@documenso/ee/server-only/stripe/delete-customer';
|
||||
import { deleteUser } from '@documenso/lib/server-only/user/delete-user';
|
||||
import { forgotPassword } from '@documenso/lib/server-only/user/forgot-password';
|
||||
import { getUserById } from '@documenso/lib/server-only/user/get-user-by-id';
|
||||
import { resetPassword } from '@documenso/lib/server-only/user/reset-password';
|
||||
@ -133,4 +135,27 @@ export const profileRouter = router({
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
deleteAccount: authenticatedProcedure.mutation(async ({ ctx }) => {
|
||||
try {
|
||||
const user = ctx.user;
|
||||
|
||||
const deletedUser = await deleteStripeCustomer(user);
|
||||
|
||||
console.log(deletedUser);
|
||||
|
||||
return await deleteUser(user);
|
||||
} catch (err) {
|
||||
let message = 'We were unable to delete your account. Please try again.';
|
||||
|
||||
if (err instanceof Error) {
|
||||
message = err.message;
|
||||
}
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user