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

Time:01-23

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>

CodePudding user response:

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

  • Related