import { useState, useEffect } from "react"; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator, RefreshControl, Alert, } from "react-native"; import { useAuth } from "@clerk/clerk-expo"; import { Ionicons } from "@expo/vector-icons"; import { API_BASE_URL, API_ENDPOINTS } from "../../config/api"; interface Recommendation { id: string; userId: string; type: "short_term" | "medium_term" | "long_term"; content: string; status: "pending" | "completed"; createdAt: string; } export default function GoalsScreen() { const { userId, getToken } = useAuth(); const [recommendations, setRecommendations] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const fetchRecommendations = async () => { if (!userId) return; try { const token = await getToken(); const response = await fetch( `${API_BASE_URL}${API_ENDPOINTS.RECOMMENDATIONS}?userId=${userId}`, { headers: { Authorization: `Bearer ${token}`, }, } ); if (response.ok) { const data = await response.json(); setRecommendations(data); } else { console.error("Failed to fetch recommendations"); } } catch (error) { console.error("Error fetching recommendations:", error); } finally { setLoading(false); setRefreshing(false); } }; useEffect(() => { fetchRecommendations(); }, [userId]); const onRefresh = () => { setRefreshing(true); fetchRecommendations(); }; const toggleStatus = async (id: string, currentStatus: string) => { const newStatus = currentStatus === "pending" ? "completed" : "pending"; // Optimistic update setRecommendations(prev => prev.map(r => r.id === id ? { ...r, status: newStatus } : r) ); try { const token = await getToken(); const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.RECOMMENDATIONS}`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ id, status: newStatus, }), }); if (!response.ok) { // Revert on failure setRecommendations(prev => prev.map(r => r.id === id ? { ...r, status: currentStatus as "pending" | "completed" } : r) ); Alert.alert("Error", "Failed to update status"); } } catch (error) { console.error(error); // Revert on error setRecommendations(prev => prev.map(r => r.id === id ? { ...r, status: currentStatus as "pending" | "completed" } : r) ); Alert.alert("Error", "Failed to update status"); } }; const renderSection = ( title: string, type: "short_term" | "medium_term" | "long_term" ) => { const items = recommendations.filter((r) => r.type === type); return ( {title} {items.length === 0 ? ( No goals set yet. ) : ( items.map((rec) => ( toggleStatus(rec.id, rec.status)} > {rec.status === "completed" && ( )} {rec.content} {new Date(rec.createdAt).toLocaleDateString()} )) )} ); }; if (loading && !refreshing) { return ( ); } return ( } > My Goals Track your fitness journey progress {renderSection("Short Term Goals", "short_term")} {renderSection("Medium Term Goals", "medium_term")} {renderSection("Long Term Goals", "long_term")} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#f3f4f6", }, center: { flex: 1, justifyContent: "center", alignItems: "center", }, header: { padding: 20, backgroundColor: "#fff", marginBottom: 10, }, headerTitle: { fontSize: 28, fontWeight: "bold", color: "#111827", }, headerSubtitle: { fontSize: 16, color: "#6b7280", marginTop: 4, }, section: { padding: 20, paddingTop: 10, }, sectionTitle: { fontSize: 18, fontWeight: "600", color: "#374151", marginBottom: 12, }, emptyText: { fontStyle: "italic", color: "#9ca3af", }, card: { backgroundColor: "#fff", padding: 16, borderRadius: 12, marginBottom: 12, flexDirection: "row", alignItems: "flex-start", shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.05, shadowRadius: 2, elevation: 2, }, cardCompleted: { backgroundColor: "#f0fdf4", // light green borderColor: "#bbf7d0", borderWidth: 1, }, checkbox: { width: 24, height: 24, borderRadius: 6, borderWidth: 2, borderColor: "#d1d5db", marginRight: 12, marginTop: 2, justifyContent: "center", alignItems: "center", backgroundColor: "#fff", }, cardContent: { flex: 1, }, cardText: { fontSize: 16, color: "#1f2937", lineHeight: 24, }, cardTextCompleted: { textDecorationLine: "line-through", color: "#9ca3af", }, dateText: { fontSize: 12, color: "#9ca3af", marginTop: 4, }, footer: { height: 40, }, });