@cimplify/sdk 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -799,14 +799,6 @@ var CatalogueQueries = class {
799
799
  async getBundles() {
800
800
  return safe(this.client.get("/api/v1/catalogue/bundles"));
801
801
  }
802
- async getBundle(id) {
803
- const encodedId = encodeURIComponent(id);
804
- return safe(this.client.get(`/api/v1/catalogue/bundles/${encodedId}`));
805
- }
806
- async getBundleBySlug(slug) {
807
- const encodedSlug = encodeURIComponent(slug);
808
- return safe(this.client.get(`/api/v1/catalogue/bundles/slug/${encodedSlug}`));
809
- }
810
802
  async searchBundles(query, limit = 20) {
811
803
  const path = withQuery("/api/v1/catalogue/bundles", { search: query, limit });
812
804
  return safe(this.client.get(path));
@@ -815,18 +807,6 @@ var CatalogueQueries = class {
815
807
  const path = withQuery("/api/v1/catalogue/composites", { limit: options?.limit });
816
808
  return safe(this.client.get(path));
817
809
  }
818
- async getComposite(id) {
819
- const encodedId = encodeURIComponent(id);
820
- return safe(this.client.get(`/api/v1/catalogue/composites/${encodedId}`));
821
- }
822
- async getCompositeByProductId(productId) {
823
- const encodedId = encodeURIComponent(productId);
824
- return safe(
825
- this.client.get(
826
- `/api/v1/catalogue/composites/by-product/${encodedId}`
827
- )
828
- );
829
- }
830
810
  async calculateCompositePrice(compositeId, selections, locationId) {
831
811
  const encodedId = encodeURIComponent(compositeId);
832
812
  return safe(
@@ -6019,256 +5999,6 @@ function useCollection(idOrSlug, options = {}) {
6019
5999
  }, [cacheKey, load]);
6020
6000
  return { collection, products, isLoading, error, refetch };
6021
6001
  }
6022
- var bundleCache = /* @__PURE__ */ new Map();
6023
- var bundleInflight = /* @__PURE__ */ new Map();
6024
- function isLikelySlug3(value) {
6025
- return /^[a-z0-9-]+$/.test(value);
6026
- }
6027
- function buildBundleCacheKey(client, locationId, idOrSlug) {
6028
- return JSON.stringify({
6029
- key: client.getPublicKey(),
6030
- location_id: locationId || "__none__",
6031
- bundle: idOrSlug
6032
- });
6033
- }
6034
- function useBundle(idOrSlug, options = {}) {
6035
- const context = useOptionalCimplify();
6036
- const client = options.client ?? context?.client;
6037
- if (!client) {
6038
- throw new Error("useBundle must be used within CimplifyProvider or passed { client }.");
6039
- }
6040
- const enabled = options.enabled ?? true;
6041
- const locationId = client.getLocationId();
6042
- const previousLocationIdRef = React3.useRef(locationId);
6043
- const requestIdRef = React3.useRef(0);
6044
- const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
6045
- const cacheKey = React3.useMemo(
6046
- () => buildBundleCacheKey(client, locationId, normalizedIdOrSlug),
6047
- [client, locationId, normalizedIdOrSlug]
6048
- );
6049
- const cached = bundleCache.get(cacheKey);
6050
- const [bundle, setBundle] = React3.useState(cached?.bundle ?? null);
6051
- const [isLoading, setIsLoading] = React3.useState(
6052
- enabled && normalizedIdOrSlug.length > 0 && !cached
6053
- );
6054
- const [error, setError] = React3.useState(null);
6055
- React3.useEffect(() => {
6056
- if (previousLocationIdRef.current !== locationId) {
6057
- bundleCache.clear();
6058
- bundleInflight.clear();
6059
- previousLocationIdRef.current = locationId;
6060
- }
6061
- }, [locationId]);
6062
- const load = React3.useCallback(
6063
- async (force = false) => {
6064
- if (!enabled || normalizedIdOrSlug.length === 0) {
6065
- setBundle(null);
6066
- setIsLoading(false);
6067
- return;
6068
- }
6069
- const nextRequestId = ++requestIdRef.current;
6070
- setError(null);
6071
- if (!force) {
6072
- const cacheEntry = bundleCache.get(cacheKey);
6073
- if (cacheEntry) {
6074
- setBundle(cacheEntry.bundle);
6075
- setIsLoading(false);
6076
- return;
6077
- }
6078
- }
6079
- setIsLoading(true);
6080
- try {
6081
- const existing = bundleInflight.get(cacheKey);
6082
- const promise = existing ?? (async () => {
6083
- const result = isLikelySlug3(normalizedIdOrSlug) ? await client.catalogue.getBundleBySlug(normalizedIdOrSlug) : await client.catalogue.getBundle(normalizedIdOrSlug);
6084
- if (!result.ok) {
6085
- throw result.error;
6086
- }
6087
- return result.value;
6088
- })();
6089
- if (!existing) {
6090
- bundleInflight.set(cacheKey, promise);
6091
- promise.finally(() => {
6092
- bundleInflight.delete(cacheKey);
6093
- }).catch(() => void 0);
6094
- }
6095
- const value = await promise;
6096
- bundleCache.set(cacheKey, { bundle: value });
6097
- if (nextRequestId === requestIdRef.current) {
6098
- setBundle(value);
6099
- setError(null);
6100
- }
6101
- } catch (loadError) {
6102
- if (nextRequestId === requestIdRef.current) {
6103
- setError(loadError);
6104
- }
6105
- } finally {
6106
- if (nextRequestId === requestIdRef.current) {
6107
- setIsLoading(false);
6108
- }
6109
- }
6110
- },
6111
- [cacheKey, client, enabled, normalizedIdOrSlug]
6112
- );
6113
- React3.useEffect(() => {
6114
- void load(false);
6115
- }, [load]);
6116
- const refetch = React3.useCallback(async () => {
6117
- bundleCache.delete(cacheKey);
6118
- await load(true);
6119
- }, [cacheKey, load]);
6120
- return { bundle, isLoading, error, refetch };
6121
- }
6122
- var compositeCache = /* @__PURE__ */ new Map();
6123
- var compositeInflight = /* @__PURE__ */ new Map();
6124
- function shouldFetchByProductId(idOrProductId, byProductId) {
6125
- if (typeof byProductId === "boolean") {
6126
- return byProductId;
6127
- }
6128
- return idOrProductId.startsWith("prod_");
6129
- }
6130
- function buildCompositeCacheKey(client, locationId, idOrProductId, byProductId) {
6131
- return JSON.stringify({
6132
- key: client.getPublicKey(),
6133
- location_id: locationId || "__none__",
6134
- composite: idOrProductId,
6135
- by_product_id: byProductId
6136
- });
6137
- }
6138
- function useComposite(idOrProductId, options = {}) {
6139
- const context = useOptionalCimplify();
6140
- const client = options.client ?? context?.client;
6141
- if (!client) {
6142
- throw new Error("useComposite must be used within CimplifyProvider or passed { client }.");
6143
- }
6144
- const enabled = options.enabled ?? true;
6145
- const locationId = client.getLocationId();
6146
- const previousLocationIdRef = React3.useRef(locationId);
6147
- const requestIdRef = React3.useRef(0);
6148
- const priceRequestIdRef = React3.useRef(0);
6149
- const normalizedIdOrProductId = React3.useMemo(
6150
- () => (idOrProductId || "").trim(),
6151
- [idOrProductId]
6152
- );
6153
- const byProductId = React3.useMemo(
6154
- () => shouldFetchByProductId(normalizedIdOrProductId, options.byProductId),
6155
- [normalizedIdOrProductId, options.byProductId]
6156
- );
6157
- const cacheKey = React3.useMemo(
6158
- () => buildCompositeCacheKey(client, locationId, normalizedIdOrProductId, byProductId),
6159
- [byProductId, client, locationId, normalizedIdOrProductId]
6160
- );
6161
- const cached = compositeCache.get(cacheKey);
6162
- const [composite, setComposite] = React3.useState(cached?.composite ?? null);
6163
- const [isLoading, setIsLoading] = React3.useState(
6164
- enabled && normalizedIdOrProductId.length > 0 && !cached
6165
- );
6166
- const [error, setError] = React3.useState(null);
6167
- const [priceResult, setPriceResult] = React3.useState(null);
6168
- const [isPriceLoading, setIsPriceLoading] = React3.useState(false);
6169
- React3.useEffect(() => {
6170
- if (previousLocationIdRef.current !== locationId) {
6171
- compositeCache.clear();
6172
- compositeInflight.clear();
6173
- previousLocationIdRef.current = locationId;
6174
- }
6175
- }, [locationId]);
6176
- const load = React3.useCallback(
6177
- async (force = false) => {
6178
- if (!enabled || normalizedIdOrProductId.length === 0) {
6179
- setComposite(null);
6180
- setPriceResult(null);
6181
- setIsLoading(false);
6182
- return;
6183
- }
6184
- const nextRequestId = ++requestIdRef.current;
6185
- setError(null);
6186
- if (!force) {
6187
- const cacheEntry = compositeCache.get(cacheKey);
6188
- if (cacheEntry) {
6189
- setComposite(cacheEntry.composite);
6190
- setIsLoading(false);
6191
- return;
6192
- }
6193
- }
6194
- setIsLoading(true);
6195
- try {
6196
- const existing = compositeInflight.get(cacheKey);
6197
- const promise = existing ?? (async () => {
6198
- const result = byProductId ? await client.catalogue.getCompositeByProductId(normalizedIdOrProductId) : await client.catalogue.getComposite(normalizedIdOrProductId);
6199
- if (!result.ok) {
6200
- throw result.error;
6201
- }
6202
- return result.value;
6203
- })();
6204
- if (!existing) {
6205
- compositeInflight.set(cacheKey, promise);
6206
- promise.finally(() => {
6207
- compositeInflight.delete(cacheKey);
6208
- }).catch(() => void 0);
6209
- }
6210
- const value = await promise;
6211
- compositeCache.set(cacheKey, { composite: value });
6212
- if (nextRequestId === requestIdRef.current) {
6213
- setComposite(value);
6214
- setPriceResult(null);
6215
- setError(null);
6216
- }
6217
- } catch (loadError) {
6218
- if (nextRequestId === requestIdRef.current) {
6219
- setError(loadError);
6220
- }
6221
- } finally {
6222
- if (nextRequestId === requestIdRef.current) {
6223
- setIsLoading(false);
6224
- }
6225
- }
6226
- },
6227
- [byProductId, cacheKey, client, enabled, normalizedIdOrProductId]
6228
- );
6229
- React3.useEffect(() => {
6230
- void load(false);
6231
- }, [load]);
6232
- const calculatePrice = React3.useCallback(
6233
- async (selections, overrideLocationId) => {
6234
- if (!composite) {
6235
- return null;
6236
- }
6237
- const nextRequestId = ++priceRequestIdRef.current;
6238
- setIsPriceLoading(true);
6239
- try {
6240
- const result = await client.catalogue.calculateCompositePrice(
6241
- composite.id,
6242
- selections,
6243
- overrideLocationId
6244
- );
6245
- if (!result.ok) {
6246
- throw result.error;
6247
- }
6248
- if (nextRequestId === priceRequestIdRef.current) {
6249
- setPriceResult(result.value);
6250
- setError(null);
6251
- }
6252
- return result.value;
6253
- } catch (loadError) {
6254
- if (nextRequestId === priceRequestIdRef.current) {
6255
- setError(loadError);
6256
- }
6257
- return null;
6258
- } finally {
6259
- if (nextRequestId === priceRequestIdRef.current) {
6260
- setIsPriceLoading(false);
6261
- }
6262
- }
6263
- },
6264
- [client, composite]
6265
- );
6266
- const refetch = React3.useCallback(async () => {
6267
- compositeCache.delete(cacheKey);
6268
- await load(true);
6269
- }, [cacheKey, load]);
6270
- return { composite, isLoading, error, refetch, calculatePrice, priceResult, isPriceLoading };
6271
- }
6272
6002
  function useSearch(options = {}) {
6273
6003
  const context = useOptionalCimplify();
6274
6004
  const client = options.client ?? context?.client;
@@ -7022,517 +6752,6 @@ function AddOnSelector({
7022
6752
  ] }, addOn.id);
7023
6753
  }) });
