refactor(coach): 重构教练组件,统一导入并简化UI实现与类型定义
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user