- Introduced new translation files for medication, personal, and weight management in Chinese. - Updated the main index file to include the new translation modules. - Enhanced the medication type definitions to include 'ointment'. - Refactored workout type labels to utilize i18n for better localization support. - Improved sleep quality descriptions and recommendations with i18n integration.
231 lines
5.9 KiB
TypeScript
231 lines
5.9 KiB
TypeScript
import { Colors } from '@/constants/Colors';
|
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
import { useI18n } from '@/hooks/useI18n';
|
|
import { WeightHistoryItem } from '@/store/userSlice';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import dayjs from 'dayjs';
|
|
import React, { useRef } from 'react';
|
|
import { Alert, Image, 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 { t } = useI18n();
|
|
const swipeableRef = useRef<Swipeable>(null);
|
|
const colorScheme = useColorScheme();
|
|
const themeColors = Colors[colorScheme ?? 'light'];
|
|
|
|
// 处理删除操作
|
|
const handleDelete = () => {
|
|
Alert.alert(
|
|
t('weightRecords.card.deleteConfirmTitle'),
|
|
t('weightRecords.card.deleteConfirmMessage'),
|
|
[
|
|
{
|
|
text: t('weightRecords.card.cancelButton'),
|
|
style: 'cancel',
|
|
},
|
|
{
|
|
text: t('weightRecords.card.deleteButton'),
|
|
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" />
|
|
</TouchableOpacity>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<View style={styles.cardContainer}>
|
|
<Swipeable
|
|
ref={swipeableRef}
|
|
renderRightActions={renderRightActions}
|
|
rightThreshold={40}
|
|
overshootRight={false}
|
|
>
|
|
<View style={styles.recordCard}>
|
|
<View style={styles.leftContent}>
|
|
<View style={styles.iconContainer}>
|
|
<Image
|
|
source={require('@/assets/images/icons/iconWeight.png')}
|
|
style={styles.icon}
|
|
/>
|
|
</View>
|
|
<View style={styles.textContent}>
|
|
<View style={styles.dateTimeContainer}>
|
|
<Text style={styles.dateText}>
|
|
{dayjs(record.createdAt).format('MM-DD')}
|
|
</Text>
|
|
<Text style={styles.timeText}>
|
|
{dayjs(record.createdAt).format('HH:mm')}
|
|
</Text>
|
|
</View>
|
|
<View style={styles.weightInfo}>
|
|
<Text style={styles.weightValue}>{record.weight}<Text style={styles.unitText}>{t('weightRecords.modal.unit')}</Text></Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.rightContent}>
|
|
{Math.abs(weightChange) > 0 && (
|
|
<View style={[
|
|
styles.changeTag,
|
|
{ backgroundColor: weightChange < 0 ? '#E8F5E8' : '#FFF2E8' }
|
|
]}>
|
|
<Ionicons
|
|
name={weightChange < 0 ? "arrow-down" : "arrow-up"}
|
|
size={10}
|
|
color={weightChange < 0 ? '#22C55E' : '#FF9500'}
|
|
/>
|
|
<Text style={[
|
|
styles.changeText,
|
|
{ color: weightChange < 0 ? '#22C55E' : '#FF9500' }
|
|
]}>
|
|
{Math.abs(weightChange).toFixed(1)}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
<TouchableOpacity
|
|
style={styles.editButton}
|
|
onPress={() => onPress?.(record)}
|
|
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
>
|
|
<Ionicons name="ellipsis-vertical" size={16} color="#9ba3c7" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</Swipeable>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
cardContainer: {
|
|
shadowColor: 'rgba(30, 41, 59, 0.08)',
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.12,
|
|
shadowRadius: 12,
|
|
elevation: 4,
|
|
},
|
|
recordCard: {
|
|
backgroundColor: '#ffffff',
|
|
borderRadius: 24,
|
|
padding: 16,
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
leftContent: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
flex: 1,
|
|
},
|
|
iconContainer: {
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: 22,
|
|
backgroundColor: '#F0F2F5',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginRight: 16,
|
|
},
|
|
icon: {
|
|
width: 24,
|
|
height: 24,
|
|
tintColor: '#4F5BD5',
|
|
},
|
|
textContent: {
|
|
justifyContent: 'center',
|
|
},
|
|
dateTimeContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 4,
|
|
},
|
|
dateText: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#1c1f3a',
|
|
marginRight: 8,
|
|
fontFamily: 'AliBold',
|
|
},
|
|
timeText: {
|
|
fontSize: 12,
|
|
color: '#6f7ba7',
|
|
fontFamily: 'AliRegular',
|
|
},
|
|
weightInfo: {
|
|
flexDirection: 'row',
|
|
alignItems: 'baseline',
|
|
},
|
|
weightValue: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: '#1c1f3a',
|
|
fontFamily: 'AliBold',
|
|
},
|
|
unitText: {
|
|
fontSize: 13,
|
|
fontWeight: '500',
|
|
color: '#6f7ba7',
|
|
marginLeft: 2,
|
|
fontFamily: 'AliRegular',
|
|
},
|
|
rightContent: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 12,
|
|
},
|
|
changeTag: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingHorizontal: 6,
|
|
paddingVertical: 2,
|
|
borderRadius: 8,
|
|
},
|
|
changeText: {
|
|
fontSize: 11,
|
|
fontWeight: '700',
|
|
marginLeft: 2,
|
|
fontFamily: 'AliBold',
|
|
},
|
|
editButton: {
|
|
padding: 4,
|
|
},
|
|
deleteButton: {
|
|
backgroundColor: '#FF6B6B',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
width: 70,
|
|
borderRadius: 24,
|
|
marginLeft: 12,
|
|
height: '100%',
|
|
},
|
|
}); |