diff --git a/apps/mobile/src/app/(tabs)/goals.tsx b/apps/mobile/src/app/(tabs)/goals.tsx index db94423..d6c8acc 100644 --- a/apps/mobile/src/app/(tabs)/goals.tsx +++ b/apps/mobile/src/app/(tabs)/goals.tsx @@ -256,7 +256,12 @@ export default function GoalsScreen() { {showAnalytics && ( - + {statistics.weeklyTrend.length > 0 && ( void; - onComplete?: () => void; - onDelete?: () => void; + goal: FitnessGoal; + onPress?: () => void; + onComplete?: () => void; + onDelete?: () => void; } -export function GoalProgressCard({ goal, onPress, onComplete, onDelete }: GoalProgressCardProps) { - const isCompleted = goal.status === 'completed'; - const progress = goal.progress || 0; +export function GoalProgressCard({ + goal, + onPress, + onComplete, + onDelete, +}: GoalProgressCardProps) { + const { colors, typography } = useTheme(); + const isCompleted = goal.status === "completed"; + const progress = (goal.progress || 0) / 100; // Convert to 0-1 scale - // Calculate days remaining - const daysRemaining = goal.targetDate - ? Math.ceil((new Date(goal.targetDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24)) - : null; + // Calculate days remaining + const daysRemaining = goal.targetDate + ? Math.ceil( + (new Date(goal.targetDate).getTime() - Date.now()) / + (1000 * 60 * 60 * 24), + ) + : null; - const getGoalTypeIcon = (type: string) => { - switch (type) { - case 'weight_target': return 'scale-outline'; - case 'strength_milestone': return 'barbell-outline'; - case 'endurance_target': return 'bicycle-outline'; - case 'flexibility_goal': return 'body-outline'; - case 'habit_building': return 'calendar-outline'; - default: return 'flag-outline'; - } - }; + const getGoalTypeIcon = (type: string) => { + switch (type) { + case "weight_target": + return "scale-outline"; + case "strength_milestone": + return "barbell-outline"; + case "endurance_target": + return "bicycle-outline"; + case "flexibility_goal": + return "body-outline"; + case "habit_building": + return "calendar-outline"; + default: + return "flag-outline"; + } + }; - const getPriorityGradient = (priority: string): readonly [string, string] => { - switch (priority) { - case 'high': return theme.gradients.danger; - case 'medium': return theme.gradients.warning; - case 'low': return theme.gradients.success; - default: return theme.gradients.primary; - } - }; + const getPriorityColor = (priority: string) => { + switch (priority) { + case "high": + return colors.danger; + case "medium": + return colors.warning; + case "low": + return colors.success; + default: + return colors.primary; + } + }; - const handleDelete = () => { - Alert.alert( - 'Delete Goal', - 'Are you sure you want to delete this goal?', - [ - { text: 'Cancel', style: 'cancel' }, - { text: 'Delete', style: 'destructive', onPress: onDelete }, - ] - ); - }; + const handleDelete = () => { + Alert.alert("Delete Goal", "Are you sure you want to delete this goal?", [ + { text: "Cancel", style: "cancel" }, + { text: "Delete", style: "destructive", onPress: onDelete }, + ]); + }; - return ( - - + + {/* Header */} + + + - {/* Priority Accent Bar */} - + + + + + {goal.title} + + {goal.description && ( + + {goal.description} + + )} + + + + {/* Action Buttons */} + + {!isCompleted && onComplete && ( + + + + )} + {onDelete && ( + + + + )} + + - - - - - - - - {goal.title} - - {goal.description && ( - - {goal.description} - - )} - - + {/* Progress Section */} + {goal.targetValue && ( + + + + {goal.currentValue || 0} / {goal.targetValue} {goal.unit || ""} + + + {(progress * 100).toFixed(0)}% + + - - {!isCompleted && onComplete && ( - - - - )} - {onDelete && ( - - - - )} - - + + + )} - {goal.targetValue && ( - - - - {goal.currentValue || 0} / {goal.targetValue} {goal.unit || ''} - - - {progress.toFixed(0)}% - - + {/* Footer */} + + {isCompleted ? ( + + ) : ( + + {goal.priority === "high" && ( + + )} + {goal.priority === "medium" && ( + + )} + {goal.priority === "low" && ( + + )} + + )} - - - - - )} + {daysRemaining !== null && !isCompleted && ( + + {daysRemaining < 0 + ? `${Math.abs(daysRemaining)} days overdue` + : `${daysRemaining} days remaining`} + + )} - - - {goal.priority.toUpperCase()} - - - {daysRemaining !== null && !isCompleted && ( - - {daysRemaining < 0 - ? `${Math.abs(daysRemaining)} days overdue` - : `${daysRemaining} days remaining` - } - - )} - - {isCompleted && goal.completedDate && ( - - Completed {new Date(goal.completedDate).toLocaleDateString()} - - )} - - - - ); + {isCompleted && goal.completedDate && ( + + Completed {new Date(goal.completedDate).toLocaleDateString()} + + )} + + + + ); } const styles = StyleSheet.create({ - card: { - borderRadius: theme.borderRadius.xl, - padding: 16, - marginBottom: 12, - borderWidth: 1, - borderColor: 'rgba(59, 130, 246, 0.1)', - overflow: 'hidden', - }, - cardCompleted: { - borderColor: 'rgba(16, 185, 129, 0.2)', - }, - priorityAccent: { - position: 'absolute', - left: 0, - top: 0, - bottom: 0, - width: 4, - }, - header: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'flex-start', - marginBottom: 12, - marginLeft: 8, - }, - titleRow: { - flexDirection: 'row', - alignItems: 'flex-start', - flex: 1, - }, - iconContainer: { - width: 40, - height: 40, - borderRadius: 20, - justifyContent: 'center', - alignItems: 'center', - marginRight: 12, - }, - titleContainer: { - flex: 1, - }, - title: { - fontSize: theme.typography.fontSize.lg, - fontWeight: theme.typography.fontWeight.semibold, - color: theme.colors.gray900, - marginBottom: 4, - }, - titleCompleted: { - color: theme.colors.gray600, - textDecorationLine: 'line-through', - }, - description: { - fontSize: theme.typography.fontSize.sm, - color: theme.colors.gray600, - lineHeight: 18, - }, - actions: { - flexDirection: 'row', - gap: 8, - }, - actionButton: { - padding: 4, - }, - progressSection: { - marginBottom: 12, - marginLeft: 8, - }, - progressInfo: { - flexDirection: 'row', - justifyContent: 'space-between', - marginBottom: 8, - }, - progressText: { - fontSize: theme.typography.fontSize.sm, - fontWeight: theme.typography.fontWeight.medium, - color: theme.colors.gray700, - }, - progressPercentage: { - fontSize: theme.typography.fontSize.sm, - fontWeight: theme.typography.fontWeight.semibold, - color: theme.colors.primary, - }, - progressBarContainer: { - height: 8, - backgroundColor: theme.colors.gray200, - borderRadius: 4, - overflow: 'hidden', - }, - progressBar: { - height: '100%', - borderRadius: 4, - }, - footer: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - marginLeft: 8, - }, - priorityBadge: { - paddingHorizontal: 10, - paddingVertical: 5, - borderRadius: theme.borderRadius.md, - }, - priorityText: { - fontSize: theme.typography.fontSize.xs, - fontWeight: theme.typography.fontWeight.semibold, - color: theme.colors.white, - }, - daysRemaining: { - fontSize: theme.typography.fontSize.xs, - color: theme.colors.gray600, - fontWeight: theme.typography.fontWeight.medium, - }, - overdue: { - color: theme.colors.danger, - fontWeight: theme.typography.fontWeight.semibold, - }, - completedDate: { - fontSize: theme.typography.fontSize.xs, - color: theme.colors.success, - fontWeight: theme.typography.fontWeight.medium, - }, + card: { + marginBottom: 12, + }, + header: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "flex-start", + marginBottom: 12, + }, + titleRow: { + flexDirection: "row", + alignItems: "flex-start", + flex: 1, + }, + titleContainer: { + flex: 1, + marginLeft: 12, + }, + actions: { + flexDirection: "row", + gap: 8, + }, + actionButton: { + padding: 4, + }, + progressSection: { + marginBottom: 12, + }, + progressInfo: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: 8, + }, + footer: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + }, });