index.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import React, { useState } from 'react';
  2. import { Formik, Field, FieldArray, FormikActions, FormikProps, FieldArrayRenderProps } from 'formik';
  3. import Recipe, { Ingredient, SubRecipe } from 'src/types/recipes';
  4. import { Grid, Row, Cell } from '@material/react-layout-grid';
  5. import './styles.scss';
  6. import sample_image from 'sample.png';
  7. type IngredientsListProps = {
  8. ingredients: SubRecipe[],
  9. }
  10. type RecipeFormProps = {
  11. initialValues: Recipe
  12. }
  13. const custom = (label: string, component = 'text') => ({field}: any) => (
  14. <span>
  15. <label>
  16. {label}
  17. </label>
  18. {
  19. component === 'text' ?
  20. <input {...field}/> :
  21. <textarea {...field}/>
  22. }
  23. </span>
  24. );
  25. const SubrecipeForm = ({form, remove, push}: any) => {
  26. const [selectedTab, setSelectedTab] = useState(0);
  27. return (
  28. <div className='subrecipe-tabs'>
  29. <ul className='tab-header'>
  30. {
  31. form.values.ingredients.map((subrecipe: any, i: number) => (
  32. <li
  33. className={`tab${selectedTab === i ? ' tab--selected' : ''}`}
  34. key={i}
  35. >
  36. <div className='tab__content' onClick={()=> setSelectedTab(i)}>
  37. <Field name={`ingredients[${i}].name`}/>
  38. </div>
  39. <button type='button' onClick={()=> remove(i)}>X</button>
  40. </li>
  41. ))
  42. }
  43. <li className='tab tab--add'>
  44. <button type='button' onClick={()=> push({name: '', ingredients: []})}>+</button>
  45. </li>
  46. </ul>
  47. <div className='ingredients-form'>
  48. <div className='ingredients-form-header'>
  49. <span>Ingredient Name</span>
  50. <span>Quantity</span>
  51. <span>Unit</span>
  52. <span>Notes</span>
  53. <span>Original</span>
  54. </div>
  55. {
  56. form.values.ingredients[selectedTab].ingredients.map((ingredient: Ingredient, index: number) => (
  57. <div key={index}>
  58. <div className='ingredients-form-item'>
  59. <Field name={`ingredients[${selectedTab}].ingredients[${index}].name`} />
  60. <Field name={`ingredients[${selectedTab}].ingredients[${index}].quantity`}/>
  61. <Field component='select' name={`ingredients[${selectedTab}].ingredients[${index}].unit`}>
  62. <option value='gr'>gr</option>
  63. <option value='cup'>cup</option>
  64. <option value='ml'>ml</option>
  65. <option value='tablespoon'>tbsp</option>
  66. <option value='teaspoon'>tsp</option>
  67. </Field>
  68. <Field name={`ingredients[${selectedTab}].ingredients[${index}].notes`} />
  69. <Field name={`ingredients[${selectedTab}].ingredients[${index}]._original`}/>
  70. </div>
  71. <div className='ingredients-form-suggestions'>
  72. {
  73. ingredient.suggestions && ingredient.suggestions.map((suggestion, index) => (
  74. <button type='button' key={index}>{suggestion.name}</button>
  75. ))
  76. }
  77. <button type='button'>Add convertion</button>
  78. </div>
  79. </div>
  80. ))
  81. }
  82. </div>
  83. </div>
  84. )
  85. }
  86. const RenderForm = ({
  87. values,
  88. handleChange,
  89. handleSubmit
  90. }: FormikProps<Recipe>) => {
  91. return (
  92. <Grid>
  93. <form onSubmit={handleSubmit} className='cbk-recipe-form'>
  94. <Row>
  95. <Cell columns={2}>
  96. <img src={sample_image} style={{ width: '100%' }}/>
  97. </Cell>
  98. <Cell columns={10}>
  99. <Field name='name' render={custom('name')}/>
  100. <Field name='summary' render={custom('summary', 'textarea')}/>
  101. </Cell>
  102. </Row>
  103. <h5>Author Information</h5>
  104. <section>
  105. <Row>
  106. <Cell columns={3}>
  107. <Field name='author.name'/>
  108. </Cell>
  109. <Cell columns={3}>
  110. <Field name='author.website'/>
  111. </Cell>
  112. </Row>
  113. </section>
  114. <h5>Recipe Information</h5>
  115. <section>
  116. <Row>
  117. <Cell columns={3}>
  118. <Field name='details.preparationTime'/>
  119. </Cell>
  120. <Cell columns={3}>
  121. <Field name='details.cookingTime'/>
  122. </Cell>
  123. <Cell columns={3}>
  124. <Field name='details.servings' type='number'/>
  125. </Cell>
  126. <Cell columns={3}>
  127. <Field name='details.url'/>
  128. </Cell>
  129. <Cell columns={12}>
  130. </Cell>
  131. </Row>
  132. </section>
  133. <h5>Ingredients</h5>
  134. <section>
  135. <FieldArray
  136. name='ingredients'
  137. component={SubrecipeForm}
  138. />
  139. </section>
  140. <h5>Instructions</h5>
  141. <section>
  142. {
  143. values.instructions.map((instruction: any, i: number) => (
  144. <Row key={i}>
  145. <Cell columns={12}>
  146. <input
  147. type='text'
  148. id={`instructions[${i}]`}
  149. value={instruction}
  150. onChange={handleChange}
  151. />
  152. </Cell>
  153. </Row>
  154. ))
  155. }
  156. </section>
  157. <button type='submit'>Submit</button>
  158. </form>
  159. </Grid>
  160. );
  161. }
  162. const RecipeForm = ({ initialValues }: RecipeFormProps) => (
  163. <Formik
  164. initialValues={initialValues}
  165. onSubmit={(values: any, actions:any) => {
  166. console.log('submit', values, actions)
  167. }}
  168. render={RenderForm}
  169. />
  170. );
  171. export default RecipeForm;