@behio/storefront-sdk 1.18.0 → 2.0.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/README.md +209 -19
- package/dist/{chunk-W2P2D3EZ.mjs → chunk-SCFR6JH7.mjs} +73 -53
- package/dist/{chunk-GAYYRRUL.js → chunk-TDIAWIQR.js} +97 -77
- package/dist/{client-B29GktSJ.d.mts → client-C4dnHtID.d.mts} +209 -26
- package/dist/{client-B29GktSJ.d.ts → client-C4dnHtID.d.ts} +209 -26
- package/dist/index.d.mts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +84 -23
- package/dist/index.mjs +68 -7
- package/dist/next.d.mts +3 -1
- package/dist/next.d.ts +3 -1
- package/dist/next.js +9 -5
- package/dist/next.mjs +5 -1
- package/dist/react.d.mts +230 -32
- package/dist/react.d.ts +230 -32
- package/dist/react.js +154 -115
- package/dist/react.mjs +154 -116
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -150,6 +150,7 @@ var BehioStorefront = class {
|
|
|
150
150
|
this.shopDomain = config.shopDomain;
|
|
151
151
|
this.defaultLocale = config.locale;
|
|
152
152
|
this.defaultCurrency = config.currency;
|
|
153
|
+
this.setCountry(config.country);
|
|
153
154
|
this.fetchFn = config.fetch || globalThis.fetch.bind(globalThis);
|
|
154
155
|
this.timeout = config.timeout ?? 3e4;
|
|
155
156
|
this.retries = config.retries ?? 1;
|
|
@@ -311,6 +312,14 @@ var BehioStorefront = class {
|
|
|
311
312
|
getCurrency() {
|
|
312
313
|
return this.defaultCurrency;
|
|
313
314
|
}
|
|
315
|
+
/** Set the catalog's delivery country. Use cart.setDestination separately for the cart. */
|
|
316
|
+
setCountry(country) {
|
|
317
|
+
const normalized = country?.trim().toUpperCase();
|
|
318
|
+
this.defaultCountry = normalized && /^[A-Z]{2}$/.test(normalized) ? normalized : void 0;
|
|
319
|
+
}
|
|
320
|
+
getCountry() {
|
|
321
|
+
return this.defaultCountry;
|
|
322
|
+
}
|
|
314
323
|
/** Set the default locale sent on every catalog request (per-call wins). */
|
|
315
324
|
setLocale(locale) {
|
|
316
325
|
this.defaultLocale = locale || void 0;
|
|
@@ -466,12 +475,16 @@ var BehioStorefront = class {
|
|
|
466
475
|
if (this.defaultCurrency && !params.has("currency")) {
|
|
467
476
|
params.set("currency", this.defaultCurrency);
|
|
468
477
|
}
|
|
478
|
+
if (this.defaultCountry && path.startsWith("/catalog/") && !params.has("country")) {
|
|
479
|
+
params.set("country", this.defaultCountry);
|
|
480
|
+
}
|
|
469
481
|
const qs = params.toString();
|
|
470
482
|
const url = `${this.baseUrl}/storefront/v1${path}${qs ? `?${qs}` : ""}`;
|
|
471
483
|
const headers = {
|
|
472
484
|
"X-Api-Key": this.apiKey,
|
|
473
485
|
"Content-Type": "application/json"
|
|
474
486
|
};
|
|
487
|
+
if (path === "/cart" || path.startsWith("/cart/")) headers["X-Behio-Cart-Contract"] = "2";
|
|
475
488
|
if (this.shopDomain) {
|
|
476
489
|
headers["X-Shop-Domain"] = this.shopDomain;
|
|
477
490
|
}
|
|
@@ -598,42 +611,46 @@ var BehioStorefront = class {
|
|
|
598
611
|
throw new BehioNetworkError("Request failed after retries");
|
|
599
612
|
}
|
|
600
613
|
};
|
|
614
|
+
function catalogProductsQuery(query) {
|
|
615
|
+
const q = {};
|
|
616
|
+
if (query) {
|
|
617
|
+
if (query.page !== void 0) q.page = query.page;
|
|
618
|
+
if (query.limit !== void 0) q.limit = query.limit;
|
|
619
|
+
if (query.category) q.category = query.category;
|
|
620
|
+
if (query.label) q.label = query.label;
|
|
621
|
+
if (query.priceMin !== void 0) q.priceMin = query.priceMin;
|
|
622
|
+
if (query.priceMax !== void 0) q.priceMax = query.priceMax;
|
|
623
|
+
if (query.currency) q.currency = query.currency;
|
|
624
|
+
if (query.country) q.country = query.country;
|
|
625
|
+
if (query.locale) q.locale = query.locale;
|
|
626
|
+
if (query.sort) q.sort = query.sort;
|
|
627
|
+
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
628
|
+
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
629
|
+
if (query.search) q.search = query.search;
|
|
630
|
+
if (query.parameters) q.parameters = JSON.stringify(query.parameters);
|
|
631
|
+
if (query.facets) q.facets = JSON.stringify(query.facets);
|
|
632
|
+
if (query.ids && query.ids.length > 0) q.ids = query.ids;
|
|
633
|
+
if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
|
|
634
|
+
if (query.labels && query.labels.length > 0) q.labels = query.labels;
|
|
635
|
+
if (query.categories && query.categories.length > 0)
|
|
636
|
+
q.categories = query.categories;
|
|
637
|
+
if (query.excludeIds && query.excludeIds.length > 0)
|
|
638
|
+
q.excludeIds = query.excludeIds;
|
|
639
|
+
if (query.excludeCategories && query.excludeCategories.length > 0)
|
|
640
|
+
q.excludeCategories = query.excludeCategories;
|
|
641
|
+
if (query.hasDiscount !== void 0) q.hasDiscount = query.hasDiscount;
|
|
642
|
+
if (query.isFeatured !== void 0) q.isFeatured = query.isFeatured;
|
|
643
|
+
if (query.createdAfter !== void 0) q.createdAfter = query.createdAfter;
|
|
644
|
+
}
|
|
645
|
+
return q;
|
|
646
|
+
}
|
|
601
647
|
var CatalogModule = class {
|
|
602
648
|
constructor(client) {
|
|
603
649
|
this.client = client;
|
|
604
650
|
}
|
|
605
651
|
/** List products with filtering, pagination, search */
|
|
606
652
|
async getProducts(query) {
|
|
607
|
-
const q =
|
|
608
|
-
if (query) {
|
|
609
|
-
if (query.page) q.page = query.page;
|
|
610
|
-
if (query.limit) q.limit = query.limit;
|
|
611
|
-
if (query.category) q.category = query.category;
|
|
612
|
-
if (query.label) q.label = query.label;
|
|
613
|
-
if (query.priceMin) q.priceMin = query.priceMin;
|
|
614
|
-
if (query.priceMax) q.priceMax = query.priceMax;
|
|
615
|
-
if (query.currency) q.currency = query.currency;
|
|
616
|
-
if (query.country) q.country = query.country;
|
|
617
|
-
if (query.locale) q.locale = query.locale;
|
|
618
|
-
if (query.sort) q.sort = query.sort;
|
|
619
|
-
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
620
|
-
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
621
|
-
if (query.search) q.search = query.search;
|
|
622
|
-
if (query.parameters) q.parameters = JSON.stringify(query.parameters);
|
|
623
|
-
if (query.facets) q.facets = JSON.stringify(query.facets);
|
|
624
|
-
if (query.ids && query.ids.length > 0) q.ids = query.ids;
|
|
625
|
-
if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
|
|
626
|
-
if (query.labels && query.labels.length > 0) q.labels = query.labels;
|
|
627
|
-
if (query.categories && query.categories.length > 0)
|
|
628
|
-
q.categories = query.categories;
|
|
629
|
-
if (query.excludeIds && query.excludeIds.length > 0)
|
|
630
|
-
q.excludeIds = query.excludeIds;
|
|
631
|
-
if (query.excludeCategories && query.excludeCategories.length > 0)
|
|
632
|
-
q.excludeCategories = query.excludeCategories;
|
|
633
|
-
if (query.hasDiscount !== void 0) q.hasDiscount = query.hasDiscount;
|
|
634
|
-
if (query.isFeatured !== void 0) q.isFeatured = query.isFeatured;
|
|
635
|
-
if (query.createdAfter !== void 0) q.createdAfter = query.createdAfter;
|
|
636
|
-
}
|
|
653
|
+
const q = catalogProductsQuery(query);
|
|
637
654
|
return this.client.request(
|
|
638
655
|
"GET",
|
|
639
656
|
"/catalog/products",
|
|
@@ -675,14 +692,7 @@ var CatalogModule = class {
|
|
|
675
692
|
}
|
|
676
693
|
/** Get products in a category */
|
|
677
694
|
async getCategoryProducts(slug, query) {
|
|
678
|
-
const q =
|
|
679
|
-
if (query) {
|
|
680
|
-
if (query.page) q.page = query.page;
|
|
681
|
-
if (query.limit) q.limit = query.limit;
|
|
682
|
-
if (query.sort) q.sort = query.sort;
|
|
683
|
-
if (query.locale) q.locale = query.locale;
|
|
684
|
-
if (query.currency) q.currency = query.currency;
|
|
685
|
-
}
|
|
695
|
+
const q = catalogProductsQuery(query);
|
|
686
696
|
return this.client.request(
|
|
687
697
|
"GET",
|
|
688
698
|
`/catalog/categories/${slug}/products`,
|
|
@@ -716,7 +726,7 @@ var CatalogModule = class {
|
|
|
716
726
|
"GET",
|
|
717
727
|
"/catalog/featured",
|
|
718
728
|
{
|
|
719
|
-
query: { locale: options?.locale, currency: options?.currency }
|
|
729
|
+
query: { locale: options?.locale, currency: options?.currency, country: options?.country }
|
|
720
730
|
}
|
|
721
731
|
);
|
|
722
732
|
}
|
|
@@ -774,9 +784,10 @@ var CatalogModule = class {
|
|
|
774
784
|
if (query) {
|
|
775
785
|
if (query.category) q.category = query.category;
|
|
776
786
|
if (query.label) q.label = query.label;
|
|
777
|
-
if (query.priceMin) q.priceMin = query.priceMin;
|
|
778
|
-
if (query.priceMax) q.priceMax = query.priceMax;
|
|
787
|
+
if (query.priceMin !== void 0) q.priceMin = query.priceMin;
|
|
788
|
+
if (query.priceMax !== void 0) q.priceMax = query.priceMax;
|
|
779
789
|
if (query.currency) q.currency = query.currency;
|
|
790
|
+
if (query.country) q.country = query.country;
|
|
780
791
|
if (query.locale) q.locale = query.locale;
|
|
781
792
|
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
782
793
|
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
@@ -798,12 +809,12 @@ var CatalogModule = class {
|
|
|
798
809
|
return this.getProducts({ search: query, ...options });
|
|
799
810
|
}
|
|
800
811
|
/** List all active bundles */
|
|
801
|
-
async getBundles() {
|
|
802
|
-
return this.client.request("GET", "/catalog/bundles");
|
|
812
|
+
async getBundles(options) {
|
|
813
|
+
return this.client.request("GET", "/catalog/bundles", { query: { ...options } });
|
|
803
814
|
}
|
|
804
815
|
/** Get a single bundle by slug */
|
|
805
|
-
async getBundle(slug) {
|
|
806
|
-
return this.client.request("GET", `/catalog/bundles/${slug}
|
|
816
|
+
async getBundle(slug, options) {
|
|
817
|
+
return this.client.request("GET", `/catalog/bundles/${encodeURIComponent(slug)}`, { query: { ...options } });
|
|
807
818
|
}
|
|
808
819
|
/**
|
|
809
820
|
* One product group ("collection") by slug with its products as standard
|
|
@@ -816,7 +827,7 @@ var CatalogModule = class {
|
|
|
816
827
|
"GET",
|
|
817
828
|
`/catalog/product-groups/${encodeURIComponent(slug)}`,
|
|
818
829
|
{
|
|
819
|
-
query: { locale: options?.locale, currency: options?.currency }
|
|
830
|
+
query: { locale: options?.locale, currency: options?.currency, country: options?.country }
|
|
820
831
|
}
|
|
821
832
|
);
|
|
822
833
|
}
|
|
@@ -831,7 +842,7 @@ var CatalogModule = class {
|
|
|
831
842
|
return this.client.request(
|
|
832
843
|
"GET",
|
|
833
844
|
`/catalog/products/${encodeURIComponent(productSlug)}/cross-sell`,
|
|
834
|
-
{ query: { locale: options?.locale, currency: options?.currency } }
|
|
845
|
+
{ query: { locale: options?.locale, currency: options?.currency, country: options?.country } }
|
|
835
846
|
);
|
|
836
847
|
}
|
|
837
848
|
/** Active promotions applicable to a product (with countdown end time) */
|
|
@@ -1039,6 +1050,7 @@ var CartModule = class {
|
|
|
1039
1050
|
body: { currency }
|
|
1040
1051
|
});
|
|
1041
1052
|
if (res.error) return res;
|
|
1053
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1042
1054
|
this.client.emit("cart:updated", res.data);
|
|
1043
1055
|
return res;
|
|
1044
1056
|
}
|
|
@@ -1059,6 +1071,7 @@ var CartModule = class {
|
|
|
1059
1071
|
body: input
|
|
1060
1072
|
});
|
|
1061
1073
|
if (res.error) return res;
|
|
1074
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1062
1075
|
this.client.emit("cart:updated", res.data);
|
|
1063
1076
|
return res;
|
|
1064
1077
|
}
|
|
@@ -1143,14 +1156,15 @@ var CartModule = class {
|
|
|
1143
1156
|
body
|
|
1144
1157
|
});
|
|
1145
1158
|
if (res.error) return res;
|
|
1159
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1146
1160
|
this.client.emit("cart:updated", res.data);
|
|
1147
1161
|
return res;
|
|
1148
1162
|
}
|
|
1149
|
-
/** Update
|
|
1150
|
-
async updateBundleQuantity(
|
|
1163
|
+
/** Update by CartBundleLine.id; legacy catalog bundle IDs are accepted by the API */
|
|
1164
|
+
async updateBundleQuantity(lineId, quantity) {
|
|
1151
1165
|
const res = await this.client.request(
|
|
1152
1166
|
"PATCH",
|
|
1153
|
-
`/cart/bundles/${
|
|
1167
|
+
`/cart/bundles/${lineId}`,
|
|
1154
1168
|
{
|
|
1155
1169
|
body: { quantity }
|
|
1156
1170
|
}
|
|
@@ -1159,11 +1173,11 @@ var CartModule = class {
|
|
|
1159
1173
|
this.client.emit("cart:updated", res.data);
|
|
1160
1174
|
return res;
|
|
1161
1175
|
}
|
|
1162
|
-
/** Remove
|
|
1163
|
-
async removeBundle(
|
|
1176
|
+
/** Remove by CartBundleLine.id; scoped to the current visitor cart */
|
|
1177
|
+
async removeBundle(lineId) {
|
|
1164
1178
|
const res = await this.client.request(
|
|
1165
1179
|
"DELETE",
|
|
1166
|
-
`/cart/bundles/${
|
|
1180
|
+
`/cart/bundles/${lineId}`
|
|
1167
1181
|
);
|
|
1168
1182
|
if (res.error) return res;
|
|
1169
1183
|
this.client.emit("cart:updated", res.data);
|
|
@@ -1197,6 +1211,12 @@ var CheckoutModule = class {
|
|
|
1197
1211
|
constructor(client) {
|
|
1198
1212
|
this.client = client;
|
|
1199
1213
|
}
|
|
1214
|
+
/** Recalculate the current cart including shipping, fees, benefits and rounding.
|
|
1215
|
+
* No order, stock claim, payment or gift-card redemption is created. Required
|
|
1216
|
+
* legal consents are enforced only on createOrder, not while quoting. */
|
|
1217
|
+
async preview(input) {
|
|
1218
|
+
return this.client.request("POST", "/checkout/preview", { body: input });
|
|
1219
|
+
}
|
|
1200
1220
|
/** Create order from cart */
|
|
1201
1221
|
async createOrder(input) {
|
|
1202
1222
|
const res = await this.client.request("POST", "/checkout", {
|
|
@@ -2091,6 +2111,7 @@ function BehioProvider({
|
|
|
2091
2111
|
});
|
|
2092
2112
|
}
|
|
2093
2113
|
const client = clientRef.current;
|
|
2114
|
+
const [sessionRestored, setSessionRestored] = useState(false);
|
|
2094
2115
|
useEffect(() => {
|
|
2095
2116
|
const accessToken = storageAdapter.get(STORAGE_KEYS.ACCESS_TOKEN);
|
|
2096
2117
|
const refreshToken = storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
|
|
@@ -2101,6 +2122,7 @@ function BehioProvider({
|
|
|
2101
2122
|
if (cartSession) {
|
|
2102
2123
|
client.setCartSession(cartSession);
|
|
2103
2124
|
}
|
|
2125
|
+
setSessionRestored(true);
|
|
2104
2126
|
}, [client, storageAdapter]);
|
|
2105
2127
|
useEffect(() => {
|
|
2106
2128
|
if (!persistCurrency) return;
|
|
@@ -2155,12 +2177,13 @@ function BehioProvider({
|
|
|
2155
2177
|
() => ({
|
|
2156
2178
|
client,
|
|
2157
2179
|
storage: storageAdapter,
|
|
2180
|
+
sessionRestored,
|
|
2158
2181
|
currency: activeCurrency,
|
|
2159
2182
|
setCurrency,
|
|
2160
2183
|
configuredDefaultCurrency: defaultCurrency,
|
|
2161
2184
|
configuredCurrencies: currencies
|
|
2162
2185
|
}),
|
|
2163
|
-
[client, storageAdapter, activeCurrency, setCurrency, defaultCurrency, currencies]
|
|
2186
|
+
[client, storageAdapter, sessionRestored, activeCurrency, setCurrency, defaultCurrency, currencies]
|
|
2164
2187
|
);
|
|
2165
2188
|
return /* @__PURE__ */ jsx(QueryClientProvider, { client: qc, children: /* @__PURE__ */ jsx(BehioContext.Provider, { value: ctxValue, children }) });
|
|
2166
2189
|
}
|
|
@@ -2410,6 +2433,15 @@ function useSearch(query, options) {
|
|
|
2410
2433
|
// src/react/hooks/use-cart.ts
|
|
2411
2434
|
import { useCallback as useCallback3 } from "react";
|
|
2412
2435
|
import { useQuery as useQuery10, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2436
|
+
|
|
2437
|
+
// src/react/utils/refresh-bundle-queries.ts
|
|
2438
|
+
async function refreshBundleQueries(queryClient) {
|
|
2439
|
+
const keys = [["behio", "bundle"], ["behio", "bundles"]];
|
|
2440
|
+
await Promise.all(keys.map((queryKey) => queryClient.cancelQueries({ queryKey })));
|
|
2441
|
+
await Promise.all(keys.map((queryKey) => queryClient.invalidateQueries({ queryKey })));
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
// src/react/hooks/use-cart.ts
|
|
2413
2445
|
var CART_KEY = ["behio", "cart"];
|
|
2414
2446
|
function useCart(options) {
|
|
2415
2447
|
const { client, storage } = useBehio();
|
|
@@ -2433,32 +2465,21 @@ function useCart(options) {
|
|
|
2433
2465
|
storage.set(STORAGE_KEYS.CART_SESSION, result.newSessionToken);
|
|
2434
2466
|
}
|
|
2435
2467
|
queryClient.setQueryData([...CART_KEY], result);
|
|
2468
|
+
void refreshBundleQueries(queryClient);
|
|
2436
2469
|
}
|
|
2437
2470
|
});
|
|
2471
|
+
const cancelCartRead = () => queryClient.cancelQueries({ queryKey: [...CART_KEY] });
|
|
2472
|
+
const acceptCart = async (result) => {
|
|
2473
|
+
await cancelCartRead();
|
|
2474
|
+
queryClient.setQueryData([...CART_KEY], result);
|
|
2475
|
+
void refreshBundleQueries(queryClient);
|
|
2476
|
+
};
|
|
2438
2477
|
const updateMutation = useMutation({
|
|
2439
2478
|
mutationFn: async ({ itemId, quantity }) => {
|
|
2440
2479
|
return unwrap(client.cart.updateQuantity(itemId, quantity));
|
|
2441
2480
|
},
|
|
2442
|
-
onMutate:
|
|
2443
|
-
|
|
2444
|
-
const previous = queryClient.getQueryData([...CART_KEY]);
|
|
2445
|
-
if (previous) {
|
|
2446
|
-
const updatedItems = previous.items.map(
|
|
2447
|
-
(item) => item.id === itemId ? { ...item, quantity, totalPrice: item.unitPrice * quantity } : item
|
|
2448
|
-
);
|
|
2449
|
-
queryClient.setQueryData([...CART_KEY], {
|
|
2450
|
-
...previous,
|
|
2451
|
-
items: updatedItems,
|
|
2452
|
-
itemCount: updatedItems.reduce((sum, i) => sum + i.quantity, 0)
|
|
2453
|
-
});
|
|
2454
|
-
}
|
|
2455
|
-
return { previous };
|
|
2456
|
-
},
|
|
2457
|
-
onError: (_err, _vars, context) => {
|
|
2458
|
-
if (context?.previous) {
|
|
2459
|
-
queryClient.setQueryData([...CART_KEY], context.previous);
|
|
2460
|
-
}
|
|
2461
|
-
},
|
|
2481
|
+
onMutate: cancelCartRead,
|
|
2482
|
+
onSuccess: acceptCart,
|
|
2462
2483
|
onSettled: () => {
|
|
2463
2484
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY] });
|
|
2464
2485
|
}
|
|
@@ -2467,24 +2488,8 @@ function useCart(options) {
|
|
|
2467
2488
|
mutationFn: async (itemId) => {
|
|
2468
2489
|
return unwrap(client.cart.removeItem(itemId));
|
|
2469
2490
|
},
|
|
2470
|
-
onMutate:
|
|
2471
|
-
|
|
2472
|
-
const previous = queryClient.getQueryData([...CART_KEY]);
|
|
2473
|
-
if (previous) {
|
|
2474
|
-
const updatedItems = previous.items.filter((item) => item.id !== itemId);
|
|
2475
|
-
queryClient.setQueryData([...CART_KEY], {
|
|
2476
|
-
...previous,
|
|
2477
|
-
items: updatedItems,
|
|
2478
|
-
itemCount: updatedItems.reduce((sum, i) => sum + i.quantity, 0)
|
|
2479
|
-
});
|
|
2480
|
-
}
|
|
2481
|
-
return { previous };
|
|
2482
|
-
},
|
|
2483
|
-
onError: (_err, _vars, context) => {
|
|
2484
|
-
if (context?.previous) {
|
|
2485
|
-
queryClient.setQueryData([...CART_KEY], context.previous);
|
|
2486
|
-
}
|
|
2487
|
-
},
|
|
2491
|
+
onMutate: cancelCartRead,
|
|
2492
|
+
onSuccess: acceptCart,
|
|
2488
2493
|
onSettled: () => {
|
|
2489
2494
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY] });
|
|
2490
2495
|
}
|
|
@@ -2495,6 +2500,7 @@ function useCart(options) {
|
|
|
2495
2500
|
queryClient.setQueryData([...CART_KEY], null);
|
|
2496
2501
|
client.clearCartSession();
|
|
2497
2502
|
storage.remove(STORAGE_KEYS.CART_SESSION);
|
|
2503
|
+
void refreshBundleQueries(queryClient);
|
|
2498
2504
|
}
|
|
2499
2505
|
});
|
|
2500
2506
|
const applyDiscountMutation = useMutation({
|
|
@@ -2515,6 +2521,7 @@ function useCart(options) {
|
|
|
2515
2521
|
queryClient.setQueryData([...CART_KEY], result);
|
|
2516
2522
|
client.clearCartSession();
|
|
2517
2523
|
storage.remove(STORAGE_KEYS.CART_SESSION);
|
|
2524
|
+
void refreshBundleQueries(queryClient);
|
|
2518
2525
|
}
|
|
2519
2526
|
});
|
|
2520
2527
|
const addItem = useCallback3(
|
|
@@ -2559,7 +2566,7 @@ function useCart(options) {
|
|
|
2559
2566
|
merge,
|
|
2560
2567
|
// Computed
|
|
2561
2568
|
itemCount: cart?.itemCount ?? 0,
|
|
2562
|
-
isEmpty: !cart || cart.items.length === 0,
|
|
2569
|
+
isEmpty: !cart || cart.items.length === 0 && (cart.bundleLines?.length ?? 0) === 0,
|
|
2563
2570
|
// Mutation states
|
|
2564
2571
|
isAdding: addMutation.isPending,
|
|
2565
2572
|
isUpdating: updateMutation.isPending,
|
|
@@ -2615,6 +2622,7 @@ function useAuth() {
|
|
|
2615
2622
|
queryClient.setQueryData([...CUSTOMER_KEY], null);
|
|
2616
2623
|
queryClient.invalidateQueries({ queryKey: ["behio", "orders"] });
|
|
2617
2624
|
queryClient.invalidateQueries({ queryKey: ["behio", "addresses"] });
|
|
2625
|
+
void refreshBundleQueries(queryClient);
|
|
2618
2626
|
}, [client, storage, queryClient]);
|
|
2619
2627
|
const postAuth = useCallback4(async () => {
|
|
2620
2628
|
await queryClient.invalidateQueries({ queryKey: [...CUSTOMER_KEY] });
|
|
@@ -2627,6 +2635,7 @@ function useAuth() {
|
|
|
2627
2635
|
}
|
|
2628
2636
|
}
|
|
2629
2637
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY3] });
|
|
2638
|
+
void refreshBundleQueries(queryClient);
|
|
2630
2639
|
}, [client, storage, queryClient]);
|
|
2631
2640
|
const loginMutation = useMutation2({
|
|
2632
2641
|
mutationFn: async ({ email, password }) => {
|
|
@@ -3590,6 +3599,11 @@ function useCheckout() {
|
|
|
3590
3599
|
reset
|
|
3591
3600
|
};
|
|
3592
3601
|
}
|
|
3602
|
+
function useCheckoutPreview() {
|
|
3603
|
+
const { client } = useBehio();
|
|
3604
|
+
const mutation = useMutation14({ mutationFn: (input) => unwrap(client.checkout.preview(input)) });
|
|
3605
|
+
return { preview: mutation.mutateAsync, data: mutation.data, isPreviewing: mutation.isPending, error: mutation.error, reset: mutation.reset };
|
|
3606
|
+
}
|
|
3593
3607
|
|
|
3594
3608
|
// src/react/hooks/use-pages.ts
|
|
3595
3609
|
import { useQuery as useQuery29 } from "@tanstack/react-query";
|
|
@@ -3754,7 +3768,8 @@ function useShopScripts(options) {
|
|
|
3754
3768
|
return useQuery33({
|
|
3755
3769
|
queryKey: ["behio", "shop-scripts"],
|
|
3756
3770
|
queryFn: () => unwrap(client.getShopScripts()),
|
|
3757
|
-
enabled: options?.enabled !== false
|
|
3771
|
+
enabled: options?.enabled !== false,
|
|
3772
|
+
initialData: options?.initialData
|
|
3758
3773
|
});
|
|
3759
3774
|
}
|
|
3760
3775
|
|
|
@@ -3823,7 +3838,7 @@ function CurrencySwitcher({
|
|
|
3823
3838
|
}
|
|
3824
3839
|
|
|
3825
3840
|
// src/react/components/storefront-scripts.tsx
|
|
3826
|
-
import { useEffect as useEffect6, useMemo as useMemo5, useState as useState10 } from "react";
|
|
3841
|
+
import { useEffect as useEffect6, useMemo as useMemo5, useRef as useRef4, useState as useState10 } from "react";
|
|
3827
3842
|
|
|
3828
3843
|
// src/react/hooks/use-consent.ts
|
|
3829
3844
|
import { useQuery as useQuery35, useMutation as useMutation16, useQueryClient as useQueryClient16 } from "@tanstack/react-query";
|
|
@@ -3888,31 +3903,32 @@ function partsFor(s) {
|
|
|
3888
3903
|
return [{ target: "head", html: `<meta name="google-site-verification" content="${id}" />` }];
|
|
3889
3904
|
case "RAW":
|
|
3890
3905
|
default:
|
|
3891
|
-
return [{ target: s.placement === "HEAD" ? "head" : "body", html: s.value }];
|
|
3906
|
+
return [{ target: s.placement === "HEAD" ? "head" : "body", start: s.placement === "BODY_START", html: s.value }];
|
|
3892
3907
|
}
|
|
3893
3908
|
}
|
|
3894
|
-
function injectHtml(target, html) {
|
|
3909
|
+
function injectHtml(target, html, start = false) {
|
|
3895
3910
|
const tpl = document.createElement("template");
|
|
3896
3911
|
tpl.innerHTML = html;
|
|
3897
3912
|
const added = [];
|
|
3913
|
+
const anchor = start ? target.firstChild : null;
|
|
3898
3914
|
Array.from(tpl.content.childNodes).forEach((node) => {
|
|
3899
3915
|
if (node.nodeName === "SCRIPT") {
|
|
3900
3916
|
const old = node;
|
|
3901
3917
|
const script = document.createElement("script");
|
|
3902
3918
|
for (const attr of Array.from(old.attributes)) script.setAttribute(attr.name, attr.value);
|
|
3903
3919
|
script.text = old.text;
|
|
3904
|
-
target.
|
|
3920
|
+
target.insertBefore(script, anchor);
|
|
3905
3921
|
added.push(script);
|
|
3906
3922
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
3907
3923
|
const clone = node.cloneNode(true);
|
|
3908
|
-
target.
|
|
3924
|
+
target.insertBefore(clone, anchor);
|
|
3909
3925
|
added.push(clone);
|
|
3910
3926
|
}
|
|
3911
3927
|
});
|
|
3912
3928
|
return added;
|
|
3913
3929
|
}
|
|
3914
|
-
function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
|
|
3915
|
-
const { data } = useShopScripts();
|
|
3930
|
+
function StorefrontScripts({ visitorId: visitorIdProp, initialScripts } = {}) {
|
|
3931
|
+
const { data } = useShopScripts({ enabled: initialScripts === void 0, initialData: initialScripts ? { scripts: initialScripts } : void 0 });
|
|
3916
3932
|
const [visitorId, setVisitorId] = useState10(visitorIdProp ?? "");
|
|
3917
3933
|
useEffect6(() => {
|
|
3918
3934
|
if (visitorIdProp) return;
|
|
@@ -3924,21 +3940,30 @@ function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
|
|
|
3924
3940
|
}, [visitorIdProp]);
|
|
3925
3941
|
const { data: consent } = useCookieConsent(visitorId || void 0);
|
|
3926
3942
|
const analyticsOk = Boolean(consent?.analytics);
|
|
3943
|
+
const marketingOk = Boolean(consent?.marketing);
|
|
3927
3944
|
const scripts = useMemo5(
|
|
3928
|
-
() => (data?.scripts ?? []).filter((s) => !s.consentRequired || analyticsOk),
|
|
3929
|
-
[data, analyticsOk]
|
|
3945
|
+
() => (initialScripts ?? data?.scripts ?? []).filter((s) => !s.consentRequired || (s.type === "META_PIXEL" ? marketingOk : analyticsOk)),
|
|
3946
|
+
[initialScripts, data, analyticsOk, marketingOk]
|
|
3930
3947
|
);
|
|
3931
3948
|
const signature = useMemo5(
|
|
3932
3949
|
() => JSON.stringify(scripts.map((s) => [s.id, s.type, s.placement, s.value])),
|
|
3933
3950
|
[scripts]
|
|
3934
3951
|
);
|
|
3952
|
+
const activeConsented = useRef4(/* @__PURE__ */ new Set());
|
|
3935
3953
|
useEffect6(() => {
|
|
3936
3954
|
if (typeof document === "undefined") return;
|
|
3955
|
+
const nextConsented = new Set(scripts.filter((s) => s.consentRequired).map((s) => s.id));
|
|
3956
|
+
const revoked = [...activeConsented.current].some((id) => !nextConsented.has(id));
|
|
3957
|
+
activeConsented.current = nextConsented;
|
|
3958
|
+
if (revoked) {
|
|
3959
|
+
window.location.reload();
|
|
3960
|
+
return;
|
|
3961
|
+
}
|
|
3937
3962
|
const added = [];
|
|
3938
3963
|
for (const s of scripts) {
|
|
3939
3964
|
for (const part of partsFor(s)) {
|
|
3940
3965
|
const target = part.target === "head" ? document.head : document.body;
|
|
3941
|
-
added.push(...injectHtml(target, part.html));
|
|
3966
|
+
added.push(...injectHtml(target, part.html, part.start));
|
|
3942
3967
|
}
|
|
3943
3968
|
}
|
|
3944
3969
|
return () => {
|
|
@@ -4200,20 +4225,22 @@ function utmFromSearch(search) {
|
|
|
4200
4225
|
// src/react/hooks/use-bundles.ts
|
|
4201
4226
|
import { useQuery as useQuery36 } from "@tanstack/react-query";
|
|
4202
4227
|
function useBundles(options) {
|
|
4203
|
-
const { client } = useBehio();
|
|
4228
|
+
const { client, sessionRestored } = useBehio();
|
|
4229
|
+
const query = { locale: options?.locale ?? client.getLocale(), currency: options?.currency ?? client.getCurrency(), country: options?.country ?? client.getCountry() };
|
|
4204
4230
|
return useQuery36({
|
|
4205
|
-
queryKey: ["behio", "bundles"],
|
|
4206
|
-
queryFn: () => unwrap(client.catalog.getBundles()),
|
|
4207
|
-
enabled: options?.enabled ?? true,
|
|
4231
|
+
queryKey: ["behio", "bundles", query],
|
|
4232
|
+
queryFn: () => unwrap(client.catalog.getBundles(query)),
|
|
4233
|
+
enabled: sessionRestored && (options?.enabled ?? true),
|
|
4208
4234
|
initialData: options?.initialData
|
|
4209
4235
|
});
|
|
4210
4236
|
}
|
|
4211
4237
|
function useBundle(slug, options) {
|
|
4212
|
-
const { client } = useBehio();
|
|
4238
|
+
const { client, sessionRestored } = useBehio();
|
|
4239
|
+
const query = { locale: options?.locale ?? client.getLocale(), currency: options?.currency ?? client.getCurrency(), country: options?.country ?? client.getCountry() };
|
|
4213
4240
|
return useQuery36({
|
|
4214
|
-
queryKey: ["behio", "bundle", slug],
|
|
4215
|
-
queryFn: () => unwrap(client.catalog.getBundle(slug)),
|
|
4216
|
-
enabled: Boolean(slug) && (options?.enabled ?? true),
|
|
4241
|
+
queryKey: ["behio", "bundle", slug, query],
|
|
4242
|
+
queryFn: () => unwrap(client.catalog.getBundle(slug, query)),
|
|
4243
|
+
enabled: sessionRestored && Boolean(slug) && (options?.enabled ?? true),
|
|
4217
4244
|
initialData: options?.initialData
|
|
4218
4245
|
});
|
|
4219
4246
|
}
|
|
@@ -4316,8 +4343,10 @@ import { useQuery as useQuery42, useMutation as useMutation18, useQueryClient as
|
|
|
4316
4343
|
function useProductReviews(productId, options) {
|
|
4317
4344
|
const { client } = useBehio();
|
|
4318
4345
|
return useQuery42({
|
|
4319
|
-
queryKey: ["behio", "reviews", productId, options?.page ?? 1],
|
|
4346
|
+
queryKey: ["behio", "reviews", productId, options?.page ?? 1, options?.limit ?? 20],
|
|
4320
4347
|
queryFn: () => unwrap(client.reviews.getProductReviews(productId, options?.page, options?.limit)),
|
|
4348
|
+
initialData: options?.initialData,
|
|
4349
|
+
staleTime: 3e4,
|
|
4321
4350
|
enabled: Boolean(productId) && (options?.enabled ?? true)
|
|
4322
4351
|
});
|
|
4323
4352
|
}
|
|
@@ -4380,15 +4409,23 @@ function useNotifyWhenAvailable() {
|
|
|
4380
4409
|
}
|
|
4381
4410
|
|
|
4382
4411
|
// src/react/utils/format-price.ts
|
|
4383
|
-
function formatPrice(amount, currency, locale) {
|
|
4412
|
+
function formatPrice(amount, currency, locale, display) {
|
|
4384
4413
|
const resolvedLocale = locale ?? "cs";
|
|
4385
4414
|
try {
|
|
4386
|
-
|
|
4415
|
+
const formatter = new Intl.NumberFormat(resolvedLocale, {
|
|
4387
4416
|
style: "currency",
|
|
4388
4417
|
currency,
|
|
4418
|
+
currencyDisplay: display === "CODE" ? "code" : "symbol",
|
|
4389
4419
|
minimumFractionDigits: Number.isInteger(amount) ? 0 : 2,
|
|
4390
4420
|
maximumFractionDigits: 2
|
|
4391
|
-
})
|
|
4421
|
+
});
|
|
4422
|
+
if (display === "SYMBOL_BEFORE" || display === "SYMBOL_AFTER") {
|
|
4423
|
+
const parts = formatter.formatToParts(amount);
|
|
4424
|
+
const symbol = parts.find((p) => p.type === "currency")?.value ?? currency;
|
|
4425
|
+
const value = parts.filter((p) => p.type !== "currency").map((p) => p.value).join("").trim();
|
|
4426
|
+
return display === "SYMBOL_BEFORE" ? `${symbol}\xA0${value}` : `${value}\xA0${symbol}`;
|
|
4427
|
+
}
|
|
4428
|
+
return formatter.format(amount);
|
|
4392
4429
|
} catch {
|
|
4393
4430
|
return `${amount} ${currency}`;
|
|
4394
4431
|
}
|
|
@@ -4521,6 +4558,7 @@ export {
|
|
|
4521
4558
|
useCategory,
|
|
4522
4559
|
useCertificateVerification,
|
|
4523
4560
|
useCheckout,
|
|
4561
|
+
useCheckoutPreview,
|
|
4524
4562
|
useCookieConsent,
|
|
4525
4563
|
useCourse,
|
|
4526
4564
|
useCourseCertificates,
|