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.
|
||||
*/
|
||||
export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorProps) {
|
||||
/** draft of the new 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[]) => {
|
||||
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>
|
||||
// @todo add handling of images
|
||||
return (
|
||||
|
|
@ -30,7 +66,7 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
|||
{/* Title */}
|
||||
<h3 className="subsection-heading">Title</h3>
|
||||
<input
|
||||
className="input-field"
|
||||
className={`input-field ${errors.title ? "border-red-500" : ""}`}
|
||||
placeholder="Title"
|
||||
value={draft.title}
|
||||
onChange={e => setDraft({ ...draft, title: e.target.value })}
|
||||
|
|
@ -61,11 +97,13 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* Ingredient List */}
|
||||
{/* Ingredient List - @todo better visualization of errors! */}
|
||||
<div className={errors.ingredients ? "border border-red-500 rounded p-2" : ""}>
|
||||
<IngredientListEditor
|
||||
ingredients={draft.ingredients}
|
||||
onChange={updateIngredients}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h3 className="subsection-heading">Instructions</h3>
|
||||
{/* Instructions */}
|
||||
|
|
@ -80,7 +118,7 @@ export default function RecipeEditor({ recipe, onSave, onCancel }: RecipeEditorP
|
|||
{/* Save Button */}
|
||||
<button
|
||||
className="primary-button"
|
||||
onClick={() => onSave(draft)}
|
||||
onClick={() => handleSave(draft)}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue