From 65cd718703ad365e10721c20d904c222615c55af Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 23 Oct 2023 17:24:45 -0400 Subject: [PATCH 01/13] chore: created the delete account section in the user settings page --- .../UserSettingsPage/user-settings-page.tsx | 92 ++++++++++++------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index eccb8d7220..99a851b7b3 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -32,6 +32,7 @@ type EmailPreferenceType = { display_email?: boolean; receive_collaboration?: boolean; }; + const UserSettingsPage = ({ user }: userSettingsPageProps) => { const { data: insightsUser, mutate } = useFetchUser(user?.user_metadata.user_name, { revalidateOnFocus: false, @@ -389,44 +390,71 @@ const UserSettingsPage = ({ user }: userSettingsPageProps) => { {userInfo && ( -
- {!hasReports && !coupon ? ( -
-
- -
- Upgrade to a subscription to gain access to generate custom reports! -
-
- - - {!coupon && } -
- ) : ( -
+ <> +
+ {!hasReports && !coupon ? (
- -
- - You are currently subscribed to the Pro plan and currently have access to all premium - features. - + +
+ Upgrade to a subscription to gain access to generate custom reports!
- + + + {!coupon && } +
+ ) : ( +
+
+
+ +
+ + You are currently subscribed to the Pro plan and currently have access to all premium + features. + +
+
+ +
+
+ )} +
+
+
+ +
+ + Please note that account deletion is irreversible. Proceed only if you are certain about this + action. +
- )} -
+ + + )}
From 7c3e44cb23d798889334af54122a376d373fa3b4 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 23 Oct 2023 17:28:04 -0400 Subject: [PATCH 02/13] chore: wip delete account API route --- pages/api/delete-account.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 pages/api/delete-account.ts diff --git a/pages/api/delete-account.ts b/pages/api/delete-account.ts new file mode 100644 index 0000000000..c42c9fa635 --- /dev/null +++ b/pages/api/delete-account.ts @@ -0,0 +1,30 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { supabase } from "lib/utils/supabase"; + +// Create a Next.js API route that receives in the request body, an action and user_id field to delete an account where the action is delete_account and the user_id is the user_id of the user to delete. +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== "POST") { + res.status(405).json({ + message: "Method not allowed", + }); + } + + const sessionResponse = await supabase.auth.getSession(); + + if (!sessionResponse.data.session) { + res.status(401).json({ + message: "Unauthorized", + }); + } else { + try { + console.log(`delete ${sessionResponse.data.session.user.id}`); + // TODO: actually delete account + + res.redirect("/?account-deleted"); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + }); + } + } +} From 79e080646ec35f8d41fb62103d17d694dc37db0e Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 24 Oct 2023 11:21:37 -0400 Subject: [PATCH 03/13] chore: updated styles of delete account button --- components/organisms/UserSettingsPage/user-settings-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index 99a851b7b3..7db22dba81 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -448,7 +448,7 @@ const UserSettingsPage = ({ user }: userSettingsPageProps) => { type="submit" rel="noopener noreferrer" target="_blank" - className="w-max border-dark-red-8 bg-dark-red-8 text-white hover:bg-white hover:text-dark-red-8" + className="w-max border-dark-red-8 bg-dark-red-8 text-white hover:border-dark-red-7 hover:bg-dark-red-7" variant="primary" > Delete Account From ce0a5b8461cd4deeae56c3f53e9cbb1d3a690ec0 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 24 Oct 2023 17:58:41 -0400 Subject: [PATCH 04/13] chore: beginnings of form action to delete user --- pages/api/delete-account.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pages/api/delete-account.ts b/pages/api/delete-account.ts index c42c9fa635..c27654d478 100644 --- a/pages/api/delete-account.ts +++ b/pages/api/delete-account.ts @@ -1,7 +1,6 @@ import { NextApiRequest, NextApiResponse } from "next"; -import { supabase } from "lib/utils/supabase"; +import { createPagesServerClient } from "@supabase/auth-helpers-nextjs"; -// Create a Next.js API route that receives in the request body, an action and user_id field to delete an account where the action is delete_account and the user_id is the user_id of the user to delete. export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") { res.status(405).json({ @@ -9,18 +8,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); } - const sessionResponse = await supabase.auth.getSession(); + const supabaseServerClient = createPagesServerClient({ + req, + res, + }); + const { + data: { user }, + } = await supabaseServerClient.auth.getUser(); - if (!sessionResponse.data.session) { + if (!user) { res.status(401).json({ message: "Unauthorized", }); } else { try { - console.log(`delete ${sessionResponse.data.session.user.id}`); - // TODO: actually delete account + supabaseServerClient.auth.signOut(); - res.redirect("/?account-deleted"); + res.redirect("/account-deleted"); } catch (error) { res.status(500).json({ message: "Internal server error", From c82dbc9fe09c937a91e5bb453697672f2aadbdca Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 24 Oct 2023 17:58:59 -0400 Subject: [PATCH 05/13] chore: small tweaks to account deleted confirmed page --- pages/account-deleted.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pages/account-deleted.tsx diff --git a/pages/account-deleted.tsx b/pages/account-deleted.tsx new file mode 100644 index 0000000000..fc66cb230f --- /dev/null +++ b/pages/account-deleted.tsx @@ -0,0 +1,23 @@ +import TopNav from "components/organisms/TopNav/top-nav"; + +const AccountDeletedPage = () => { + return ( +
+ +
+
+

Account Deleted

+

Your account has been deleted.

+
+
+
+ ); +}; + +export default AccountDeletedPage; + +/** + * Add intermediate modal, clarify what's gonna happen. + * Hover state, subtle background color change. + * Add survey for future. + */ From a879c236747017d267770ea2afaf025fa9a9f77f Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 24 Oct 2023 22:59:51 -0400 Subject: [PATCH 06/13] chore: added delete account confirm dialog --- .../UserSettingsPage/user-settings-page.tsx | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index 7db22dba81..5876f366f9 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -22,6 +22,7 @@ import { useFetchUser } from "lib/hooks/useFetchUser"; import { getInterestOptions } from "lib/utils/getInterestOptions"; import { useToast } from "lib/hooks/useToast"; import { validateTwitterUsername } from "lib/utils/validate-twitter-username"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "components/molecules/Dialog/dialog"; import CouponForm from "./coupon-form"; interface userSettingsPageProps { @@ -33,7 +34,50 @@ type EmailPreferenceType = { receive_collaboration?: boolean; }; +interface DeleteAccountModalProps { + open: boolean; + setOpen: (open: boolean) => void; + onDelete: () => void; +} + +const DeleteAccountModal = ({ open, setOpen, onDelete }: DeleteAccountModalProps) => { + return ( + + + + Delete Account + +
+ Are you sure you want to delete your account? +
+ + +
+
+
+
+ ); +}; + const UserSettingsPage = ({ user }: userSettingsPageProps) => { + const [isModalOpen, setIsModalOpen] = useState(false); + const deleteFormRef = useRef(null); const { data: insightsUser, mutate } = useFetchUser(user?.user_metadata.user_name, { revalidateOnFocus: false, }); @@ -434,6 +478,11 @@ const UserSettingsPage = ({ user }: userSettingsPageProps) => { action="/api/delete-account" method="POST" className="flex flex-col order-first gap-6 md:order-last" + ref={deleteFormRef} + onSubmit={(e) => { + setIsModalOpen(true); + e.preventDefault(); + }} >
@@ -453,6 +502,14 @@ const UserSettingsPage = ({ user }: userSettingsPageProps) => { > Delete Account + { + setIsModalOpen(false); + deleteFormRef.current?.submit(); + }} + /> )} From 708ca2a43bf08bdad63124d8790dc5817f2db915 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 24 Oct 2023 23:01:47 -0400 Subject: [PATCH 07/13] chore: style tweeks to dialog --- components/organisms/UserSettingsPage/user-settings-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index 5876f366f9..3ff18a3067 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -45,7 +45,7 @@ const DeleteAccountModal = ({ open, setOpen, onDelete }: DeleteAccountModalProps - Delete Account + Delete Account
Are you sure you want to delete your account? From f81c72b96751405748a1b8b3e31f08efe6accca7 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Thu, 26 Oct 2023 15:27:11 -0400 Subject: [PATCH 08/13] chore: added type DELETE to confirm --- .../UserSettingsPage/user-settings-page.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index 3ff18a3067..a0ba501869 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -41,6 +41,9 @@ interface DeleteAccountModalProps { } const DeleteAccountModal = ({ open, setOpen, onDelete }: DeleteAccountModalProps) => { + const [confirmText, setConfirmText] = useState(""); + const disabled = confirmText !== "DELETE"; + return ( @@ -49,6 +52,14 @@ const DeleteAccountModal = ({ open, setOpen, onDelete }: DeleteAccountModalProps
Are you sure you want to delete your account? + + Type DELETE in all caps to confirm + + { + setConfirmText(e.target.value); + }} + />
From c101029d630818e3ffbe34f268d49adde36e960d Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Fri, 27 Oct 2023 08:51:28 -0400 Subject: [PATCH 09/13] chore: now user is signed out via middleware when they are deleted --- middleware.ts | 9 +++++++++ pages/api/delete-account.ts | 39 ++++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/middleware.ts b/middleware.ts index b5d43c52bc..864fb5d67b 100644 --- a/middleware.ts +++ b/middleware.ts @@ -12,6 +12,7 @@ const pathsToMatch = [ "/feed/", "/user/notifications", "/user/settings", + "/account-deleted" ]; export async function middleware(req: NextRequest) { @@ -28,6 +29,14 @@ export async function middleware(req: NextRequest) { data: { session }, } = await supabase.auth.getSession(); + if (session?.user && req.nextUrl.pathname === "/account-deleted") { + // Delete the account from Supabase and log the user out. + await supabase.auth.admin.deleteUser(session.user.id); + await supabase.auth.signOut(); + + return res; + } + // Check auth condition if (session?.user || req.nextUrl.searchParams.has("login")) { // Authentication successful, forward request to protected route. diff --git a/pages/api/delete-account.ts b/pages/api/delete-account.ts index c27654d478..dc674cd2a6 100644 --- a/pages/api/delete-account.ts +++ b/pages/api/delete-account.ts @@ -1,5 +1,6 @@ import { NextApiRequest, NextApiResponse } from "next"; import { createPagesServerClient } from "@supabase/auth-helpers-nextjs"; +import { fetchApiData } from "helpers/fetchApiData"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") { @@ -12,23 +13,33 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) req, res, }); - const { - data: { user }, - } = await supabaseServerClient.auth.getUser(); - if (!user) { - res.status(401).json({ - message: "Unauthorized", - }); - } else { - try { - supabaseServerClient.auth.signOut(); + try { + const { + data: { session }, + } = await supabaseServerClient.auth.getSession(); + + if (session) { + const { error } = await fetchApiData({ + path: "/profile", + method: "DELETE", + bearerToken: session.access_token, + pathValidator: () => true, + }); - res.redirect("/account-deleted"); - } catch (error) { - res.status(500).json({ - message: "Internal server error", + if (error) { + throw error; + } + } else { + res.status(401).json({ + message: "Unauthorized", }); } + + res.redirect("/account-deleted"); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + }); } } From 86993e0ca680fbf2b5a52890b66dcd84e60127ad Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Fri, 27 Oct 2023 08:51:53 -0400 Subject: [PATCH 10/13] chore: removed unnecessary comment --- pages/account-deleted.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pages/account-deleted.tsx b/pages/account-deleted.tsx index fc66cb230f..a07c9688b1 100644 --- a/pages/account-deleted.tsx +++ b/pages/account-deleted.tsx @@ -15,9 +15,3 @@ const AccountDeletedPage = () => { }; export default AccountDeletedPage; - -/** - * Add intermediate modal, clarify what's gonna happen. - * Hover state, subtle background color change. - * Add survey for future. - */ From 494d0f44ac70a090bc537af18fbf24d2713af3a9 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Fri, 27 Oct 2023 09:03:07 -0400 Subject: [PATCH 11/13] chore: added some style to h1 for now since no base styles --- pages/account-deleted.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/account-deleted.tsx b/pages/account-deleted.tsx index a07c9688b1..0de2ea4d2b 100644 --- a/pages/account-deleted.tsx +++ b/pages/account-deleted.tsx @@ -6,7 +6,7 @@ const AccountDeletedPage = () => {
-

Account Deleted

+

Account Deleted

Your account has been deleted.

From fbe0cd5e6dec3ff4cf0e1dfe43700a96b6b1b69d Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 31 Oct 2023 09:33:05 -0400 Subject: [PATCH 12/13] chore: removed unnecessary props from a button --- components/organisms/UserSettingsPage/user-settings-page.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/organisms/UserSettingsPage/user-settings-page.tsx b/components/organisms/UserSettingsPage/user-settings-page.tsx index 2f326b270b..928e8225b6 100644 --- a/components/organisms/UserSettingsPage/user-settings-page.tsx +++ b/components/organisms/UserSettingsPage/user-settings-page.tsx @@ -63,8 +63,6 @@ const DeleteAccountModal = ({ open, setOpen, onDelete }: DeleteAccountModalProps