@behio/storefront-sdk 1.19.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-DhW5x2Zr.d.mts → client-C4dnHtID.d.mts} +197 -26
- package/dist/{client-DhW5x2Zr.d.ts → client-C4dnHtID.d.ts} +197 -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 +218 -32
- package/dist/react.d.ts +218 -32
- package/dist/react.js +154 -115
- package/dist/react.mjs +154 -116
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -53,6 +53,7 @@ __export(react_exports, {
|
|
|
53
53
|
useCategory: () => useCategory,
|
|
54
54
|
useCertificateVerification: () => useCertificateVerification,
|
|
55
55
|
useCheckout: () => useCheckout,
|
|
56
|
+
useCheckoutPreview: () => useCheckoutPreview,
|
|
56
57
|
useCookieConsent: () => useCookieConsent,
|
|
57
58
|
useCourse: () => useCourse,
|
|
58
59
|
useCourseCertificates: () => useCourseCertificates,
|
|
@@ -259,6 +260,7 @@ var BehioStorefront = class {
|
|
|
259
260
|
this.shopDomain = config.shopDomain;
|
|
260
261
|
this.defaultLocale = config.locale;
|
|
261
262
|
this.defaultCurrency = config.currency;
|
|
263
|
+
this.setCountry(config.country);
|
|
262
264
|
this.fetchFn = config.fetch || globalThis.fetch.bind(globalThis);
|
|
263
265
|
this.timeout = config.timeout ?? 3e4;
|
|
264
266
|
this.retries = config.retries ?? 1;
|
|
@@ -420,6 +422,14 @@ var BehioStorefront = class {
|
|
|
420
422
|
getCurrency() {
|
|
421
423
|
return this.defaultCurrency;
|
|
422
424
|
}
|
|
425
|
+
/** Set the catalog's delivery country. Use cart.setDestination separately for the cart. */
|
|
426
|
+
setCountry(country) {
|
|
427
|
+
const normalized = country?.trim().toUpperCase();
|
|
428
|
+
this.defaultCountry = normalized && /^[A-Z]{2}$/.test(normalized) ? normalized : void 0;
|
|
429
|
+
}
|
|
430
|
+
getCountry() {
|
|
431
|
+
return this.defaultCountry;
|
|
432
|
+
}
|
|
423
433
|
/** Set the default locale sent on every catalog request (per-call wins). */
|
|
424
434
|
setLocale(locale) {
|
|
425
435
|
this.defaultLocale = locale || void 0;
|
|
@@ -575,12 +585,16 @@ var BehioStorefront = class {
|
|
|
575
585
|
if (this.defaultCurrency && !params.has("currency")) {
|
|
576
586
|
params.set("currency", this.defaultCurrency);
|
|
577
587
|
}
|
|
588
|
+
if (this.defaultCountry && path.startsWith("/catalog/") && !params.has("country")) {
|
|
589
|
+
params.set("country", this.defaultCountry);
|
|
590
|
+
}
|
|
578
591
|
const qs = params.toString();
|
|
579
592
|
const url = `${this.baseUrl}/storefront/v1${path}${qs ? `?${qs}` : ""}`;
|
|
580
593
|
const headers = {
|
|
581
594
|
"X-Api-Key": this.apiKey,
|
|
582
595
|
"Content-Type": "application/json"
|
|
583
596
|
};
|
|
597
|
+
if (path === "/cart" || path.startsWith("/cart/")) headers["X-Behio-Cart-Contract"] = "2";
|
|
584
598
|
if (this.shopDomain) {
|
|
585
599
|
headers["X-Shop-Domain"] = this.shopDomain;
|
|
586
600
|
}
|
|
@@ -707,42 +721,46 @@ var BehioStorefront = class {
|
|
|
707
721
|
throw new BehioNetworkError("Request failed after retries");
|
|
708
722
|
}
|
|
709
723
|
};
|
|
724
|
+
function catalogProductsQuery(query) {
|
|
725
|
+
const q = {};
|
|
726
|
+
if (query) {
|
|
727
|
+
if (query.page !== void 0) q.page = query.page;
|
|
728
|
+
if (query.limit !== void 0) q.limit = query.limit;
|
|
729
|
+
if (query.category) q.category = query.category;
|
|
730
|
+
if (query.label) q.label = query.label;
|
|
731
|
+
if (query.priceMin !== void 0) q.priceMin = query.priceMin;
|
|
732
|
+
if (query.priceMax !== void 0) q.priceMax = query.priceMax;
|
|
733
|
+
if (query.currency) q.currency = query.currency;
|
|
734
|
+
if (query.country) q.country = query.country;
|
|
735
|
+
if (query.locale) q.locale = query.locale;
|
|
736
|
+
if (query.sort) q.sort = query.sort;
|
|
737
|
+
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
738
|
+
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
739
|
+
if (query.search) q.search = query.search;
|
|
740
|
+
if (query.parameters) q.parameters = JSON.stringify(query.parameters);
|
|
741
|
+
if (query.facets) q.facets = JSON.stringify(query.facets);
|
|
742
|
+
if (query.ids && query.ids.length > 0) q.ids = query.ids;
|
|
743
|
+
if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
|
|
744
|
+
if (query.labels && query.labels.length > 0) q.labels = query.labels;
|
|
745
|
+
if (query.categories && query.categories.length > 0)
|
|
746
|
+
q.categories = query.categories;
|
|
747
|
+
if (query.excludeIds && query.excludeIds.length > 0)
|
|
748
|
+
q.excludeIds = query.excludeIds;
|
|
749
|
+
if (query.excludeCategories && query.excludeCategories.length > 0)
|
|
750
|
+
q.excludeCategories = query.excludeCategories;
|
|
751
|
+
if (query.hasDiscount !== void 0) q.hasDiscount = query.hasDiscount;
|
|
752
|
+
if (query.isFeatured !== void 0) q.isFeatured = query.isFeatured;
|
|
753
|
+
if (query.createdAfter !== void 0) q.createdAfter = query.createdAfter;
|
|
754
|
+
}
|
|
755
|
+
return q;
|
|
756
|
+
}
|
|
710
757
|
var CatalogModule = class {
|
|
711
758
|
constructor(client) {
|
|
712
759
|
this.client = client;
|
|
713
760
|
}
|
|
714
761
|
/** List products with filtering, pagination, search */
|
|
715
762
|
async getProducts(query) {
|
|
716
|
-
const q =
|
|
717
|
-
if (query) {
|
|
718
|
-
if (query.page) q.page = query.page;
|
|
719
|
-
if (query.limit) q.limit = query.limit;
|
|
720
|
-
if (query.category) q.category = query.category;
|
|
721
|
-
if (query.label) q.label = query.label;
|
|
722
|
-
if (query.priceMin) q.priceMin = query.priceMin;
|
|
723
|
-
if (query.priceMax) q.priceMax = query.priceMax;
|
|
724
|
-
if (query.currency) q.currency = query.currency;
|
|
725
|
-
if (query.country) q.country = query.country;
|
|
726
|
-
if (query.locale) q.locale = query.locale;
|
|
727
|
-
if (query.sort) q.sort = query.sort;
|
|
728
|
-
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
729
|
-
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
730
|
-
if (query.search) q.search = query.search;
|
|
731
|
-
if (query.parameters) q.parameters = JSON.stringify(query.parameters);
|
|
732
|
-
if (query.facets) q.facets = JSON.stringify(query.facets);
|
|
733
|
-
if (query.ids && query.ids.length > 0) q.ids = query.ids;
|
|
734
|
-
if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
|
|
735
|
-
if (query.labels && query.labels.length > 0) q.labels = query.labels;
|
|
736
|
-
if (query.categories && query.categories.length > 0)
|
|
737
|
-
q.categories = query.categories;
|
|
738
|
-
if (query.excludeIds && query.excludeIds.length > 0)
|
|
739
|
-
q.excludeIds = query.excludeIds;
|
|
740
|
-
if (query.excludeCategories && query.excludeCategories.length > 0)
|
|
741
|
-
q.excludeCategories = query.excludeCategories;
|
|
742
|
-
if (query.hasDiscount !== void 0) q.hasDiscount = query.hasDiscount;
|
|
743
|
-
if (query.isFeatured !== void 0) q.isFeatured = query.isFeatured;
|
|
744
|
-
if (query.createdAfter !== void 0) q.createdAfter = query.createdAfter;
|
|
745
|
-
}
|
|
763
|
+
const q = catalogProductsQuery(query);
|
|
746
764
|
return this.client.request(
|
|
747
765
|
"GET",
|
|
748
766
|
"/catalog/products",
|
|
@@ -784,14 +802,7 @@ var CatalogModule = class {
|
|
|
784
802
|
}
|
|
785
803
|
/** Get products in a category */
|
|
786
804
|
async getCategoryProducts(slug, query) {
|
|
787
|
-
const q =
|
|
788
|
-
if (query) {
|
|
789
|
-
if (query.page) q.page = query.page;
|
|
790
|
-
if (query.limit) q.limit = query.limit;
|
|
791
|
-
if (query.sort) q.sort = query.sort;
|
|
792
|
-
if (query.locale) q.locale = query.locale;
|
|
793
|
-
if (query.currency) q.currency = query.currency;
|
|
794
|
-
}
|
|
805
|
+
const q = catalogProductsQuery(query);
|
|
795
806
|
return this.client.request(
|
|
796
807
|
"GET",
|
|
797
808
|
`/catalog/categories/${slug}/products`,
|
|
@@ -825,7 +836,7 @@ var CatalogModule = class {
|
|
|
825
836
|
"GET",
|
|
826
837
|
"/catalog/featured",
|
|
827
838
|
{
|
|
828
|
-
query: { locale: options?.locale, currency: options?.currency }
|
|
839
|
+
query: { locale: options?.locale, currency: options?.currency, country: options?.country }
|
|
829
840
|
}
|
|
830
841
|
);
|
|
831
842
|
}
|
|
@@ -883,9 +894,10 @@ var CatalogModule = class {
|
|
|
883
894
|
if (query) {
|
|
884
895
|
if (query.category) q.category = query.category;
|
|
885
896
|
if (query.label) q.label = query.label;
|
|
886
|
-
if (query.priceMin) q.priceMin = query.priceMin;
|
|
887
|
-
if (query.priceMax) q.priceMax = query.priceMax;
|
|
897
|
+
if (query.priceMin !== void 0) q.priceMin = query.priceMin;
|
|
898
|
+
if (query.priceMax !== void 0) q.priceMax = query.priceMax;
|
|
888
899
|
if (query.currency) q.currency = query.currency;
|
|
900
|
+
if (query.country) q.country = query.country;
|
|
889
901
|
if (query.locale) q.locale = query.locale;
|
|
890
902
|
if (query.inStock !== void 0) q.inStock = query.inStock;
|
|
891
903
|
if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
|
|
@@ -907,12 +919,12 @@ var CatalogModule = class {
|
|
|
907
919
|
return this.getProducts({ search: query, ...options });
|
|
908
920
|
}
|
|
909
921
|
/** List all active bundles */
|
|
910
|
-
async getBundles() {
|
|
911
|
-
return this.client.request("GET", "/catalog/bundles");
|
|
922
|
+
async getBundles(options) {
|
|
923
|
+
return this.client.request("GET", "/catalog/bundles", { query: { ...options } });
|
|
912
924
|
}
|
|
913
925
|
/** Get a single bundle by slug */
|
|
914
|
-
async getBundle(slug) {
|
|
915
|
-
return this.client.request("GET", `/catalog/bundles/${slug}
|
|
926
|
+
async getBundle(slug, options) {
|
|
927
|
+
return this.client.request("GET", `/catalog/bundles/${encodeURIComponent(slug)}`, { query: { ...options } });
|
|
916
928
|
}
|
|
917
929
|
/**
|
|
918
930
|
* One product group ("collection") by slug with its products as standard
|
|
@@ -925,7 +937,7 @@ var CatalogModule = class {
|
|
|
925
937
|
"GET",
|
|
926
938
|
`/catalog/product-groups/${encodeURIComponent(slug)}`,
|
|
927
939
|
{
|
|
928
|
-
query: { locale: options?.locale, currency: options?.currency }
|
|
940
|
+
query: { locale: options?.locale, currency: options?.currency, country: options?.country }
|
|
929
941
|
}
|
|
930
942
|
);
|
|
931
943
|
}
|
|
@@ -940,7 +952,7 @@ var CatalogModule = class {
|
|
|
940
952
|
return this.client.request(
|
|
941
953
|
"GET",
|
|
942
954
|
`/catalog/products/${encodeURIComponent(productSlug)}/cross-sell`,
|
|
943
|
-
{ query: { locale: options?.locale, currency: options?.currency } }
|
|
955
|
+
{ query: { locale: options?.locale, currency: options?.currency, country: options?.country } }
|
|
944
956
|
);
|
|
945
957
|
}
|
|
946
958
|
/** Active promotions applicable to a product (with countdown end time) */
|
|
@@ -1148,6 +1160,7 @@ var CartModule = class {
|
|
|
1148
1160
|
body: { currency }
|
|
1149
1161
|
});
|
|
1150
1162
|
if (res.error) return res;
|
|
1163
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1151
1164
|
this.client.emit("cart:updated", res.data);
|
|
1152
1165
|
return res;
|
|
1153
1166
|
}
|
|
@@ -1168,6 +1181,7 @@ var CartModule = class {
|
|
|
1168
1181
|
body: input
|
|
1169
1182
|
});
|
|
1170
1183
|
if (res.error) return res;
|
|
1184
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1171
1185
|
this.client.emit("cart:updated", res.data);
|
|
1172
1186
|
return res;
|
|
1173
1187
|
}
|
|
@@ -1252,14 +1266,15 @@ var CartModule = class {
|
|
|
1252
1266
|
body
|
|
1253
1267
|
});
|
|
1254
1268
|
if (res.error) return res;
|
|
1269
|
+
if (res.data.sessionToken) this.client.setCartSession(res.data.sessionToken);
|
|
1255
1270
|
this.client.emit("cart:updated", res.data);
|
|
1256
1271
|
return res;
|
|
1257
1272
|
}
|
|
1258
|
-
/** Update
|
|
1259
|
-
async updateBundleQuantity(
|
|
1273
|
+
/** Update by CartBundleLine.id; legacy catalog bundle IDs are accepted by the API */
|
|
1274
|
+
async updateBundleQuantity(lineId, quantity) {
|
|
1260
1275
|
const res = await this.client.request(
|
|
1261
1276
|
"PATCH",
|
|
1262
|
-
`/cart/bundles/${
|
|
1277
|
+
`/cart/bundles/${lineId}`,
|
|
1263
1278
|
{
|
|
1264
1279
|
body: { quantity }
|
|
1265
1280
|
}
|
|
@@ -1268,11 +1283,11 @@ var CartModule = class {
|
|
|
1268
1283
|
this.client.emit("cart:updated", res.data);
|
|
1269
1284
|
return res;
|
|
1270
1285
|
}
|
|
1271
|
-
/** Remove
|
|
1272
|
-
async removeBundle(
|
|
1286
|
+
/** Remove by CartBundleLine.id; scoped to the current visitor cart */
|
|
1287
|
+
async removeBundle(lineId) {
|
|
1273
1288
|
const res = await this.client.request(
|
|
1274
1289
|
"DELETE",
|
|
1275
|
-
`/cart/bundles/${
|
|
1290
|
+
`/cart/bundles/${lineId}`
|
|
1276
1291
|
);
|
|
1277
1292
|
if (res.error) return res;
|
|
1278
1293
|
this.client.emit("cart:updated", res.data);
|
|
@@ -1306,6 +1321,12 @@ var CheckoutModule = class {
|
|
|
1306
1321
|
constructor(client) {
|
|
1307
1322
|
this.client = client;
|
|
1308
1323
|
}
|
|
1324
|
+
/** Recalculate the current cart including shipping, fees, benefits and rounding.
|
|
1325
|
+
* No order, stock claim, payment or gift-card redemption is created. Required
|
|
1326
|
+
* legal consents are enforced only on createOrder, not while quoting. */
|
|
1327
|
+
async preview(input) {
|
|
1328
|
+
return this.client.request("POST", "/checkout/preview", { body: input });
|
|
1329
|
+
}
|
|
1309
1330
|
/** Create order from cart */
|
|
1310
1331
|
async createOrder(input) {
|
|
1311
1332
|
const res = await this.client.request("POST", "/checkout", {
|
|
@@ -2200,6 +2221,7 @@ function BehioProvider({
|
|
|
2200
2221
|
});
|
|
2201
2222
|
}
|
|
2202
2223
|
const client = clientRef.current;
|
|
2224
|
+
const [sessionRestored, setSessionRestored] = (0, import_react2.useState)(false);
|
|
2203
2225
|
(0, import_react2.useEffect)(() => {
|
|
2204
2226
|
const accessToken = storageAdapter.get(STORAGE_KEYS.ACCESS_TOKEN);
|
|
2205
2227
|
const refreshToken = storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
|
|
@@ -2210,6 +2232,7 @@ function BehioProvider({
|
|
|
2210
2232
|
if (cartSession) {
|
|
2211
2233
|
client.setCartSession(cartSession);
|
|
2212
2234
|
}
|
|
2235
|
+
setSessionRestored(true);
|
|
2213
2236
|
}, [client, storageAdapter]);
|
|
2214
2237
|
(0, import_react2.useEffect)(() => {
|
|
2215
2238
|
if (!persistCurrency) return;
|
|
@@ -2264,12 +2287,13 @@ function BehioProvider({
|
|
|
2264
2287
|
() => ({
|
|
2265
2288
|
client,
|
|
2266
2289
|
storage: storageAdapter,
|
|
2290
|
+
sessionRestored,
|
|
2267
2291
|
currency: activeCurrency,
|
|
2268
2292
|
setCurrency,
|
|
2269
2293
|
configuredDefaultCurrency: defaultCurrency,
|
|
2270
2294
|
configuredCurrencies: currencies
|
|
2271
2295
|
}),
|
|
2272
|
-
[client, storageAdapter, activeCurrency, setCurrency, defaultCurrency, currencies]
|
|
2296
|
+
[client, storageAdapter, sessionRestored, activeCurrency, setCurrency, defaultCurrency, currencies]
|
|
2273
2297
|
);
|
|
2274
2298
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: qc, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BehioContext.Provider, { value: ctxValue, children }) });
|
|
2275
2299
|
}
|
|
@@ -2519,6 +2543,15 @@ function useSearch(query, options) {
|
|
|
2519
2543
|
// src/react/hooks/use-cart.ts
|
|
2520
2544
|
var import_react5 = require("react");
|
|
2521
2545
|
var import_react_query12 = require("@tanstack/react-query");
|
|
2546
|
+
|
|
2547
|
+
// src/react/utils/refresh-bundle-queries.ts
|
|
2548
|
+
async function refreshBundleQueries(queryClient) {
|
|
2549
|
+
const keys = [["behio", "bundle"], ["behio", "bundles"]];
|
|
2550
|
+
await Promise.all(keys.map((queryKey) => queryClient.cancelQueries({ queryKey })));
|
|
2551
|
+
await Promise.all(keys.map((queryKey) => queryClient.invalidateQueries({ queryKey })));
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
// src/react/hooks/use-cart.ts
|
|
2522
2555
|
var CART_KEY = ["behio", "cart"];
|
|
2523
2556
|
function useCart(options) {
|
|
2524
2557
|
const { client, storage } = useBehio();
|
|
@@ -2542,32 +2575,21 @@ function useCart(options) {
|
|
|
2542
2575
|
storage.set(STORAGE_KEYS.CART_SESSION, result.newSessionToken);
|
|
2543
2576
|
}
|
|
2544
2577
|
queryClient.setQueryData([...CART_KEY], result);
|
|
2578
|
+
void refreshBundleQueries(queryClient);
|
|
2545
2579
|
}
|
|
2546
2580
|
});
|
|
2581
|
+
const cancelCartRead = () => queryClient.cancelQueries({ queryKey: [...CART_KEY] });
|
|
2582
|
+
const acceptCart = async (result) => {
|
|
2583
|
+
await cancelCartRead();
|
|
2584
|
+
queryClient.setQueryData([...CART_KEY], result);
|
|
2585
|
+
void refreshBundleQueries(queryClient);
|
|
2586
|
+
};
|
|
2547
2587
|
const updateMutation = (0, import_react_query12.useMutation)({
|
|
2548
2588
|
mutationFn: async ({ itemId, quantity }) => {
|
|
2549
2589
|
return unwrap(client.cart.updateQuantity(itemId, quantity));
|
|
2550
2590
|
},
|
|
2551
|
-
onMutate:
|
|
2552
|
-
|
|
2553
|
-
const previous = queryClient.getQueryData([...CART_KEY]);
|
|
2554
|
-
if (previous) {
|
|
2555
|
-
const updatedItems = previous.items.map(
|
|
2556
|
-
(item) => item.id === itemId ? { ...item, quantity, totalPrice: item.unitPrice * quantity } : item
|
|
2557
|
-
);
|
|
2558
|
-
queryClient.setQueryData([...CART_KEY], {
|
|
2559
|
-
...previous,
|
|
2560
|
-
items: updatedItems,
|
|
2561
|
-
itemCount: updatedItems.reduce((sum, i) => sum + i.quantity, 0)
|
|
2562
|
-
});
|
|
2563
|
-
}
|
|
2564
|
-
return { previous };
|
|
2565
|
-
},
|
|
2566
|
-
onError: (_err, _vars, context) => {
|
|
2567
|
-
if (context?.previous) {
|
|
2568
|
-
queryClient.setQueryData([...CART_KEY], context.previous);
|
|
2569
|
-
}
|
|
2570
|
-
},
|
|
2591
|
+
onMutate: cancelCartRead,
|
|
2592
|
+
onSuccess: acceptCart,
|
|
2571
2593
|
onSettled: () => {
|
|
2572
2594
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY] });
|
|
2573
2595
|
}
|
|
@@ -2576,24 +2598,8 @@ function useCart(options) {
|
|
|
2576
2598
|
mutationFn: async (itemId) => {
|
|
2577
2599
|
return unwrap(client.cart.removeItem(itemId));
|
|
2578
2600
|
},
|
|
2579
|
-
onMutate:
|
|
2580
|
-
|
|
2581
|
-
const previous = queryClient.getQueryData([...CART_KEY]);
|
|
2582
|
-
if (previous) {
|
|
2583
|
-
const updatedItems = previous.items.filter((item) => item.id !== itemId);
|
|
2584
|
-
queryClient.setQueryData([...CART_KEY], {
|
|
2585
|
-
...previous,
|
|
2586
|
-
items: updatedItems,
|
|
2587
|
-
itemCount: updatedItems.reduce((sum, i) => sum + i.quantity, 0)
|
|
2588
|
-
});
|
|
2589
|
-
}
|
|
2590
|
-
return { previous };
|
|
2591
|
-
},
|
|
2592
|
-
onError: (_err, _vars, context) => {
|
|
2593
|
-
if (context?.previous) {
|
|
2594
|
-
queryClient.setQueryData([...CART_KEY], context.previous);
|
|
2595
|
-
}
|
|
2596
|
-
},
|
|
2601
|
+
onMutate: cancelCartRead,
|
|
2602
|
+
onSuccess: acceptCart,
|
|
2597
2603
|
onSettled: () => {
|
|
2598
2604
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY] });
|
|
2599
2605
|
}
|
|
@@ -2604,6 +2610,7 @@ function useCart(options) {
|
|
|
2604
2610
|
queryClient.setQueryData([...CART_KEY], null);
|
|
2605
2611
|
client.clearCartSession();
|
|
2606
2612
|
storage.remove(STORAGE_KEYS.CART_SESSION);
|
|
2613
|
+
void refreshBundleQueries(queryClient);
|
|
2607
2614
|
}
|
|
2608
2615
|
});
|
|
2609
2616
|
const applyDiscountMutation = (0, import_react_query12.useMutation)({
|
|
@@ -2624,6 +2631,7 @@ function useCart(options) {
|
|
|
2624
2631
|
queryClient.setQueryData([...CART_KEY], result);
|
|
2625
2632
|
client.clearCartSession();
|
|
2626
2633
|
storage.remove(STORAGE_KEYS.CART_SESSION);
|
|
2634
|
+
void refreshBundleQueries(queryClient);
|
|
2627
2635
|
}
|
|
2628
2636
|
});
|
|
2629
2637
|
const addItem = (0, import_react5.useCallback)(
|
|
@@ -2668,7 +2676,7 @@ function useCart(options) {
|
|
|
2668
2676
|
merge,
|
|
2669
2677
|
// Computed
|
|
2670
2678
|
itemCount: cart?.itemCount ?? 0,
|
|
2671
|
-
isEmpty: !cart || cart.items.length === 0,
|
|
2679
|
+
isEmpty: !cart || cart.items.length === 0 && (cart.bundleLines?.length ?? 0) === 0,
|
|
2672
2680
|
// Mutation states
|
|
2673
2681
|
isAdding: addMutation.isPending,
|
|
2674
2682
|
isUpdating: updateMutation.isPending,
|
|
@@ -2724,6 +2732,7 @@ function useAuth() {
|
|
|
2724
2732
|
queryClient.setQueryData([...CUSTOMER_KEY], null);
|
|
2725
2733
|
queryClient.invalidateQueries({ queryKey: ["behio", "orders"] });
|
|
2726
2734
|
queryClient.invalidateQueries({ queryKey: ["behio", "addresses"] });
|
|
2735
|
+
void refreshBundleQueries(queryClient);
|
|
2727
2736
|
}, [client, storage, queryClient]);
|
|
2728
2737
|
const postAuth = (0, import_react6.useCallback)(async () => {
|
|
2729
2738
|
await queryClient.invalidateQueries({ queryKey: [...CUSTOMER_KEY] });
|
|
@@ -2736,6 +2745,7 @@ function useAuth() {
|
|
|
2736
2745
|
}
|
|
2737
2746
|
}
|
|
2738
2747
|
queryClient.invalidateQueries({ queryKey: [...CART_KEY3] });
|
|
2748
|
+
void refreshBundleQueries(queryClient);
|
|
2739
2749
|
}, [client, storage, queryClient]);
|
|
2740
2750
|
const loginMutation = (0, import_react_query14.useMutation)({
|
|
2741
2751
|
mutationFn: async ({ email, password }) => {
|
|
@@ -3699,6 +3709,11 @@ function useCheckout() {
|
|
|
3699
3709
|
reset
|
|
3700
3710
|
};
|
|
3701
3711
|
}
|
|
3712
|
+
function useCheckoutPreview() {
|
|
3713
|
+
const { client } = useBehio();
|
|
3714
|
+
const mutation = (0, import_react_query34.useMutation)({ mutationFn: (input) => unwrap(client.checkout.preview(input)) });
|
|
3715
|
+
return { preview: mutation.mutateAsync, data: mutation.data, isPreviewing: mutation.isPending, error: mutation.error, reset: mutation.reset };
|
|
3716
|
+
}
|
|
3702
3717
|
|
|
3703
3718
|
// src/react/hooks/use-pages.ts
|
|
3704
3719
|
var import_react_query35 = require("@tanstack/react-query");
|
|
@@ -3863,7 +3878,8 @@ function useShopScripts(options) {
|
|
|
3863
3878
|
return (0, import_react_query39.useQuery)({
|
|
3864
3879
|
queryKey: ["behio", "shop-scripts"],
|
|
3865
3880
|
queryFn: () => unwrap(client.getShopScripts()),
|
|
3866
|
-
enabled: options?.enabled !== false
|
|
3881
|
+
enabled: options?.enabled !== false,
|
|
3882
|
+
initialData: options?.initialData
|
|
3867
3883
|
});
|
|
3868
3884
|
}
|
|
3869
3885
|
|
|
@@ -3997,31 +4013,32 @@ function partsFor(s) {
|
|
|
3997
4013
|
return [{ target: "head", html: `<meta name="google-site-verification" content="${id}" />` }];
|
|
3998
4014
|
case "RAW":
|
|
3999
4015
|
default:
|
|
4000
|
-
return [{ target: s.placement === "HEAD" ? "head" : "body", html: s.value }];
|
|
4016
|
+
return [{ target: s.placement === "HEAD" ? "head" : "body", start: s.placement === "BODY_START", html: s.value }];
|
|
4001
4017
|
}
|
|
4002
4018
|
}
|
|
4003
|
-
function injectHtml(target, html) {
|
|
4019
|
+
function injectHtml(target, html, start = false) {
|
|
4004
4020
|
const tpl = document.createElement("template");
|
|
4005
4021
|
tpl.innerHTML = html;
|
|
4006
4022
|
const added = [];
|
|
4023
|
+
const anchor = start ? target.firstChild : null;
|
|
4007
4024
|
Array.from(tpl.content.childNodes).forEach((node) => {
|
|
4008
4025
|
if (node.nodeName === "SCRIPT") {
|
|
4009
4026
|
const old = node;
|
|
4010
4027
|
const script = document.createElement("script");
|
|
4011
4028
|
for (const attr of Array.from(old.attributes)) script.setAttribute(attr.name, attr.value);
|
|
4012
4029
|
script.text = old.text;
|
|
4013
|
-
target.
|
|
4030
|
+
target.insertBefore(script, anchor);
|
|
4014
4031
|
added.push(script);
|
|
4015
4032
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
4016
4033
|
const clone = node.cloneNode(true);
|
|
4017
|
-
target.
|
|
4034
|
+
target.insertBefore(clone, anchor);
|
|
4018
4035
|
added.push(clone);
|
|
4019
4036
|
}
|
|
4020
4037
|
});
|
|
4021
4038
|
return added;
|
|
4022
4039
|
}
|
|
4023
|
-
function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
|
|
4024
|
-
const { data } = useShopScripts();
|
|
4040
|
+
function StorefrontScripts({ visitorId: visitorIdProp, initialScripts } = {}) {
|
|
4041
|
+
const { data } = useShopScripts({ enabled: initialScripts === void 0, initialData: initialScripts ? { scripts: initialScripts } : void 0 });
|
|
4025
4042
|
const [visitorId, setVisitorId] = (0, import_react18.useState)(visitorIdProp ?? "");
|
|
4026
4043
|
(0, import_react18.useEffect)(() => {
|
|
4027
4044
|
if (visitorIdProp) return;
|
|
@@ -4033,21 +4050,30 @@ function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
|
|
|
4033
4050
|
}, [visitorIdProp]);
|
|
4034
4051
|
const { data: consent } = useCookieConsent(visitorId || void 0);
|
|
4035
4052
|
const analyticsOk = Boolean(consent?.analytics);
|
|
4053
|
+
const marketingOk = Boolean(consent?.marketing);
|
|
4036
4054
|
const scripts = (0, import_react18.useMemo)(
|
|
4037
|
-
() => (data?.scripts ?? []).filter((s) => !s.consentRequired || analyticsOk),
|
|
4038
|
-
[data, analyticsOk]
|
|
4055
|
+
() => (initialScripts ?? data?.scripts ?? []).filter((s) => !s.consentRequired || (s.type === "META_PIXEL" ? marketingOk : analyticsOk)),
|
|
4056
|
+
[initialScripts, data, analyticsOk, marketingOk]
|
|
4039
4057
|
);
|
|
4040
4058
|
const signature = (0, import_react18.useMemo)(
|
|
4041
4059
|
() => JSON.stringify(scripts.map((s) => [s.id, s.type, s.placement, s.value])),
|
|
4042
4060
|
[scripts]
|
|
4043
4061
|
);
|
|
4062
|
+
const activeConsented = (0, import_react18.useRef)(/* @__PURE__ */ new Set());
|
|
4044
4063
|
(0, import_react18.useEffect)(() => {
|
|
4045
4064
|
if (typeof document === "undefined") return;
|
|
4065
|
+
const nextConsented = new Set(scripts.filter((s) => s.consentRequired).map((s) => s.id));
|
|
4066
|
+
const revoked = [...activeConsented.current].some((id) => !nextConsented.has(id));
|
|
4067
|
+
activeConsented.current = nextConsented;
|
|
4068
|
+
if (revoked) {
|
|
4069
|
+
window.location.reload();
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4046
4072
|
const added = [];
|
|
4047
4073
|
for (const s of scripts) {
|
|
4048
4074
|
for (const part of partsFor(s)) {
|
|
4049
4075
|
const target = part.target === "head" ? document.head : document.body;
|
|
4050
|
-
added.push(...injectHtml(target, part.html));
|
|
4076
|
+
added.push(...injectHtml(target, part.html, part.start));
|
|
4051
4077
|
}
|
|
4052
4078
|
}
|
|
4053
4079
|
return () => {
|
|
@@ -4309,20 +4335,22 @@ function utmFromSearch(search) {
|
|
|
4309
4335
|
// src/react/hooks/use-bundles.ts
|
|
4310
4336
|
var import_react_query42 = require("@tanstack/react-query");
|
|
4311
4337
|
function useBundles(options) {
|
|
4312
|
-
const { client } = useBehio();
|
|
4338
|
+
const { client, sessionRestored } = useBehio();
|
|
4339
|
+
const query = { locale: options?.locale ?? client.getLocale(), currency: options?.currency ?? client.getCurrency(), country: options?.country ?? client.getCountry() };
|
|
4313
4340
|
return (0, import_react_query42.useQuery)({
|
|
4314
|
-
queryKey: ["behio", "bundles"],
|
|
4315
|
-
queryFn: () => unwrap(client.catalog.getBundles()),
|
|
4316
|
-
enabled: options?.enabled ?? true,
|
|
4341
|
+
queryKey: ["behio", "bundles", query],
|
|
4342
|
+
queryFn: () => unwrap(client.catalog.getBundles(query)),
|
|
4343
|
+
enabled: sessionRestored && (options?.enabled ?? true),
|
|
4317
4344
|
initialData: options?.initialData
|
|
4318
4345
|
});
|
|
4319
4346
|
}
|
|
4320
4347
|
function useBundle(slug, options) {
|
|
4321
|
-
const { client } = useBehio();
|
|
4348
|
+
const { client, sessionRestored } = useBehio();
|
|
4349
|
+
const query = { locale: options?.locale ?? client.getLocale(), currency: options?.currency ?? client.getCurrency(), country: options?.country ?? client.getCountry() };
|
|
4322
4350
|
return (0, import_react_query42.useQuery)({
|
|
4323
|
-
queryKey: ["behio", "bundle", slug],
|
|
4324
|
-
queryFn: () => unwrap(client.catalog.getBundle(slug)),
|
|
4325
|
-
enabled: Boolean(slug) && (options?.enabled ?? true),
|
|
4351
|
+
queryKey: ["behio", "bundle", slug, query],
|
|
4352
|
+
queryFn: () => unwrap(client.catalog.getBundle(slug, query)),
|
|
4353
|
+
enabled: sessionRestored && Boolean(slug) && (options?.enabled ?? true),
|
|
4326
4354
|
initialData: options?.initialData
|
|
4327
4355
|
});
|
|
4328
4356
|
}
|
|
@@ -4425,8 +4453,10 @@ var import_react_query48 = require("@tanstack/react-query");
|
|
|
4425
4453
|
function useProductReviews(productId, options) {
|
|
4426
4454
|
const { client } = useBehio();
|
|
4427
4455
|
return (0, import_react_query48.useQuery)({
|
|
4428
|
-
queryKey: ["behio", "reviews", productId, options?.page ?? 1],
|
|
4456
|
+
queryKey: ["behio", "reviews", productId, options?.page ?? 1, options?.limit ?? 20],
|
|
4429
4457
|
queryFn: () => unwrap(client.reviews.getProductReviews(productId, options?.page, options?.limit)),
|
|
4458
|
+
initialData: options?.initialData,
|
|
4459
|
+
staleTime: 3e4,
|
|
4430
4460
|
enabled: Boolean(productId) && (options?.enabled ?? true)
|
|
4431
4461
|
});
|
|
4432
4462
|
}
|
|
@@ -4489,15 +4519,23 @@ function useNotifyWhenAvailable() {
|
|
|
4489
4519
|
}
|
|
4490
4520
|
|
|
4491
4521
|
// src/react/utils/format-price.ts
|
|
4492
|
-
function formatPrice(amount, currency, locale) {
|
|
4522
|
+
function formatPrice(amount, currency, locale, display) {
|
|
4493
4523
|
const resolvedLocale = locale ?? "cs";
|
|
4494
4524
|
try {
|
|
4495
|
-
|
|
4525
|
+
const formatter = new Intl.NumberFormat(resolvedLocale, {
|
|
4496
4526
|
style: "currency",
|
|
4497
4527
|
currency,
|
|
4528
|
+
currencyDisplay: display === "CODE" ? "code" : "symbol",
|
|
4498
4529
|
minimumFractionDigits: Number.isInteger(amount) ? 0 : 2,
|
|
4499
4530
|
maximumFractionDigits: 2
|
|
4500
|
-
})
|
|
4531
|
+
});
|
|
4532
|
+
if (display === "SYMBOL_BEFORE" || display === "SYMBOL_AFTER") {
|
|
4533
|
+
const parts = formatter.formatToParts(amount);
|
|
4534
|
+
const symbol = parts.find((p) => p.type === "currency")?.value ?? currency;
|
|
4535
|
+
const value = parts.filter((p) => p.type !== "currency").map((p) => p.value).join("").trim();
|
|
4536
|
+
return display === "SYMBOL_BEFORE" ? `${symbol}\xA0${value}` : `${value}\xA0${symbol}`;
|
|
4537
|
+
}
|
|
4538
|
+
return formatter.format(amount);
|
|
4501
4539
|
} catch {
|
|
4502
4540
|
return `${amount} ${currency}`;
|
|
4503
4541
|
}
|
|
@@ -4631,6 +4669,7 @@ async function revokeAnalyticsConsent(client) {
|
|
|
4631
4669
|
useCategory,
|
|
4632
4670
|
useCertificateVerification,
|
|
4633
4671
|
useCheckout,
|
|
4672
|
+
useCheckoutPreview,
|
|
4634
4673
|
useCookieConsent,
|
|
4635
4674
|
useCourse,
|
|
4636
4675
|
useCourseCertificates,
|