"use client" import { useState, useEffect, useRef } from "react" import { View, Text, Image, TouchableOpacity, ScrollView, ActivityIndicator, FlatList, Alert, TextInput, KeyboardAvoidingView, Platform, Keyboard, } from "react-native" import { Feather, MaterialCommunityIcons, Ionicons } from "@expo/vector-icons" import { useLocalSearchParams, router } from "expo-router" import { useAuth } from "../../context/auth-context" import { supabase } from "../../services/supabase" import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query" import { getComments, createComment, getLikesCount, getSavesCount, getCommentsCount, checkUserLiked, checkUserSaved, } from "../../services/data/forum" import { getProfile } from "../../services/data/profile" import { queryKeys, useLikeMutation, useSaveMutation } from "../../hooks/use-foods" export default function PostDetailScreen() { const params = useLocalSearchParams() const foodId = typeof params.id === "string" ? params.id : "" const queryClient = useQueryClient() const scrollViewRef = useRef(null) console.log("Post detail screen - Food ID:", foodId) const { isAuthenticated } = useAuth() const [currentUserId, setCurrentUserId] = useState(null) const [commentText, setCommentText] = useState("") const [submittingComment, setSubmittingComment] = useState(false) const [showReviews, setShowReviews] = useState(true) const [keyboardVisible, setKeyboardVisible] = useState(false) // Listen for keyboard events useEffect(() => { const keyboardDidShowListener = Keyboard.addListener("keyboardDidShow", () => { setKeyboardVisible(true) }) const keyboardDidHideListener = Keyboard.addListener("keyboardDidHide", () => { setKeyboardVisible(false) }) return () => { keyboardDidShowListener.remove() keyboardDidHideListener.remove() } }, []) // Recipe info cards data const recipeInfoCards = [ { id: "cooking_time", title: "Cooking Time", icon: ( ), value: (food: any) => food.time_to_cook_minutes, unit: (food: any) => (food.time_to_cook_minutes === 1 ? "minute" : "minutes"), gradient: ["#fff8e1", "#fffde7"], valueColor: "#bb0718", }, { id: "skill_level", title: "Skill Level", icon: ( ), value: (food: any) => food.skill_level, unit: () => "", gradient: ["#e8f5e9", "#f1f8e9"], valueColor: "", customContent: (food: any) => ( {food.skill_level} {renderSkillLevelDots(food.skill_level)} ), }, { id: "ingredients", title: "Ingredients", icon: ( ), value: (food: any) => food.ingredient_count, unit: (food: any) => (food.ingredient_count === 1 ? "item" : "items"), gradient: ["#e3f2fd", "#e8f5e9"], valueColor: "#2196F3", }, { id: "calories", title: "Calories", icon: ( ), value: (food: any) => food.calories, unit: () => "kcal", gradient: ["#ffebee", "#fff8e1"], valueColor: "#F44336", }, ] // Get current user ID from Supabase session useEffect(() => { async function getCurrentUser() { if (isAuthenticated) { const { data } = await supabase.auth.getSession() const userId = data.session?.user?.id console.log("Current user ID:", userId) setCurrentUserId(userId || null) } else { setCurrentUserId(null) } } getCurrentUser() }, [isAuthenticated]) // Fetch food details const { data: food, isLoading: isLoadingFood, error: foodError, } = useQuery({ queryKey: queryKeys.foodDetails(foodId), queryFn: async () => { const { data, error } = await supabase.from("foods").select("*").eq("id", foodId).single() if (error) throw error return { ...data, description: data.description || "", ingredient_count: data.ingredient_count ?? 0, calories: data.calories ?? 0, time_to_cook_minutes: data.time_to_cook_minutes ?? 0, skill_level: data.skill_level || "Easy", image_url: data.image_url || "", } }, enabled: !!foodId, }) // Fetch food creator const { data: foodCreator, isLoading: isLoadingCreator } = useQuery({ queryKey: ["food-creator", food?.created_by], queryFn: async () => { if (!food?.created_by) return null const { data, error } = await getProfile(food.created_by) if (error) throw error return data }, enabled: !!food?.created_by, }) // Fetch food stats const { data: stats = { likes: 0, saves: 0, comments: 0 }, isLoading: isLoadingStats, refetch: refetchStats, } = useQuery({ queryKey: ["food-stats", foodId], queryFn: async () => { const [likesRes, savesRes, commentsRes] = await Promise.all([ getLikesCount(foodId), getSavesCount(foodId), getCommentsCount(foodId), ]) return { likes: likesRes.count || 0, saves: savesRes.count || 0, comments: commentsRes.count || 0, } }, enabled: !!foodId, }) // Fetch user interactions const { data: interactions = { liked: false, saved: false }, isLoading: isLoadingInteractions, refetch: refetchInteractions, } = useQuery({ queryKey: ["user-interactions", foodId, currentUserId], queryFn: async () => { if (!currentUserId) return { liked: false, saved: false } const [likedRes, savedRes] = await Promise.all([ checkUserLiked(foodId, currentUserId), checkUserSaved(foodId, currentUserId), ]) return { liked: !!likedRes.data, saved: !!savedRes.data, } }, enabled: !!foodId && !!currentUserId, }) // Fetch comments const { data: comments = [], isLoading: isLoadingComments, refetch: refetchComments, } = useQuery({ queryKey: queryKeys.foodComments(foodId), queryFn: async () => { const { data, error } = await getComments(foodId) if (error) throw error return data || [] }, enabled: !!foodId, }) // Set up mutations const likeMutation = useLikeMutation() const saveMutation = useSaveMutation() const commentMutation = useMutation({ mutationFn: async ({ foodId, userId, content }: { foodId: string; userId: string; content: string }) => { return createComment(foodId, userId, content) }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.foodComments(foodId) }) queryClient.invalidateQueries({ queryKey: ["food-stats", foodId] }) setCommentText("") Keyboard.dismiss() }, }) // Set up real-time subscription for comments useEffect(() => { if (!foodId) return console.log(`Setting up real-time subscription for comments on food_id: ${foodId}`) const subscription = supabase .channel(`food_comments:${foodId}`) .on( "postgres_changes", { event: "*", schema: "public", table: "food_comments", filter: `food_id=eq.${foodId}`, }, () => { console.log("Comment change detected, refreshing comments") refetchComments() refetchStats() }, ) .subscribe() return () => { supabase.removeChannel(subscription) } }, [foodId, refetchComments, refetchStats]) // Set up real-time subscription for likes and saves useEffect(() => { if (!foodId) return const likesSubscription = supabase .channel(`food_likes:${foodId}`) .on( "postgres_changes", { event: "*", schema: "public", table: "food_likes", filter: `food_id=eq.${foodId}`, }, () => { console.log("Like change detected, refreshing stats and interactions") refetchStats() refetchInteractions() }, ) .subscribe() const savesSubscription = supabase .channel(`food_saves:${foodId}`) .on( "postgres_changes", { event: "*", schema: "public", table: "food_saves", filter: `food_id=eq.${foodId}`, }, () => { console.log("Save change detected, refreshing stats and interactions") refetchStats() refetchInteractions() }, ) .subscribe() return () => { supabase.removeChannel(likesSubscription) supabase.removeChannel(savesSubscription) } }, [foodId, refetchStats, refetchInteractions]) const handleLike = async () => { if (!isAuthenticated || !currentUserId || !food) { Alert.alert("Authentication Required", "Please log in to like posts.") return } try { likeMutation.mutate({ foodId, userId: currentUserId, isLiked: interactions.liked, }) } catch (error) { console.error("Error toggling like:", error) Alert.alert("Error", "Failed to update like. Please try again.") } } const handleSave = async () => { if (!isAuthenticated || !currentUserId || !food) { Alert.alert("Authentication Required", "Please log in to save posts.") return } try { saveMutation.mutate({ foodId, userId: currentUserId, isSaved: interactions.saved, }) } catch (error) { console.error("Error toggling save:", error) Alert.alert("Error", "Failed to update save. Please try again.") } } const handleSubmitComment = async () => { if (!isAuthenticated || !currentUserId || !foodId || !commentText.trim()) { if (!isAuthenticated || !currentUserId) { Alert.alert("Authentication Required", "Please log in to comment.") } return } setSubmittingComment(true) try { await commentMutation.mutateAsync({ foodId, userId: currentUserId, content: commentText.trim(), }) } catch (error) { console.error("Error submitting comment:", error) Alert.alert("Error", "Failed to submit comment. Please try again.") } finally { setSubmittingComment(false) } } // Helper function to get skill level color const getSkillLevelColor = (level: string) => { switch (level) { case "Easy": return "#4CAF50" // Green case "Medium": return "#FFC107" // Amber case "Hard": return "#F44336" // Red default: return "#4CAF50" // Default to green } } // Helper function to get skill level dots const renderSkillLevelDots = (level: string) => { const totalDots = 3 let activeDots = 1 if (level === "Medium") activeDots = 2 if (level === "Hard") activeDots = 3 return ( {[...Array(totalDots)].map((_, i) => ( ))} ) } // Render recipe info card const renderRecipeInfoCard = ({ item }: { item: any }) => { if (!food) return null return ( {item.icon} {item.title} {item.customContent ? ( item.customContent(food) ) : ( {item.value(food)} {item.unit(food)} )} ) } const isLoading = isLoadingFood || isLoadingCreator || isLoadingStats || isLoadingInteractions || isLoadingComments if (isLoading) { return ( ) } if (foodError || !food) { return ( Post not found router.back()} > Go Back ) } return ( {/* Fixed Header */} router.back()} > Post {/* Scrollable Content */} {/* User info */} {foodCreator?.avatar_url ? ( ) : ( {foodCreator?.username?.charAt(0).toUpperCase() || food.created_by?.charAt(0).toUpperCase() || "?"} )} {foodCreator?.username || foodCreator?.full_name || "Chef"} {/* Food image */} {/* Food title and description */} {food.name} {food.description} {new Date(food.created_at).toLocaleDateString()} -{" "} {new Date(food.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })} {/* Recipe Info Cards - Horizontal Scrollable */} Recipe Details item.id} contentContainerStyle={{ paddingLeft: 16, paddingRight: 8 }} /> {/* Interaction buttons */} {stats.likes} Save {/* Reviews section */} setShowReviews(!showReviews)} > Reviews {stats.comments} {showReviews && ( {comments.length > 0 ? ( comments.map((comment) => ( {/* Profile picture */} {comment.user?.avatar_url ? ( ) : ( {comment.user?.username?.charAt(0).toUpperCase() || comment.user_id?.charAt(0).toUpperCase() || "?"} )} {/* Comment bubble with username inside */} {/* Username inside bubble */} {comment.user?.username || comment.user?.full_name || "User"} {/* Comment content */} {comment.content} {/* Date below bubble */} {new Date(comment.created_at).toLocaleDateString()} {/* Separator */} )) ) : ( No reviews yet. Be the first to comment! )} )} {/* Comment input - Positioned above keyboard */} {!isAuthenticated && ( Please log in to comment )} ) }