+
diff --git a/app/settings/page.tsx b/app/settings/page.tsx
new file mode 100644
index 0000000..4a4dd5a
--- /dev/null
+++ b/app/settings/page.tsx
@@ -0,0 +1,48 @@
+"use client";
+
+import { Page, PageTitle } from "@/components/Page";
+import { Button } from "@/components/ui/button";
+import { api } from "@/convex/_generated/api";
+import { useAuthActions } from "@convex-dev/auth/react";
+import { useMutation, useQuery } from "convex/react";
+import { redirect, useRouter } from "next/navigation";
+
+export default function Settings() {
+ const { signOut } = useAuthActions();
+ const deleteAccount = useMutation(api.users.deleteUserById);
+ const user = useQuery(api.users.getUserOrNull);
+
+ const router = useRouter();
+
+ const handleDelete = async () => {
+ if (confirm("Are you sure you want to delete your account?")) {
+ if (user) {
+ await signOut();
+ await deleteAccount({ userId: user._id });
+
+ router.push("/");
+ }
+ }
+ };
+
+ return (
+
+ Settings
+
+
Delete your account
+
+ If you delete your account, all of your data will be permanently
+ removed. This includes your game results, and your user information.
+ Any maps you created and that were approved will not be removed but
+ you will no longer be the creator of them. This action cannot be
+ undone.
+
+
+
+ Confirm
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/convex/users.ts b/convex/users.ts
index 396a284..932b42e 100644
--- a/convex/users.ts
+++ b/convex/users.ts
@@ -4,7 +4,7 @@ import {
customMutation,
customQuery,
} from "convex-helpers/server/customFunctions";
-import { ConvexError } from "convex/values";
+import { ConvexError, v } from "convex/values";
import { mutation, query } from "./_generated/server";
export const viewer = query({
@@ -118,3 +118,52 @@ export const authenticatedMutation = customMutation(
};
}),
);
+
+export const deleteUserById = authenticatedMutation({
+ handler: async (ctx, args) => {
+
+ const userId = ctx.userId;
+ if (userId === null) {
+ throw new ConvexError(SIGN_IN_ERROR_MESSAGE);
+ }
+
+ const userResults = await ctx.db
+ .query("userResults")
+ .filter((q) => q.eq(q.field("userId"), userId))
+ .collect();
+
+ const promises: Promise
[] = [];
+
+ for (const result of userResults) {
+ promises.push(ctx.db.delete(result._id));
+ }
+
+ const maps = await ctx.db
+ .query("maps")
+ .filter((q) => q.eq(q.field("submittedBy"), userId))
+ .collect();
+ for (const map of maps) {
+ promises.push(ctx.db.patch(map._id, { submittedBy: undefined }));
+ }
+
+ const authAccounts = await ctx.db.query("authAccounts").filter(q => q.eq(q.field("userId"), userId)).collect();
+
+ // Iterate over the queried documents and delete each one
+ for (const account of authAccounts) {
+ promises.push(ctx.db.delete(account._id));
+ }
+
+ const admin = await ctx.db
+ .query("admins")
+ .withIndex("by_userId", (q) => q.eq("userId", userId))
+ .first();
+
+ if (admin) {
+ promises.push(ctx.db.delete(admin._id));
+ }
+
+ promises.push(ctx.db.delete(userId));
+
+ await Promise.all(promises);
+ },
+});