fix(frontend): account menu still showing after logout (#10143)

### Changes 🏗️

<img width="800" alt="Screenshot 2025-06-10 at 14 21 48"
src="https://github.com/user-attachments/assets/d0dba02d-049d-446c-9a25-0f7cec9108bc"
/>

When logging out, I'm redirected to the `/login` page but the account
menu is still visible (however I'm not longer logged out). Refreshing
the page fixes it.

The problem was that `supabase.logOut()` is a client side action, and
`<Navbar />` is a RSC who fetchs the session on the server to display
the state and does not know on the client it was invalidated.
`router.refresh()` solves the issue by forcing RSC on the page to
refetch their state and update server side. Further reading
[here](https://nextjs.org/docs/app/deep-dive/caching#invalidation-1).

I also improved the UX awaiting the promise and displaying a spinner
while the log out action is happening. If logout fails ( _should be very
rare_ ) I'm displaying a toast to not let the user be hanging wondering
what happened.

### Checklist 📋

#### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
  - [x] Login
  - [x] Open account menu
  - [x] Click `Logout`
  - [x] I see a spinner while the action is happening
- [x] I'm redirected to `/login` and I no longer see the account menu
This commit is contained in:
Ubbe
2025-06-11 08:49:56 +04:00
committed by GitHub
parent 1e89bf5c37
commit 8028a766b1

View File

@@ -1,22 +1,57 @@
"use client";
import useSupabase from "@/lib/supabase/useSupabase";
import { IconLogOut } from "@/components/ui/icons";
import { useTransition } from "react";
import { LoadingSpinner } from "../ui/loading";
import { cn } from "@/lib/utils";
import { useRouter } from "next/navigation";
import { toast } from "../ui/use-toast";
import * as Sentry from "@sentry/nextjs";
export const ProfilePopoutMenuLogoutButton = () => {
export function ProfilePopoutMenuLogoutButton() {
const router = useRouter();
const [isPending, startTransition] = useTransition();
const supabase = useSupabase();
function handleLogout() {
startTransition(async () => {
try {
await supabase.logOut();
router.refresh();
} catch (e) {
Sentry.captureException(e);
toast({
title: "Error logging out",
description:
"Something went wrong when logging out. Please try again. If the problem persists, please contact support.",
variant: "destructive",
});
}
});
}
return (
<div
className="inline-flex w-full items-center justify-start gap-2.5"
onClick={() => supabase.logOut()}
className={cn(
"inline-flex w-full items-center justify-start gap-2.5",
isPending && "justify-center",
)}
onClick={handleLogout}
role="button"
tabIndex={0}
>
<div className="relative h-6 w-6">
<IconLogOut className="h-6 w-6" />
</div>
<div className="font-sans text-base font-medium leading-normal text-neutral-800 dark:text-neutral-200">
Log out
</div>
{isPending ? (
<LoadingSpinner className="size-5" />
) : (
<>
<div className="relative h-6 w-6">
<IconLogOut className="h-6 w-6" />
</div>
<div className="font-sans text-base font-medium leading-normal text-neutral-800 dark:text-neutral-200">
Log out
</div>
</>
)}
</div>
);
};
}