feat: add cooking step page

This commit is contained in:
Sosokker 2025-05-11 22:52:51 +07:00
parent 44a2f89a59
commit 79add76034

View File

@ -1,68 +1,75 @@
"use client"; "use client";
import { IconSymbol } from "@/components/ui/IconSymbol"; import { IconSymbol } from "@/components/ui/IconSymbol";
import { Image } from "expo-image"; import { supabase } from "@/services/supabase";
import { useQuery } from "@tanstack/react-query";
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
import "nativewind";
import { useState } from "react"; import { useState } from "react";
import { import { Alert, ScrollView, Text, TouchableOpacity, View } from "react-native";
Alert,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context"; import { SafeAreaView } from "react-native-safe-area-context";
interface Step {
id: string;
food_id: string;
title: string;
step_order: number;
description: string;
created_at: string;
}
export default function CookingSessionScreen() { export default function CookingSessionScreen() {
const { id } = useLocalSearchParams(); const { id: foodId } = useLocalSearchParams();
const [currentStep, setCurrentStep] = useState(0); const [currentStep, setCurrentStep] = useState(0);
// Mock data - in a real app, you would fetch this based on the ID const {
const recipeData = { data: steps,
id: 1, isLoading: stepsLoading,
name: "Pad Kra Pao Moo Sab with Eggs", error: stepsError,
steps: [ } = useQuery<Step[], Error>({
{ queryKey: ["food-steps", foodId],
title: "Gather and prepare all ingredients", queryFn: async () => {
description: const { data, error } = await supabase
"Chop garlic, Thai chilies, and protein of choice (chicken, pork, beef, or tofu)", .from("cooking_steps")
image: require("@/assets/images/cooking/step1.png"), .select(
`
id,
food_id,
title,
step_order,
description,
created_at
`
)
.eq("food_id", foodId)
.order("step_order", { ascending: true });
if (error) throw error;
return data ?? [];
}, },
{ enabled: !!foodId,
title: "Heat oil in a wok or large frying pan", });
description:
"Use medium-high heat. The oil should be hot but not smoking.",
image: require("@/assets/images/cooking/step2.png"),
},
{
title: "Fry the eggs sunny side up",
description:
"Heat oil in a separate pan and fry eggs until whites are set but yolks are still runny. Set aside.",
image: require("@/assets/images/cooking/step3.png"),
},
{
title: "Stir-fry garlic and chilies",
description:
"Add chopped garlic and chilies to the hot oil and stir-fry until fragrant, about 30 seconds.",
image: require("@/assets/images/cooking/step4.png"),
},
{
title: "Add ground pork and cook until browned",
description:
"Break up the meat with a spatula and cook until no longer pink, about 3-4 minutes.",
image: require("@/assets/images/cooking/step5.png"),
},
{
title: "Add sauces and basil",
description:
"Add soy sauce, oyster sauce, sugar, and holy basil. Stir well and cook for another minute. Serve with rice and top with the fried egg.",
image: require("@/assets/images/cooking/step6.png"),
},
],
};
const totalSteps = recipeData.steps.length; if (stepsLoading) {
return (
<SafeAreaView className="flex-1 bg-white" edges={["top"]}>
<View className="flex-1 justify-center items-center">
<Text>Loading...</Text>
</View>
</SafeAreaView>
);
}
if (stepsError) {
return (
<SafeAreaView className="flex-1 bg-white" edges={["top"]}>
<View className="flex-1 justify-center items-center">
<Text>Error loading steps</Text>
</View>
</SafeAreaView>
);
}
const totalSteps = steps?.length || 0;
const goToNextStep = () => { const goToNextStep = () => {
if (currentStep < totalSteps - 1) { if (currentStep < totalSteps - 1) {
@ -76,24 +83,6 @@ export default function CookingSessionScreen() {
} }
}; };
const getHelpWithStep = () => {
Alert.alert(
"Need Help?",
`Tips for ${recipeData.steps[currentStep].title}:\n\n` +
"• Make sure ingredients are properly prepared\n" +
"• Watch your heat level\n" +
"• Don't overcook the ingredients\n\n" +
"Would you like to see a video tutorial?",
[
{ text: "No, thanks", style: "cancel" },
{
text: "Yes, show video",
onPress: () => console.log("Show video tutorial"),
},
]
);
};
const stopCookingSession = () => { const stopCookingSession = () => {
Alert.alert( Alert.alert(
"Stop Cooking?", "Stop Cooking?",
@ -104,14 +93,31 @@ export default function CookingSessionScreen() {
] ]
); );
}; };
if (!steps || steps.length === 0) {
return (
<SafeAreaView className="flex-1 bg-white" edges={["top"]}>
<View className="flex-1 items-center justify-center">
<Text>No steps found</Text>
<TouchableOpacity
className="px-4 py-2 bg-yellow-400 rounded-full mt-4"
onPress={() => router.back()}
>
<Text className="text-lg font-bold text-white">
Go back to home page
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
return ( return (
<SafeAreaView style={styles.container} edges={["top"]}> <SafeAreaView className="flex-1 bg-white" edges={["top"]}>
<ScrollView style={styles.scrollView}> <ScrollView className="flex-1">
{/* Header with back button */} {/* Header with back button */}
<View style={styles.header}> <View className="px-4 py-3">
<TouchableOpacity <TouchableOpacity
style={styles.backButton} className="w-10 h-10 rounded-full bg-yellow-300 justify-center items-center"
onPress={() => router.back()} onPress={() => router.back()}
> >
<IconSymbol name="chevron.left" size={24} color="#333333" /> <IconSymbol name="chevron.left" size={24} color="#333333" />
@ -119,41 +125,38 @@ export default function CookingSessionScreen() {
</View> </View>
{/* Step Illustration */} {/* Step Illustration */}
<View style={styles.illustrationContainer}> <View className="items-center my-5">
<Image {/* If your steps have an image property, render it. Otherwise, skip the image or add a placeholder. */}
source={recipeData.steps[currentStep].image} {/* <Image source={{ uri: steps[currentStep].image }} className="w-48 h-48 rounded-full bg-yellow-300" contentFit="contain" /> */}
style={styles.stepImage}
contentFit="contain"
/>
</View> </View>
{/* Step Information */} {/* Step Information */}
<View style={styles.stepInfoContainer}> <View className="px-6 mb-6 items-center">
<Text style={styles.stepCounter}> <Text className="text-lg text-lime-600 font-bold mb-2">
Step {currentStep + 1} of {totalSteps} Step {currentStep + 1} of {totalSteps}
</Text> </Text>
<Text style={styles.stepTitle}> <Text className="text-2xl font-bold text-gray-800 text-center mb-3">
{recipeData.steps[currentStep].title} {steps && steps[currentStep]?.title}
</Text> </Text>
<Text style={styles.stepDescription}> <Text className="text-base text-gray-600 text-center leading-6">
{recipeData.steps[currentStep].description} {steps && steps[currentStep]?.description}
</Text> </Text>
</View> </View>
{/* Step Indicators */} {/* Step Indicators */}
<View style={styles.stepIndicatorsContainer}> <View className="px-6 mb-6">
<Text style={styles.stepsLabel}>Steps</Text> <Text className="text-lg font-bold text-gray-800 mb-3">Steps</Text>
<View style={styles.stepDots}> <View className="flex-row justify-center">
{recipeData.steps.map((_, index) => ( {steps &&
steps.map((_: any, index: any) => (
<TouchableOpacity <TouchableOpacity
key={index} key={index}
onPress={() => setCurrentStep(index)} onPress={() => setCurrentStep(index)}
> >
<View <View
style={[ className={`w-10 h-10 rounded-full mx-2 ${
styles.stepDot, currentStep === index ? "bg-yellow-300" : "bg-gray-200"
currentStep === index && styles.activeStepDot, }`}
]}
/> />
</TouchableOpacity> </TouchableOpacity>
))} ))}
@ -161,36 +164,38 @@ export default function CookingSessionScreen() {
</View> </View>
{/* Navigation Buttons */} {/* Navigation Buttons */}
<View style={styles.navigationContainer}> <View className="px-6 mb-20">
<TouchableOpacity style={styles.helpButton} onPress={getHelpWithStep}> <View className="flex-row justify-between">
<Text style={styles.helpButtonText}>Help me!</Text>
</TouchableOpacity>
<View style={styles.stepNavigation}>
{currentStep > 0 && ( {currentStep > 0 && (
<TouchableOpacity <TouchableOpacity
style={[styles.navButton, styles.prevButton]} className="flex-1 flex-row items-center justify-center py-4 rounded-lg bg-white border border-gray-300 mr-2"
onPress={goToPreviousStep} onPress={goToPreviousStep}
> >
<IconSymbol name="chevron.left" size={20} color="#333333" /> <IconSymbol name="chevron.left" size={20} color="#333333" />
<Text style={styles.prevButtonText}>Previous</Text> <Text className="text-base font-bold text-gray-800 ml-2">
Previous
</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
{currentStep < totalSteps - 1 ? ( {currentStep < totalSteps - 1 ? (
<TouchableOpacity <TouchableOpacity
style={[styles.navButton, styles.nextButton]} className="flex-1 flex-row items-center justify-center py-4 rounded-lg bg-yellow-300 ml-2"
onPress={goToNextStep} onPress={goToNextStep}
> >
<Text style={styles.nextButtonText}>Next Step</Text> <Text className="text-base font-bold text-gray-800 mr-2">
Next Step
</Text>
<IconSymbol name="chevron.right" size={20} color="#333333" /> <IconSymbol name="chevron.right" size={20} color="#333333" />
</TouchableOpacity> </TouchableOpacity>
) : ( ) : (
<TouchableOpacity <TouchableOpacity
style={[styles.navButton, styles.finishButton]} className="flex-1 flex-row items-center justify-center py-4 rounded-lg bg-green-600 ml-2"
onPress={() => router.back()} onPress={() => router.back()}
> >
<Text style={styles.finishButtonText}>Finish</Text> <Text className="text-base font-bold text-white mr-2">
Finish
</Text>
<IconSymbol name="checkmark" size={20} color="#FFFFFF" /> <IconSymbol name="checkmark" size={20} color="#FFFFFF" />
</TouchableOpacity> </TouchableOpacity>
)} )}
@ -199,165 +204,15 @@ export default function CookingSessionScreen() {
</ScrollView> </ScrollView>
{/* Stop Session Button */} {/* Stop Session Button */}
<TouchableOpacity style={styles.stopButton} onPress={stopCookingSession}> <TouchableOpacity
<Text style={styles.stopButtonText}>Stop Session</Text> className="absolute bottom-0 left-0 right-0 bg-red-800 flex-row justify-center items-center py-4"
onPress={stopCookingSession}
>
<Text className="text-lg font-bold text-yellow-300 mr-2">
Stop Session
</Text>
<IconSymbol name="fork.knife" size={20} color="#FFCC00" /> <IconSymbol name="fork.knife" size={20} color="#FFCC00" />
</TouchableOpacity> </TouchableOpacity>
</SafeAreaView> </SafeAreaView>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFFFFF",
},
scrollView: {
flex: 1,
},
header: {
paddingHorizontal: 16,
paddingVertical: 12,
},
backButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#FFCC00",
justifyContent: "center",
alignItems: "center",
},
illustrationContainer: {
alignItems: "center",
marginVertical: 20,
},
stepImage: {
width: 200,
height: 200,
borderRadius: 100,
backgroundColor: "#FFCC00",
},
stepInfoContainer: {
paddingHorizontal: 24,
alignItems: "center",
marginBottom: 30,
},
stepCounter: {
fontSize: 18,
color: "#8BC34A",
fontWeight: "bold",
marginBottom: 8,
},
stepTitle: {
fontSize: 24,
fontWeight: "bold",
color: "#333333",
textAlign: "center",
marginBottom: 12,
},
stepDescription: {
fontSize: 16,
color: "#666666",
textAlign: "center",
lineHeight: 24,
},
stepIndicatorsContainer: {
paddingHorizontal: 24,
marginBottom: 24,
},
stepsLabel: {
fontSize: 18,
fontWeight: "bold",
color: "#333333",
marginBottom: 12,
},
stepDots: {
flexDirection: "row",
justifyContent: "center",
},
stepDot: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#EEEEEE",
marginHorizontal: 8,
},
activeStepDot: {
backgroundColor: "#FFCC00",
},
navigationContainer: {
paddingHorizontal: 24,
marginBottom: 80,
},
helpButton: {
backgroundColor: "#FF6B6B",
borderRadius: 8,
paddingVertical: 16,
alignItems: "center",
marginBottom: 16,
},
helpButtonText: {
fontSize: 18,
fontWeight: "bold",
color: "#FFFFFF",
},
stepNavigation: {
flexDirection: "row",
justifyContent: "space-between",
},
navButton: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
paddingVertical: 16,
borderRadius: 8,
},
prevButton: {
backgroundColor: "#FFFFFF",
borderWidth: 1,
borderColor: "#DDDDDD",
marginRight: 8,
},
prevButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
marginLeft: 8,
},
nextButton: {
backgroundColor: "#FFCC00",
},
nextButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
marginRight: 8,
},
finishButton: {
backgroundColor: "#4CAF50",
},
finishButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#FFFFFF",
marginRight: 8,
},
stopButton: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#C62828",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
paddingVertical: 16,
},
stopButtonText: {
fontSize: 18,
fontWeight: "bold",
color: "#FFCC00",
marginRight: 8,
},
});