diff --git a/backend/src/core/modules/auth/auth.repository.js b/backend/src/core/modules/auth/auth.repository.js index 1df2139..3ad754b 100644 --- a/backend/src/core/modules/auth/auth.repository.js +++ b/backend/src/core/modules/auth/auth.repository.js @@ -17,6 +17,10 @@ const PROFILE_SELECT = { banned_by: true, is_email_confirmed: true, created_at: true, + status: true, + roles: { + select: { name: true } + } }; diff --git a/backend/src/core/modules/auth/service/auth.service.js b/backend/src/core/modules/auth/service/auth.service.js index fb44310..acc3660 100644 --- a/backend/src/core/modules/auth/service/auth.service.js +++ b/backend/src/core/modules/auth/service/auth.service.js @@ -338,6 +338,8 @@ class Service { ? { planName: user.subscriptions.plan_name ?? null } : undefined, createdAt: user.created_at ?? undefined, + status: user.status ?? 'ACTIVE', + roleName: user.roles?.name || (Array.isArray(user.roles) ? user.roles[0]?.name : null) || 'USER' }; } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fc125be..290ced7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,13 +4,14 @@ import { Agentation } from 'agentation' import { ThemeProvider } from '@/app/providers/theme-provider' import AutoScrollToTop from '@/components/scroll/auto-scroll-to-top' +import { authApi } from '@/core/services/auth.service' import { scheduleTokenRefresh } from '@/core/shared/auth-refresh' import { getAccessTokenFromLS } from '@/core/shared/storage' import { useAuthStore } from '@/core/store/features/auth/authStore' import useRoutesElements from '@/hooks/routes/use-router-element' +import { type Account } from '@/models/interface/auth.interface' import '@/styles/theme.css' -import { useUserInfo } from './hooks/tanstack-query/auth/use-query-auth' import { type UserRole } from './models/user/types' const AppContent = () => { @@ -22,21 +23,22 @@ const App = () => { const [isAppLoading, setIsAppLoading] = useState(true) const logout = useAuthStore((state) => state.logout) const updateUser = useAuthStore((state) => state.updateUser) - const { data: userData } = useUserInfo() - useEffect(() => { const initializeApp = async () => { const accessToken = getAccessTokenFromLS() if (accessToken) { try { + const userData = await authApi.getUserInfo() as Account + const currentUser = useAuthStore.getState().user updateUser({ - userId: userData?.id || '', - fullName: userData?.fullName || '', - email: userData?.email || '', - phone: userData?.phone || '', - location: userData?.location || '', - avatarUrl: userData?.avatarUrl || '', - roleName: userData?.roleName as UserRole + userId: userData.id || '', + fullName: userData.fullName || '', + email: userData.email || '', + phone: userData.phone || '', + location: userData.location || '', + avatarUrl: userData.avatarUrl || '', + roleName: userData.roleName as UserRole || currentUser?.roleName || 'USER', + status: userData.status || currentUser?.status || 'ACTIVE' }) scheduleTokenRefresh() } catch (error: any) { @@ -50,7 +52,7 @@ const App = () => { } initializeApp() - }, [logout, updateUser, userData?.avatarUrl, userData?.email, userData?.fullName, userData?.id, userData?.location, userData?.phone, userData?.roleName]) + }, [logout, updateUser]) if (isAppLoading) { return ( diff --git a/frontend/src/core/services/axios-client.ts b/frontend/src/core/services/axios-client.ts index a372e78..6ed098e 100644 --- a/frontend/src/core/services/axios-client.ts +++ b/frontend/src/core/services/axios-client.ts @@ -83,11 +83,12 @@ axiosClient.interceptors.response.use( controllers.delete(response.config.url) } - // Check if response indicates user is banned + // Check if response indicates user is banned (only for auth/profile endpoints of the current user) const dataObj = response.data as any const user = dataObj?.data?.user || dataObj?.user const userStatus = user?.status || dataObj?.data?.status || dataObj?.status - if (userStatus === 'BANNED' || userStatus === 'banned') { + const isAuthRequestUrl = response.config.url && response.config.url.includes('/auth/') + if (isAuthRequestUrl && (userStatus === 'BANNED' || userStatus === 'banned')) { handleBannedUser( user?.banReason || dataObj?.data?.banReason || dataObj?.banReason, user?.bannedAt || dataObj?.data?.bannedAt || dataObj?.bannedAt @@ -100,17 +101,19 @@ axiosClient.interceptors.response.use( async (error) => { const originalRequest = error.config - // Check if error response indicates user is banned + // Check if error response indicates user is banned (only for auth/profile endpoints of the current user) const errorStatus = error.response?.status const errorData = error.response?.data as any const errorMessage = errorData?.message || '' + const isAuthRequestUrl = originalRequest?.url && originalRequest.url.includes('/auth/') if ( - errorStatus === 403 || + isAuthRequestUrl && + (errorStatus === 403 || errorStatus === 401 || errorMessage.toLowerCase().includes('banned') || errorData?.status === 'BANNED' || - errorData?.status === 'banned' + errorData?.status === 'banned') ) { if ( errorMessage.toLowerCase().includes('banned') || diff --git a/frontend/src/hooks/tanstack-query/auth/use-query-auth.ts b/frontend/src/hooks/tanstack-query/auth/use-query-auth.ts index 29802c6..b8f3c78 100644 --- a/frontend/src/hooks/tanstack-query/auth/use-query-auth.ts +++ b/frontend/src/hooks/tanstack-query/auth/use-query-auth.ts @@ -30,6 +30,7 @@ export const useLoginAuth = () => { mutationFn: (data: Account) => authApi.login(data), onSuccess: (response: LoginApiResponse) => { const user = response.data?.user + console.log(user) const userStatus = user?.status || 'ACTIVE' if (userStatus === 'ACTIVE') { @@ -145,6 +146,7 @@ export const useUserInfo = () => { if (query.data) { // Map Account to UserResponseType structure const account = query.data + const currentUser = useAuthStore.getState().user updateUser({ userId: account.id || '', fullName: account.fullName || '', @@ -152,7 +154,8 @@ export const useUserInfo = () => { phone: account.phone, location: account.location, avatarUrl: account.avatarUrl, - roleName: account.roleName as UserRole + roleName: account.roleName as UserRole || currentUser?.roleName || 'USER', + status: account.status || currentUser?.status || 'ACTIVE' }) } }, [query.data, updateUser]) diff --git a/frontend/src/hooks/users/use-users.ts b/frontend/src/hooks/users/use-users.ts index 71d466e..cfc9e05 100644 --- a/frontend/src/hooks/users/use-users.ts +++ b/frontend/src/hooks/users/use-users.ts @@ -72,12 +72,13 @@ export const useDeleteUser = () => { } export const useBanUser = () => { - // const queryClient = useQueryClient() + const queryClient = useQueryClient() return useMutation({ mutationKey: [MUTATION_KEYS.banUser], mutationFn: ({ id, reason }: { id: string; reason: string }) => usersApi.banUser(id, reason), onSuccess: () => { toastifyCommon.success('Khóa tài khoản thành công') + queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.users] }) }, onError: (error) => { handleError(error, 'Khóa tài khoản thất bại') @@ -86,11 +87,13 @@ export const useBanUser = () => { } export const useUnbanUser = () => { + const queryClient = useQueryClient() return useMutation({ mutationKey: [MUTATION_KEYS.unbanUser], mutationFn: ({ id, reason }: { id: string; reason: string }) => usersApi.unbanUser(id, reason), onSuccess: () => { toastifyCommon.success('Kích hoạt tài khoản thành công') + queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.users] }) }, onError: (error) => { handleError(error, 'Kích hoạt tài khoản thất bại')