7024
6754
  }
7025
- function CompositeSelector({
7026
- productId,
7027
- onSelectionsChange,
7028
- onPriceChange,
7029
- onReady,
7030
- className
7031
- }) {
7032
- const { composite, isLoading, error, calculatePrice, priceResult, isPriceLoading } = useComposite(productId);
7033
- const [groupSelections, setGroupSelections] = React3.useState({});
7034
- const selections = React3.useMemo(() => {
7035
- const result = [];
7036
- for (const groupSels of Object.values(groupSelections)) {
7037
- for (const [componentId, qty] of Object.entries(groupSels)) {
7038
- if (qty > 0) {
7039
- result.push({ component_id: componentId, quantity: qty });
7040
- }
7041
- }
7042
- }
7043
- return result;
7044
- }, [groupSelections]);
7045
- React3.useEffect(() => {
7046
- onSelectionsChange(selections);
7047
- }, [selections, onSelectionsChange]);
7048
- React3.useEffect(() => {
7049
- onPriceChange?.(priceResult);
7050
- }, [priceResult, onPriceChange]);
7051
- const allGroupsSatisfied = React3.useMemo(() => {
7052
- if (!composite) return false;
7053
- for (const group of composite.groups) {
7054
- const groupSels = groupSelections[group.id] || {};
7055
- const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7056
- if (totalSelected < group.min_selections) return false;
7057
- }
7058
- return true;
7059
- }, [composite, groupSelections]);
7060
- React3.useEffect(() => {
7061
- onReady?.(allGroupsSatisfied);
7062
- }, [allGroupsSatisfied, onReady]);
7063
- React3.useEffect(() => {
7064
- if (allGroupsSatisfied && selections.length > 0) {
7065
- void calculatePrice(selections);
7066
- }
7067
- }, [selections, allGroupsSatisfied, calculatePrice]);
7068
- const toggleComponent = React3.useCallback(
7069
- (group, component) => {
7070
- setGroupSelections((prev) => {
7071
- const groupSels = { ...prev[group.id] || {} };
7072
- const currentQty = groupSels[component.id] || 0;
7073
- if (currentQty > 0) {
7074
- if (group.min_selections > 0) {
7075
- const totalOthers = Object.entries(groupSels).filter(([id]) => id !== component.id).reduce((sum, [, q]) => sum + q, 0);
7076
- if (totalOthers < group.min_selections) {
7077
- return prev;
7078
- }
7079
- }
7080
- delete groupSels[component.id];
7081
- } else {
7082
- const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7083
- if (group.max_selections && totalSelected >= group.max_selections) {
7084
- if (group.max_selections === 1) {
7085
- return { ...prev, [group.id]: { [component.id]: 1 } };
7086
- }
7087
- return prev;
7088
- }
7089
- groupSels[component.id] = 1;
7090
- }
7091
- return { ...prev, [group.id]: groupSels };
7092
- });
7093
- },
7094
- []
7095
- );
7096
- const updateQuantity = React3.useCallback(
7097
- (group, componentId, delta) => {
7098
- setGroupSelections((prev) => {
7099
- const groupSels = { ...prev[group.id] || {} };
7100
- const current = groupSels[componentId] || 0;
7101
- const next = Math.max(0, current + delta);
7102
- if (group.max_quantity_per_component && next > group.max_quantity_per_component) {
7103
- return prev;
7104
- }
7105
- if (next === 0) {
7106
- delete groupSels[componentId];
7107
- } else {
7108
- groupSels[componentId] = next;
7109
- }
7110
- return { ...prev, [group.id]: groupSels };
7111
- });
7112
- },
7113
- []
7114
- );
7115
- if (isLoading) {
7116
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-selector": true, "data-loading": true, className, children: "Loading options..." });
7117
- }
7118
- if (error || !composite) {
7119
- return null;
7120
- }
7121
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-selector": true, className, children: [
7122
- composite.groups.sort((a, b) => a.display_order - b.display_order).map((group) => {
7123
- const groupSels = groupSelections[group.id] || {};
7124
- const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7125
- const minMet = totalSelected >= group.min_selections;
7126
- const isSingleSelect = group.max_selections === 1;
7127
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-group": true, children: [
7128
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-group-header": true, children: [
7129
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7130
- /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-composite-group-name": true, children: [
7131
- group.name,
7132
- group.min_selections > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-required": true, children: " *" })
7133
- ] }),
7134
- group.description && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-group-description": true, children: group.description }),
7135
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-group-constraint": true, children: group.min_selections > 0 && group.max_selections ? `Choose ${group.min_selections}\u2013${group.max_selections}` : group.min_selections > 0 ? `Choose at least ${group.min_selections}` : group.max_selections ? `Choose up to ${group.max_selections}` : "Choose as many as you like" })
7136
- ] }),
7137
- !minMet && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-validation": true, children: "Required" })
7138
- ] }),
7139
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-components": true, children: group.components.filter((c) => c.is_available && !c.is_archived).sort((a, b) => a.display_order - b.display_order).map((component) => {
7140
- const qty = groupSels[component.id] || 0;
7141
- const isSelected = qty > 0;
7142
- const displayName = component.display_name || component.product_id || component.id;
7143
- return /* @__PURE__ */ jsxRuntime.jsxs(
7144
- "button",
7145
- {
7146
- type: "button",
7147
- role: isSingleSelect ? "radio" : "checkbox",
7148
- "aria-checked": isSelected,
7149
- onClick: () => toggleComponent(group, component),
7150
- "data-cimplify-composite-component": true,
7151
- "data-selected": isSelected || void 0,
7152
- children: [
7153
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-component-info": true, children: [
7154
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-component-name": true, children: displayName }),
7155
- component.is_popular && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-badge": "popular", children: "Popular" }),
7156
- component.is_premium && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-badge": "premium", children: "Premium" }),
7157
- component.display_description && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-component-description": true, children: component.display_description }),
7158
- component.calories != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-composite-component-calories": true, children: [
7159
- component.calories,
7160
- " cal"
7161
- ] })
7162
- ] }),
7163
- group.allow_quantity && isSelected && /* @__PURE__ */ jsxRuntime.jsxs(
7164
- "span",
7165
- {
7166
- "data-cimplify-composite-qty": true,
7167
- onClick: (e) => e.stopPropagation(),
7168
- children: [
7169
- /* @__PURE__ */ jsxRuntime.jsx(
7170
- "button",
7171
- {
7172
- type: "button",
7173
- onClick: () => updateQuantity(group, component.id, -1),
7174
- "aria-label": `Decrease ${displayName} quantity`,
7175
- children: "\u2212"
7176
- }
7177
- ),
7178
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: qty }),
7179
- /* @__PURE__ */ jsxRuntime.jsx(
7180
- "button",
7181
- {
7182
- type: "button",
7183
- onClick: () => updateQuantity(group, component.id, 1),
7184
- "aria-label": `Increase ${displayName} quantity`,
7185
- children: "+"
7186
- }
7187
- )
7188
- ]
7189
- }
7190
- ),
7191
- component.price && component.price !== "0" && /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: component.price, prefix: "+" })
7192
- ]
7193
- },
7194
- component.id
7195
- );
7196
- }) })
7197
- ] }, group.id);
7198
- }),
7199
- priceResult && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary": true, children: [
7200
- priceResult.base_price !== "0" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-line": true, children: [
7201
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Base" }),
7202
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.base_price })
7203
- ] }),
7204
- priceResult.components_total !== "0" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-line": true, children: [
7205
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Selections" }),
7206
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.components_total })
7207
- ] }),
7208
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-total": true, children: [
7209
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
7210
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.final_price })
7211
- ] })
7212
- ] }),
7213
- isPriceLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-calculating": true, children: "Calculating price..." })
7214
- ] });
7215
- }
7216
- function BundleSelector({
7217
- bundleIdOrSlug,
7218
- onSelectionsChange,
7219
- onReady,
7220
- className
7221
- }) {
7222
- const { bundle, isLoading, error } = useBundle(bundleIdOrSlug);
7223
- const [variantChoices, setVariantChoices] = React3.useState({});
7224
- React3.useEffect(() => {
7225
- if (!bundle) return;
7226
- const defaults = {};
7227
- for (const comp of bundle.components) {
7228
- if (comp.component.variant_id) {
7229
- defaults[comp.component.id] = comp.component.variant_id;
7230
- } else if (comp.variants.length > 0) {
7231
- const defaultVariant = comp.variants.find((v) => v.is_default) || comp.variants[0];
7232
- if (defaultVariant) {
7233
- defaults[comp.component.id] = defaultVariant.id;
7234
- }
7235
- }
7236
- }
7237
- setVariantChoices(defaults);
7238
- }, [bundle]);
7239
- const selections = React3.useMemo(() => {
7240
- if (!bundle) return [];
7241
- return bundle.components.map((comp) => ({
7242
- component_id: comp.component.id,
7243
- variant_id: variantChoices[comp.component.id],
7244
- quantity: comp.component.quantity
7245
- }));
7246
- }, [bundle, variantChoices]);
7247
- React3.useEffect(() => {
7248
- onSelectionsChange(selections);
7249
- }, [selections, onSelectionsChange]);
7250
- React3.useEffect(() => {
7251
- onReady?.(bundle != null && selections.length > 0);
7252
- }, [bundle, selections, onReady]);
7253
- const handleVariantChange = React3.useCallback(
7254
- (componentId, variantId) => {
7255
- setVariantChoices((prev) => ({ ...prev, [componentId]: variantId }));
7256
- },
7257
- []
7258
- );
7259
- if (isLoading) {
7260
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-selector": true, "data-loading": true, className, children: "Loading bundle..." });
7261
- }
7262
- if (error || !bundle) {
7263
- return null;
7264
- }
7265
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-selector": true, className, children: [
7266
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-bundle-heading": true, children: "Included in this bundle" }),
7267
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-components": true, children: bundle.components.map((comp) => /* @__PURE__ */ jsxRuntime.jsx(
7268
- BundleComponentCard,
7269
- {
7270
- data: comp,
7271
- selectedVariantId: variantChoices[comp.component.id],
7272
- onVariantChange: (variantId) => handleVariantChange(comp.component.id, variantId)
7273
- },
7274
- comp.component.id
7275
- )) }),
7276
- bundle.bundle_price && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-summary": true, children: [
7277
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Bundle price" }),
7278
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: bundle.bundle_price })
7279
- ] }),
7280
- bundle.discount_value && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-savings": true, children: [
7281
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "You save" }),
7282
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: bundle.discount_value })
7283
- ] })
7284
- ] });
7285
- }
7286
- function BundleComponentCard({
7287
- data,
7288
- selectedVariantId,
7289
- onVariantChange
7290
- }) {
7291
- const { component, product, variants } = data;
7292
- const showVariantPicker = component.allow_variant_choice && variants.length > 1;
7293
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-component": true, children: [
7294
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-component-header": true, children: [
7295
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7296
- component.quantity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-bundle-component-qty": true, children: [
7297
- "\xD7",
7298
- component.quantity
7299
- ] }),
7300
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-bundle-component-name": true, children: product.name })
7301
- ] }),
7302
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price })
7303
- ] }),
7304
- showVariantPicker && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-variant-picker": true, children: variants.map((variant) => {
7305
- const isSelected = selectedVariantId === variant.id;
7306
- const adjustment = parsePrice(variant.price_adjustment);
7307
- return /* @__PURE__ */ jsxRuntime.jsxs(
7308
- "button",
7309
- {
7310
- type: "button",
7311
- "aria-selected": isSelected,
7312
- onClick: () => onVariantChange(variant.id),
7313
- "data-cimplify-bundle-variant-option": true,
7314
- "data-selected": isSelected || void 0,
7315
- children: [
7316
- getVariantDisplayName(variant, product.name),
7317
- adjustment !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-bundle-variant-adjustment": true, children: [
7318
- adjustment > 0 ? "+" : "",
7319
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: variant.price_adjustment })
7320
- ] })
7321
- ]
7322
- },
7323
- variant.id
7324
- );
7325
- }) })
7326
- ] });
7327
- }
7328
- function ProductCustomizer({
7329
- product,
7330
- onAddToCart,
7331
- className
7332
- }) {
7333
- const [quantity, setQuantity] = React3.useState(1);
7334
- const [isAdded, setIsAdded] = React3.useState(false);
7335
- const [isSubmitting, setIsSubmitting] = React3.useState(false);
7336
- const [selectedVariantId, setSelectedVariantId] = React3.useState();
7337
- const [selectedVariant, setSelectedVariant] = React3.useState();
7338
- const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] = React3.useState([]);
7339
- const [compositeSelections, setCompositeSelections] = React3.useState([]);
7340
- const [compositePrice, setCompositePrice] = React3.useState(null);
7341
- const [compositeReady, setCompositeReady] = React3.useState(false);
7342
- const [bundleSelections, setBundleSelections] = React3.useState([]);
7343
- const [bundleReady, setBundleReady] = React3.useState(false);
7344
- const cart = useCart();
7345
- const productType = product.type || "product";
7346
- const isComposite = productType === "composite";
7347
- const isBundle = productType === "bundle";
7348
- const isStandard = !isComposite && !isBundle;
7349
- const hasVariants = isStandard && product.variants && product.variants.length > 0;
7350
- const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
7351
- React3.useEffect(() => {
7352
- setQuantity(1);
7353
- setIsAdded(false);
7354
- setIsSubmitting(false);
7355
- setSelectedVariantId(void 0);
7356
- setSelectedVariant(void 0);
7357
- setSelectedAddOnOptionIds([]);
7358
- setCompositeSelections([]);
7359
- setCompositePrice(null);
7360
- setCompositeReady(false);
7361
- setBundleSelections([]);
7362
- setBundleReady(false);
7363
- }, [product.id]);
7364
- const selectedAddOnOptions = React3.useMemo(() => {
7365
- if (!product.add_ons) return [];
7366
- const options = [];
7367
- for (const addOn of product.add_ons) {
7368
- for (const option of addOn.options) {
7369
- if (selectedAddOnOptionIds.includes(option.id)) {
7370
- options.push(option);
7371
- }
7372
- }
7373
- }
7374
- return options;
7375
- }, [product.add_ons, selectedAddOnOptionIds]);
7376
- const normalizedAddOnOptionIds = React3.useMemo(() => {
7377
- if (selectedAddOnOptionIds.length === 0) return [];
7378
- return Array.from(new Set(selectedAddOnOptionIds.map((id) => id.trim()).filter(Boolean))).sort();
7379
- }, [selectedAddOnOptionIds]);
7380
- const localTotalPrice = React3.useMemo(() => {
7381
- if (isComposite && compositePrice) {
7382
- return parsePrice(compositePrice.final_price) * quantity;
7383
- }
7384
- let price = parsePrice(product.default_price);
7385
- if (selectedVariant?.price_adjustment) {
7386
- price += parsePrice(selectedVariant.price_adjustment);
7387
- }
7388
- for (const option of selectedAddOnOptions) {
7389
- if (option.default_price) {
7390
- price += parsePrice(option.default_price);
7391
- }
7392
- }
7393
- return price * quantity;
7394
- }, [product.default_price, selectedVariant, selectedAddOnOptions, quantity, isComposite, compositePrice]);
7395
- const requiredAddOnsSatisfied = React3.useMemo(() => {
7396
- if (!product.add_ons) return true;
7397
- for (const addOn of product.add_ons) {
7398
- if (addOn.is_required) {
7399
- const selectedInGroup = selectedAddOnOptionIds.filter(
7400
- (id) => addOn.options.some((opt) => opt.id === id)
7401
- ).length;
7402
- const minRequired = addOn.min_selections || 1;
7403
- if (selectedInGroup < minRequired) {
7404
- return false;
7405
- }
7406
- }
7407
- }
7408
- return true;
7409
- }, [product.add_ons, selectedAddOnOptionIds]);
7410
- const quoteInput = React3.useMemo(
7411
- () => ({
7412
- productId: product.id,
7413
- quantity,
7414
- variantId: selectedVariantId,
7415
- addOnOptionIds: normalizedAddOnOptionIds.length > 0 ? normalizedAddOnOptionIds : void 0
7416
- }),
7417
- [product.id, quantity, selectedVariantId, normalizedAddOnOptionIds]
7418
- );
7419
- const { quote } = useQuote(quoteInput, {
7420
- enabled: isStandard && requiredAddOnsSatisfied
7421
- });
7422
- const quoteId = quote?.quote_id;
7423
- const quotedTotalPrice = React3.useMemo(() => {
7424
- if (!quote) return void 0;
7425
- const quotedTotal = quote.quoted_total_price_info?.final_price ?? quote.final_price_info.final_price;
7426
- return quotedTotal === void 0 || quotedTotal === null ? void 0 : parsePrice(quotedTotal);
7427
- }, [quote]);
7428
- const displayTotalPrice = quotedTotalPrice ?? localTotalPrice;
7429
- const canAddToCart = React3.useMemo(() => {
7430
- if (isComposite) return compositeReady;
7431
- if (isBundle) return bundleReady;
7432
- return requiredAddOnsSatisfied;
7433
- }, [isComposite, isBundle, compositeReady, bundleReady, requiredAddOnsSatisfied]);
7434
- const handleVariantChange = React3.useCallback(
7435
- (variantId, variant) => {
7436
- setSelectedVariantId(variantId);
7437
- setSelectedVariant(variant);
7438
- },
7439
- []
7440
- );
7441
- const handleAddToCart = async () => {
7442
- if (isSubmitting) return;
7443
- setIsSubmitting(true);
7444
- const options = {
7445
- variantId: selectedVariantId,
7446
- variant: selectedVariant ? { id: selectedVariant.id, name: selectedVariant.name || "", price_adjustment: selectedVariant.price_adjustment } : void 0,
7447
- quoteId,
7448
- addOnOptionIds: normalizedAddOnOptionIds.length > 0 ? normalizedAddOnOptionIds : void 0,
7449
- addOnOptions: selectedAddOnOptions.length > 0 ? selectedAddOnOptions.map((opt) => ({
7450
- id: opt.id,
7451
- name: opt.name,
7452
- add_on_id: opt.add_on_id,
7453
- default_price: opt.default_price
7454
- })) : void 0,
7455
- compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
7456
- bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0
7457
- };
7458
- try {
7459
- if (onAddToCart) {
7460
- await onAddToCart(product, quantity, options);
7461
- } else {
7462
- await cart.addItem(product, quantity, options);
7463
- }
7464
- setIsAdded(true);
7465
- setTimeout(() => {
7466
- setIsAdded(false);
7467
- setQuantity(1);
7468
- }, 2e3);
7469
- } catch {
7470
- } finally {
7471
- setIsSubmitting(false);
7472
- }
7473
- };
7474
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer": true, className, children: [
7475
- isComposite && /* @__PURE__ */ jsxRuntime.jsx(
7476
- CompositeSelector,
7477
- {
7478
- productId: product.id,
7479
- onSelectionsChange: setCompositeSelections,
7480
- onPriceChange: setCompositePrice,
7481
- onReady: setCompositeReady
7482
- }
7483
- ),
7484
- isBundle && /* @__PURE__ */ jsxRuntime.jsx(
7485
- BundleSelector,
7486
- {
7487
- bundleIdOrSlug: product.slug,
7488
- onSelectionsChange: setBundleSelections,
7489
- onReady: setBundleReady
7490
- }
7491
- ),
7492
- hasVariants && /* @__PURE__ */ jsxRuntime.jsx(
7493
- VariantSelector,
7494
- {
7495
- variants: product.variants,
7496
- variantAxes: product.variant_axes,
7497
- basePrice: product.default_price,
7498
- selectedVariantId,
7499
- onVariantChange: handleVariantChange
7500
- }
7501
- ),
7502
- hasAddOns && /* @__PURE__ */ jsxRuntime.jsx(
7503
- AddOnSelector,
7504
- {
7505
- addOns: product.add_ons,
7506
- selectedOptions: selectedAddOnOptionIds,
7507
- onOptionsChange: setSelectedAddOnOptionIds
7508
- }
7509
- ),
7510
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer-actions": true, children: [
7511
- /* @__PURE__ */ jsxRuntime.jsx(
7512
- QuantitySelector,
7513
- {
7514
- value: quantity,
7515
- onChange: setQuantity,
7516
- min: 1
7517
- }
7518
- ),
7519
- /* @__PURE__ */ jsxRuntime.jsx(
7520
- "button",
7521
- {
7522
- type: "button",
7523
- onClick: handleAddToCart,
7524
- disabled: isAdded || isSubmitting || !canAddToCart,
7525
- "data-cimplify-customizer-submit": true,
7526
- children: isAdded ? "Added to Cart" : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7527
- "Add to Cart \xB7 ",
7528
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: displayTotalPrice })
7529
- ] })
7530
- }
7531
- )
7532
- ] }),
7533
- !canAddToCart && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-customizer-validation": true, children: "Please select all required options" })
7534
- ] });
7535
- }
7536
6755
  var ASPECT_STYLES = {
7537
6756
  square: { aspectRatio: "1/1" },
7538
6757
  "4/3": { aspectRatio: "4/3" },
@@ -7714,28 +6933,23 @@ exports.AdProvider = AdProvider;
7714
6933
  exports.AddOnSelector = AddOnSelector;
7715
6934
  exports.AddressElement = AddressElement;
7716
6935
  exports.AuthElement = AuthElement;
7717
- exports.BundleSelector = BundleSelector;
7718
6936
  exports.CartSummary = CartSummary;
7719
6937
  exports.CimplifyCheckout = CimplifyCheckout;
7720
6938
  exports.CimplifyProvider = CimplifyProvider;
7721
- exports.CompositeSelector = CompositeSelector;
7722
6939
  exports.ElementsProvider = ElementsProvider;
7723
6940
  exports.PaymentElement = PaymentElement;
7724
6941
  exports.Price = Price;
7725
- exports.ProductCustomizer = ProductCustomizer;
7726
6942
  exports.ProductImageGallery = ProductImageGallery;
7727
6943
  exports.QuantitySelector = QuantitySelector;
7728
6944
  exports.VariantSelector = VariantSelector;
7729
6945
  exports.getVariantDisplayName = getVariantDisplayName;
7730
6946
  exports.useAds = useAds;
7731
- exports.useBundle = useBundle;
7732
6947
  exports.useCart = useCart;
7733
6948
  exports.useCategories = useCategories;
7734
6949
  exports.useCheckout = useCheckout;
7735
6950
  exports.useCimplify = useCimplify;
7736
6951
  exports.useCollection = useCollection;
7737
6952
  exports.useCollections = useCollections;
7738
- exports.useComposite = useComposite;
7739
6953
  exports.useElements = useElements;
7740
6954
  exports.useElementsReady = useElementsReady;
7741
6955
  exports.useLocations = useLocations;