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

@@ -0,0 +1,183 @@
import { Colors } from '@/constants/Colors';
import { WeightHistoryItem } from '@/store/userSlice';
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import React, { useRef } from 'react';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Swipeable } from 'react-native-gesture-handler';
interface WeightRecordCardProps {
record: WeightHistoryItem;
onPress?: (record: WeightHistoryItem) => void;
onDelete?: (recordId: string) => void;
weightChange?: number;
}
export const WeightRecordCard: React.FC<WeightRecordCardProps> = ({
record,
onPress,
onDelete,
weightChange = 0
}) => {
const swipeableRef = useRef<Swipeable>(null);
// 处理删除操作
const handleDelete = () => {
Alert.alert(
'确认删除',
`确定要删除这条体重记录吗?此操作无法撤销。`,
[
{
text: '取消',
style: 'cancel',
},
{
text: '删除',
style: 'destructive',
onPress: () => {
const recordId = record.id || record.createdAt;
onDelete?.(recordId);
swipeableRef.current?.close();
},
},
]
);
};
// 渲染删除按钮
const renderRightActions = () => {
return (
<TouchableOpacity
style={styles.deleteButton}
onPress={handleDelete}
activeOpacity={0.8}
>
<Ionicons name="trash" size={20} color="#FFFFFF" />
<Text style={styles.deleteButtonText}></Text>
</TouchableOpacity>
);
};
return (
<Swipeable
ref={swipeableRef}
renderRightActions={renderRightActions}
rightThreshold={40}
overshootRight={false}
>
<TouchableOpacity
style={styles.recordCard}
onPress={() => onPress?.(record)}
activeOpacity={0.7}
>
<View style={styles.recordHeader}>
<Text style={styles.recordDateTime}>
{dayjs(record.createdAt).format('MM月DD日 HH:mm')}
</Text>
<TouchableOpacity
style={styles.recordEditButton}
onPress={() => onPress?.(record)}
>
<Ionicons name="create-outline" size={16} color="#FF9500" />
</TouchableOpacity>
</View>
<View style={styles.recordContent}>
<Text style={styles.recordWeightLabel}></Text>
<Text style={styles.recordWeightValue}>{record.weight}kg</Text>
{Math.abs(weightChange) > 0 && (
<View style={[
styles.weightChangeTag,
{ backgroundColor: weightChange < 0 ? '#E8F5E8' : '#FFF2E8' }
]}>
<Ionicons
name={weightChange < 0 ? "arrow-down" : "arrow-up"}
size={12}
color={weightChange < 0 ? Colors.light.accentGreen : '#FF9500'}
/>
<Text style={[
styles.weightChangeText,
{ color: weightChange < 0 ? Colors.light.accentGreen : '#FF9500' }
]}>
{Math.abs(weightChange).toFixed(1)}
</Text>
</View>
)}
</View>
</TouchableOpacity>
</Swipeable>
);
};
const styles = StyleSheet.create({
recordCard: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 20,
marginBottom: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.06,
shadowRadius: 8,
elevation: 2,
},
recordHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
recordDateTime: {
fontSize: 14,
color: '#687076',
fontWeight: '500',
},
recordEditButton: {
padding: 6,
borderRadius: 8,
backgroundColor: 'rgba(255, 149, 0, 0.1)',
},
recordContent: {
flexDirection: 'row',
alignItems: 'center',
},
recordWeightLabel: {
fontSize: 16,
color: '#687076',
fontWeight: '500',
},
recordWeightValue: {
fontSize: 18,
fontWeight: '700',
color: '#192126',
marginLeft: 4,
flex: 1,
},
weightChangeTag: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 12,
marginLeft: 12,
},
weightChangeText: {
fontSize: 12,
fontWeight: '600',
marginLeft: 2,
},
deleteButton: {
backgroundColor: '#EF4444',
justifyContent: 'center',
alignItems: 'center',
width: 80,
borderRadius: 16,
marginBottom: 12,
marginLeft: 8,
},
deleteButtonText: {
color: '#FFFFFF',
fontSize: 12,
fontWeight: '600',
marginTop: 4,
},
});