import {useParams} from "react-router-dom" import type {RecipeModel} from "../../models/RecipeModel" import {useEffect, useState} from "react" import {fetchRecipe} from "../../api/points/RecipePoint" import {getRecipeEditUrl, getRecipeListUrl} from "../../routes" import ButtonLink from "../basics/ButtonLink" import {mapRecipeDtoToModel} from "../../mappers/RecipeMapper" import {NumberStepControl} from "../basics/NumberStepControl.tsx"; import {NumberedListItem} from "../basics/NumberedListItem.tsx"; /** * Displays the full detail of a single recipe, * including its ingredients, instructions, and image. */ export default function RecipeDetailPage() { // Extract recipe ID from route params const {id} = useParams<{ id: string }>() // the recipe loaded from the backend, don't change this! it's required for scaling const [recipe, setRecipe] = useState(null) // Working copy for re-calculating ingredients const [recipeWorkingCopy, setRecipeWorkingCopy] = useState(null) // load recipe data whenever id changes useEffect(() => { const loadRecipe = async () => { if (id) { // Fetch recipe data when editing an existing one console.log("loading recipe with id", id) const data = await fetchRecipe(id) if (data.id != id) { throw new Error("Id mismatch when loading recipes: " + id + " requested and " + data.id + " received!"); } setRecipe(mapRecipeDtoToModel(data)) } } loadRecipe() }, [id]) // set original recipe data and working copy when recipe changes useEffect(() => { setRecipeWorkingCopy(recipe); }, [recipe]) if (!recipe || !recipeWorkingCopy) { return

Recipe not found.

} /** recalculate ingredients based on the amount of servings */ const recalculateIngredients = (newAmount: number) => { // Always calculate factor from the *original recipe*, not the working copy const factor = newAmount / recipe.servings.amount // Create a new ingredient list with updated amounts const updatedIngredientGroupList = recipe.ingredientGroupList.map((ingGrp) => ({ ...ingGrp, ingredientList: ingGrp.ingredientList.map((ing) => ({ ...ing, amount: ing.amount * factor, })) })) // Update working copy with new servings + recalculated ingredients setRecipeWorkingCopy({ ...recipeWorkingCopy, servings: { ...recipeWorkingCopy.servings, amount: newAmount, }, ingredientGroupList: updatedIngredientGroupList, }) } return ( /*Container spanning entire screen used to center content horizontally */
{/* Container defining the maximum width of the content */}
{/* Header - remains in position when scrolling */}

{recipeWorkingCopy.title}

{/* Content */}
{/* Recipe image */} {recipe.imageUrl && ( {recipe.title} )} {/* Servings */}

Für {recipeWorkingCopy.servings.amount} {recipeWorkingCopy.servings.unit}

{/* Ingredients */}

Zutaten

    {recipeWorkingCopy.ingredientGroupList.map((group, i) => (
    {/* the title is optional, only print if present */} {group.title && group.title.trim() !== "" && (

    {group.title}

    )}
      {group.ingredientList.map((ing, j) => (
    • {ing.amount} {ing.unit ?? ""} {ing.name}
    • ))}
    ))}
{/* Instructions - @todo add reasonable list delegate component*/}
    {recipe.instructionStepList.map((step, j) => ( ))}
{/* Action buttons */}
) }