Nomad Jensen Montreal
Nomad Jensen Montreal

Reputation: 111

How to change the State in React to match selected configurable product options?

How to change the State of option separately, so that the behavior should be based on option which means only one configurable option can be selected?

Use case scenario:

  1. Nothing selected, validate to select Color and Size
  2. Either Color or Size selected validate one option which was not selected.

This is what I'm trying to achieve: enter image description here

JSON:

{
  "configurable_options": [
    {
      "__typename": "ConfigurableProductOptions",
      "id": 167,
      "attribute_id": "93",
      "label": "Color",
      "position": 1,
      "use_default": false,
      "attribute_code": "color",
      "values": [
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 50,
          "label": "Blue",
          "swatch_data": {
            "__typename": "ColorSwatchData",
            "value": "#1857f7"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 53,
          "label": "Green",
          "swatch_data": {
            "__typename": "ColorSwatchData",
            "value": "#53a828"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 56,
          "label": "Orange",
          "swatch_data": {
            "__typename": "ColorSwatchData",
            "value": "#eb6703"
          }
        }
      ],
      "product_id": 1194
    },
    {
      "__typename": "ConfigurableProductOptions",
      "id": 166,
      "attribute_id": "144",
      "label": "Size",
      "position": 0,
      "use_default": false,
      "attribute_code": "size",
      "values": [
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 166,
          "label": "XS",
          "swatch_data": {
            "__typename": "TextSwatchData",
            "value": "XS"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 167,
          "label": "S",
          "swatch_data": {
            "__typename": "TextSwatchData",
            "value": "S"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 168,
          "label": "M",
          "swatch_data": {
            "__typename": "TextSwatchData",
            "value": "M"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 169,
          "label": "L",
          "swatch_data": {
            "__typename": "TextSwatchData",
            "value": "L"
          }
        },
        {
          "__typename": "ConfigurableProductOptionsValues",
          "value_index": 170,
          "label": "XL",
          "swatch_data": {
            "__typename": "TextSwatchData",
            "value": "XL"
          }
        }
      ],
      "product_id": 1194
    }
  ]
}

import {
  Box,
  Button,
  Container,
  Stack,
  ToggleButton,
  ToggleButtonGroup,
} from "@mui/material";
import { ReactElement, useState } from "react";
import products from "../utils/data.json";

const ProductDetail = (): ReactElement => {
  const [selectedProductOptions, setSelectedProductOptions] = useState<any>();
  const [cartItems, setCartItems] = useState<any>();

  const handleOption = (
    event: React.MouseEvent<HTMLElement>,
    newOption: any
  ) => {
    setSelectedProductOptions(newOption);
  };

  const addToCart = () => {
    setCartItems(selectedProductOptions);
  };

  console.log("cartItems", cartItems);

  return (
    <>
      <Box>
        <Container maxWidth="sm">
          {products.configurable_options.map((product: any, index: number) => (
            <Stack
              key={index}
              direction="row"
              alignItems="center"
              justifyContent="left"
            >
              <ToggleButtonGroup
                sx={{ mt: 5 }}
                color="primary"
                exclusive
                aria-label="Platform"
                onChange={handleOption}
              >
                {product.values.map((item: any, index: number) => (
                  <ToggleButton key={index} value={item}>
                    {item.label}
                  </ToggleButton>
                ))}
              </ToggleButtonGroup>
            </Stack>
          ))}
          <Button variant="contained" sx={{ mt: 5 }} onClick={addToCart}>
            Add To Cart
          </Button>
        </Container>
      </Box>
    </>
  );
};

export default ProductDetail;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Upvotes: 1

Views: 93

Answers (1)

ksav
ksav

Reputation: 20831

Create an initial state object that is derived from data.json.

eg {166: null, 167: null}

Then onChange, set the product's value_index as the selected state on the configurable_option.id key within selectedProductOptions.

eg clicking "Orange" would set selectedProductOptions to {166: null, 167: 56}

import products from "./data.json";
const initialState = {};

products.configurable_options.forEach(({ id }) => {
  initialState[id] = null;
});

const ProductDetail = () => {
  const [selectedProductOptions, setSelectedProductOptions] = useState(
    initialState
  );

  return (
    <Container maxWidth="sm">
      {products.configurable_options.map((configurable_option) => (
        <div>
          <ToggleButtonGroup
            sx={{ mt: 5 }}
            color="primary"
            onChange={(_event, value) => {
              setSelectedProductOptions({
                ...selectedProductOptions,
                [configurable_option.id]: value[0].value_index
              });
            }}
          >
            {configurable_option.values.map((item, index) => (
              <ToggleButton
                key={index}
                value={item}
                selected={
                  selectedProductOptions[configurable_option.id] ===
                  item.value_index
                }
              >
                {item.label}
              </ToggleButton>
            ))}
          </ToggleButtonGroup>
        </div>
      ))}
    </Container>
  );
};

Edit damp-brook-rn25g1

Upvotes: 1

Related Questions