import React, { useState, useCallback, useRef } from "react"; import { View, Text, StyleSheet, ScrollView, RefreshControl, TouchableOpacity, Animated, Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { LinearGradient } from "expo-linear-gradient"; import { theme } from "../../styles/theme"; import { GoalProgressCard } from "../../components/GoalProgressCard"; import { GoalCreationModal } from "../../components/GoalCreationModal"; import { useUser, useAuth } from "@clerk/clerk-expo"; import { fitnessGoalsService, type FitnessGoal, type CreateGoalData, } from "../../services/fitnessGoals"; import { useFocusEffect } from "expo-router"; import * as SecureStore from "expo-secure-store"; import log from "../../utils/logger"; export default function GoalsScreen() { const { user } = useUser(); const { getToken } = useAuth(); const [goals, setGoals] = useState([]); const [refreshing, setRefreshing] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false); const fabScale = useRef(new Animated.Value(1)).current; const loadGoals = useCallback(async () => { if (!user?.id) return; try { const token = await getToken(); log.debug("Token obtained", { hasToken: !!token, tokenPreview: token ? token.substring(0, 20) + "..." : "No", userId: user.id, }); // Decode and log token details for debugging if (token) { try { const parts = token.split("."); if (parts.length === 3) { const payload = JSON.parse(atob(parts[1])); log.debug("Token details", { issuer: payload.iss, kid: JSON.parse(atob(parts[0])).kid, }); } } catch (e) { log.warn("Could not decode token"); } } const loadedGoals = await fitnessGoalsService.getGoals(user.id, token); setGoals(loadedGoals); } catch (error) { log.error("Failed to load goals", error); } }, [user?.id, getToken]); const clearClerkCache = async () => { Alert.alert( "Clear Clerk Cache", "This will clear all cached Clerk tokens. You will need to sign out and sign back in.", [ { text: "Cancel", style: "cancel" }, { text: "Clear Cache", style: "destructive", onPress: async () => { try { // Clear all possible Clerk token keys const keysToDelete = [ "__clerk_client_jwt", "__clerk_db_jwt", "__clerk_client_uat", "__clerk_session_id", "__clerk_refresh_token", "__clerk_session_jwt", ]; for (const key of keysToDelete) { try { await SecureStore.deleteItemAsync(key); } catch (e) { // Key might not exist } } Alert.alert( "Success", "Cache cleared! Please sign out and sign back in.", ); } catch (error) { log.error("Failed to clear cache", error); Alert.alert("Error", "Failed to clear cache"); } }, }, ], ); }; useFocusEffect( useCallback(() => { loadGoals(); }, [loadGoals]), ); const onRefresh = async () => { setRefreshing(true); await loadGoals(); setRefreshing(false); }; const handleCreateGoal = async (newGoal: CreateGoalData) => { const token = await getToken(); await fitnessGoalsService.createGoal(newGoal, token); await loadGoals(); setIsModalVisible(false); }; const handleCompleteGoal = async (goal: FitnessGoal) => { const token = await getToken(); await fitnessGoalsService.completeGoal(goal.id, token); await loadGoals(); }; const handleDeleteGoal = async (goalId: string) => { const token = await getToken(); await fitnessGoalsService.deleteGoal(goalId, token); await loadGoals(); }; const activeGoals = goals.filter((g) => g.status === "active"); const completedGoals = goals.filter((g) => g.status === "completed"); return ( } > Fitness Goals Track your fitness journey progress {/* Stats Summary */} {goals.length > 0 && ( {activeGoals.length} Active {completedGoals.length} Completed {activeGoals.length > 0 ? Math.round( activeGoals.reduce( (sum, g) => sum + (g.progress || 0), 0, ) / activeGoals.length, ) : 0} % Avg Progress )} {/* Active Goals */} Active Goals ({activeGoals.length}) {activeGoals.length === 0 ? ( No active goals yet Tap the + button to create your first goal ) : ( activeGoals.map((goal) => ( handleCompleteGoal(goal)} onDelete={() => handleDeleteGoal(goal.id)} /> )) )} {/* Completed Goals */} {completedGoals.length > 0 && ( Completed Goals ({completedGoals.length}) {completedGoals.map((goal) => ( handleDeleteGoal(goal.id)} /> ))} )} {/* Floating Action Button */} setIsModalVisible(true)} onPressIn={() => { Animated.spring(fabScale, { toValue: 0.9, friction: 8, tension: 100, useNativeDriver: true, }).start(); }} onPressOut={() => { Animated.spring(fabScale, { toValue: 1, friction: 8, tension: 100, useNativeDriver: true, }).start(); }} activeOpacity={0.9} > {/* Create Goal Modal */} setIsModalVisible(false)} onSubmit={handleCreateGoal} /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: theme.colors.background, }, scrollContent: { paddingBottom: 20, }, header: { padding: 24, paddingTop: 60, paddingBottom: 24, marginBottom: 10, borderBottomLeftRadius: theme.borderRadius.xl, borderBottomRightRadius: theme.borderRadius.xl, }, headerContent: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", }, debugButton: { padding: 8, }, headerTitle: { fontSize: theme.typography.fontSize["3xl"], fontWeight: theme.typography.fontWeight.bold, color: theme.colors.white, }, headerSubtitle: { fontSize: theme.typography.fontSize.base, color: "rgba(255, 255, 255, 0.9)", marginTop: 4, }, statsContainer: { flexDirection: "row", padding: 16, gap: 12, }, statCard: { flex: 1, backgroundColor: theme.colors.white, padding: 16, borderRadius: theme.borderRadius.xl, alignItems: "center", ...theme.shadows.medium, borderWidth: 1, borderColor: "rgba(59, 130, 246, 0.1)", }, statValue: { fontSize: theme.typography.fontSize["2xl"], fontWeight: theme.typography.fontWeight.bold, color: theme.colors.primary, marginBottom: 4, }, statLabel: { fontSize: 12, color: "#6b7280", fontWeight: "500", }, section: { padding: 20, paddingTop: 10, }, sectionTitle: { fontSize: 18, fontWeight: "600", color: "#374151", marginBottom: 12, }, emptyState: { alignItems: "center", paddingVertical: 40, }, emptyText: { fontSize: 16, fontWeight: "500", color: "#6b7280", marginTop: 12, }, emptySubtext: { fontSize: 14, color: "#9ca3af", marginTop: 4, }, footer: { height: 100, }, fabContainer: { position: "absolute", right: 20, bottom: 110, // Adjusted for tab bar height }, fab: { width: 64, height: 64, borderRadius: 32, justifyContent: "center", alignItems: "center", ...theme.shadows.glow, }, });