Skip to content

Commit

Permalink
Add delete account functionality with server action
Browse files Browse the repository at this point in the history
  • Loading branch information
pheralb committed Mar 23, 2024
1 parent 493702f commit 70c14e6
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { Metadata } from "next";

import { auth } from "@/auth";
import UpdateNameAvatar from "@/components/settings/update-name-avatar";
import DeleteAccount from "@/components/settings/delete-account";
import { Button } from "@/ui/button";
import SettingsCard from "@/components/settings/card";

export const metadata: Metadata = {
title: "Settings - Dashboard",
Expand All @@ -13,13 +16,26 @@ const SettingsPage = async () => {
if (!session) return null;

return (
<main className="duration-500 animate-in fade-in-5 slide-in-from-bottom-2">
<main className="flex flex-col space-y-4 duration-500 animate-in fade-in-5 slide-in-from-bottom-2">
<UpdateNameAvatar
name={session.user.name!}
username={session.user.username!}
email={session.user.email!}
avatar={session.user.image!}
/>
<SettingsCard title="Account" description="Update your account settings:">
<div className="flex w-52 flex-col space-y-2">
<p>Delete account:</p>
<DeleteAccount
email={session.user.email!}
trigger={
<Button variant="destructive" size="sm">
Delete Account
</Button>
}
/>
</div>
</SettingsCard>
</main>
);
};
Expand Down
95 changes: 95 additions & 0 deletions src/components/settings/delete-account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"use client";

import { useState, type ReactNode } from "react";

import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/ui/dialog";
import { deleteProfile } from "@/server/actions/profile";
import { toast } from "sonner";
import { Input } from "@/ui/input";
import { LoaderIcon } from "lucide-react";
import { Button } from "@/ui/button";

interface DeleteAccountProps {
trigger: ReactNode;
email: string;
}

const DeleteAccount = (props: DeleteAccountProps) => {
const [confirmEmail, setConfirmEmail] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);

const handleDeleteAccount = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (confirmEmail !== props.email) {
toast.error("Email does not match.");
return;
}
setLoading(true);
toast.promise(deleteProfile, {
loading: "Deleting account...",
description: "Your account is being deleted.",
success: () => {
setLoading(false);
return `Your account has been deleted.`;
},
error: "Failed to delete account. Please try again or contact us.",
});
};

return (
<Dialog>
<DialogTrigger asChild>{props.trigger}</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Account</DialogTitle>
<DialogDescription>
<span className="text-red-500">This action cannot be undone.</span>{" "}
This will permanently delete your account and remove all links from
our servers.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleDeleteAccount}>
<div className="flex flex-col space-y-3">
<p className="text-sm">
To confirm, please type your email address:{" "}
<span className="font-mono">{props.email}</span>
</p>
<Input
type="email"
className="input"
onChange={(e) => setConfirmEmail(e.target.value)}
placeholder="Your email address"
disabled={loading}
/>
<DialogFooter className="mt-3">
<DialogClose asChild>
<Button variant="ghost" disabled={loading}>
Cancel
</Button>
</DialogClose>
<Button
disabled={loading || confirmEmail !== props.email}
type="submit"
variant="destructive"
>
{loading ?? <LoaderIcon size={16} className="animate-spin" />}
<span>{loading ? "Deleting..." : "Delete"}</span>
</Button>
</DialogFooter>
</div>
</form>
</DialogContent>
</Dialog>
);
};

export default DeleteAccount;

0 comments on commit 70c14e6

Please sign in to comment.