'Selection of product options as a combination
I am trying to achieve the following for my project.
my data structure for options and combinations as following:
"options": [
{
"id": "96ce60e9-b09b-4cf6-aeca-83f75af9ef4b",
"position": 0,
"name": "Color",
"values": [
{
"id": "9056c8d4-a950-43bc-9477-283a8954285b",
"name": "",
"label": "RED"
},
{
"id": "35c7cc36-2ff4-4eb6-bc96-03cc3ea04751",
"name": "",
"label": "BLACK"
}
]
},
{
"id": "c657ee5b-57bb-4265-8113-4fefca71f785",
"position": 1,
"type": "",
"name": "SIZE",
"values": [
{
"id": "494196ec-5857-48b1-be35-ffc785e5020d",
"name": "",
"label": "LARGE"
},
{
"id": "389255cb-0c88-45e8-a1dc-6ce9fedbd98c",
"name": "",
"label": "SMALL"
}
]
}
],
Combinations:
"combinations": [
{
"id": "84468215-d6b5-455e-bfdc-6a03cfe49d21",
"ids": [
"9056c8d4-a950-43bc-9477-283a8954285b",
"494196ec-5857-48b1-be35-ffc785e5020d"
],
"quantity": "12",
"code": 0,
"barcode": 0,
"sellPrice": 0
},
{
"id": "4c84ec32-bf4c-463d-9872-bc6a9794e7ba",
"ids": [
"9056c8d4-a950-43bc-9477-283a8954285b",
"389255cb-0c88-45e8-a1dc-6ce9fedbd98c"
],
"quantity": "12",
"code": 0,
"barcode": 0,
"sellPrice": 0
},
{
"id": "76a3ccdd-c8b4-44dc-99bf-a83a65dc0fe0",
"ids": [
"35c7cc36-2ff4-4eb6-bc96-03cc3ea04751",
"494196ec-5857-48b1-be35-ffc785e5020d"
],
"quantity": 0,
"code": 0,
"barcode": 0,
"sellPrice": 0
},
{
"id": "ec8c8cec-d2a7-4c90-8c9b-12cfeb78d0f6",
"ids": [
"35c7cc36-2ff4-4eb6-bc96-03cc3ea04751",
"389255cb-0c88-45e8-a1dc-6ce9fedbd98c"
],
"quantity": 0,
"code": 0,
"barcode": 0,
"sellPrice": 0
}
],
I've never worked on something like that before. For each combination for example (RED/SMALL), I am storing the 'RED' option id and 'Small' option id. till now I've tried the following logic, where I want to compare between ids to get the combination as object then process the order as I want:
{product.options.map((opt) => (
<div key={opt.id}>
<h4 className="font-bold">{opt.name}</h4>
<ul>
{opt.values.map((val) => (
<li key={val.id}>
<button
type="button"
className={'bg-black text-white'}
onClick={() => {
//push to comboIds
comboIds.push(val.id);
console.log(comboIds);
//search for the combinations from comboIds
availableCombinations = product.combinations.filter(
(comb) => {
return comb.ids.includes(
comboIds.map((s) => `"${s}"`).join(', ')
);
}
);
console.log(availableCombinations);
}}
>
{val.label}
</button>
</li>
))}
</ul>
</div>
))}
I appreciate any help! Thanks
Solution 1:[1]
The below snippet may be a solution to achieve the desired objective:
Code Snippet
const {useState} = React;
const SomeComponent = ({allColors, allSizes, available, ...props}) => {
const [color, setColor] = useState('red');
const [size, setSize] = useState('S');
const notSelectable = {
backgroundColor: "#DDEEFF", cursor: "default",
borderColor: "#DDEEFF", opacity: '40%'
};
const getOptionsFor = (propName, propValue = null) => (
available.filter(obj => (
propValue === null ||
([propName] in obj && obj[propName] === propValue)
))
);
const isAvailable = (propName, propValue = null, prop2Name, prop2Value) => (
getOptionsFor(propName, propValue)
.some(obj => prop2Value && prop2Value.length > 0 && obj[prop2Name] === prop2Value)
);
return (
<div class="flexCol">
Colors
<div class="boxOne">
{allColors.map((c, i) => (
<div
class={"boxTwo " + c}
style={ isAvailable('size', size, 'color', c) ? {} : {
...notSelectable
}}
key={i}
onClick={() => {
if (isAvailable('size', size, 'color', c)) setColor(c);
}}
>
{c}
</div>
))}
</div>
Sizes
<div class="boxOne">
{allSizes.map((s, i) => (
<div
class="boxTwo"
style={ isAvailable('color', color, 'size', s) ? {} : {
...notSelectable
}}
key={i}
onClick={() => {
if (isAvailable('color', color, 'size', s)) setSize(s);
}}
>
{s}
</div>
))}
</div>
<br /><br /><br /><br />
picked-color: {color}  
sizes: {JSON.stringify(getOptionsFor('color', color).map(({size}) => size))}
<br />
picked-size: {size}  
colors: {JSON.stringify(getOptionsFor('size', size).map(({color}) => color))}
</div>
);
};
const getAsArray = s => s.split(',').map(x => x.trim());
const colors = getAsArray('red, white, black, blue, magenta');
const sizes = getAsArray('XS, S, M, L, XL');
const combos = [
{ color: 'red', size: 'S'},
{ color: 'red', size: 'L'},
{ color: 'red', size: 'XS'},
{ color: 'magenta', size: 'XS'},
{ color: 'magenta', size: 'XL'},
{ color: 'magenta', size: 'S'},
{ color: 'white', size: 'M'},
{ color: 'black', size: 'M'},
{ color: 'black', size: 'L'},
{ color: 'black', size: 'XL'},
{ color: 'blue', size: 'M'},
{ color: 'blue', size: 'S'},
{ color: 'blue', size: 'XL'},
];
ReactDOM.render(
<div>
<b>DEMO :</b> Color+Size - Combo Selection
<SomeComponent
allColors={colors} allSizes={sizes}
available={combos}
/>
</div>,
document.getElementById("rd")
);
.flexCol {
display: flex;
flex-direction: column;
}
.boxOne {
display: flex;
border: 2px solid black;
width: fit-content;
padding: 5px 15px;
margin-top: 5px;
}
.boxTwo {
border: 1px solid grey;
padding: 5px;
margin-right: 20px;
cursor: pointer;
border-radius: 5px;
background-color: #FFCCAA;
}
.boxTwo:last-child { margin-right: 0; }
.red { color: red }
.blue { color: blue }
.magenta { color: magenta }
.white {
color: darkgrey;
border-color: black;
}
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
Explanation
Have tried my best to keep the approach simple.
- Two string arrays are sent as props from parent, namely
allColorsandallSizes - An object array named
availableis also sent as prop, and this has all the available color-size combinations - Within the child (
SomeComponent), an initial state is set withcolor = 'red'andsize = 'S' - The style of each choice as well as its
click-ability is determined by using the methodisAvailablewith the prop names, values - This method (
isAvailable) takes two pairs of prop name-values - For example, when checking whether a particular color (named
cin the iteration) is available (ie,click-able),isAvailableis invoked with thesizethat has been selected as the first prop-pair. - It filters
availableto get all options wheresizematches the one selected by the user. - Then, it checks for
someoption in the filtered-options where thecolormatches the particular color (namedcin the iteration) - When found, the particular color (
c) isclick-able. Else, it is disabled (different style, not clickable)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

