@lime-bundles/react 7.3.1 → 7.4.0

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/index.d.cts CHANGED
@@ -59,6 +59,14 @@ interface BundleComponentProps {
59
59
  * more than one product should pass it.
60
60
  */
61
61
  productId?: string;
62
+ /**
63
+ * Store→presentment currency rate. Merchant-configured amounts
64
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
65
+ * the shop's store currency; pass the rate for the buyer's currency so
66
+ * quoted sale prices match what the checkout's discount function
67
+ * charges. Omit (or pass 1) on store-currency storefronts.
68
+ */
69
+ currencyRate?: number;
62
70
  }
63
71
 
64
72
  declare function FixedBundle(props: BundleComponentProps): react_jsx_runtime.JSX.Element | null;
@@ -187,12 +195,24 @@ interface FetchBundleDataOptions {
187
195
  */
188
196
  buyer?: BuyerResolver;
189
197
  /**
190
- * Shopify Market GID for the current visitor. When set and the bundle's
191
- * `marketVisibility === "specific"`, the bundle is filtered out if its
192
- * `marketIds` doesn't include this market. Returned to the caller via
193
- * `BundleVisibilityWarning[]` for surfacing.
198
+ * Shopify Market GID for the current visitor. Legacy market-gate signal:
199
+ * when set and the bundle's `marketVisibility === "specific"`, a direct
200
+ * market-id match shows the bundle. Prefer letting the gate work from
201
+ * `country` (retail) and `buyer.companyLocationId` (B2B) — Shopify has
202
+ * deprecated market IDs as buyer-targeting signals, and a B2B buyer's
203
+ * company-location market has no storefront market context at all.
204
+ * Misses are returned via `BundleVisibilityWarning[]` for surfacing.
194
205
  */
195
206
  marketId?: string;
207
+ /**
208
+ * Store→presentment currency rate. Merchant-configured amounts
209
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
210
+ * the shop's store currency; pass the rate for the buyer's currency so
211
+ * quoted sale prices match what the checkout's discount function
212
+ * charges. Omit (or pass 1) on store-currency storefronts. See
213
+ * `convertBundleToPresentment` in `@lime-bundles/core`.
214
+ */
215
+ currencyRate?: number;
196
216
  }
197
217
  declare function fetchBundleData(options: FetchBundleDataOptions): Promise<ParsedBundle>;
198
218
 
@@ -229,6 +249,12 @@ interface UseBundleDataOptions {
229
249
  buyer?: BuyerResolver;
230
250
  /** Current visitor's Market GID — filters market-restricted bundles client-side. */
231
251
  marketId?: string;
252
+ /**
253
+ * Store→presentment currency rate for merchant-configured amounts
254
+ * (fixed_amount / flat_price values, volume tier amounts). See
255
+ * `FetchBundleDataOptions.currencyRate`.
256
+ */
257
+ currencyRate?: number;
232
258
  }
