"use client"; import { useAuth } from "@/context/auth-context"; import { getFoods } from "@/services/data/foods"; import { getProfile, updateProfile } from "@/services/data/profile"; import { supabase } from "@/services/supabase"; import { useIsFocused } from "@react-navigation/native"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import * as ImagePicker from "expo-image-picker"; import { useState } from "react"; import { ActivityIndicator, Image, Modal, Pressable, ScrollView, Text, TextInput, TouchableOpacity, View, } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import uuid from "react-native-uuid"; export default function ProfileScreen() { const [activeTab, setActiveTab] = useState("My Recipes"); const { isAuthenticated } = useAuth(); const isFocused = useIsFocused(); const queryClient = useQueryClient(); const { data: userData, isLoading: isUserLoading, error: userError, } = useQuery({ queryKey: ["auth-user"], queryFn: async () => { const { data, error } = await supabase.auth.getUser(); if (error) throw error; return data?.user; }, enabled: isAuthenticated, staleTime: 0, }); const userId = userData?.id; const { data: profileData, error, isLoading, } = useQuery({ queryKey: ["profile", userId], queryFn: async () => { if (!userId) throw new Error("No user id"); return getProfile(userId); }, enabled: !!userId, staleTime: 0, subscribed: isFocused, }); const { data: foodsData, isLoading: isFoodsLoading, error: foodsError, } = useQuery({ queryKey: ["my-recipes", userId], queryFn: async () => { if (!userId) throw new Error("No user id"); return getFoods(userId); }, enabled: !!userId && activeTab === "My Recipes", staleTime: 0, }); const [modalVisible, setModalVisible] = useState(false); const [editUsername, setEditUsername] = useState(""); const [editImage, setEditImage] = useState(null); const [editLoading, setEditLoading] = useState(false); const [editError, setEditError] = useState(null); const pickImage = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== "granted") { setEditError("Permission to access media library is required."); return; } const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ["images"], quality: 0.7, allowsEditing: true, }); if (!result.canceled) { setEditImage(result.assets[0].uri); } }; const uploadImageToSupabase = async (uri: string): Promise => { const fileName = `${userId}/${uuid.v4()}.jpg`; const response = await fetch(uri); const blob = await response.blob(); const { error: uploadError } = await supabase.storage .from("avatars") .upload(fileName, blob, { contentType: "image/jpeg", upsert: true, }); if (uploadError) throw uploadError; const { data } = supabase.storage.from("avatars").getPublicUrl(fileName); return data.publicUrl; }; const handleSaveProfile = async () => { setEditLoading(true); setEditError(null); try { if (!editUsername.trim()) throw new Error("Username cannot be empty"); let avatarUrl = profileData?.data?.avatar_url ?? null; if (editImage && editImage !== avatarUrl) { avatarUrl = await uploadImageToSupabase(editImage); } const { error: updateError } = await updateProfile( userId!, editUsername.trim(), avatarUrl ); if (updateError) throw updateError; setModalVisible(false); await queryClient.invalidateQueries({ queryKey: ["profile", userId] }); } catch (err: any) { setEditError(err.message || "Failed to update profile"); } finally { setEditLoading(false); } }; if (isUserLoading) { return ( ); } if (userError) { return ( {userError.message || "Failed to load user data."} ); } return ( {isLoading ? ( ) : error ? ( {error.message || error.toString()} ) : ( {profileData?.data?.username ?? "-"} )} { setEditUsername(profileData?.data?.username ?? ""); setEditImage(profileData?.data?.avatar_url ?? null); setEditError(null); setModalVisible(true); }} > Edit {/* Edit Modal */} setModalVisible(false)} > Edit Profile Change Photo Username {editError && ( {editError} )} setModalVisible(false)} disabled={editLoading} > Cancel {editLoading ? ( ) : ( Save )} {/* Tab Navigation */} {["My Recipes", "Likes", "Saved"].map((tab) => ( setActiveTab(tab)} > {tab} ))} {/* Recipes */} {activeTab === "My Recipes" && ( {isFoodsLoading ? ( ) : foodsError ? ( {foodsError.message || foodsError.toString()} ) : foodsData?.data?.length ? ( foodsData.data.map((item) => ( {item.name} )) ) : ( No recipes found. )} )} ); }