import React from "react";
import {config} from "utils";
import {useMenuContext} from "components/providers/Menu/MenuContext";
/**
* @typedef {object} props
* @property {string} [className] - additional classes for parent container
* @property {boolean} [isOptionalSingle] - if this modifier item is maximum of 1 and is not required
* @property {object} item - itemsHash data from menu context
* @property {boolean} [multiSelect] - if this modifier item has a maximum greater than 1
* @property {function} removeModifier - remove a modifier payload from parent state
* @property {function} addModifier - add a modifier payload to parent state
* @property {object} parent - parent payload (option and item with selected nested modifiers)
* @property {number} [quantity] - current modifier quantity in parent state
* @property {string} type - style cell type from theme
*/
/**
* withModifierItem - HOC for modifier items
* @param {*} Component
* @param {props} Component.props - The {@link props} from the option
* @return {*}
*/
const withModifierItem = (Component) => (props) => {
const {
className = "",
isOptionalSingle = true,
isSingleSelect,
item = {},
multiSelect = false,
removeModifier = () => {},
addModifier = () => {},
parent = {},
quantity = 0,
type = "optionItem",
} = props;
const {isNested, options, price} = item;
const {optionsHash} = useMenuContext();
// payload is the current modifier item data for adding and removing
const payload = {
// Add current modifier price to payload
price,
// Extend parent payload
...parent,
// Populate modifiers with default options when none are present (adding new nested mod)
...(isNested &&
!Object.keys(parent?.modifiers).length && {
modifiers: options.reduce((acc, cur) => {
return {...acc, [cur.id]: []};
}, {}),
}),
};
// handleClick toggles the parent container click action, ignored when parent is nested
const handleClick = Boolean(isOptionalSingle || !quantity);
const handleRemove =
(isNested || isOptionalSingle || isSingleSelect) && quantity;
// nestedItems is an array of objects with selected nested modifier item data
const nestedItems =
(isNested &&
parent?.quantity &&
Object.entries(parent?.modifiers).reduce((accu, [id, items]) => {
if (!items?.length) {
return accu;
}
let counter = 0;
const currItems = items.filter(({item}, index) => {
return items.indexOf({item}) === index;
});
const {name} = optionsHash[id];
return [
...accu,
{
id,
name,
},
];
}, [])) ||
[];
/**
* @function increment - increase the current modifier quantity by 1, onClick of addition button
*/
const increment = () => addModifier(payload);
/**
* @function decrement - decrease the current modifier quantity by 1, onClick of reduction button
*/
const decrement = () => removeModifier(payload);
/**
* @function onClick - parent container click action (adds initial or render first nested drawer)
* @param {*} e - event
* @returns {function} - add or remove current modifier from parent state
*/
const onClick = (e) => {
if (!isNested && !handleClick) {
return null;
}
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
if (isNested || !quantity || multiSelect) {
return addModifier(payload, quantity || 1);
}
return removeModifier(payload);
};
/**
* additionalProps - render inputs for modifier items
* @constant {object}
*/
const additionalProps = {
className,
configType: config.theme.item_details.modifier_items,
decrement,
handleRemove,
increment,
item,
multiSelect,
nestedItems,
onClick,
quantity,
type,
};
return (
<Component
{...props} // TODO: Safely remove unknown prop spreads...
{...additionalProps}
/>
);
};
export default withModifierItem;