refactor(coach): 重构教练组件,统一导入并简化UI实现与类型定义

This commit is contained in:
richarjiang
2025-08-28 09:46:14 +08:00
parent ba2d829e02
commit 5a59508b88
17 changed files with 2400 additions and 866 deletions

View File

@@ -1,7 +1,8 @@
import { api, loadPersistedToken, setAuthToken, STORAGE_KEYS } from '@/services/api';
import { updateUser, UpdateUserDto } from '@/services/users';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { createAsyncThunk, createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
import dayjs from 'dayjs';
export type Gender = 'male' | 'female' | '';
@@ -24,6 +25,7 @@ export type UserProfile = {
};
export type WeightHistoryItem = {
id: string; // 添加 id 字段用于删除和更新操作
weight: string;
source: string;
createdAt: string;
@@ -211,6 +213,32 @@ export const updateUserProfile = createAsyncThunk(
}
);
// 删除体重记录
export const deleteWeightRecord = createAsyncThunk(
'user/deleteWeightRecord',
async (recordId: string, { rejectWithValue }) => {
try {
await api.delete(`/api/users/weight-records/${recordId}`);
return recordId;
} catch (err: any) {
return rejectWithValue(err?.message ?? '删除体重记录失败');
}
}
);
// 更新体重记录
export const updateWeightRecord = createAsyncThunk(
'user/updateWeightRecord',
async ({ id, weight }: { id: string; weight: number }, { rejectWithValue }) => {
try {
const data = await api.put<WeightHistoryItem>(`/api/users/weight-records/${id}`, { weight });
return data;
} catch (err: any) {
return rejectWithValue(err?.message ?? '更新体重记录失败');
}
}
);
const userSlice = createSlice({
name: 'user',
initialState,
@@ -286,9 +314,54 @@ const userSlice = createSlice({
})
.addCase(updateUserProfile.rejected, (state, action) => {
state.error = (action.payload as string) ?? '更新用户资料失败';
})
.addCase(deleteWeightRecord.fulfilled, (state, action) => {
state.weightHistory = state.weightHistory.filter(record =>
record.id !== action.payload && record.createdAt !== action.payload
);
})
.addCase(deleteWeightRecord.rejected, (state, action) => {
state.error = (action.payload as string) ?? '删除体重记录失败';
})
.addCase(updateWeightRecord.fulfilled, (state, action) => {
const index = state.weightHistory.findIndex(record =>
record.id === action.payload.id || record.createdAt === action.payload.id
);
if (index !== -1) {
state.weightHistory[index] = { ...state.weightHistory[index], ...action.payload };
}
})
.addCase(updateWeightRecord.rejected, (state, action) => {
state.error = (action.payload as string) ?? '更新体重记录失败';
});
},
});
export const { updateProfile, setDailyStepsGoal, setDailyCaloriesGoal, setPilatesPurposes } = userSlice.actions;
// Selectors
export const selectUserProfile = (state: { user: UserState }) => state.user.profile;
// 计算用户年龄的 selector
export const selectUserAge = createSelector(
[selectUserProfile],
(profile) => {
if (!profile?.birthDate) return null;
const birthDate = dayjs(profile.birthDate);
const today = dayjs();
// 计算精确年龄(考虑月份和日期)
let age = today.year() - birthDate.year();
// 如果今年的生日还没到年龄减1
if (today.month() < birthDate.month() ||
(today.month() === birthDate.month() && today.date() < birthDate.date())) {
age--;
}
return age;
}
);
export default userSlice.reducer;