From 9125ca19bae9f193e65400d66bb579a392255d45 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Mon, 12 May 2025 00:34:27 +0700 Subject: [PATCH] feat: add recipes page --- app/(tabs)/home.tsx | 2 +- app/(tabs)/recipes.tsx | 164 ++++++++++++++--------------- app/_layout.tsx | 7 -- components/RecipeHighlightCard.tsx | 60 +++++++++++ 4 files changed, 138 insertions(+), 95 deletions(-) create mode 100644 components/RecipeHighlightCard.tsx diff --git a/app/(tabs)/home.tsx b/app/(tabs)/home.tsx index ef56af1..127396e 100644 --- a/app/(tabs)/home.tsx +++ b/app/(tabs)/home.tsx @@ -28,7 +28,7 @@ const useFoodsQuery = () => { return useQuery({ queryKey: ["highlight-foods"], queryFn: async () => { - const { data, error } = await getFoods(undefined, true, undefined, 4); + const { data, error } = await getFoods(undefined, true, undefined, 3); if (error) throw error; return data || []; }, diff --git a/app/(tabs)/recipes.tsx b/app/(tabs)/recipes.tsx index 66d5001..23ab5d3 100644 --- a/app/(tabs)/recipes.tsx +++ b/app/(tabs)/recipes.tsx @@ -1,99 +1,89 @@ -import { IconSymbol } from "@/components/ui/IconSymbol"; -import { Image } from "expo-image"; -import { - ScrollView, - Text, - TextInput, - TouchableOpacity, - View, -} from "react-native"; +"use client"; + +import RecipeHighlightCard from "@/components/RecipeHighlightCard"; +import { supabase } from "@/services/supabase"; +import { useQuery } from "@tanstack/react-query"; +import { router } from "expo-router"; +import { ActivityIndicator, ScrollView, Text, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; +interface Recipe { + id: number; + name: string; + description: string; + image_url: string; + created_by: string; + is_shared: boolean; + time_to_cook_minutes?: number; +} + export default function RecipesScreen() { - const foodItems = [ - { - id: 1, - name: "Padthaipro", - image: require("@/assets/images/food/padthai.jpg"), - color: "#FFCC00", + const { + data: allRecipes, + isLoading: isAllLoading, + error: allError, + } = useQuery({ + queryKey: ["all-recipes"], + queryFn: async () => { + const { data, error } = await supabase + .from("foods") + .select("*") + .eq("is_shared", true) + .order("created_at", { ascending: false }); + if (error) throw error; + return data ?? []; }, - { - id: 2, - name: "Jjajangmyeon", - image: require("@/assets/images/food/jjajangmyeon.jpg"), - color: "#FFA500", - }, - { - id: 3, - name: "Wingztab", - image: require("@/assets/images/food/wings.jpg"), - color: "#FFCC00", - }, - { - id: 4, - name: "Ramen", - image: require("@/assets/images/food/ramen.jpg"), - color: "#FFA500", - }, - { - id: 5, - name: "Tiramisu", - image: require("@/assets/images/food/tiramisu.jpg"), - color: "#FFCC00", - }, - { - id: 6, - name: "Beef wellington", - image: require("@/assets/images/food/beef.jpg"), - color: "#FFA500", - }, - ]; + staleTime: 1000 * 60, + }); + + const recipes: Recipe[] = allRecipes || []; + const loading = isAllLoading; + const error = allError; + + if (loading) { + return ( + + + + ); + } + if (error) { + return ( + + Failed to load recipes + + ); + } return ( + + All Recipes + - {/* Search Bar */} - - - - - - {/* Filter Buttons */} - - - All Recipes - - - My Recipes - - - - {/* Divider */} - - - {/* Food Grid */} - - {foodItems.map((item) => ( - - - - - {item.name} - - + + {recipes.length === 0 ? ( + + No recipes found. - ))} + ) : ( + recipes.map((item, idx) => ( + + { + router.push(`/food/${item.id}`); + }} + /> + + )) + )} diff --git a/app/_layout.tsx b/app/_layout.tsx index b965d57..38f7cbc 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -18,13 +18,6 @@ export default function RootLayout() { headerShown: false, }} /> - diff --git a/components/RecipeHighlightCard.tsx b/components/RecipeHighlightCard.tsx new file mode 100644 index 0000000..86a88cf --- /dev/null +++ b/components/RecipeHighlightCard.tsx @@ -0,0 +1,60 @@ +import { IconSymbol } from "@/components/ui/IconSymbol"; +import { Image } from "expo-image"; +import { TouchableOpacity, View, Text } from "react-native"; + +interface RecipeHighlightCardProps { + recipe: { + id: number; + name: string; + description?: string; + image_url?: string; + time_to_cook_minutes?: number; + calories?: number; + }; + onPress?: () => void; +} + +export default function RecipeHighlightCard({ recipe, onPress }: RecipeHighlightCardProps) { + return ( + + + {recipe.image_url ? ( + + ) : ( + + No Image + + )} + {/* Calories badge */} + {recipe.calories !== undefined && ( + + {recipe.calories} kcal + + )} + + + + {recipe.name} + + + {recipe.description || "No description"} + + + + + {recipe.time_to_cook_minutes ? `${recipe.time_to_cook_minutes} min` : "-"} + + + + + ); +}