feat: 更新隐私同意弹窗和应用名称

- 将应用名称修改为“每日普拉提”,提升品牌识别度
- 新增隐私同意弹窗,确保用户在使用应用前同意隐私政策
- 更新 Redux 状态管理,添加隐私同意状态的处理
- 优化用户信息页面,确保体重和身高的格式化显示
- 更新今日训练页面标题为“快速训练”,提升用户体验
- 添加开发工具函数,便于测试隐私同意功能
This commit is contained in:
2025-08-15 20:44:06 +08:00
parent 6b6c4fdbad
commit 97e89b9bf0
15 changed files with 326 additions and 26 deletions

View File

@@ -9,8 +9,8 @@ export type UserProfile = {
email?: string;
gender?: Gender;
birthDate?: string;
weight?: number;
height?: number;
weight?: string;
height?: string;
avatar?: string | null;
dailyStepsGoal?: number; // 每日步数目标(用于 Explore 页等)
dailyCaloriesGoal?: number; // 每日卡路里消耗目标
@@ -22,6 +22,7 @@ export type UserState = {
profile: UserProfile;
loading: boolean;
error: string | null;
privacyAgreed: boolean;
};
export const DEFAULT_MEMBER_NAME = '普拉提星球学员';
@@ -33,6 +34,7 @@ const initialState: UserState = {
},
loading: false,
error: null,
privacyAgreed: false,
};
export type LoginPayload = Record<string, any> & {
@@ -105,22 +107,30 @@ export const login = createAsyncThunk(
);
export const rehydrateUser = createAsyncThunk('user/rehydrate', async () => {
const [token, profileStr] = await Promise.all([
const [token, profileStr, privacyAgreedStr] = await Promise.all([
loadPersistedToken(),
AsyncStorage.getItem(STORAGE_KEYS.userProfile),
AsyncStorage.getItem(STORAGE_KEYS.privacyAgreed),
]);
await setAuthToken(token);
let profile: UserProfile = {};
if (profileStr) {
try { profile = JSON.parse(profileStr) as UserProfile; } catch { profile = {}; }
}
return { token, profile } as { token: string | null; profile: UserProfile };
const privacyAgreed = privacyAgreedStr === 'true';
return { token, profile, privacyAgreed } as { token: string | null; profile: UserProfile; privacyAgreed: boolean };
});
export const setPrivacyAgreed = createAsyncThunk('user/setPrivacyAgreed', async () => {
await AsyncStorage.setItem(STORAGE_KEYS.privacyAgreed, 'true');
return true;
});
export const logout = createAsyncThunk('user/logout', async () => {
await Promise.all([
AsyncStorage.removeItem(STORAGE_KEYS.authToken),
AsyncStorage.removeItem(STORAGE_KEYS.userProfile),
AsyncStorage.removeItem(STORAGE_KEYS.privacyAgreed),
]);
await setAuthToken(null);
return true;
@@ -176,6 +186,7 @@ const userSlice = createSlice({
.addCase(rehydrateUser.fulfilled, (state, action) => {
state.token = action.payload.token;
state.profile = action.payload.profile;
state.privacyAgreed = action.payload.privacyAgreed;
if (!state.profile?.name || !state.profile.name.trim()) {
state.profile.name = DEFAULT_MEMBER_NAME;
}
@@ -193,6 +204,10 @@ const userSlice = createSlice({
.addCase(logout.fulfilled, (state) => {
state.token = null;
state.profile = {};
state.privacyAgreed = false;
})
.addCase(setPrivacyAgreed.fulfilled, (state) => {
state.privacyAgreed = true;
});
},
});