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 <tukon479@gmail.com>
This commit is contained in:
Innei
2025-11-30 18:10:37 +08:00
parent 8f0e9e7fd7
commit f81b3d0ae9
3 changed files with 34 additions and 5 deletions

View File

@@ -28,6 +28,11 @@ export const authApi = {
async getSession(): Promise<SessionPayload | null> {
return await apiFetch<SessionPayload | null>('/api/auth/session')
},
async signOut(): Promise<void> {
await apiFetch('/api/auth/sign-out', {
method: 'POST',
})
},
async getSocialProviders(): Promise<SocialProvidersResponse> {
return await apiFetch<SocialProvidersResponse>('/api/auth/social/providers')
},

View File

@@ -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 = ({
</div>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => {
// TODO: Implement sign out
window.location.reload()
}}
onClick={handleSignOut}
icon={<i className="i-lucide-log-out text-base" />}
disabled={isSigningOut}
>
{t('action.signOut')}
</DropdownMenuItem>

View File

@@ -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()