feat(personal): 持久化开发者模式状态并优化登录后数据加载
- 新增 kv-store 持久化开发者模式开关,避免每次冷启动丢失 - 登录成功后立即拉取用户资料,减少首页空数据闪烁 - 修复体重卡片在未登录时重复请求的问题 - 移除 ActivityHeatMap 与 userSlice 中的调试日志 - useAuthGuard 增加 token 调试输出(临时)
This commit is contained in:
@@ -8,6 +8,7 @@ import { useNotifications } from '@/hooks/useNotifications';
|
|||||||
import { DEFAULT_MEMBER_NAME, fetchActivityHistory, fetchMyProfile } from '@/store/userSlice';
|
import { DEFAULT_MEMBER_NAME, fetchActivityHistory, fetchMyProfile } from '@/store/userSlice';
|
||||||
import { log } from '@/utils/logger';
|
import { log } from '@/utils/logger';
|
||||||
import { getNotificationEnabled, setNotificationEnabled as saveNotificationEnabled } from '@/utils/userPreferences';
|
import { getNotificationEnabled, setNotificationEnabled as saveNotificationEnabled } from '@/utils/userPreferences';
|
||||||
|
import { getItem, setItem } from '@/utils/kvStore';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
|
|
||||||
import { useFocusEffect } from '@react-navigation/native';
|
import { useFocusEffect } from '@react-navigation/native';
|
||||||
@@ -54,6 +55,8 @@ export default function PersonalScreen() {
|
|||||||
dispatch(fetchActivityHistory());
|
dispatch(fetchActivityHistory());
|
||||||
// 加载用户推送偏好设置
|
// 加载用户推送偏好设置
|
||||||
loadNotificationPreference();
|
loadNotificationPreference();
|
||||||
|
// 加载开发者模式状态
|
||||||
|
loadDeveloperModeState();
|
||||||
}, [dispatch])
|
}, [dispatch])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -67,6 +70,27 @@ export default function PersonalScreen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 加载开发者模式状态
|
||||||
|
const loadDeveloperModeState = async () => {
|
||||||
|
try {
|
||||||
|
const enabled = await getItem('developer_mode_enabled');
|
||||||
|
if (enabled === 'true') {
|
||||||
|
setShowDeveloperSection(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载开发者模式状态失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存开发者模式状态
|
||||||
|
const saveDeveloperModeState = async (enabled: boolean) => {
|
||||||
|
try {
|
||||||
|
await setItem('developer_mode_enabled', enabled.toString());
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存开发者模式状态失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 数据格式化函数
|
// 数据格式化函数
|
||||||
const formatHeight = () => {
|
const formatHeight = () => {
|
||||||
if (userProfile.height == null) return '--';
|
if (userProfile.height == null) return '--';
|
||||||
@@ -89,9 +113,10 @@ export default function PersonalScreen() {
|
|||||||
// 显示名称
|
// 显示名称
|
||||||
const displayName = (userProfile.name?.trim()) ? userProfile.name : DEFAULT_MEMBER_NAME;
|
const displayName = (userProfile.name?.trim()) ? userProfile.name : DEFAULT_MEMBER_NAME;
|
||||||
|
|
||||||
// 初始化时加载推送偏好设置
|
// 初始化时加载推送偏好设置和开发者模式状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadNotificationPreference();
|
loadNotificationPreference();
|
||||||
|
loadDeveloperModeState();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 处理用户名连续点击
|
// 处理用户名连续点击
|
||||||
@@ -110,6 +135,7 @@ export default function PersonalScreen() {
|
|||||||
// 检查是否有3次连续点击
|
// 检查是否有3次连续点击
|
||||||
if (clickTimestamps.current.length >= 3) {
|
if (clickTimestamps.current.length >= 3) {
|
||||||
setShowDeveloperSection(true);
|
setShowDeveloperSection(true);
|
||||||
|
saveDeveloperModeState(true); // 持久化保存开发者模式状态
|
||||||
clickTimestamps.current = []; // 清空点击记录
|
clickTimestamps.current = []; // 清空点击记录
|
||||||
log.info('开发者模式已激活');
|
log.info('开发者模式已激活');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default function ExploreScreen() {
|
|||||||
|
|
||||||
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
||||||
|
|
||||||
|
|
||||||
// 使用 dayjs:当月日期与默认选中"今天"
|
// 使用 dayjs:当月日期与默认选中"今天"
|
||||||
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
||||||
// const tabBarHeight = useBottomTabBarHeight();
|
// const tabBarHeight = useBottomTabBarHeight();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { PRIVACY_POLICY_URL, USER_AGREEMENT_URL } from '@/constants/Agree';
|
|||||||
import { Colors } from '@/constants/Colors';
|
import { Colors } from '@/constants/Colors';
|
||||||
import { useAppDispatch } from '@/hooks/redux';
|
import { useAppDispatch } from '@/hooks/redux';
|
||||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||||
import { login } from '@/store/userSlice';
|
import { fetchMyProfile, login } from '@/store/userSlice';
|
||||||
import Toast from 'react-native-toast-message';
|
import Toast from 'react-native-toast-message';
|
||||||
|
|
||||||
export default function LoginScreen() {
|
export default function LoginScreen() {
|
||||||
@@ -113,6 +113,9 @@ export default function LoginScreen() {
|
|||||||
}
|
}
|
||||||
await dispatch(login({ appleIdentityToken: identityToken })).unwrap();
|
await dispatch(login({ appleIdentityToken: identityToken })).unwrap();
|
||||||
|
|
||||||
|
// 拉取用户信息
|
||||||
|
await dispatch(fetchMyProfile())
|
||||||
|
|
||||||
Toast.show({
|
Toast.show({
|
||||||
text1: '登录成功',
|
text1: '登录成功',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|||||||
@@ -100,8 +100,6 @@ const ActivityHeatMap = () => {
|
|||||||
return weeks;
|
return weeks;
|
||||||
}, [generateActivityData, weeksToShow]);
|
}, [generateActivityData, weeksToShow]);
|
||||||
|
|
||||||
console.log('organizeDataByWeeks', organizeDataByWeeks);
|
|
||||||
|
|
||||||
|
|
||||||
// 获取月份标签(简化的月份标签系统)
|
// 获取月份标签(简化的月份标签系统)
|
||||||
const getMonthLabels = useMemo(() => {
|
const getMonthLabels = useMemo(() => {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function WeightHistoryCard() {
|
|||||||
const [showBMIModal, setShowBMIModal] = useState(false);
|
const [showBMIModal, setShowBMIModal] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const { pushIfAuthedElseLogin } = useAuthGuard();
|
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
const themeColors = Colors[colorScheme ?? 'light'];
|
const themeColors = Colors[colorScheme ?? 'light'];
|
||||||
|
|
||||||
@@ -42,14 +42,12 @@ export function WeightHistoryCard() {
|
|||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasWeight) {
|
|
||||||
loadWeightHistory();
|
loadWeightHistory();
|
||||||
}
|
}, [userProfile?.weight, isLoggedIn]);
|
||||||
}, [userProfile?.weight]);
|
|
||||||
|
|
||||||
const loadWeightHistory = async () => {
|
const loadWeightHistory = async () => {
|
||||||
try {
|
try {
|
||||||
await dispatch(fetchWeightHistory() as any);
|
await dispatch(fetchWeightHistory() as any).unwrap();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载体重历史失败:', error);
|
console.error('加载体重历史失败:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export function useAuthGuard() {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const currentPath = usePathname();
|
const currentPath = usePathname();
|
||||||
const token = useAppSelector((s) => (s as any)?.user?.token as string | null);
|
const token = useAppSelector((s) => (s as any)?.user?.token as string | null);
|
||||||
|
|
||||||
|
console.log('useAuthGuard!!!token', token);
|
||||||
|
|
||||||
const isLoggedIn = !!token;
|
const isLoggedIn = !!token;
|
||||||
|
|
||||||
const ensureLoggedIn = useCallback(async (options?: EnsureOptions): Promise<boolean> => {
|
const ensureLoggedIn = useCallback(async (options?: EnsureOptions): Promise<boolean> => {
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ export const fetchMyProfile = createAsyncThunk('user/fetchMyProfile', async (_,
|
|||||||
try {
|
try {
|
||||||
// 固定使用后端文档的接口:/api/users/info
|
// 固定使用后端文档的接口:/api/users/info
|
||||||
const data: any = await api.get('/api/users/info');
|
const data: any = await api.get('/api/users/info');
|
||||||
console.log('fetchMyProfile', data);
|
|
||||||
const profile: UserProfile = (data as any).profile ?? (data as any).user ?? (data as any).account ?? (data as any);
|
const profile: UserProfile = (data as any).profile ?? (data as any).user ?? (data as any).account ?? (data as any);
|
||||||
await AsyncStorage.setItem(STORAGE_KEYS.userProfile, JSON.stringify(profile ?? {}));
|
await AsyncStorage.setItem(STORAGE_KEYS.userProfile, JSON.stringify(profile ?? {}));
|
||||||
return profile;
|
return profile;
|
||||||
|
|||||||
Reference in New Issue
Block a user