Files
frontend/app/(app)/_layout.tsx

55 lines
1.8 KiB
TypeScript
Raw Normal View History

import { useEffect, useState } from 'react';
import { ActivityIndicator, View } from 'react-native';
import { Redirect } from 'expo-router';
import { AppRouteStack } from '../../src/app-navigation/AppRouteStack';
import { messageManager, useAuthStore } from '../../src/stores';
import { useRegisterPushDevice } from '../../src/hooks';
import { hrefAuthLogin } from '../../src/navigation/hrefs';
import { useAppColors } from '../../src/theme';
export default function AppLayout() {
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
const fetchCurrentUser = useAuthStore((s) => s.fetchCurrentUser);
const userID = useAuthStore((s) => s.currentUser?.id);
const colors = useAppColors();
const [verified, setVerified] = useState(false);
useEffect(() => {
// 冷启动 token 校验:仅鉴权分组 (app) 需要。
// 公开页(/privacy、/terms和 (auth) 分组在根布局直接渲染,不受此校验影响,
// 因此冷启动 401 不会把公开页顶到 /login。
fetchCurrentUser().finally(() => setVerified(true));
}, [fetchCurrentUser]);
useRegisterPushDevice(isAuthenticated, userID);
useEffect(() => {
messageManager.initialize();
}, []);
// 持久化状态显示已登录则立即渲染(后台静默校验)
if (isAuthenticated) {
return <AppRouteStack />;
}
// 未登录且校验未完成,显示 loading
if (!verified) {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.background.default,
}}
>
<ActivityIndicator size="large" color={colors.primary.main} />
</View>
);
}
// 校验完成仍未登录,跳转登录页
return <Redirect href={hrefAuthLogin()} />;
}