Files
digital-pilates/components/statistic/CircumferenceCard.tsx

245 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { FloatingSelectionModal, SelectionItem } from '@/components/ui/FloatingSelectionModal';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { selectUserProfile, updateUserBodyMeasurements, UserProfile } from '@/store/userSlice';
import { router } from 'expo-router';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
interface CircumferenceCardProps {
style?: any;
}
const CircumferenceCard: React.FC<CircumferenceCardProps> = ({ style }) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const userProfile = useAppSelector(selectUserProfile);
console.log('userProfile', userProfile);
const { ensureLoggedIn } = useAuthGuard()
const [modalVisible, setModalVisible] = useState(false);
const [selectedMeasurement, setSelectedMeasurement] = useState<{
key: string;
label: string;
currentValue?: number;
} | null>(null);
const measurements = [
{
key: 'chestCircumference',
label: t('statistics.components.circumference.measurements.chest'),
value: userProfile?.chestCircumference,
},
{
key: 'waistCircumference',
label: t('statistics.components.circumference.measurements.waist'),
value: userProfile?.waistCircumference,
},
{
key: 'upperHipCircumference',
label: t('statistics.components.circumference.measurements.hip'),
value: userProfile?.upperHipCircumference,
},
{
key: 'armCircumference',
label: t('statistics.components.circumference.measurements.arm'),
value: userProfile?.armCircumference,
},
{
key: 'thighCircumference',
label: t('statistics.components.circumference.measurements.thigh'),
value: userProfile?.thighCircumference,
},
{
key: 'calfCircumference',
label: t('statistics.components.circumference.measurements.calf'),
value: userProfile?.calfCircumference,
},
];
// 根据不同围度类型获取合理的默认值
const getDefaultCircumferenceValue = (measurementKey: string, userProfile?: UserProfile): number => {
// 如果用户已有该围度数据,直接使用
const existingValue = userProfile?.[measurementKey as keyof UserProfile] as number;
if (existingValue) {
return existingValue;
}
// 根据性别设置合理的默认值
const isMale = userProfile?.gender === 'male';
switch (measurementKey) {
case 'chestCircumference':
// 胸围:男性 85-110cm女性 75-95cm
return isMale ? 95 : 80;
case 'waistCircumference':
// 腰围:男性 70-90cm女性 60-80cm
return isMale ? 80 : 70;
case 'upperHipCircumference':
// 上臀围:
return 30;
case 'armCircumference':
// 臂围:男性 25-35cm女性 20-30cm
return isMale ? 30 : 25;
case 'thighCircumference':
// 大腿围:男性 45-60cm女性 40-55cm
return isMale ? 50 : 45;
case 'calfCircumference':
// 小腿围:男性 30-40cm女性 25-35cm
return isMale ? 35 : 30;
default:
return 70; // 默认70cm
}
};
// Generate circumference options (30-150 cm)
const circumferenceOptions: SelectionItem[] = Array.from({ length: 121 }, (_, i) => {
const value = i + 30;
return {
label: `${value} cm`,
value: value,
};
});
const handleMeasurementPress = async (measurement: typeof measurements[0]) => {
const isLoggedIn = await ensureLoggedIn();
if (!isLoggedIn) {
// 如果未登录,用户会被重定向到登录页面
return;
}
// 使用智能默认值,如果用户已有数据则使用现有数据,否则使用基于性别的合理默认值
const defaultValue = getDefaultCircumferenceValue(measurement.key, userProfile);
setSelectedMeasurement({
key: measurement.key,
label: measurement.label,
currentValue: measurement.value || defaultValue,
});
setModalVisible(true);
};
const handleUpdateMeasurement = (value: string | number) => {
if (!selectedMeasurement) return;
const updateData = {
[selectedMeasurement.key]: Number(value),
};
dispatch(updateUserBodyMeasurements(updateData));
setModalVisible(false);
setSelectedMeasurement(null);
};
// 处理整个卡片点击,跳转到详情页
const handleCardPress = () => {
router.push('/circumference-detail');
};
return (
<TouchableOpacity
style={[styles.container, style]}
onPress={handleCardPress}
activeOpacity={0.8}
>
<Text style={styles.title}>{t('statistics.components.circumference.title')}</Text>
<View style={styles.measurementsContainer}>
{measurements.map((measurement, index) => (
<TouchableOpacity
key={index}
style={styles.measurementItem}
onPress={(e) => {
e.stopPropagation(); // 阻止事件冒泡
handleMeasurementPress(measurement);
}}
activeOpacity={0.7}
>
<Text style={styles.label}>{measurement.label}</Text>
<View style={styles.valueContainer}>
<Text style={styles.value}>
{measurement.value ? measurement.value.toString() : '--'}
</Text>
</View>
</TouchableOpacity>
))}
</View>
<FloatingSelectionModal
visible={modalVisible}
onClose={() => {
setModalVisible(false);
setSelectedMeasurement(null);
}}
title={selectedMeasurement ? t('statistics.components.circumference.setTitle', { label: selectedMeasurement.label }) : t('statistics.components.circumference.title')}
items={circumferenceOptions}
selectedValue={selectedMeasurement?.currentValue}
onValueChange={() => { }} // Real-time update not needed
onConfirm={handleUpdateMeasurement}
confirmButtonText={t('statistics.components.circumference.confirm')}
pickerHeight={180}
/>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 20,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.12,
shadowRadius: 12,
elevation: 6,
},
title: {
fontSize: 14,
fontWeight: '600',
color: '#192126',
marginBottom: 16,
fontFamily: 'AliBold',
},
measurementsContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
flexWrap: 'nowrap',
},
measurementItem: {
alignItems: 'center',
},
label: {
fontSize: 12,
color: '#888',
marginBottom: 8,
textAlign: 'center',
fontFamily: 'AliRegular',
},
valueContainer: {
backgroundColor: '#F5F5F7',
borderRadius: 10,
paddingHorizontal: 8,
paddingVertical: 6,
minWidth: 20,
alignItems: 'center',
justifyContent: 'center',
},
value: {
fontSize: 14,
fontWeight: '600',
color: '#192126',
textAlign: 'center',
fontFamily: 'AliBold',
},
});
export default CircumferenceCard;