/addRecipe.js Secret
Created
April 6, 2020 13:31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useReducer } from 'react'; | |
import { Form, Button, ListGroup } from 'react-bootstrap'; | |
import { useForm } from 'react-hook-form'; | |
import FormGroupArray from '../formGroupArray' | |
import { reducer, itemReducer, init } from './inputHandlers'; | |
//controlled inputs initial state | |
const initialState = { | |
title: '', | |
brief: '', | |
ingredient: '', | |
quantity: '', | |
unit: '', | |
step: '', | |
type: '', | |
main: '', | |
occasion: '', | |
method: '', | |
diet: '', | |
notes: '' | |
}; | |
const AddRecipe = () => { | |
//state reducers for input elements and list elements | |
const [input, dispatch] = useReducer(reducer, initialState, init); | |
const [ingredients, updateIngredients] = useReducer(itemReducer, []); | |
const [steps, updateSteps] = useReducer(itemReducer, []); | |
//event handler for input elements | |
/*const handleChange = e => { | |
dispatch({ field: e.target.name, value: e.target.value }) | |
}*/ | |
//handler for adding list item elements | |
async function addItem(fields) { | |
//add list item with input field value | |
let values = []; | |
let keys = []; | |
for (const key in fields) { | |
values.push(fields[key]); | |
keys.push(key); | |
} | |
const valid = await triggerValidation(keys); | |
if (!valid) return; | |
let action = { type: 'add', payload: <ListGroup.Item onClick={removeItem}>{values.join(' ')}</ListGroup.Item> }; | |
switch (keys[0]) { | |
case 'ingredient': | |
updateIngredients(action) | |
break; | |
case 'step': | |
updateSteps(action) | |
break; | |
default: | |
break; | |
} | |
//clear input fields | |
//keys.forEach(key => dispatch({ field: key, value: '' })) | |
keys.forEach(key => { | |
setValue(key, ''); | |
}) | |
} | |
//handler for removing list item elements | |
const removeItem = (e) => { | |
//remove list item upon click on | |
let action = { type: 'remove', payload: e.currentTarget.textContent }; | |
console.log(e.target.parentNode.id); | |
switch (e.target.parentNode.id) { | |
case 'ingredientsList': | |
updateIngredients(action); | |
break; | |
case 'stepsList': | |
updateSteps(action); | |
break; | |
default: break; | |
} | |
} | |
//state object for input elements | |
const { title, brief, ingredient, quantity, unit, step, type, main, occasion, method, diet, notes } = input; | |
//Form validation | |
const { register, handleSubmit, errors, watch, triggerValidation, setValue } = useForm(); //react-hook-form package | |
const quantityPattern = /(^\s*$)|(^\s*[-]?\d+([.,]?\d+)?([\/][-]?\d+([.,]?\d+)?)?\s*$)/; | |
const requiredMessage = "This field is required"; | |
//submit function for validation proccess | |
const onSubmit = (data, e) => { | |
e.preventDefault(); | |
alert('test'); | |
} | |
//submiting recipe form | |
let createRecipe = (title, brief, ingredientsList, stepsList, type, main, occasion, method, diet, notes) => { | |
let ingredients = ingredientsList.map(el => el.props.children); | |
let steps = stepsList.map(el => el.props.children); | |
let details = { type, main, occasion, method, diet }; | |
return { title, brief, ingredients, steps, details, notes } | |
} | |
const submitRecipe = () => { | |
dispatch({ type: 'reset', value: initialState }) | |
let recipe = createRecipe(title, brief, ingredients, steps, type, main, occasion, method, diet, notes); | |
} | |
//Actual element for addRecipe form | |
return ( | |
<Form onSubmit={handleSubmit(onSubmit)}> | |
{/*TITLE AND BRIEF DESCRIPTION*/} | |
<FormGroupArray errors={errors} groups={ | |
[ | |
{ | |
id: "title", | |
label: "Title:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.title }, | |
message: [{ type: "required", text: requiredMessage }] | |
}, | |
{ | |
id: "brief", | |
label: "Brief description:", | |
control: { as: "textarea", ref: register({ required: true }), isInvalid: errors.brief }, | |
message: [{ type: "required", text: requiredMessage }] | |
} | |
]} | |
/> | |
{/*////////////////////////////////////////////////////////////////////////////////////////////*/} | |
{/*SECTION INGREDIENTS*/} | |
<section className="hr"> | |
<h2>Ingredients</h2> | |
<FormGroupArray errors={errors} groups={ | |
[ | |
{ | |
id: "ingredient", | |
label: "Ingredient:", | |
control: { as: "input", type: "text", ref: register({ required: true, minLength: 2 }), isInvalid: errors.ingredient }, | |
message: [{ type: "required", text: requiredMessage }, { type: "minLength", text: "Ingredient should be at least 2 characters" }], | |
}, | |
{ | |
id: "quantity", | |
label: "Quantity:", | |
control: { as: "input", type: "text", ref: register({ required: true, pattern: quantityPattern }), isInvalid: errors.quantity }, | |
message: [{ type: "required", text: requiredMessage }, { type: "pattern", text: "Quantity should be a number" }] | |
}, | |
{ | |
id: "unit", | |
label: "Unit:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.unit }, | |
message: [{ type: "required", text: requiredMessage }], | |
button: { name: "addIngredient", variant: "primary", text: "Add ingredient", onClick: () => addItem({ ingredient: watch("ingredient"), quantity: watch("quantity"), unit: watch("unit") }) } | |
} | |
]} | |
/> | |
{ingredients && | |
<ListGroup as="ul" id="ingredientsList">{ingredients}</ListGroup> | |
} | |
</section> | |
{/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////*/} | |
{/*SECTION PREPARATION*/} | |
<section className="hr"> | |
<h2>Preparation</h2> | |
<Form.Group controlId="step"> | |
<Form.Label>Step:</Form.Label> | |
<Form.Control as="input" type="text" name="step" ref={register({ required: true, minLength: 2, /*pattern: stepPattern*/ })} isInvalid={errors.step} /> | |
<Form.Control.Feedback type="invalid"> | |
{errors.step && errors.step.type === "required" && requiredMessage} | |
{errors.step && errors.step.type === "minLength" && "Step should be at least 2 characters"} | |
</Form.Control.Feedback> | |
</Form.Group> | |
<Button name="addStep" variant="primary" onClick={() => addItem({ step: watch('step') })}>Add step</Button> | |
{steps && | |
<ListGroup as="ul" id="stepsList">{steps}</ListGroup> | |
} | |
</section> | |
{/*////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/} | |
{/*SECTION DETAILS*/} | |
<section className="hr"> | |
<h2>Details</h2> | |
<FormGroupArray errors={errors} groups={ | |
[ | |
{ | |
id: "type", | |
label: "Type:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.type }, | |
message: [{ type: "required", text: requiredMessage }] | |
}, | |
{ | |
id: "main", | |
label: "Main ingredient(s):", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.main }, | |
message: [{ type: "required", text: requiredMessage }] | |
}, | |
{ | |
id: "occasion", | |
label: "Season/Ocasion:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.occasion }, | |
message: [{ type: "required", text: requiredMessage }] | |
}, | |
{ | |
id: "method", | |
label: "Preparation method:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.method }, | |
message: [{ type: "required", text: requiredMessage }] | |
}, | |
{ | |
id: "diet", | |
label: "Dietary consideration:", | |
control: { as: "input", type: "text", ref: register({ required: true }), isInvalid: errors.diet }, | |
message: [{ type: "required", text: requiredMessage }] | |
} | |
]} | |
/> | |
</section> | |
{/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/} | |
{/*SECTION NOTES*/} | |
<section className="hr"> | |
<h2>Notes</h2> | |
<Form.Group controlId="notes"> | |
<Form.Control as="textarea" name="notes" ref={register({ required: true })} isInvalid={errors.notes} /> | |
<Form.Control.Feedback type="invalid"> | |
{errors.step && errors.step.type === "required" && requiredMessage} | |
</Form.Control.Feedback> | |
</Form.Group> | |
</section> | |
{/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/} | |
<Button type="submit" name="submitRecipe" variant="primary" size="lg" block>Add recipe</Button> | |
</Form> | |
) | |
} | |
export default AddRecipe; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment