feat: synchronize recipe completion controls

Fixes #5\nRefs #1, #2
This commit is contained in:
2026-08-14 13:28:57 -05:00
parent b61ca70bed
commit 6f28f83f4a
10 changed files with 334 additions and 29 deletions
+35
View File
@@ -0,0 +1,35 @@
function flattenInstructions(instructions) {
return instructions.flatMap((instruction) => {
if (typeof instruction === "string") return [instruction];
if (Array.isArray(instruction?.itemListElement)) return flattenInstructions(instruction.itemListElement);
return instruction?.text ? [instruction.text] : [];
});
}
function normalizeProgress(progress = {}) {
return {
completedIngredients: [...new Set((progress.completedIngredients || []).filter(Number.isInteger))],
completedSteps: [...new Set((progress.completedSteps || []).filter(Number.isInteger))]
};
}
function updateProgress(recipe, progress, { kind, index, completed }) {
if (!recipe || !["ingredient", "step"].includes(kind)
|| !Number.isInteger(index) || typeof completed !== "boolean") {
throw new Error("Invalid progress update");
}
const limit = kind === "ingredient"
? (recipe.recipeIngredient || []).length
: flattenInstructions(recipe.recipeInstructions || []).length;
if (index < 0 || index >= limit) throw new Error("Progress item does not exist");
const key = kind === "ingredient" ? "completedIngredients" : "completedSteps";
const next = normalizeProgress(progress);
const items = new Set(next[key]);
if (completed) items.add(index);
else items.delete(index);
next[key] = [...items].sort((left, right) => left - right);
return next;
}
module.exports = { flattenInstructions, normalizeProgress, updateProgress };