import { useState } from "react" import type { Recipe } from "../../types/recipe" import type { IngredientGroup } from "../../types/ingredientGroup" import { IngredientGroupListEditor } from "./IngredientGroupListEditor" type RecipeEditorProps = { recipe: Recipe onSave: (recipe: Recipe) => void onCancel: () => void } /** * Editor component for managing a recipe, including title, * ingredients (with amount, unit, name), instructions, and image URL. * @todo adapt to ingredientGroups! */ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorProps) { /** draft of the new recipe */ const [draft, setDraft] = useState(recipe) /** Error list */ const [errors, setErrors] = useState<{ title?: boolean; ingredients?: boolean }>({}) /** * Update ingredients * @param ingredients new ingredients */ const updateIngredientGroupList = (ingredientGroupList: IngredientGroup[]) => { setDraft({ ...draft, ingredientGroupList }) } /** * Validate recipe * @returns Information on the errors the validation encountered */ const validate = () => { const newErrors: { title?: boolean; ingredients?: boolean } = {} // each recipe requires a title if (!draft.title.trim()) { newErrors.title = true } /* there must be at least one ingredient group * no group may contain an empty ingredient list * @todo check whether all ingredients are valid * @todo enhance visualization of ingredient errors */ if (!draft.ingredientGroupList || draft.ingredientGroupList.length === 0) { newErrors.ingredients = true } else { let isAnyIngredientListEmpty = draft.ingredientGroupList.some( ingGrp => { return !ingGrp.ingredientList || ingGrp.ingredientList.length === 0 } ) if(isAnyIngredientListEmpty){ newErrors.ingredients = true } } setErrors(newErrors) return Object.keys(newErrors).length === 0 } /** Handles saving and ensures that the draft is only saved if valid */ const handleSave = (draft: Recipe) => { if (validate()) { onSave(draft) } } // ensure that there is a recipe and show error otherwise if (!recipe) return
Oops, there's no recipe in RecipeEditor...
// @todo add handling of images return (

{recipe.id ? "Edit Recipe" : "New Recipe"}

{/* Title */}

Title

setDraft({ ...draft, title: e.target.value })} /> {/* Servings */}

Servings

{ const tempServings = draft.servings tempServings.amount = Number(e.target.value) setDraft({...draft, servings: tempServings}) }} /> { const tempServings = draft.servings tempServings.unit = e.target.value setDraft({...draft, servings: tempServings}) }} />
{/* Ingredient List - @todo better visualization of errors! */}

Instructions

{/* Instructions */}