Skip to content

Commit

Permalink
Added screen to request account deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
Dosbodoke committed Feb 7, 2025
1 parent 2229326 commit c9d6e24
Show file tree
Hide file tree
Showing 8 changed files with 4,120 additions and 878 deletions.
92 changes: 92 additions & 0 deletions app/[locale]/delete/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"use client";

import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";

import { deleteAccount } from "@/app/actions/deleteAccount";
import { LoadingIcon } from "@/assets";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import useSupabaseBrowser from "@/utils/supabase/client";

export default function DeleteAccountPage() {
const supabase = useSupabaseBrowser();
const [isDeleting, setIsDeleting] = useState(false);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const router = useRouter();
const t = useTranslations("deleteAccount");

const handleDeleteRequest = async () => {
setIsDeleting(true);
setError(null);

const result = await deleteAccount();

if (result.error) {
setError(result.error);
setIsDeleting(false);
} else if (result.success) {
// Show success message and redirect after a short delay
alert(t("successMessage"));
setTimeout(() => router.push("/"), 2000);
}
};

useEffect(() => {
async function setUsername() {
const {
data: { session },
} = await supabase.auth.getSession();

if (session) {
setLoading(false);
} else router.replace("/");
}
setUsername();
}, [router, supabase.auth]);

if (loading)
return (
<div className="grid h-full w-full place-items-center">
<div className="h-16 w-16">
<LoadingIcon className="animate-spin" />
</div>
</div>
);

return (
<div className="container mx-auto p-4">
<Card className="mx-auto max-w-md">
<CardHeader>
<CardTitle>{t("title")}</CardTitle>
<CardDescription>{t("description")}</CardDescription>
</CardHeader>
<CardContent>
<p className="mb-4 text-sm text-gray-500">{t("info")}</p>
{error && <p className="mb-4 text-sm text-red-500">{error}</p>}
</CardContent>
<CardFooter className="flex justify-end space-x-2">
<Button variant="outline" onClick={() => router.back()}>
{t("cancelButton")}
</Button>
<Button
variant="destructive"
onClick={handleDeleteRequest}
disabled={isDeleting}
>
{isDeleting ? t("processingButton") : t("deleteButton")}
</Button>
</CardFooter>
</Card>
</div>
);
}
51 changes: 51 additions & 0 deletions app/actions/deleteAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use server";

import { type CookieOptions, createServerClient } from "@supabase/ssr";
import { revalidatePath } from "next/cache";
import { cookies } from "next/headers";

import { Database } from "@/utils/supabase/database.types";

export async function deleteAccount() {
const cookieStore = await cookies();
const supabase = createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
cookieStore.set({ name, value, ...options });
},
remove(name: string, options: CookieOptions) {
cookieStore.set({ name, value: "", ...options });
},
},
}
);
const {
data: { user },
} = await supabase.auth.getUser();

if (!user) {
return { error: "User not authenticated" };
}

const { error } = await supabase
.from("profiles")
.update({ deletion_requested: new Date().toISOString() })
.eq("id", user.id);

if (error) {
console.error("Error marking account for deletion:", error);
return { error: "Failed to process deletion request" };
}

await supabase.auth.signOut();

revalidatePath("/");

return { success: true };
}
Loading

0 comments on commit c9d6e24

Please sign in to comment.