"use client" import { IconSymbol } from "@/components/ui/IconSymbol" import { getFoods, insertGenAIResult } from "@/services/data/foods" import { uploadImageToSupabase } from "@/services/data/imageUpload" import { getProfile } from "@/services/data/profile" import { callGenAIonImage } from "@/services/gemini" import { supabase } from "@/services/supabase" import { Feather, FontAwesome, Ionicons } from "@expo/vector-icons" import { useQuery } from "@tanstack/react-query" import * as FileSystem from "expo-file-system" import * as ImagePicker from "expo-image-picker" import { router } from "expo-router" import { useMemo, useState, useEffect } from "react" import { Alert, Image, SafeAreaView, ScrollView, StatusBar, Text, TextInput, TouchableOpacity, View, ActivityIndicator, } from "react-native" const useFoodsQuery = () => { return useQuery({ queryKey: ["highlight-foods"], queryFn: async () => { const { data, error } = await getFoods(undefined, true, undefined, 4) if (error) throw error return data || [] }, staleTime: 1000 * 60 * 5, }) } const useUserProfile = () => { const [userId, setUserId] = useState(null) const [isLoadingUserId, setIsLoadingUserId] = useState(true) // Get current user ID useEffect(() => { const fetchUserId = async () => { try { const { data, error } = await supabase.auth.getUser() if (error) throw error setUserId(data?.user?.id || null) } catch (error) { console.error("Error fetching user:", error) } finally { setIsLoadingUserId(false) } } fetchUserId() }, []) // Fetch user profile data const { data: profileData, isLoading: isLoadingProfile, error: profileError, } = useQuery({ queryKey: ["profile", userId], queryFn: async () => { if (!userId) throw new Error("No user id") return getProfile(userId) }, enabled: !!userId, staleTime: 1000 * 60 * 5, // 5 minutes }) return { userId, profileData: profileData?.data, isLoading: isLoadingUserId || isLoadingProfile, error: profileError, } } const runImagePipeline = async (imageBase64: string, imageType: string, userId: string) => { const imageUri = await uploadImageToSupabase(imageBase64, imageType, userId) const genAIResult = await callGenAIonImage(imageUri) if (genAIResult.error) throw genAIResult.error const { data: genAIResultData } = genAIResult if (!genAIResultData) throw new Error("GenAI result is null") await insertGenAIResult(genAIResultData, userId, imageUri) } const processImage = async (asset: ImagePicker.ImagePickerAsset, userId: string) => { const base64 = await FileSystem.readAsStringAsync(asset.uri, { encoding: "base64", }) const imageType = asset.mimeType || "image/jpeg" await runImagePipeline(base64, imageType, userId) } const navigateToFoodDetail = (foodId: string) => { router.push({ pathname: "/recipe-detail", params: { id: foodId } }) } const handleImageSelection = async ( pickerFn: typeof ImagePicker.launchCameraAsync | typeof ImagePicker.launchImageLibraryAsync, ) => { const result = await pickerFn({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, aspect: [1, 1], quality: 1, }) if (!result.canceled) { try { const { data, error } = await supabase.auth.getUser() if (error || !data?.user?.id) throw new Error("Cannot get user id") const userId = data.user.id await processImage(result.assets[0], userId) } catch (err) { Alert.alert("Image Processing Failed", (err as Error).message || "Unknown error") } router.push({ pathname: "/recipe-detail", params: { title: "My New Recipe", image: result.assets[0].uri, }, }) } } export default function HomeScreen() { const [searchQuery, setSearchQuery] = useState("") const { data: foodsData = [], isLoading: isLoadingFoods, error: foodsError } = useFoodsQuery() const { profileData, isLoading: isLoadingProfile, userId } = useUserProfile() const filteredFoods = useMemo(() => { return searchQuery ? foodsData.filter((food) => food.name.toLowerCase().includes(searchQuery.toLowerCase())) : foodsData }, [foodsData, searchQuery]) // Get username or fallback to a default greeting const username = profileData?.username || profileData?.full_name || "Chef" const greeting = `Hi! ${username}` return ( {isLoadingProfile ? ( Hi! ) : ( {greeting} )} {/* Main content container with consistent padding */} {/* "Show your dishes" section */} Show your dishes {/* Upload feature section */} { const { status } = await ImagePicker.requestCameraPermissionsAsync() if (status !== "granted") { Alert.alert("Permission needed", "Please grant camera permissions.") return } await handleImageSelection(ImagePicker.launchCameraAsync) }} > From Camera Straight from Camera { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync() if (status !== "granted") { Alert.alert("Permission needed", "Please grant gallery permissions.") return } await handleImageSelection(ImagePicker.launchImageLibraryAsync) }} > From Gallery Straight from Gallery {/* Highlights section */} Highlights {isLoadingFoods ? ( Loading highlights... ) : foodsError ? ( Failed to load highlights ) : filteredFoods.length === 0 ? ( No highlights available ) : ( {filteredFoods.map((food, idx) => ( navigateToFoodDetail(food.id)} > {food.image_url ? ( ) : ( No Image )} {food.name} {food.description || "No description"} {food.time_to_cook_minutes ? `${food.time_to_cook_minutes} min` : "-"} ))} )} {/* Extra space at bottom */} ) }