diff --git a/app/api/updateRecipe/route.ts b/app/api/updateRecipe/route.ts new file mode 100644 index 0000000..21eae0e --- /dev/null +++ b/app/api/updateRecipe/route.ts @@ -0,0 +1,46 @@ +import { NextResponse } from 'next/server'; +import { getServerSession } from 'next-auth/next'; +import { authOptions } from '../auth/[...nextauth]/route'; +import { getClientPromise } from '@/lib/mongodb'; + +export async function PUT(request: Request) { + const session = await getServerSession(authOptions); + + if (!session?.user?.id) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + try { + const recipeData = await request.json(); + const client = await getClientPromise(); + const db = client.db(); + + // Ensure the 'id' field exists and is a string + if (!recipeData.id) { + return NextResponse.json({ error: 'Recipe ID is missing' }, { status: 400 }); + } + + recipeData.id = recipeData.id.toString(); + + // Remove '_id' field if it exists to prevent immutable field update error + if (recipeData._id) { + delete recipeData._id; + } + + // Update the recipe in the database + const result = await db.collection('recipes').updateOne( + { id: recipeData.id, userId: session.user.id }, + { $set: recipeData }, + { upsert: true } + ); + + if (result.modifiedCount > 0 || result.upsertedCount > 0) { + return NextResponse.json({ message: 'Recipe updated successfully!' }, { status: 200 }); + } else { + return NextResponse.json({ error: 'Failed to update recipe' }, { status: 500 }); + } + } catch (error) { + console.error('Error updating recipe:', error); + return NextResponse.json({ error: 'Failed to update recipe' }, { status: 500 }); + } +} diff --git a/app/saved-recipes/page.tsx b/app/saved-recipes/page.tsx index 06cae88..b993c96 100644 --- a/app/saved-recipes/page.tsx +++ b/app/saved-recipes/page.tsx @@ -5,11 +5,13 @@ import axios from "axios"; import { useSession } from "next-auth/react"; import Navbar from '../../components/Navbar'; import RecipeCard from '../../components/RecipeCard'; +import EditRecipeCard from '@/components/EditRecipeCard'; function SavedRecipesPage() { const { data: session, status } = useSession(); const [recipes, setRecipes] = useState([]); const [favoritedRecipes, setFavoritedRecipes] = useState>(new Set()); + const [editingRecipe, setEditingRecipe] = useState(null); useEffect(() => { if (session) { @@ -57,6 +59,23 @@ function SavedRecipesPage() { } }; + const handleEditRecipe = (recipe: any) => { + setEditingRecipe(recipe); + }; + + const handleSaveEditedRecipe = (editedRecipe: any) => { + setRecipes(prevRecipes => + prevRecipes.map(recipe => + recipe.id === editedRecipe.id ? editedRecipe : recipe + ) + ); + setEditingRecipe(null); + }; + + const handleCancelEdit = () => { + setEditingRecipe(null); + }; + if (status === "loading") return

Loading...

; if (!session) return

You need to be logged in to view this page.

; @@ -67,26 +86,35 @@ function SavedRecipesPage() {

Favorite Recipes

-
- {recipes.length > 0 ? ( - recipes.map((recipe) => ( - - )) - ) : ( -

No saved recipes found.

- )} -
+ + {editingRecipe ? ( + + ) : ( +
+ {recipes.length > 0 ? ( + recipes.map((recipe) => ( + + )) + ) : ( +

No saved recipes found.

+ )} +
+ )} ); } export default SavedRecipesPage; - diff --git a/components/EditRecipeCard.tsx b/components/EditRecipeCard.tsx index 14acbb9..3a81789 100644 --- a/components/EditRecipeCard.tsx +++ b/components/EditRecipeCard.tsx @@ -6,13 +6,10 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Checkbox } from '@/components/ui/checkbox'; -import { MoreHorizontal, Plus } from 'lucide-react'; +import { X, Plus } from 'lucide-react'; import OpenAI from 'openai'; import { useCallback } from 'react'; - - - const openaiKey = process.env.NEXT_PUBLIC_OPENAI_API_KEY; let openai: OpenAI; if (openaiKey) { @@ -56,6 +53,14 @@ export default function EditRecipeCard({ setIngredients([...ingredients, { id: Date.now(), original: '', selected: true }]); }; + const handleRemoveIngredient = (index: number) => { + setIngredients((prevIngredients: any) => { + const updatedIngredients = [...prevIngredients]; + updatedIngredients.splice(index, 1); + return updatedIngredients; + }); + }; + const handleUpdateRecipe = async () => { // console.log('Updating recipe...'); // console.log('Ingredients:', ingredients); @@ -72,7 +77,11 @@ export default function EditRecipeCard({ }, { role: "user", - content: `Update the following recipe with these new ingredients: ${selectedIngredients.map((ing: { original: any; }) => ing.original).join(', ')}. Original recipe: ${editedRecipe.instructions}. Strictly include the ingredient amount values and only use the new ingredients in the instructions. Stricly just write out the instructions very descriptively, nothing else.` + content: `Here is the original recipe: ${editedRecipe.instructions}. \ + Here are the only ingredients we have: ${selectedIngredients.map((ing: { original: any; }) => ing.original).join(', ')}. \ + Edit the recipe as little as possible with these new ingredients. Make sure not to include any ingredient not in the list.\ + Strictly include the ingredient amount values and only use the new ingredients in the instructions. \ + Stricly just write out the instructions very descriptively, nothing else.` } ], temperature: 0.7, @@ -91,19 +100,42 @@ export default function EditRecipeCard({ } }; - const handleInputChange = useCallback((e: React.ChangeEvent) => { const { name, value } = e.target; setEditedRecipe((prev: any) => ({ ...prev, [name]: value })); }, [setEditedRecipe]); // Include all dependencies used inside the callback - const handleSave = () => { - const updatedRecipe = { - ...editedRecipe, - extendedIngredients: ingredients, - }; - onSave(updatedRecipe); - }; +const handleSave = async () => { + const { _id, ...recipeToUpdate } = editedRecipe; // Exclude _id + + const updatedRecipe = { + ...recipeToUpdate, + extendedIngredients: ingredients, + }; + + try { + const response = await fetch('/api/updateRecipe', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(updatedRecipe), + }); + + const data = await response.json(); + + if (response.ok) { + // Update successful + console.log('Recipe updated successfully:', data); + onSave(updatedRecipe); // Optionally update parent state or close modal + } else { + // Handle error + console.error('Failed to update recipe:', data.error); + } + } catch (error) { + console.error('Error updating recipe:', error); + } +}; return ( @@ -139,8 +171,12 @@ export default function EditRecipeCard({ onChange={(e) => handleIngredientEdit(index, e.target.value)} className={`ml-2 flex-grow ${!ingredient.selected ? 'text-gray-400' : ''}`} /> - ))} @@ -156,7 +192,7 @@ export default function EditRecipeCard({ - + );