Selaa lähdekoodia

Implement Tabs in ingredientForm

Tatiana Inama 7 vuotta sitten
vanhempi
commit
28ed30ad80

+ 1 - 1
recipes/.storybook/config.js

@@ -1,6 +1,6 @@
 import { configure } from '@storybook/react';
 
-const req = require.context('../src/components', true, /\.stories\.js$/);
+const req = require.context('../src/components', true, /stories\.js$/);
 
 function loadStories() {
   req.keys().forEach(filename => req(filename));

+ 19 - 31
recipes/src/components/IngredientForm/index.tsx

@@ -2,23 +2,20 @@ import React from 'react';
 import Input from 'components/Input';
 import Select from 'components/Select';
 import List, {ListItem, ListItemText} from '@material/react-list';
-import Tab from '@material/react-tab';
-import TabBar from '@material/react-tab-bar';
+import { TabBar } from 'components/TabBar';
 
 import IRecipe, { ISubRecipe, IAuthor, IDetails, _recipe, _subRecipe, _ingredient, IIngredient, ISuggestion } from 'types/recipes';
 
 import '@material/react-list/dist/list.min.css';
-import '@material/react-tab-bar/dist/tab-bar.css';
-import '@material/react-tab-scroller/dist/tab-scroller.css';
-import '@material/react-tab/dist/tab.css';
-import '@material/react-tab-indicator/dist/tab-indicator.css';
 import './styles.scss';
 import MaterialIcon from '@material/react-material-icon';
 
 type IngredientFormProps = {
   components: ISubRecipe[],
   updateField: (key: any[]) => (e: any) => void,
-
+  addSubrecipe: () => void,
+  updateSubrecipeName: (subrecipe: number, newValue: string) => void,
+  removeSubrecipe: (index: number) => void,
 };
 
 class IngredientForm extends React.Component<IngredientFormProps, { activeGroup: number }>{
@@ -36,34 +33,25 @@ class IngredientForm extends React.Component<IngredientFormProps, { activeGroup:
     console.log('change', event);
   }
 
-  render() {
-    const {updateField, components} = this.props;
+  addTag = () => {
+    this.setState({
 
+    })
+  }
+  render() {
+    const {updateField, components, addSubrecipe, updateSubrecipeName, removeSubrecipe} = this.props;
+    const tabs = components.map(group => group.name);
     return (
       <div className='cbk-ingredient-form'>
         <div className='cbk-ingredients-subrecipe-list'>
-          <TabBar>
-          {
-            components.map((group, groupIdx) => (
-              // <div>
-              //   <Input
-              //     label='sub recipe name'
-              //     value={group.name}
-              //     style='display'
-              //     onChange={updateField(['ingredients', groupIdx, 'name'])}
-              //   />
-              // </div>
-              <Tab key={groupIdx}>
-                <Input
-                   label='sub recipe name'
-                   value={group.name}
-                   style='display'
-                   onChange={updateField(['ingredients', groupIdx, 'name'])}
-                />
-              </Tab>
-            ))
-          }
-          </TabBar>
+          <TabBar
+            tabs={tabs}
+            onAddTab={addSubrecipe}
+            onUpdateTab={updateSubrecipeName}
+            onDeleteTab={removeSubrecipe}
+            onSelectTab={this.handleActiveIndexUpdate}
+            activeIndex={this.state.activeGroup}
+          />
         </div>
         {
           components.map((group, groupIdx) => (

+ 309 - 0
recipes/src/components/IngredientForm/stories.js

@@ -0,0 +1,309 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+import { action } from '@storybook/addon-actions';
+import IngredientForm from './index';
+import { assocPath } from 'ramda';
+
+const tabs = [
+  'for the chicken',
+  'for the sauce',
+  'for the rice',
+  'for the extra steps',
+]
+
+class Form extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      components: [
+        {
+          "name": "",
+          "ingredients": []
+        },
+        {
+          "name": "For the Chicken:",
+          "ingredients": [
+            {
+              "name": "thin boneless skinless chicken breast",
+              "quantity": 1.5,
+              "unit": "pound",
+              "_original": "1-1/2 lb of Thin Boneless Skinless Chicken Breast",
+              "suggestions": []
+            },
+            {
+              "name": "olive oil",
+              "quantity": 2,
+              "unit": "tablespoon",
+              "_original": "2 Tbsp of Olive Oil",
+              "suggestions": []
+            },
+            {
+              "name": "juice of  lime",
+              "quantity": 1,
+              "unit": "",
+              "_original": "Juice of 1 Lime",
+              "suggestions": []
+            },
+            {
+              "name": "chili powder",
+              "quantity": 0.5,
+              "unit": "teaspoon",
+              "_original": "1/2 tsp of Chili Powder",
+              "suggestions": [
+                {
+                  "_id": "5cf1397d72cd194524435041",
+                  "name": "cocoa powder",
+                  "variants": [
+                    "cocoa"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 118,
+                    "tbsp": 16,
+                    "tsp": 48
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr"
+                },
+                {
+                  "_id": "5cf1397d72cd19452443503c",
+                  "name": "icing sugar",
+                  "variants": [
+                    "confectioner sugar",
+                    "powdered sugar"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 125,
+                    "oz": 0.27,
+                    "tbsp": 15,
+                    "tsp": 45,
+                    "lb": 0.27
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr"
+                }
+              ]
+            },
+            {
+              "name": "oregano",
+              "quantity": 0.5,
+              "unit": "teaspoon",
+              "_original": "1/2 tsp of Oregano",
+              "suggestions": []
+            },
+            {
+              "name": "cumin",
+              "quantity": 0.5,
+              "unit": "teaspoon",
+              "_original": "1/2 tsp of Cumin",
+              "suggestions": []
+            },
+            {
+              "name": "paprika",
+              "quantity": 0.5,
+              "unit": "teaspoon",
+              "_original": "1/2 tsp of Paprika",
+              "suggestions": []
+            },
+            {
+              "name": "granulated garlic",
+              "quantity": 0.5,
+              "unit": "teaspoon",
+              "_original": "1/2 tsp of Granulated Garlic",
+              "suggestions": [
+                {
+                  "_id": "5cf1397d72cd19452443503b",
+                  "name": "granulated sugar",
+                  "variants": [
+                    "sugar",
+                    "plain sugar"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 200,
+                    "oz": 7.1,
+                    "tbsp": 14,
+                    "tsp": 42,
+                    "lb": 0.4
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr"
+                }
+              ]
+            },
+            {
+              "name": "salt, to taste",
+              "quantity": 0,
+              "unit": "",
+              "_original": "Salt, to taste",
+              "suggestions": []
+            }
+          ]
+        },
+        {
+          "name": "For the Dressing:",
+          "ingredients": [
+            {
+              "name": "plain greek yogurt",
+              "quantity": 0.5,
+              "unit": "cup",
+              "_original": "1/2 cup of Plain Greek Yogurt",
+              "suggestions": [
+                {
+                  "_id": "5cf1397d72cd194524435040",
+                  "name": "yogurt",
+                  "variants": [
+                    "plain yogurt"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 245,
+                    "oz": 8.64,
+                    "tbsp": 16,
+                    "tsp": 48
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr"
+                },
+                {
+                  "_id": "5cf1397d72cd19452443503b",
+                  "name": "granulated sugar",
+                  "variants": [
+                    "sugar",
+                    "plain sugar"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 200,
+                    "oz": 7.1,
+                    "tbsp": 14,
+                    "tsp": 42,
+                    "lb": 0.4
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr"
+                },
+                {
+                  "_id": "5cf1397d72cd194524435030",
+                  "name": "all purpose flour",
+                  "variants": [
+                    "plain flour",
+                    "all purpose flour",
+                    "regular flour",
+                    "flour"
+                  ],
+                  "equivalences": {
+                    "cup": 1,
+                    "gr": 125,
+                    "tbsp": 15.5,
+                    "tsp": 47
+                  },
+                  "referenceUnit": "cup",
+                  "prefferedUnit": "gr",
+                  "translation": {
+                    "dutch": "patentbloem"
+                  }
+                }
+              ]
+            },
+            {
+              "name": "fresh cilantro",
+              "quantity": 1,
+              "unit": "cup",
+              "_original": "1 cup of Fresh Cilantro",
+              "suggestions": []
+            },
+            {
+              "name": "scallions, roughly chopped",
+              "quantity": 2,
+              "unit": "",
+              "_original": "2 Scallions, roughly chopped",
+              "suggestions": []
+            },
+            {
+              "name": "juice of  lime or more, according to taste",
+              "quantity": 1,
+              "unit": "",
+              "_original": "Juice of 1 Lime or more, according to taste",
+              "suggestions": []
+            },
+            {
+              "name": "olive oil",
+              "quantity": 1,
+              "unit": "tablespoon",
+              "_original": "1 Tbsp of Olive Oil",
+              "suggestions": []
+            },
+            {
+              "name": "salt, to taste",
+              "quantity": 0,
+              "unit": "",
+              "_original": "Salt, to taste",
+              "suggestions": []
+            }
+          ]
+        },
+        {
+          "name": "For the rest of the salad:",
+          "ingredients": [
+            {
+              "name": "fresh lettuce of your choice",
+              "quantity": 0,
+              "unit": "",
+              "_original": "Fresh Lettuce of your choice",
+              "suggestions": []
+            },
+            {
+              "name": "bell peppers, halved and seeded",
+              "quantity": 2,
+              "unit": "",
+              "_original": "2 Bell Peppers, halved and seeded",
+              "suggestions": []
+            },
+            {
+              "name": "scallions or red onion, sliced",
+              "quantity": 0,
+              "unit": "",
+              "_original": "Scallions or REd Onion, sliced",
+              "suggestions": []
+            },
+            {
+              "name": "pico de gallo salsa",
+              "quantity": 0.5,
+              "unit": "cup",
+              "_original": "1/2 cup of Pico De Gallo Salsa",
+              "suggestions": []
+            },
+            {
+              "name": "avocado, sliced",
+              "quantity": 1,
+              "unit": "",
+              "_original": "1 Avocado, sliced",
+              "suggestions": []
+            }
+          ]
+        }
+      ]
+    }
+  }
+
+  updateField = (key) => {
+    return (e) => {
+      const newValue = e.currentTarget.value;
+      this.setState(assocPath(key, newValue, this.state.components))
+    }
+  }
+
+  render(){
+    return (
+      <IngredientForm
+        components={this.state.components}
+        updateField={this.updateField}
+      />
+    )
+  }
+}
+
+storiesOf('IngredientForm', module)
+  .add('Basic ingredients form', () => <Form/>)

+ 69 - 50
recipes/src/components/TabBar/index.tsx

@@ -1,26 +1,27 @@
 import React from 'react';
-import Tab from '@material/react-tab';
-import TabBar from '@material/react-tab-bar';
-import TabIndicator from '@material/react-tab-indicator';
 import Input from 'components/Input';
 import Button from 'components/Button';
 import { assocPath, remove } from 'ramda';
 import classnames from 'classnames';
 
-import '@material/react-list/dist/list.min.css';
-import '@material/react-tab-bar/dist/tab-bar.css';
-import '@material/react-tab-scroller/dist/tab-scroller.css';
-import '@material/react-tab/dist/tab.css';
-import '@material/react-tab-indicator/dist/tab-indicator.css';
-
 import './styles.scss';
 
 type TabBarProps = {
   tabs: string[]
-  onUpdateTab?: (newValue: string) => void,
+  onUpdateTab?: (key: string|number[], newValue: string) => void,
   onDeleteTab?: (deletedIndex: number) => void,
-  onClickText?: (e: any) => void,
-  onClickTab?: (e: any) => void,
+  onSelectTab?: (selectedIndex: number) => void,
+  onAddTab?: () => void,
+  activeIndex?: number,
+}
+
+type TabBarPropsII = {
+  tabs: string[]
+  onUpdateTab: (index: number, newValue: string) => void,
+  onDeleteTab: (deletedIndex: number) => void,
+  onSelectTab: (selectedIndex: number) => void,
+  onAddTab: () => void,
+  activeIndex?: number,
 }
 
 type TabBarState = {
@@ -28,23 +29,51 @@ type TabBarState = {
   tabs: string[],
 }
 
+const TabBar = ({tabs, onUpdateTab, onDeleteTab, onSelectTab, onAddTab, activeIndex}: TabBarPropsII) => (
+  <div className='cbk-tab-bar' role="tablist">
+    { tabs.map((tab, index) => (
+      <div
+        className={classnames({
+          'cbk-tab': true,
+          'cbk-tab--active': index === activeIndex
+        })}
+        onClick={(e: any) => onSelectTab(index)}>
+        <div className='cbk-tab__content'> 
+          <Input
+            value={tab}
+            label=''
+            onChange={({ currentTarget }) => onUpdateTab(index, currentTarget.value)}
+          />
+        </div>
+        <div className='cbk-tab__actions'>
+          <Button icon='clear' onClick={(e: any) => onDeleteTab(index)}></Button>
+        </div>
+      </div>
+    )) }
+    <div className='cbk-tab cbk-tab-add'>
+      <Button icon='add' onClick={(e: any) => onAddTab()}></Button>
+    </div>
+  </div>
+);
+
 class CBKTabBar extends React.Component<TabBarProps, TabBarState> {
   constructor(props: TabBarProps) {
     super(props);
     this.state = {
-      activeIndex: 0,
+      activeIndex: this.props.activeIndex || 0,
       tabs: props.tabs
     };
   }
 
-  handleActiveIndexUpdate = (activeIndex:number) => this.setState({activeIndex});
-
   updateTabs = (key: string|number[]) => {
     return (e: any) => {
       const newValue = e.currentTarget.value;
       this.setState({
         tabs: assocPath(key, newValue, this.state.tabs)
       });
+      if (this.props.onUpdateTab) {
+        this.props.onUpdateTab(key, newValue);
+      }
     }
   }
 
@@ -69,50 +98,40 @@ class CBKTabBar extends React.Component<TabBarProps, TabBarState> {
   }
 
   render () {
-    const { onClickText, onClickTab } = this.props;
     const { tabs, activeIndex } = this.state;
 
     return (
-      <div>
-        {/* <TabBar
-          activeIndex={this.state.activeIndex}
-          handleActiveIndexUpdate={this.handleActiveIndexUpdate}
-        >
-          { tabs.map((tab, index) => (
-              <Tab key={index}>
-                {tab}
-              </Tab>
-            ))
-          }
-        </TabBar> */}
-        <div className='cbk-tab-bar' role="tablist">
-          { tabs.map((tab, index) => (
-            <div
-              className={classnames({
-                'cbk-tab': true,
-                'cbk-tab--active': index === activeIndex
-              })}
-              onClick={this.clickTab(index)}>
-              <div className='cbk-tab__content'> 
-                <Input
-                  value={tab}
-                  label=''
-                  onChange={this.updateTabs([index])}
-                />
-              </div>
-              <div className='cbk-tab__actions'>
-                <Button icon='clear' onClick={this.deleteTab(index)}></Button>
-              </div>
-              <TabIndicator active={index === activeIndex}/>
+      <div className='cbk-tab-bar' role="tablist">
+        { tabs.map((tab, index) => (
+          <div
+            className={classnames({
+              'cbk-tab': true,
+              'cbk-tab--active': index === activeIndex
+            })}
+            onClick={this.clickTab(index)}>
+            <div className='cbk-tab__content'> 
+              <Input
+                value={tab}
+                label=''
+                onChange={this.updateTabs([index])}
+              />
+            </div>
+            <div className='cbk-tab__actions'>
+              <Button icon='clear' onClick={this.deleteTab(index)}></Button>
             </div>
-          )) }
-          <div className='cbk-tab cbk-tab-add'>
-            <Button icon='add' onClick={this.addTab}></Button>
           </div>
+        )) }
+        <div className='cbk-tab cbk-tab-add'>
+          <Button icon='add' onClick={this.addTab}></Button>
         </div>
       </div>
     )
   }
 }
 
+export {
+  CBKTabBar,
+  TabBar,
+};
+
 export default CBKTabBar;

recipes/src/components/TabBar/tabBar.stories.js → recipes/src/components/TabBar/stories.js


+ 1 - 0
recipes/src/components/TabBar/styles.scss

@@ -3,6 +3,7 @@
 .cbk-tab-bar {
   display: flex;
   justify-content: space-between;
+  width: 100%;
 
   .cbk-tab {
     display: flex;

+ 281 - 8
recipes/src/containers/Recipes/Create.tsx

@@ -41,6 +41,272 @@ class CreateRecipe extends React.Component<CreateRecipeProps, CreateRecipeState>
     this.state = {
       form: { 
         ..._recipe,
+        ingredients: [
+          {
+            "name": "For the Chicken:",
+            "ingredients": [
+              {
+                "name": "thin boneless skinless chicken breast",
+                "quantity": 1.5,
+                "unit": "pound",
+                "_original": "1-1/2 lb of Thin Boneless Skinless Chicken Breast",
+                "suggestions": []
+              },
+              {
+                "name": "olive oil",
+                "quantity": 2,
+                "unit": "tablespoon",
+                "_original": "2 Tbsp of Olive Oil",
+                "suggestions": []
+              },
+              {
+                "name": "juice of  lime",
+                "quantity": 1,
+                "unit": "",
+                "_original": "Juice of 1 Lime",
+                "suggestions": []
+              },
+              {
+                "name": "chili powder",
+                "quantity": 0.5,
+                "unit": "teaspoon",
+                "_original": "1/2 tsp of Chili Powder",
+                "suggestions": [
+                  {
+                    "_id": "5cf1397d72cd194524435041",
+                    "name": "cocoa powder",
+                    "variants": [
+                      "cocoa"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 118,
+                      "tbsp": 16,
+                      "tsp": 48
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr"
+                  },
+                  {
+                    "_id": "5cf1397d72cd19452443503c",
+                    "name": "icing sugar",
+                    "variants": [
+                      "confectioner sugar",
+                      "powdered sugar"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 125,
+                      "oz": 0.27,
+                      "tbsp": 15,
+                      "tsp": 45,
+                      "lb": 0.27
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr"
+                  }
+                ]
+              },
+              {
+                "name": "oregano",
+                "quantity": 0.5,
+                "unit": "teaspoon",
+                "_original": "1/2 tsp of Oregano",
+                "suggestions": []
+              },
+              {
+                "name": "cumin",
+                "quantity": 0.5,
+                "unit": "teaspoon",
+                "_original": "1/2 tsp of Cumin",
+                "suggestions": []
+              },
+              {
+                "name": "paprika",
+                "quantity": 0.5,
+                "unit": "teaspoon",
+                "_original": "1/2 tsp of Paprika",
+                "suggestions": []
+              },
+              {
+                "name": "granulated garlic",
+                "quantity": 0.5,
+                "unit": "teaspoon",
+                "_original": "1/2 tsp of Granulated Garlic",
+                "suggestions": [
+                  {
+                    "_id": "5cf1397d72cd19452443503b",
+                    "name": "granulated sugar",
+                    "variants": [
+                      "sugar",
+                      "plain sugar"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 200,
+                      "oz": 7.1,
+                      "tbsp": 14,
+                      "tsp": 42,
+                      "lb": 0.4
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr"
+                  }
+                ]
+              },
+              {
+                "name": "salt, to taste",
+                "quantity": 0,
+                "unit": "",
+                "_original": "Salt, to taste",
+                "suggestions": []
+              }
+            ]
+          },
+          {
+            "name": "For the Dressing:",
+            "ingredients": [
+              {
+                "name": "plain greek yogurt",
+                "quantity": 0.5,
+                "unit": "cup",
+                "_original": "1/2 cup of Plain Greek Yogurt",
+                "suggestions": [
+                  {
+                    "_id": "5cf1397d72cd194524435040",
+                    "name": "yogurt",
+                    "variants": [
+                      "plain yogurt"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 245,
+                      "oz": 8.64,
+                      "tbsp": 16,
+                      "tsp": 48
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr"
+                  },
+                  {
+                    "_id": "5cf1397d72cd19452443503b",
+                    "name": "granulated sugar",
+                    "variants": [
+                      "sugar",
+                      "plain sugar"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 200,
+                      "oz": 7.1,
+                      "tbsp": 14,
+                      "tsp": 42,
+                      "lb": 0.4
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr"
+                  },
+                  {
+                    "_id": "5cf1397d72cd194524435030",
+                    "name": "all purpose flour",
+                    "variants": [
+                      "plain flour",
+                      "all purpose flour",
+                      "regular flour",
+                      "flour"
+                    ],
+                    "equivalences": {
+                      "cup": 1,
+                      "gr": 125,
+                      "tbsp": 15.5,
+                      "tsp": 47
+                    },
+                    "referenceUnit": "cup",
+                    "prefferedUnit": "gr",
+                    "translation": {
+                      "dutch": "patentbloem"
+                    }
+                  }
+                ]
+              },
+              {
+                "name": "fresh cilantro",
+                "quantity": 1,
+                "unit": "cup",
+                "_original": "1 cup of Fresh Cilantro",
+                "suggestions": []
+              },
+              {
+                "name": "scallions, roughly chopped",
+                "quantity": 2,
+                "unit": "",
+                "_original": "2 Scallions, roughly chopped",
+                "suggestions": []
+              },
+              {
+                "name": "juice of  lime or more, according to taste",
+                "quantity": 1,
+                "unit": "",
+                "_original": "Juice of 1 Lime or more, according to taste",
+                "suggestions": []
+              },
+              {
+                "name": "olive oil",
+                "quantity": 1,
+                "unit": "tablespoon",
+                "_original": "1 Tbsp of Olive Oil",
+                "suggestions": []
+              },
+              {
+                "name": "salt, to taste",
+                "quantity": 0,
+                "unit": "",
+                "_original": "Salt, to taste",
+                "suggestions": []
+              }
+            ]
+          },
+          {
+            "name": "For the rest of the salad:",
+            "ingredients": [
+              {
+                "name": "fresh lettuce of your choice",
+                "quantity": 0,
+                "unit": "",
+                "_original": "Fresh Lettuce of your choice",
+                "suggestions": []
+              },
+              {
+                "name": "bell peppers, halved and seeded",
+                "quantity": 2,
+                "unit": "",
+                "_original": "2 Bell Peppers, halved and seeded",
+                "suggestions": []
+              },
+              {
+                "name": "scallions or red onion, sliced",
+                "quantity": 0,
+                "unit": "",
+                "_original": "Scallions or REd Onion, sliced",
+                "suggestions": []
+              },
+              {
+                "name": "pico de gallo salsa",
+                "quantity": 0.5,
+                "unit": "cup",
+                "_original": "1/2 cup of Pico De Gallo Salsa",
+                "suggestions": []
+              },
+              {
+                "name": "avocado, sliced",
+                "quantity": 1,
+                "unit": "",
+                "_original": "1 Avocado, sliced",
+                "suggestions": []
+              }
+            ]
+          }
+        ],
       },
       scrapeUrl: '',
     }
@@ -69,6 +335,12 @@ class CreateRecipe extends React.Component<CreateRecipeProps, CreateRecipeState>
     }
   }
 
+  updateSubrecipeName = (subrecipe: number, newValue: string) => {
+    this.setState({
+      form: assocPath(['ingredients', subrecipe, 'name'], newValue, this.state.form),
+    } as Pick<CreateRecipeState, keyof CreateRecipeState>)
+  }
+
   addIngredient = (subrecipe: number, last: number) => {
     return () => {
       const { ingredients } = this.state.form;
@@ -143,14 +415,12 @@ class CreateRecipe extends React.Component<CreateRecipeProps, CreateRecipeState>
   }
 
   removeSubrecipe = (index: number) => {
-    return () => {
-      this.setState({
-        form: {
-          ...this.state.form,
-          ingredients: remove(index, 1, this.state.form.ingredients)
-        }
-      })
-    }
+    this.setState({
+      form: {
+        ...this.state.form,
+        ingredients: remove(index, 1, this.state.form.ingredients)
+      }
+    })
   }
   
   render() {
@@ -271,6 +541,9 @@ class CreateRecipe extends React.Component<CreateRecipeProps, CreateRecipeState>
               <IngredientForm
                 components={form.ingredients}
                 updateField={this.updateField}
+                addSubrecipe={this.addSubrecipe}
+                updateSubrecipeName={this.updateSubrecipeName}
+                removeSubrecipe={this.removeSubrecipe}
               />
               {/* {
                 form.ingredients.map((group, i) => (