233
259
  type UseBundleDataResult = {
234
260
  status: "loading";
@@ -251,6 +277,12 @@ interface UseBundlesForProductOptions {
251
277
  productHandle: string;
252
278
  /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR paths. */
253
279
  buyerIp?: string;
280
+ /**
281
+ * Store→presentment currency rate for merchant-configured amounts
282
+ * (fixed_amount / flat_price values, volume tier amounts). See
283
+ * `FetchBundlesForProductOptions.currencyRate`.
284
+ */
285
+ currencyRate?: number;
254
286
  }
255
287
  type UseBundlesForProductResult = {
256
288
  status: "loading";
package/dist/index.d.ts CHANGED
@@ -59,6 +59,14 @@ interface BundleComponentProps {
59
59
  * more than one product should pass it.
60
60
  */
61
61
  productId?: string;
62
+ /**
63
+ * Store→presentment currency rate. Merchant-configured amounts
64
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
65
+ * the shop's store currency; pass the rate for the buyer's currency so
66
+ * quoted sale prices match what the checkout's discount function
67
+ * charges. Omit (or pass 1) on store-currency storefronts.
68
+ */
69
+ currencyRate?: number;
62
70
  }
63
71
 
64
72
  declare function FixedBundle(props: BundleComponentProps): react_jsx_runtime.JSX.Element | null;
@@ -187,12 +195,24 @@ interface FetchBundleDataOptions {
187
195
  */
188
196
  buyer?: BuyerResolver;
189
197
  /**
190
- * Shopify Market GID for the current visitor. When set and the bundle's
191
- * `marketVisibility === "specific"`, the bundle is filtered out if its
192
- * `marketIds` doesn't include this market. Returned to the caller via
193
- * `BundleVisibilityWarning[]` for surfacing.
198
+ * Shopify Market GID for the current visitor. Legacy market-gate signal:
199
+ * when set and the bundle's `marketVisibility === "specific"`, a direct
200
+ * market-id match shows the bundle. Prefer letting the gate work from
201
+ * `country` (retail) and `buyer.companyLocationId` (B2B) — Shopify has
202
+ * deprecated market IDs as buyer-targeting signals, and a B2B buyer's
203
+ * company-location market has no storefront market context at all.
204
+ * Misses are returned via `BundleVisibilityWarning[]` for surfacing.
194
205
  */
195
206
  marketId?: string;
207
+ /**
208
+ * Store→presentment currency rate. Merchant-configured amounts
209
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
210
+ * the shop's store currency; pass the rate for the buyer's currency so
211
+ * quoted sale prices match what the checkout's discount function
212
+ * charges. Omit (or pass 1) on store-currency storefronts. See
213
+ * `convertBundleToPresentment` in `@lime-bundles/core`.
214
+ */
215
+ currencyRate?: number;
196
216
  }
197
217
  declare function fetchBundleData(options: FetchBundleDataOptions): Promise<ParsedBundle>;
198
218
 
@@ -229,6 +249,12 @@ interface UseBundleDataOptions {
229
249
  buyer?: BuyerResolver;
230
250
  /** Current visitor's Market GID — filters market-restricted bundles client-side. */
231
251
  marketId?: string;
252
+ /**
253
+ * Store→presentment currency rate for merchant-configured amounts
254
+ * (fixed_amount / flat_price values, volume tier amounts). See
255
+ * `FetchBundleDataOptions.currencyRate`.
256
+ */
257
+ currencyRate?: number;
232
258
  }
233
259
  type UseBundleDataResult = {
234
260
  status: "loading";
@@ -251,6 +277,12 @@ interface UseBundlesForProductOptions {
251
277
  productHandle: string;
252
278
  /** Forwarded as `Shopify-Storefront-Buyer-IP` — required for SSR paths. */
253
279
  buyerIp?: string;
280
+ /**
281
+ * Store→presentment currency rate for merchant-configured amounts
282
+ * (fixed_amount / flat_price values, volume tier amounts). See
283
+ * `FetchBundlesForProductOptions.currencyRate`.
284
+ */
285
+ currencyRate?: number;
254
286
  }
255
287
  type UseBundlesForProductResult = {
256
288
  status: "loading";
package/dist/index.js CHANGED
@@ -22,7 +22,8 @@ import {
22
22
  BUNDLE_METAOBJECT_QUERY,
23
23
  withInContext,
24
24
  parseMetaobjectBundleStrict,
25
- isVisibleInMarket,
25
+ convertBundleToPresentment,
26
+ isVisibleToBuyer,
26
27
  BundleParseError
27
28
  } from "@lime-bundles/core";
28
29
  async function fetchBundleData(options) {
@@ -36,6 +37,7 @@ async function fetchBundleData(options) {
36
37
  return result.bundle;
37
38
  }
38
39
  async function fetchBundleDataWithWarnings(options) {
40
+ const buyer = typeof options.buyer === "function" ? await options.buyer() : options.buyer;
39
41
  const config = {
40
42
  shopDomain: options.shopDomain,
41
43
  accessToken: options.storefrontAccessToken,
@@ -43,7 +45,7 @@ async function fetchBundleDataWithWarnings(options) {
43
45
  apiVersion: options.apiVersion,
44
46
  country: options.country,
45
47
  language: options.language,
46
- buyer: options.buyer
48
+ buyer
47
49
  };
48
50
  const client = createStorefrontClient(config);
49
51
  const query = hasInContext(config) ? withInContext(BUNDLE_METAOBJECT_QUERY) : BUNDLE_METAOBJECT_QUERY;
@@ -58,11 +60,16 @@ async function fetchBundleDataWithWarnings(options) {
58
60
  "not_found"
59
61
  );
60
62
  }
61
- const bundle = parseMetaobjectBundleStrict(
62
- data.metaobject.id,
63
- data.metaobject.fields
63
+ const bundle = convertBundleToPresentment(
64
+ parseMetaobjectBundleStrict(data.metaobject.id, data.metaobject.fields),
65
+ options.currencyRate
64
66
  );
65
- if (!isVisibleInMarket(bundle, options.marketId)) {
67
+ const buyerContext = {
68
+ marketId: options.marketId,
69
+ countryCode: options.country,
70
+ companyLocationId: buyer?.companyLocationId
71
+ };
72
+ if (!isVisibleToBuyer(bundle, buyerContext)) {
66
73
  return {
67
74
  bundle: null,
68
75
  warnings: [
@@ -70,7 +77,11 @@ async function fetchBundleDataWithWarnings(options) {
70
77
  bundleGid: options.bundleGid,
71
78
  reason: "market_mismatch",
72
79
  currentMarketId: options.marketId ?? null,
73
- allowedMarketIds: bundle.marketIds
80
+ currentCountryCode: options.country ?? null,
81
+ currentCompanyLocationId: buyer?.companyLocationId ?? null,
82
+ allowedMarketIds: bundle.marketIds,
83
+ allowedCountryCodes: bundle.countryCodes,
84
+ allowedCompanyLocationIds: bundle.companyLocationIds
74
85
  }
75
86
  ]
76
87
  };
@@ -140,7 +151,8 @@ function useBundleData(options) {
140
151
  country: options.country,
141
152
  language: options.language,
142
153
  buyer: options.buyer,
143
- marketId: options.marketId
154
+ marketId: options.marketId,
155
+ currencyRate: options.currencyRate
144
156
  }).then((bundle) => {
145
157
  if (controller.signal.aborted) return;
146
158
  setState({ status: "success", bundle, error: null });
@@ -171,7 +183,8 @@ function useBundleData(options) {
171
183
  options.country,
172
184
  options.language,
173
185
  options.buyer,
174
- options.marketId
186
+ options.marketId,
187
+ options.currencyRate
175
188
  ]);
176
189
  return state;
177
190
  }
@@ -706,12 +719,22 @@ function FixedBundle(props) {
706
719
  analyticsEnabled,
707
720
  onAddToCart,
708
721
  onError,
709
- className
722
+ className,
723
+ country,
724
+ language,
725
+ buyer,
726
+ marketId,
727
+ currencyRate
710
728
  } = props;
711
729
  const result = useBundleData({
712
730
  shopDomain,
713
731
  storefrontAccessToken,
714
- bundleGid
732
+ bundleGid,
733
+ country,
734
+ language,
735
+ buyer,
736
+ marketId,
737
+ currencyRate
715
738
  });
716
739
  const { elementRef, trackAddToCart } = useAnalytics({
717
740
  shopDomain,
@@ -1784,12 +1807,22 @@ function MixMatchBundle(props) {
1784
1807
  onAddToCart,
1785
1808
  onError,
1786
1809
  className,
1787
- productHandle
1810
+ productHandle,
1811
+ country,
1812
+ language,
1813
+ buyer,
1814
+ marketId,
1815
+ currencyRate
1788
1816
  } = props;
1789
1817
  const result = useBundleData({
1790
1818
  shopDomain,
1791
1819
  storefrontAccessToken,
1792
- bundleGid
1820
+ bundleGid,
1821
+ country,
1822
+ language,
1823
+ buyer,
1824
+ marketId,
1825
+ currencyRate
1793
1826
  });
1794
1827
  const { elementRef, trackAddToCart } = useAnalytics({
1795
1828
  shopDomain,
@@ -2327,12 +2360,22 @@ function VolumeBundle(props) {
2327
2360
  onAddToCart,
2328
2361
  onError,
2329
2362
  className,
2330
- productId
2363
+ productId,
2364
+ country,
2365
+ language,
2366
+ buyer,
2367
+ marketId,
2368
+ currencyRate
2331
2369
  } = props;
2332
2370
  const result = useBundleData({
2333
2371
  shopDomain,
2334
2372
  storefrontAccessToken,
2335
- bundleGid
2373
+ bundleGid,
2374
+ country,
2375
+ language,
2376
+ buyer,
2377
+ marketId,
2378
+ currencyRate
2336
2379
  });
2337
2380
  const { elementRef, trackAddToCart } = useAnalytics({
2338
2381
  shopDomain,
@@ -2712,12 +2755,22 @@ function BogoBundle(props) {
2712
2755
  analyticsEnabled,
2713
2756
  onAddToCart,
2714
2757
  onError,
2715
- className
2758
+ className,
2759
+ country,
2760
+ language,
2761
+ buyer,
2762
+ marketId,
2763
+ currencyRate
2716
2764
  } = props;
2717
2765
  const result = useBundleData({
2718
2766
  shopDomain,
2719
2767
  storefrontAccessToken,
2720
- bundleGid
2768
+ bundleGid,
2769
+ country,
2770
+ language,
2771
+ buyer,
2772
+ marketId,
2773
+ currencyRate
2721
2774
  });
2722
2775
  const { elementRef, trackAddToCart } = useAnalytics({
2723
2776
  shopDomain,
@@ -3788,12 +3841,22 @@ function MultiStepBundle(props) {
3788
3841
  analyticsEnabled,
3789
3842
  onAddToCart,
3790
3843
  onError,
3791
- className
3844
+ className,
3845
+ country,
3846
+ language,
3847
+ buyer,
3848
+ marketId,
3849
+ currencyRate
3792
3850
  } = props;
3793
3851
  const result = useBundleData({
3794
3852
  shopDomain,
3795
3853
  storefrontAccessToken,
3796
- bundleGid
3854
+ bundleGid,
3855
+ country,
3856
+ language,
3857
+ buyer,
3858
+ marketId,
3859
+ currencyRate
3797
3860
  });
3798
3861
  const { elementRef, trackAddToCart } = useAnalytics({
3799
3862
  shopDomain,
@@ -4402,7 +4465,8 @@ function useBundlesForProduct(options) {
4402
4465
  storefrontAccessToken: options.storefrontAccessToken,
4403
4466
  productHandle: options.productHandle,
4404
4467
  buyerIp: options.buyerIp,
4405
- signal: controller.signal
4468
+ signal: controller.signal,
4469
+ currencyRate: options.currencyRate
4406
4470
  }).then((bundles) => {
4407
4471
  if (controller.signal.aborted) return;
4408
4472
  setState({ status: "success", bundles, error: null });
@@ -4430,7 +4494,8 @@ function useBundlesForProduct(options) {
4430
4494
  options.shopDomain,
4431
4495
  options.storefrontAccessToken,
4432
4496
  options.productHandle,
4433
- options.buyerIp
4497
+ options.buyerIp,
4498
+ options.currencyRate
4434
4499
  ]);
4435
4500
  return state;
4436
4501
  }