@shopify/hydrogen-react
Version:
React components, hooks, and utilities for creating custom Shopify storefronts
194 lines (193 loc) • 6.92 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const jsxRuntime = require("react/jsx-runtime");
const React = require("react");
const flattenConnection = require("./flatten-connection.js");
const ProductOptionsContext = React.createContext(null);
function ProductProvider({
children,
data: product,
initialVariantId: explicitVariantId
}) {
const variants = React.useMemo(
() => flattenConnection.flattenConnection(product.variants ?? {}),
[product.variants]
);
if (!isProductVariantArray(variants)) {
throw new Error(
`<ProductProvider/> requires 'product.variants.nodes' or 'product.variants.edges'`
);
}
const options = React.useMemo(() => getOptions(variants), [variants]);
const [selectedVariant, setSelectedVariant] = React.useState(() => getVariantBasedOnIdProp(explicitVariantId, variants));
const [selectedOptions, setSelectedOptions] = React.useState(
() => getSelectedOptions(selectedVariant)
);
React.useEffect(() => {
const newSelectedVariant = getVariantBasedOnIdProp(
explicitVariantId,
variants
);
setSelectedVariant(newSelectedVariant);
setSelectedOptions(getSelectedOptions(newSelectedVariant));
}, [explicitVariantId, variants]);
const setSelectedOption = React.useCallback(
(name, value2) => {
setSelectedOptions((selectedOptions2) => {
const opts = { ...selectedOptions2, [name]: value2 };
setSelectedVariant(getSelectedVariant(variants, opts));
return opts;
});
},
[setSelectedOptions, variants]
);
const isOptionInStock = React.useCallback(
(option, value2) => {
const proposedVariant = getSelectedVariant(variants, {
...selectedOptions,
...{ [option]: value2 }
});
return (proposedVariant == null ? void 0 : proposedVariant.availableForSale) ?? true;
},
[selectedOptions, variants]
);
const sellingPlanGroups = React.useMemo(
() => flattenConnection.flattenConnection(product.sellingPlanGroups ?? {}).map(
(sellingPlanGroup) => ({
...sellingPlanGroup,
sellingPlans: flattenConnection.flattenConnection((sellingPlanGroup == null ? void 0 : sellingPlanGroup.sellingPlans) ?? {})
})
),
[product.sellingPlanGroups]
);
const [selectedSellingPlan, setSelectedSellingPlan] = React.useState(void 0);
const selectedSellingPlanAllocation = React.useMemo(() => {
var _a, _b;
if (!selectedVariant || !selectedSellingPlan) {
return;
}
if (!((_a = selectedVariant.sellingPlanAllocations) == null ? void 0 : _a.nodes) && !((_b = selectedVariant.sellingPlanAllocations) == null ? void 0 : _b.edges)) {
throw new Error(
`<ProductProvider/>: You must include 'sellingPlanAllocations.nodes' or 'sellingPlanAllocations.edges' in your variants in order to calculate selectedSellingPlanAllocation`
);
}
return flattenConnection.flattenConnection(selectedVariant.sellingPlanAllocations).find(
(allocation) => {
var _a2;
return ((_a2 = allocation == null ? void 0 : allocation.sellingPlan) == null ? void 0 : _a2.id) === selectedSellingPlan.id;
}
);
}, [selectedVariant, selectedSellingPlan]);
const value = React.useMemo(
() => ({
product,
variants,
variantsConnection: product.variants,
options,
selectedVariant,
setSelectedVariant,
selectedOptions,
setSelectedOption,
setSelectedOptions,
isOptionInStock,
selectedSellingPlan,
setSelectedSellingPlan,
selectedSellingPlanAllocation,
sellingPlanGroups,
sellingPlanGroupsConnection: product.sellingPlanGroups
}),
[
product,
isOptionInStock,
options,
selectedOptions,
selectedSellingPlan,
selectedSellingPlanAllocation,
selectedVariant,
sellingPlanGroups,
setSelectedOption,
variants
]
);
return /* @__PURE__ */ jsxRuntime.jsx(ProductOptionsContext.Provider, { value, children });
}
function useProduct() {
const context = React.useContext(ProductOptionsContext);
if (!context) {
throw new Error(`'useProduct' must be a child of <ProductProvider />`);
}
return context;
}
function getSelectedVariant(variants, choices) {
var _a, _b;
if (!variants.length || ((_b = (_a = variants == null ? void 0 : variants[0]) == null ? void 0 : _a.selectedOptions) == null ? void 0 : _b.length) !== Object.keys(choices).length) {
return;
}
return variants == null ? void 0 : variants.find((variant) => {
return Object.entries(choices).every(([name, value]) => {
var _a2;
return (_a2 = variant == null ? void 0 : variant.selectedOptions) == null ? void 0 : _a2.some(
(option) => (option == null ? void 0 : option.name) === name && (option == null ? void 0 : option.value) === value
);
});
});
}
function getOptions(variants) {
const map = variants.reduce(
(memo, variant) => {
var _a;
if (!variant.selectedOptions) {
throw new Error(`'getOptions' requires 'variant.selectedOptions'`);
}
(_a = variant == null ? void 0 : variant.selectedOptions) == null ? void 0 : _a.forEach((opt) => {
memo[(opt == null ? void 0 : opt.name) ?? ""] = memo[(opt == null ? void 0 : opt.name) ?? ""] || /* @__PURE__ */ new Set();
memo[(opt == null ? void 0 : opt.name) ?? ""].add((opt == null ? void 0 : opt.value) ?? "");
});
return memo;
},
{}
);
return Object.keys(map).map((option) => {
return {
name: option,
values: Array.from(map[option])
};
});
}
function getVariantBasedOnIdProp(explicitVariantId, variants) {
if (explicitVariantId) {
const foundVariant = variants.find(
(variant) => (variant == null ? void 0 : variant.id) === explicitVariantId
);
if (!foundVariant) {
console.warn(
`<ProductProvider/> received a 'initialVariantId' prop, but could not actually find a variant with that ID`
);
}
return foundVariant;
}
if (explicitVariantId === null) {
return null;
}
if (explicitVariantId === void 0) {
return variants.find((variant) => variant == null ? void 0 : variant.availableForSale) || variants[0];
}
}
function getSelectedOptions(selectedVariant) {
return (selectedVariant == null ? void 0 : selectedVariant.selectedOptions) ? selectedVariant.selectedOptions.reduce(
(memo, optionSet) => {
memo[(optionSet == null ? void 0 : optionSet.name) ?? ""] = (optionSet == null ? void 0 : optionSet.value) ?? "";
return memo;
},
{}
) : {};
}
function isProductVariantArray(maybeVariantArray) {
if (!maybeVariantArray || !Array.isArray(maybeVariantArray)) {
return false;
}
return true;
}
exports.ProductProvider = ProductProvider;
exports.useProduct = useProduct;
//# sourceMappingURL=ProductProvider.js.map