Files
digital-pilates/components/TaskProgressCard.tsx
richarjiang 3f89023447 feat: 更新 CLAUDE.md 文件及多个组件以优化用户体验和功能
- 更新 CLAUDE.md 文件,重构架构部分,增加认证和数据层的描述
- 在 GoalsScreen 中新增目标模板选择功能,支持用户选择和创建目标
- 在 CreateGoalModal 中添加初始数据支持,优化目标创建体验
- 新增 GoalTemplateModal 组件,提供目标模板选择界面
- 更新 NotificationHelpers,支持构建深度链接以便于导航
- 在 CoachScreen 中处理路由参数,增强用户交互体验
- 更新多个组件的样式和逻辑,提升整体用户体验
- 删除不再使用的中文回复规则文档
2025-08-26 15:04:04 +08:00

168 lines
4.2 KiB
TypeScript

import { TaskListItem } from '@/types/goals';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useRouter } from 'expo-router';
import React, { ReactNode } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
interface TaskProgressCardProps {
tasks: TaskListItem[];
headerButtons?: ReactNode;
}
export const TaskProgressCard: React.FC<TaskProgressCardProps> = ({
tasks,
headerButtons,
}) => {
const router = useRouter();
// 计算各状态的任务数量
const pendingTasks = tasks.filter(task => task.status === 'pending');
const completedTasks = tasks.filter(task => task.status === 'completed');
const skippedTasks = tasks.filter(task => task.status === 'skipped');
// 处理跳转到目标列表
const handleNavigateToGoals = () => {
router.push('/goals-list');
};
return (
<View style={styles.container}>
{/* 标题区域 */}
<View style={styles.header}>
<View style={styles.titleContainer}>
<Text style={styles.title}></Text>
<TouchableOpacity
style={styles.goalsIconButton}
onPress={handleNavigateToGoals}
>
<MaterialIcons name="flag" size={18} color="#7A5AF8" />
</TouchableOpacity>
</View>
<View style={styles.headerActions}>
{headerButtons && (
<View style={styles.headerButtons}>
{headerButtons}
</View>
)}
</View>
</View>
{/* 状态卡片区域 */}
<View style={styles.statusCards}>
{/* 待完成 卡片 */}
<View style={styles.statusCard}>
<View style={styles.cardHeader}>
<MaterialIcons name="pending" size={16} color="#7A5AF8" />
<Text style={styles.cardLabel} numberOfLines={1}></Text>
</View>
<Text style={styles.cardCount}>{pendingTasks.length}</Text>
</View>
{/* 已完成 卡片 */}
<View style={styles.statusCard}>
<View style={styles.cardHeader}>
<MaterialIcons name="check-circle" size={16} color="#10B981" />
<Text style={styles.cardLabel} numberOfLines={1}></Text>
</View>
<Text style={styles.cardCount}>{completedTasks.length}</Text>
</View>
{/* 已跳过 卡片 */}
<View style={styles.statusCard}>
<View style={styles.cardHeader}>
<MaterialIcons name="skip-next" size={16} color="#F59E0B" />
<Text style={styles.cardLabel} numberOfLines={1}></Text>
</View>
<Text style={styles.cardCount}>{skippedTasks.length}</Text>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 20,
marginHorizontal: 20,
marginBottom: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4,
},
header: {
marginBottom: 20,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
titleContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
headerButtons: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
headerActions: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
goalsIconButton: {
},
title: {
fontSize: 20,
fontWeight: '700',
lineHeight: 24,
height: 24,
color: '#1F2937',
marginBottom: 4,
},
subtitle: {
fontSize: 14,
color: '#6B7280',
fontWeight: '400',
},
statusCards: {
flexDirection: 'row',
justifyContent: 'space-between',
gap: 8,
},
statusCard: {
flex: 1,
backgroundColor: '#FFFFFF',
borderRadius: 12,
padding: 12,
borderWidth: 1,
borderColor: '#E5E7EB',
alignItems: 'flex-start',
minHeight: 80,
},
cardHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
gap: 6,
flexWrap: 'wrap',
},
cardLabel: {
fontSize: 11,
fontWeight: '500',
color: '#1F2937',
lineHeight: 14,
},
cardCount: {
fontSize: 24,
fontWeight: '700',
color: '#1F2937',
},
});