Archived course lesson

Add a Delete Ingredient Button

Part of Frontend Serverless with React and GraphQL

Objective: Create a delete button for the GenerateIngredients component that will allow users to remove ingredients from the list.

We need to create a delete button for each ingredient to ensure that users can remove unneeded ingredients from the list. We can add an additional column by concatinating a delete column onto the list of columns that we already have.

import { Row, Col, Button, Table, Input, Dropdown } from 'antd';
import { MenuList } from './MenuList';
import * as _ from 'lodash';

type IngredientsProps = {
  names?: string[];
  values?: [{ amount: string; unit: string; type: string }];
  handleAddIngredient: (event: any) => void;
  handleDeleteIngredient: (event: any) => void;
  handleInputChange: (event: any) => void;
  handleDropdownChange: (event: any) => void;
};

const units = ['-', 'ounce', 'lb', 'cup', 'tb', 'tsp', 'g', 'kg'];

export const GenerateIngredients = ({
  names,
  values,
  handleAddIngredient,
  handleDeleteIngredient,
  handleInputChange,
  handleDropdownChange,
}: IngredientsProps) => {
  const columns = _.concat(
    names.map((name) => ({
      title: `${name}`,
      key: `${name}`,
      render: (ingredient, _record, index: number) => {
        return name === 'unit' ? (
          <Dropdown
            overlay={
              <MenuList
                iterableList={units}
                name={`ingredients[${index}].${name}`}
                handleDropdownChange={handleDropdownChange}
              />
            }
            placement="bottomLeft"
          >
            <Button>{ingredient[name]}</Button>
          </Dropdown>
        ) : (
          <Input
            value={ingredient[name]}
            placeholder={`${name}`}
            name={`ingredients[${index}].${name}`}
            onChange={handleInputChange}
          />
        );
      },
    })),
    [
      {
        title: 'delete',
        key: 'delete',
        render: (_ingredient, _record, index: number) => (
          <Button
            onClick={handleDeleteIngredient}
            type="danger"
            shape="circle"
            size="small"
            name={`${index}`}
          >
            -
          </Button>
        ),
      },
    ],
  );

  return (
    <>
      <Row>
        <Col span={12} offset={6}>
          <p>
            <Button
              onClick={handleAddIngredient}
              type="primary"
              shape="circle"
              size="small"
            >
              +
            </Button>
            ingredients:
          </p>
        </Col>
      </Row>
      {values.length > 0 ? (
        <Row>
          <Col span={12} offset={6}>
            <Table
              dataSource={values}
              columns={columns}
              pagination={{ pageSize: 25 }}
            />
          </Col>
        </Row>
      ) : null}
    </>
  );
};

The delete button will call a delete ingredient handler, so we need to now create this in the submitForm hook and pass it into the <GenerateIngredients> component

import { useState } from 'react';
import * as _ from 'lodash';

export const submitForm = (initialValues, callback) => {
  const [inputs, setInputs] = useState(initialValues);

  const handleInputChange = (event) => {
    event.persist();
    setInputs((inputs) => {
      const newInputs = _.cloneDeep(inputs);
      _.set(newInputs, event.target.name, event.target.value);
      return newInputs;
    });
  };

  const handleDropdownChange = (event) => {
    setInputs((inputs) => {
      const newInputs = _.cloneDeep(inputs);
      _.set(newInputs, event.item.props.title, event.key);
      return newInputs;
    });
  };
  const handleAddIngredient = (event) => {
    event.persist();
    setInputs((inputs) => {
      const sortedIngredients = _.sortBy(inputs.ingredients, ['key']);

      const key =
        sortedIngredients.length > 0
          ? sortedIngredients[sortedIngredients.length - 1].key + 1
          : 0;
      return {
        ...inputs,
        ingredients: _.concat(inputs.ingredients, [
          { key, amount: '', unit: '-', type: '' },
        ]),
      };
    });
  };

  const handleDeleteIngredient = (event) => {
    console.log('deleted');
    event.persist();
    const position = parseInt(event.target.name);
    setInputs((inputs) => ({
      ...inputs,
      ingredients: _.filter(
        inputs.ingredients,
        (_i, index) => index !== position,
      ),
    }));
  };

  const handleSubmit = () => {
    callback();
    setInputs(() => ({ ...initialValues }));
  };

  return {
    inputs,
    handleSubmit,
    handleInputChange,
    handleAddIngredient,
    handleDeleteIngredient,
    handleDropdownChange,
  };
};