"use client"; import { Feather, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { router, useLocalSearchParams } from "expo-router"; import { useEffect, useRef, useState } from "react"; import { ActivityIndicator, Alert, FlatList, Image, Keyboard, KeyboardAvoidingView, Platform, ScrollView, Text, TextInput, TouchableOpacity, View, } from "react-native"; import { useAuth } from "../../context/auth-context"; import { queryKeys, useLikeMutation, useSaveMutation, } from "../../hooks/use-foods"; import { checkUserLiked, checkUserSaved, createComment, getComments, getCommentsCount, getLikesCount, getSavesCount, } from "../../services/data/forum"; import { getProfile } from "../../services/data/profile"; import { supabase } from "../../services/supabase"; 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 router.push(`/food/${food.id}`)}> {/* 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()} )) ) : ( No reviews yet. Be the first to comment! )} )} {/* Comment input - Positioned above keyboard */} {!isAuthenticated && ( Please log in to comment )} ); }