From e94be51f3e9234ed972744fd6ee1aa3beac4a1f1 Mon Sep 17 00:00:00 2001 From: Anika Raemer Date: Sat, 11 Oct 2025 07:32:50 +0200 Subject: [PATCH] basic instructions editor --- .../src/api/dtos/RecipeInstructionStepDto.ts | 1 + frontend/src/api/points/CompactRecipePoint.ts | 2 +- .../recipes/IngredientListEditor.tsx | 2 +- .../recipes/InstructionStepListEditor.tsx | 56 +++++++++++++++++++ .../components/recipes/RecipeDetailPage.tsx | 10 +++- .../src/components/recipes/RecipeEditPage.tsx | 2 +- .../src/components/recipes/RecipeEditor.tsx | 25 ++++++--- frontend/src/mappers/recipeMapper.ts | 33 +++++------ frontend/src/models/InstructionStepModel.ts | 7 +++ frontend/src/models/RecipeModel.ts | 3 +- 10 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 frontend/src/components/recipes/InstructionStepListEditor.tsx create mode 100644 frontend/src/models/InstructionStepModel.ts diff --git a/frontend/src/api/dtos/RecipeInstructionStepDto.ts b/frontend/src/api/dtos/RecipeInstructionStepDto.ts index b9b902e..a6f5b3b 100644 --- a/frontend/src/api/dtos/RecipeInstructionStepDto.ts +++ b/frontend/src/api/dtos/RecipeInstructionStepDto.ts @@ -2,6 +2,7 @@ import { UUID } from "crypto"; import { AbstractDto } from "./AbstractDto.ts"; export class RecipeInstructionStepDto extends AbstractDto{ + id?: string; text!: string; sortOrder!: number; recipeId?: UUID; diff --git a/frontend/src/api/points/CompactRecipePoint.ts b/frontend/src/api/points/CompactRecipePoint.ts index 7855594..45cf28b 100644 --- a/frontend/src/api/points/CompactRecipePoint.ts +++ b/frontend/src/api/points/CompactRecipePoint.ts @@ -19,7 +19,7 @@ const RECIPE_URL = `${BASE_URL}/compact-recipe` * @returns Array of recipe */ export async function fetchRecipeList(searchString : string): Promise { - let url : string = RECIPE_URL; + let url : string = RECIPE_URL; // add an s to the base URL as we want to load a list // if there's a search string add it as query parameter if(searchString && searchString !== ""){ url +="?search=" + searchString; diff --git a/frontend/src/components/recipes/IngredientListEditor.tsx b/frontend/src/components/recipes/IngredientListEditor.tsx index 19c3d65..9b029ae 100644 --- a/frontend/src/components/recipes/IngredientListEditor.tsx +++ b/frontend/src/components/recipes/IngredientListEditor.tsx @@ -1,6 +1,6 @@ import type { IngredientModel } from "../../models/IngredientModel" import Button, { ButtonType } from "../basics/Button" -import SvgIcon, { Icon } from "../basics/SvgIcon" +import { Icon } from "../basics/SvgIcon" /** * Editor for handling the ingredient list diff --git a/frontend/src/components/recipes/InstructionStepListEditor.tsx b/frontend/src/components/recipes/InstructionStepListEditor.tsx new file mode 100644 index 0000000..c1fb4ee --- /dev/null +++ b/frontend/src/components/recipes/InstructionStepListEditor.tsx @@ -0,0 +1,56 @@ +import type { InstructionStepModel } from "../../models/InstructionStepModel" +import Button, { ButtonType } from "../basics/Button" +import { Icon } from "../basics/SvgIcon" + +/** + * Editor for handling the instruction step list + * Ingredients can be edited, added and removed + */ +type InstructionStepListEditorProps = { + instructionStepList: InstructionStepModel[] + onChange: (ingredients: InstructionStepModel[]) => void +} + +export function InstructionStepListEditor({ instructionStepList, onChange }: InstructionStepListEditorProps) { + const handleUpdate = (index: number, field: keyof InstructionStepModel, value: string) => { + const updated = instructionStepList.map((ing, i) => + i === index ? { ...ing, [field]: value } : ing + ) + onChange(updated) + } + + const handleAdd = () => { + onChange([...instructionStepList, { text: "" }]) + } + + const handleRemove = (index: number) => { + onChange(instructionStepList.filter((_, i) => i !== index)) + } + + return ( +
+

Zubereitung

+ {instructionStepList.map((step, index) => ( +
+ handleUpdate(index, "text", e.target.value)} + /> +
+ ))} +
+ ) +} diff --git a/frontend/src/components/recipes/RecipeDetailPage.tsx b/frontend/src/components/recipes/RecipeDetailPage.tsx index aebbc66..7e8e863 100644 --- a/frontend/src/components/recipes/RecipeDetailPage.tsx +++ b/frontend/src/components/recipes/RecipeDetailPage.tsx @@ -122,9 +122,15 @@ export default function RecipeDetailPage() { ))} - {/* Instructions */} + {/* Instructions - @todo add reasonable list delegate component*/}

Zubereitung

-

{recipe.instructions}

+
    + {recipe.instructionStepList.map((step,j) =>( +
  1. + {step.text} +
  2. + ))} +
{/* Action buttons */}
diff --git a/frontend/src/components/recipes/RecipeEditPage.tsx b/frontend/src/components/recipes/RecipeEditPage.tsx index 3732056..2b9d8b2 100644 --- a/frontend/src/components/recipes/RecipeEditPage.tsx +++ b/frontend/src/components/recipes/RecipeEditPage.tsx @@ -30,7 +30,7 @@ export default function RecipeEditPage() { title: "", ingredientGroupList: [ ], - instructions: "", + instructionStepList: [], servings: { amount: 1, unit: "" diff --git a/frontend/src/components/recipes/RecipeEditor.tsx b/frontend/src/components/recipes/RecipeEditor.tsx index e4f1289..e5b7062 100644 --- a/frontend/src/components/recipes/RecipeEditor.tsx +++ b/frontend/src/components/recipes/RecipeEditor.tsx @@ -3,6 +3,8 @@ import type { RecipeModel } from "../../models/RecipeModel" import type { IngredientGroupModel } from "../../models/IngredientGroupModel" import { IngredientGroupListEditor } from "./IngredientGroupListEditor" import Button, { ButtonType } from "../basics/Button" +import { InstructionStepListEditor } from "./InstructionStepListEditor" +import type { InstructionStepModel } from "../../models/InstructionStepModel" type RecipeEditorProps = { recipe: RecipeModel @@ -23,11 +25,20 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP /** * Update ingredients - * @param ingredients new ingredients + * @param ingredientGroupList updated ingredient groups and ingredients */ const updateIngredientGroupList = (ingredientGroupList: IngredientGroupModel[]) => { setDraft({ ...draft, ingredientGroupList }) } + + /** + * Update instruction steps + * @param instructionStepList updated instructions + */ + const updateInstructionList = (instructionStepList: InstructionStepModel[]) => { + setDraft({ ...draft, instructionStepList }) + } + /** * Validate recipe * @returns Information on the errors the validation encountered @@ -119,14 +130,12 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP />
-

Instructions

- {/* Instructions */} -