added validation of recipes to editor
This commit is contained in:
parent
69b7920f23
commit
37057f19f1
1 changed files with 41 additions and 3 deletions
|
|
@ -14,11 +14,47 @@ type RecipeEditorProps = {
|
||||||
* ingredients (with amount, unit, name), instructions, and image URL.
|
* ingredients (with amount, unit, name), instructions, and image URL.
|
||||||
*/
|
*/
|
||||||
export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorProps) {
|
export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorProps) {
|
||||||
|
/** draft of the new recipe */
|
||||||
const [draft, setDraft] = useState<Recipe>(recipe)
|
const [draft, setDraft] = useState<Recipe>(recipe)
|
||||||
|
/** Error list */
|
||||||
|
const [errors, setErrors] = useState<{ title?: boolean; ingredients?: boolean }>({})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update ingredients
|
||||||
|
* @param ingredients new ingredients
|
||||||
|
*/
|
||||||
const updateIngredients = (ingredients: Ingredient[]) => {
|
const updateIngredients = (ingredients: Ingredient[]) => {
|
||||||
setDraft({ ...draft, ingredients })
|
setDraft({ ...draft, ingredients })
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// the incredient list must not be empty
|
||||||
|
// @todo enhance validation and visualization of ingredient errors
|
||||||
|
if (!draft.ingredients || draft.ingredients.length === 0) {
|
||||||
|
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 <div>Oops, there's no recipe in RecipeEditor...</div>
|
if (!recipe) return <div>Oops, there's no recipe in RecipeEditor...</div>
|
||||||
// @todo add handling of images
|
// @todo add handling of images
|
||||||
return (
|
return (
|
||||||
|
|
@ -30,7 +66,7 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<h3 className="subsection-heading">Title</h3>
|
<h3 className="subsection-heading">Title</h3>
|
||||||
<input
|
<input
|
||||||
className="input-field"
|
className={`input-field ${errors.title ? "border-red-500" : ""}`}
|
||||||
placeholder="Title"
|
placeholder="Title"
|
||||||
value={draft.title}
|
value={draft.title}
|
||||||
onChange={e => setDraft({ ...draft, title: e.target.value })}
|
onChange={e => setDraft({ ...draft, title: e.target.value })}
|
||||||
|
|
@ -61,11 +97,13 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* Ingredient List */}
|
{/* Ingredient List - @todo better visualization of errors! */}
|
||||||
|
<div className={errors.ingredients ? "border border-red-500 rounded p-2" : ""}>
|
||||||
<IngredientListEditor
|
<IngredientListEditor
|
||||||
ingredients={draft.ingredients}
|
ingredients={draft.ingredients}
|
||||||
onChange={updateIngredients}
|
onChange={updateIngredients}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 className="subsection-heading">Instructions</h3>
|
<h3 className="subsection-heading">Instructions</h3>
|
||||||
{/* Instructions */}
|
{/* Instructions */}
|
||||||
|
|
@ -80,7 +118,7 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
||||||
{/* Save Button */}
|
{/* Save Button */}
|
||||||
<button
|
<button
|
||||||
className="primary-button"
|
className="primary-button"
|
||||||
onClick={() => onSave(draft)}
|
onClick={() => handleSave(draft)}
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue