实现了完整的应用引导功能,包括: - 新增引导页面UI,包含健康数据追踪、轻断食计划和健康挑战三个介绍页面 - 添加引导状态持久化存储,使用AsyncStorage管理用户完成状态 - 修改应用启动逻辑,根据引导状态决定跳转到主页或引导页 - 在开发者选项中添加重置引导状态功能,方便测试 - 更新路由配置和存储键常量,统一管理引导相关配置
152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
import AsyncStorage from '@/utils/kvStore';
|
|
import { usePathname, useRouter } from 'expo-router';
|
|
import { useCallback } from 'react';
|
|
import { Alert } from 'react-native';
|
|
|
|
import { ROUTES } from '@/constants/Routes';
|
|
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
|
import { STORAGE_KEYS, api } from '@/services/api';
|
|
import { logout as logoutAction } from '@/store/userSlice';
|
|
|
|
type RedirectParams = Record<string, string | number | boolean | undefined>;
|
|
|
|
type EnsureOptions = {
|
|
redirectTo?: string;
|
|
redirectParams?: RedirectParams;
|
|
};
|
|
|
|
export function useAuthGuard() {
|
|
const router = useRouter();
|
|
const dispatch = useAppDispatch();
|
|
const currentPath = usePathname();
|
|
const user = useAppSelector(state => state.user);
|
|
|
|
const isLoggedIn = !!user?.profile?.id;
|
|
|
|
const ensureLoggedIn = useCallback(async (options?: EnsureOptions): Promise<boolean> => {
|
|
if (isLoggedIn) return true;
|
|
|
|
const redirectTo = options?.redirectTo ?? currentPath ?? ROUTES.TAB_STATISTICS;
|
|
const paramsJson = options?.redirectParams ? JSON.stringify(options.redirectParams) : undefined;
|
|
|
|
router.push({
|
|
pathname: '/auth/login',
|
|
params: {
|
|
redirectTo,
|
|
...(paramsJson ? { redirectParams: paramsJson } : {}),
|
|
},
|
|
} as any);
|
|
return false;
|
|
}, [isLoggedIn, router, currentPath]);
|
|
|
|
const pushIfAuthedElseLogin = useCallback((pathname: string, params?: RedirectParams) => {
|
|
if (isLoggedIn) {
|
|
router.push({ pathname, params } as any);
|
|
return;
|
|
}
|
|
const paramsJson = params ? JSON.stringify(params) : undefined;
|
|
router.push({ pathname: '/auth/login', params: { redirectTo: pathname, ...(paramsJson ? { redirectParams: paramsJson } : {}) } } as any);
|
|
}, [isLoggedIn, router]);
|
|
|
|
const guardHandler = useCallback(
|
|
<T extends any[]>(fn: (...args: T) => any | Promise<any>, options?: EnsureOptions) => {
|
|
return async (...args: T) => {
|
|
const ok = await ensureLoggedIn(options);
|
|
if (!ok) return;
|
|
return fn(...args);
|
|
};
|
|
},
|
|
[ensureLoggedIn]
|
|
);
|
|
|
|
// 退出登录功能
|
|
const handleLogout = useCallback(async () => {
|
|
try {
|
|
// 调用 Redux action 清除本地状态和缓存
|
|
await dispatch(logoutAction()).unwrap();
|
|
|
|
// 跳转到登录页面
|
|
router.push('/auth/login');
|
|
} catch (error) {
|
|
console.error('退出登录失败:', error);
|
|
Alert.alert('错误', '退出登录失败,请稍后重试');
|
|
}
|
|
}, [dispatch, router]);
|
|
|
|
// 带确认对话框的退出登录
|
|
const confirmLogout = useCallback(() => {
|
|
Alert.alert(
|
|
'确认退出',
|
|
'确定要退出当前账号吗?',
|
|
[
|
|
{
|
|
text: '取消',
|
|
style: 'cancel',
|
|
},
|
|
{
|
|
text: '确定',
|
|
style: 'default',
|
|
onPress: handleLogout,
|
|
},
|
|
]
|
|
);
|
|
}, [handleLogout]);
|
|
|
|
// 注销账号功能
|
|
const handleDeleteAccount = useCallback(async () => {
|
|
try {
|
|
// 调用注销账号API
|
|
await api.delete('/api/users/delete-account');
|
|
|
|
// 清除额外的本地数据
|
|
await AsyncStorage.multiRemove(['@user_personal_info', STORAGE_KEYS.onboardingCompleted]);
|
|
|
|
// 执行退出登录逻辑
|
|
await dispatch(logoutAction()).unwrap();
|
|
|
|
Alert.alert('账号已注销', '您的账号已成功注销', [
|
|
{
|
|
text: '确定',
|
|
onPress: () => router.push('/auth/login'),
|
|
},
|
|
]);
|
|
} catch (error: any) {
|
|
console.error('注销账号失败:', error);
|
|
const message = error?.message || '注销失败,请稍后重试';
|
|
Alert.alert('注销失败', message);
|
|
}
|
|
}, [dispatch, router]);
|
|
|
|
// 带确认对话框的注销账号
|
|
const confirmDeleteAccount = useCallback(() => {
|
|
Alert.alert(
|
|
'确认注销账号',
|
|
'此操作不可恢复,将删除您的账号及相关数据。确定继续吗?',
|
|
[
|
|
{
|
|
text: '取消',
|
|
style: 'cancel',
|
|
},
|
|
{
|
|
text: '确认注销',
|
|
style: 'destructive',
|
|
onPress: handleDeleteAccount,
|
|
},
|
|
],
|
|
{ cancelable: true }
|
|
);
|
|
}, [handleDeleteAccount]);
|
|
|
|
return {
|
|
isLoggedIn,
|
|
ensureLoggedIn,
|
|
pushIfAuthedElseLogin,
|
|
guardHandler,
|
|
handleLogout,
|
|
confirmLogout,
|
|
handleDeleteAccount,
|
|
confirmDeleteAccount,
|
|
} as const;
|
|
}
|
|
|