"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 { useEffect, useMemo, useState } from "react"; import { Alert, Image, SafeAreaView, ScrollView, StatusBar, Text, TextInput, TouchableOpacity, View, } 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 } }); }; export default function HomeScreen() { const [imageProcessing, setImageProcessing] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const { profileData } = useUserProfile(); const { data: foodsData = [], isLoading: isLoadingFoods, error: foodsError, } = useFoodsQuery(); const handleImageSelection = async ( pickerFn: | typeof ImagePicker.launchCameraAsync | typeof ImagePicker.launchImageLibraryAsync ) => { const result = await pickerFn({ mediaTypes: ["images"], allowsEditing: true, aspect: [1, 1], quality: 1, }); if (!result.canceled) { setImageProcessing(true); 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" ); } finally { setImageProcessing(false); } router.push({ pathname: "/recipe-detail", params: { title: "My New Recipe", image: result.assets[0].uri, }, }); } }; 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 ( {imageProcessing && ( Processing image... Please wait )} {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 */} ); }