+ );
+}
diff --git a/frontend/src/components/recipes/InstructionStepListDesktopEditor.tsx b/frontend/src/components/recipes/InstructionStepListDesktopEditor.tsx
new file mode 100644
index 0000000..49d68d4
--- /dev/null
+++ b/frontend/src/components/recipes/InstructionStepListDesktopEditor.tsx
@@ -0,0 +1,86 @@
+/**
+ * Desktop editor using drag-and-drop via @dnd-kit
+ */
+
+import {
+ DndContext,
+ closestCenter,
+ PointerSensor,
+ useSensor,
+ useSensors,
+} from "@dnd-kit/core";
+import {
+ arrayMove,
+ SortableContext,
+ verticalListSortingStrategy,
+} from "@dnd-kit/sortable";
+import type { InstructionStepModel } from "../../models/InstructionStepModel";
+import { InstructionStepDesktopListItem } from "./InstructionStepDesktopListItem";
+import { useInstructionStepListEditor } from "./InstructionStepListEditor";
+import Button, { ButtonType } from "../basics/Button";
+import { Icon } from "../basics/SvgIcon";
+
+type InstructionStepListDesktopEditorProps = {
+ instructionStepList: InstructionStepModel[];
+ onChange: (steps: InstructionStepModel[]) => void;
+};
+
+export function InstructionStepListDesktopEditor({
+ instructionStepList,
+ onChange,
+}: InstructionStepListDesktopEditorProps) {
+ const { handleUpdate, handleAdd, handleRemove } = useInstructionStepListEditor(
+ instructionStepList,
+ onChange
+ );
+
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } }));
+
+ const handleDragEnd = (event: any) => {
+ const { active, over } = event;
+ if (active.id !== over.id) {
+ /* find element by internal id
+ * Caution! Due to new elements not having a real ID yet, each list item has an internal ID
+ * in order to give it a unique identifier before saving it to the backend. We have to compare
+ * the id of the drag item to the internalId of the list item here!
+ */
+ const oldIndex = instructionStepList.findIndex((i) => i.internalId === active.id);
+ const newIndex = instructionStepList.findIndex((i) => i.internalId === over.id);
+ // move element to new position
+ const newOrder = arrayMove(instructionStepList, oldIndex, newIndex);
+ onChange(newOrder);
+ }
+ };
+
+ return (
+
diff --git a/frontend/src/components/recipes/RecipeEditPage.tsx b/frontend/src/components/recipes/RecipeEditPage.tsx
index 2b9d8b2..594b42e 100644
--- a/frontend/src/components/recipes/RecipeEditPage.tsx
+++ b/frontend/src/components/recipes/RecipeEditPage.tsx
@@ -4,7 +4,7 @@ import type { RecipeModel } from "../../models/RecipeModel"
import RecipeEditor from "./RecipeEditor"
import { fetchRecipe, createOrUpdateRecipe } from "../../api/points/RecipePoint"
import { getRecipeDetailUrl, getRecipeListUrl } from "../../routes"
-import { mapRecipeDtoToModel, mapRecipeModelToDto } from "../../mappers/recipeMapper"
+import { mapRecipeDtoToModel, mapRecipeModelToDto } from "../../mappers/RecipeMapper"
import type { RecipeDto } from "../../api/dtos/RecipeDto"
export default function RecipeEditPage() {
diff --git a/frontend/src/mappers/recipeMapper.ts b/frontend/src/mappers/RecipeMapper.ts
similarity index 88%
rename from frontend/src/mappers/recipeMapper.ts
rename to frontend/src/mappers/RecipeMapper.ts
index d398687..fe72204 100644
--- a/frontend/src/mappers/recipeMapper.ts
+++ b/frontend/src/mappers/RecipeMapper.ts
@@ -16,13 +16,17 @@ export function mapRecipeDtoToModel(dto: RecipeDto): RecipeModel {
amount: dto.amount ?? 1,
unit: dto.amountDescription ?? "",
},
- // @todo implement steps in frontend
// join all instruction step texts into a single string for display
instructionStepList: dto.instructions
.sort((a, b) => a.sortOrder - b.sortOrder) // ensure correct order
.map(step => ({
text: step.text,
- id: step.id
+ id: step.id,
+ /* When mapping a stepDTO, it should already contain a UUID. If
+ * If, however, for some reason, it does not, add a UUID as sorting
+ * steps in teh GUI requires a unique identifier for each item.
+ */
+ internalId: step.id !== undefined? step.id : crypto.randomUUID()
})
),
diff --git a/frontend/src/models/InstructionStepModel.ts b/frontend/src/models/InstructionStepModel.ts
index bdcfdf1..fec1123 100644
--- a/frontend/src/models/InstructionStepModel.ts
+++ b/frontend/src/models/InstructionStepModel.ts
@@ -3,5 +3,10 @@
*/
export interface InstructionStepModel{
id?: string;
+ /**
+ * Unique id required for sorting via drag & drop
+ * Local to the frontend!
+ */
+ internalId: string;
text: string;
}
\ No newline at end of file