From f81b3d0ae9e820349b4be26b2b9a293f041b1628 Mon Sep 17 00:00:00 2001 From: Innei Date: Sun, 30 Nov 2025 18:10:37 +0800 Subject: [PATCH] feat: implement sign-out functionality in auth API and user menu - Added a signOut method to the auth API for handling user sign-out requests. - Integrated sign-out functionality in the UserMenuButton component, updating session state and invalidating queries upon successful sign-out. Signed-off-by: Innei --- apps/web/src/lib/api/auth.ts | 5 ++++ .../gallery/PageHeader/PageHeaderRight.tsx | 25 +++++++++++++++---- .../modules/platform/auth/auth.controller.ts | 9 +++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/web/src/lib/api/auth.ts b/apps/web/src/lib/api/auth.ts index 7f8f014a..812d3105 100644 --- a/apps/web/src/lib/api/auth.ts +++ b/apps/web/src/lib/api/auth.ts @@ -28,6 +28,11 @@ export const authApi = { async getSession(): Promise { return await apiFetch('/api/auth/session') }, + async signOut(): Promise { + await apiFetch('/api/auth/sign-out', { + method: 'POST', + }) + }, async getSocialProviders(): Promise { return await apiFetch('/api/auth/social/providers') }, diff --git a/apps/web/src/modules/gallery/PageHeader/PageHeaderRight.tsx b/apps/web/src/modules/gallery/PageHeader/PageHeaderRight.tsx index 3e0aff84..843f1ae6 100644 --- a/apps/web/src/modules/gallery/PageHeader/PageHeaderRight.tsx +++ b/apps/web/src/modules/gallery/PageHeader/PageHeaderRight.tsx @@ -5,7 +5,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '@afilmory/ui' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' @@ -251,8 +251,25 @@ const UserMenuButton = ({ user: { id: string; name?: string | null; image?: string | null; role?: string | null } }) => { const { t } = useTranslation() + const setSessionUser = useSetAtom(sessionUserAtom) + const queryClient = useQueryClient() + const [isSigningOut, setIsSigningOut] = useState(false) const isAdmin = user.role === 'admin' || user.role === 'superadmin' + const handleSignOut = async () => { + if (isSigningOut) return + setIsSigningOut(true) + try { + await authApi.signOut() + setSessionUser(null) + await queryClient.invalidateQueries({ queryKey: ['session'] }) + } catch (error) { + console.error('Sign out failed:', error) + } finally { + setIsSigningOut(false) + } + } + // 如果是 admin,点击头像直接导航到 dashboard if (isAdmin) { return ( @@ -285,11 +302,9 @@ const UserMenuButton = ({ { - // TODO: Implement sign out - window.location.reload() - }} + onClick={handleSignOut} icon={} + disabled={isSigningOut} > {t('action.signOut')} diff --git a/be/apps/core/src/modules/platform/auth/auth.controller.ts b/be/apps/core/src/modules/platform/auth/auth.controller.ts index 24afed51..1593c3d5 100644 --- a/be/apps/core/src/modules/platform/auth/auth.controller.ts +++ b/be/apps/core/src/modules/platform/auth/auth.controller.ts @@ -161,6 +161,15 @@ export class AuthController { } } + @AllowPlaceholderTenant() + @Post('/sign-out') + @SkipTenantGuard() + async signOut(@ContextParam() context: Context) { + const auth = await this.auth.getAuth() + const { headers } = context.req.raw + return await auth.api.signOut({ headers, asResponse: true }) + } + @AllowPlaceholderTenant() @Get('/social/providers') @BypassResponseTransform()