crush-level-web/src/hooks/auth.ts

204 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
authService,
CheckNicknameRequest,
CompleteUserInfoRequest,
UpdateUserInfoRequest,
type LoginRequest,
type LoginResponse,
} from '@/services/auth';
import { authKeys, userKeys } from '@/lib/query-keys';
import { tokenManager } from '@/lib/auth/token';
import { toast } from 'sonner';
import type { ApiError } from '@/types/api';
import { useRouter } from 'next/navigation';
import { userService } from '@/services/user';
export function useLogin() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: LoginRequest): Promise<LoginResponse> => authService.login(data),
onSuccess: (response: LoginResponse) => {
console.log('useLogin onSuccess save token', response.token);
// 保存token到cookie
tokenManager.setToken(response.token);
// 刷新当前用户信息
queryClient.invalidateQueries({
queryKey: authKeys.currentUser(),
});
},
});
}
export function useToken() {
return {
isLogin: tokenManager.isAuthenticated(),
token: tokenManager.getToken(),
getLoginStatus: () => {
return tokenManager.isAuthenticated();
},
};
}
export function useLogout() {
const queryClient = useQueryClient();
const router = useRouter();
return useMutation({
mutationFn: () => authService.logout(),
onSuccess: () => {
// 清除token
tokenManager.removeToken();
// 显示成功提示
toast.success('Log out successful!');
// 清除所有查询缓存
queryClient.clear();
router.push('/');
},
onError: (error: ApiError) => {
// 即使登出接口失败也要清除本地token
tokenManager.removeToken();
queryClient.clear();
// 跳转到登录页
router.push('/');
},
});
}
export function useCurrentUser() {
return useQuery({
queryKey: authKeys.currentUser(),
queryFn: () => authService.getCurrentUser(),
// 只有在有token的情况下才请求
enabled: tokenManager.isAuthenticated(),
// 如果获取用户信息失败,根据错误码处理
retry: (failureCount, error: ApiError) => {
// 如果是认证相关错误不重试并清除token
if (
error.errorCode === 'AUTH_TOKEN_EXPIRED' ||
error.errorCode === 'AUTH_TOKEN_INVALID' ||
error.errorCode === 'AUTH_UNAUTHORIZED'
) {
tokenManager.removeToken();
return false;
}
return failureCount < 1;
},
staleTime: 60 * 1000, // 60秒后缓存过期
});
}
export function useCompleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CompleteUserInfoRequest) => authService.completeUserInfo(data),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: authKeys.currentUser(),
});
},
});
}
export function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: UpdateUserInfoRequest) => authService.updateUserInfo(data),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: authKeys.currentUser(),
});
},
});
}
export function useDeleteUser() {
const queryClient = useQueryClient();
const router = useRouter();
return useMutation({
mutationFn: () => authService.deleteUser(),
onSuccess: () => {
tokenManager.removeToken();
queryClient.clear();
router.push('/login');
},
});
}
// 注册功能暂未实现,保留接口定义
export function useRegister() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: any) => {
// TODO: 实现注册接口
throw new Error('注册功能暂未实现');
},
onSuccess: (response: LoginResponse) => {
// 注册成功后自动登录
tokenManager.setToken(response.token);
toast.success('Successful registration!');
queryClient.invalidateQueries({
queryKey: authKeys.currentUser(),
});
},
onError: (error: ApiError) => {
console.error('注册失败:', {
errorCode: error.errorCode,
errorMsg: error.errorMsg,
traceId: error.traceId,
});
toast.error('Registration failed.', {
description: error.errorMsg || '请稍后重试',
});
},
});
}
// 检查是否已登录的hook
export function useIsAuthenticated() {
return tokenManager.isAuthenticated();
}
export function useCheckNickname({ onError }: { onError?: (error: ApiError) => void }) {
return useMutation({
mutationFn: (data: CheckNicknameRequest) => authService.checkNickname(data),
onError: onError,
});
}
export function useCheckText() {
return useMutation({
mutationFn: async (data: { content: string }) => {
const result = await authService.checkText(data);
if (result) {
return `We found some words that might not be allowed: ${result}`;
}
return '';
},
});
}
export function useUserNoticeStat() {
return useQuery({
queryKey: userKeys.noticeStat(),
queryFn: () => userService.getUserNoticeStat(),
enabled: tokenManager.isAuthenticated(),
});
}
export function useUserNoticeListInfinite(pageSize: number = 20, enabled: boolean = true) {
return useInfiniteQuery({
queryKey: userKeys.noticeList({ page: { pn: 1, ps: pageSize } }),
queryFn: ({ pageParam = 1 }) =>
userService.getUserNoticeList({ page: { pn: pageParam, ps: pageSize } }),
getNextPageParam: (lastPage, allPages) => {
const totalPages = Math.ceil((lastPage.tc || 0) / pageSize);
const nextPage = allPages.length + 1;
return nextPage <= totalPages ? nextPage : undefined;
},
initialPageParam: 1,
enabled, // 只有在启用时才执行查询
});
}