@kasuvia/sdk 0.0.2 → 0.0.5

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.
Files changed (77) hide show
  1. package/dist/hooks/index.d.mts +430 -0
  2. package/dist/hooks/index.d.ts +430 -0
  3. package/dist/hooks/index.js +3073 -0
  4. package/dist/hooks/index.js.map +1 -0
  5. package/dist/hooks/index.mjs +2962 -0
  6. package/dist/hooks/index.mjs.map +1 -0
  7. package/dist/index-CxNLI4nw.d.ts +786 -0
  8. package/dist/index-CzVMyUs4.d.mts +492 -0
  9. package/dist/index-CzVMyUs4.d.ts +492 -0
  10. package/dist/index-Dowl5224.d.mts +786 -0
  11. package/dist/index.d.mts +48 -1739
  12. package/dist/index.d.ts +48 -1739
  13. package/dist/index.js +1544 -2359
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +1527 -2258
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/sdk-context-BuarJbeb.d.ts +75 -0
  18. package/dist/sdk-context-Db8kf1Tv.d.mts +75 -0
  19. package/dist/services/index.d.mts +2 -0
  20. package/dist/services/index.d.ts +2 -0
  21. package/dist/services/index.js +2369 -0
  22. package/dist/services/index.js.map +1 -0
  23. package/dist/services/index.mjs +2252 -0
  24. package/dist/services/index.mjs.map +1 -0
  25. package/package.json +11 -2
  26. package/src/config/index.ts +10 -91
  27. package/src/constants.ts +13 -0
  28. package/src/context/sdk-context.tsx +70 -0
  29. package/src/graphql/collections.graphql.ts +2 -10
  30. package/src/graphql/products.graphql.ts +215 -65
  31. package/src/graphql/wishlist.graphql.ts +7 -6
  32. package/src/hooks/index.ts +2 -0
  33. package/src/hooks/use-auth.ts +82 -158
  34. package/src/hooks/use-bespoke-availability.ts +25 -8
  35. package/src/hooks/use-cart.ts +222 -119
  36. package/src/hooks/use-cms.ts +179 -86
  37. package/src/hooks/use-collections.ts +52 -15
  38. package/src/hooks/use-consultation-stream.ts +4 -3
  39. package/src/hooks/use-consultations.ts +120 -51
  40. package/src/hooks/use-countries.ts +35 -13
  41. package/src/hooks/use-currencies.ts +26 -13
  42. package/src/hooks/use-google-translate.ts +22 -8
  43. package/src/hooks/use-languages.ts +40 -20
  44. package/src/hooks/use-mobile.ts +23 -0
  45. package/src/hooks/use-order-stream.ts +9 -5
  46. package/src/hooks/use-orders.ts +99 -44
  47. package/src/hooks/use-payment.ts +108 -40
  48. package/src/hooks/use-products.ts +251 -53
  49. package/src/hooks/use-service-booking.ts +152 -90
  50. package/src/hooks/use-states.ts +35 -15
  51. package/src/hooks/use-wishlist.ts +92 -91
  52. package/src/index.ts +26 -30
  53. package/src/services/auth.service.ts +209 -167
  54. package/src/services/bespoke.service.ts +12 -4
  55. package/src/services/cart.service.ts +172 -70
  56. package/src/services/cms.service.ts +70 -35
  57. package/src/services/collection.service.ts +22 -5
  58. package/src/services/config.service.ts +34 -14
  59. package/src/services/consultation.service.ts +72 -18
  60. package/src/services/logistics.service.ts +35 -11
  61. package/src/services/notifications.service.ts +27 -12
  62. package/src/services/order.service.ts +74 -15
  63. package/src/services/payment.service.ts +86 -31
  64. package/src/services/product.service.ts +279 -39
  65. package/src/services/service-booking.service.ts +98 -26
  66. package/src/services/wishlist.service.ts +69 -25
  67. package/src/types/auth/index.ts +6 -4
  68. package/src/types/business/index.ts +7 -2
  69. package/src/types/payments/index.ts +3 -3
  70. package/src/types/services/index.ts +2 -5
  71. package/src/types/store/index.ts +38 -3
  72. package/src/utils/error-handler.ts +10 -5
  73. package/src/utils/storage.ts +48 -26
  74. package/src/utils/validators.ts +85 -0
  75. package/src/client/authClient.ts +0 -135
  76. package/src/client/graphqlClient.ts +0 -53
  77. package/src/client/httpClient.ts +0 -298
@@ -0,0 +1,3073 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/hooks/index.ts
31
+ var hooks_exports = {};
32
+ __export(hooks_exports, {
33
+ CartCtx: () => CartCtx,
34
+ CartProvider: () => CartProvider,
35
+ SdkProvider: () => SdkProvider,
36
+ collectionKeys: () => collectionKeys,
37
+ getCountries: () => getCountries,
38
+ getStates: () => getStates,
39
+ getSupportedCurrenciesList: () => getSupportedCurrenciesList,
40
+ getSupportedLanguagesList: () => getSupportedLanguagesList,
41
+ productKeys: () => productKeys,
42
+ resolveHookArgs: () => resolveHookArgs,
43
+ useAcceptQuote: () => useAcceptQuote,
44
+ useAddToWishlist: () => useAddToWishlist,
45
+ useAppointment: () => useAppointment,
46
+ useAppointments: () => useAppointments,
47
+ useApproveDeliverable: () => useApproveDeliverable,
48
+ useAuthUser: () => useAuthUser,
49
+ useAvailableSlots: () => useAvailableSlots,
50
+ useBespokeAvailability: () => useBespokeAvailability,
51
+ useBookAppointment: () => useBookAppointment,
52
+ useCancelAppointment: () => useCancelAppointment,
53
+ useCancelOrder: () => useCancelOrder,
54
+ useCart: () => useCart,
55
+ useCheckInWishlist: () => useCheckInWishlist,
56
+ useCmsEntries: () => useCmsEntries,
57
+ useCmsEntry: () => useCmsEntry,
58
+ useConsultation: () => useConsultation,
59
+ useConsultationStream: () => useConsultationStream,
60
+ useConsultations: () => useConsultations,
61
+ useCountries: () => useCountries,
62
+ useCreateCmsEntry: () => useCreateCmsEntry,
63
+ useCreateConsultation: () => useCreateConsultation,
64
+ useCreateDVA: () => useCreateDVA,
65
+ useCreateOrder: () => useCreateOrder,
66
+ useCurrencies: () => useCurrencies,
67
+ useDeleteCmsEntry: () => useDeleteCmsEntry,
68
+ useDeliverables: () => useDeliverables,
69
+ useFeaturedProducts: () => useFeaturedProducts,
70
+ useFindOrder: () => useFindOrder,
71
+ useGoogleTranslate: () => useGoogleTranslate,
72
+ useInitiatePayment: () => useInitiatePayment,
73
+ useIsMobile: () => useIsMobile,
74
+ useIsMounted: () => useIsMounted,
75
+ useLatestProducts: () => useLatestProducts,
76
+ useLogin: () => useLogin,
77
+ useLogout: () => useLogout,
78
+ useLowStockProducts: () => useLowStockProducts,
79
+ useNewProducts: () => useNewProducts,
80
+ useOnSaleProducts: () => useOnSaleProducts,
81
+ useOrder: () => useOrder,
82
+ useOrderStream: () => useOrderStream,
83
+ useOrderTracking: () => useOrderTracking,
84
+ useOrders: () => useOrders,
85
+ useOrdersList: () => useOrdersList,
86
+ usePollTransactionStatus: () => usePollTransactionStatus,
87
+ usePopularProducts: () => usePopularProducts,
88
+ useProduct: () => useProduct,
89
+ useRecommendedProducts: () => useRecommendedProducts,
90
+ useRegister: () => useRegister,
91
+ useRejectQuote: () => useRejectQuote,
92
+ useRemoveFromWishlist: () => useRemoveFromWishlist,
93
+ useRemoveProductFromWishlist: () => useRemoveProductFromWishlist,
94
+ useRequestRevision: () => useRequestRevision,
95
+ useSdkContext: () => useSdkContext,
96
+ useSendMessage: () => useSendMessage,
97
+ useStates: () => useStates,
98
+ useStorefrontCollection: () => useStorefrontCollection,
99
+ useStorefrontCollections: () => useStorefrontCollections,
100
+ useStorefrontProducts: () => useStorefrontProducts,
101
+ useSupportedLanguages: () => useSupportedLanguages,
102
+ useTransactionStatus: () => useTransactionStatus,
103
+ useUpdateCmsEntry: () => useUpdateCmsEntry,
104
+ useUpdateProfile: () => useUpdateProfile,
105
+ useVerifyTransaction: () => useVerifyTransaction,
106
+ useWishlist: () => useWishlist,
107
+ wishlistKeys: () => wishlistKeys
108
+ });
109
+ module.exports = __toCommonJS(hooks_exports);
110
+
111
+ // src/hooks/use-cart.ts
112
+ var import_react2 = __toESM(require("react"));
113
+ var import_react_query = require("@tanstack/react-query");
114
+
115
+ // src/services/cart.service.ts
116
+ function parseItems(items) {
117
+ return items.map((item) => ({
118
+ ...item,
119
+ variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
120
+ }));
121
+ }
122
+ async function getGuestCart(config, guestSessionId) {
123
+ if (!guestSessionId) return [];
124
+ try {
125
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
126
+ headers: {
127
+ "X-Storefront-Key": config.storefrontApiKey,
128
+ "X-Business-ID": config.businessId,
129
+ "X-Guest-Session": guestSessionId
130
+ }
131
+ });
132
+ if (!response.ok) return [];
133
+ const data = await response.json();
134
+ return parseItems(data.items || []);
135
+ } catch {
136
+ return [];
137
+ }
138
+ }
139
+ async function getCart(config, accessToken) {
140
+ if (!accessToken) {
141
+ return { id: "", items: [], subtotal: 0, total: 0, product_type: "physical" };
142
+ }
143
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
144
+ headers: {
145
+ "Authorization": `Bearer ${accessToken}`,
146
+ "X-Storefront-Key": config.storefrontApiKey,
147
+ "X-Business-ID": config.businessId
148
+ }
149
+ });
150
+ if (!response.ok) throw new Error("Failed to fetch cart");
151
+ const data = await response.json();
152
+ const parsedItems = parseItems(data.items || []);
153
+ return { ...data, items: parsedItems };
154
+ }
155
+ async function addToCart(config, accessToken, item) {
156
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
157
+ method: "POST",
158
+ headers: {
159
+ "Content-Type": "application/json",
160
+ "Authorization": `Bearer ${accessToken}`,
161
+ "X-Storefront-Key": config.storefrontApiKey,
162
+ "X-Business-ID": config.businessId
163
+ },
164
+ body: JSON.stringify(item)
165
+ });
166
+ if (!response.ok) throw new Error("Failed to add to cart");
167
+ const data = await response.json();
168
+ const parsedItems = parseItems(data.items || []);
169
+ return { ...data, items: parsedItems };
170
+ }
171
+ async function updateCartItem(config, accessToken, itemId, quantity) {
172
+ const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
173
+ method: "PATCH",
174
+ headers: {
175
+ "Content-Type": "application/json",
176
+ "Authorization": `Bearer ${accessToken}`,
177
+ "X-Storefront-Key": config.storefrontApiKey,
178
+ "X-Business-ID": config.businessId
179
+ },
180
+ body: JSON.stringify({ quantity })
181
+ });
182
+ if (!response.ok) throw new Error("Failed to update cart item");
183
+ const data = await response.json();
184
+ const parsedItems = parseItems(data.items || []);
185
+ return { ...data, items: parsedItems };
186
+ }
187
+ async function removeFromCart(config, accessToken, itemId) {
188
+ await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
189
+ method: "DELETE",
190
+ headers: {
191
+ "Authorization": `Bearer ${accessToken}`,
192
+ "X-Storefront-Key": config.storefrontApiKey,
193
+ "X-Business-ID": config.businessId
194
+ }
195
+ });
196
+ return getCart(config, accessToken);
197
+ }
198
+ async function clearCart(config, accessToken) {
199
+ await fetch(`${config.backendUrls.store}/cart/clear`, {
200
+ method: "DELETE",
201
+ headers: {
202
+ "Authorization": `Bearer ${accessToken}`,
203
+ "X-Storefront-Key": config.storefrontApiKey,
204
+ "X-Business-ID": config.businessId
205
+ }
206
+ });
207
+ }
208
+ async function mergeGuestCart(config, accessToken, guestSessionId) {
209
+ const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
210
+ if (guestItems.length === 0) {
211
+ return getCart(config, accessToken);
212
+ }
213
+ const payloadItems = guestItems.map((item) => ({
214
+ product_id: item.product_id,
215
+ product_slug: item.product_slug,
216
+ product_name: item.product_name,
217
+ image: item.image,
218
+ variant_id: item.variant_id,
219
+ variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
220
+ unit_price: item.unit_price,
221
+ quantity: item.quantity,
222
+ custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
223
+ is_bespoke: item.is_bespoke
224
+ }));
225
+ const headers = {
226
+ "Content-Type": "application/json",
227
+ "Authorization": `Bearer ${accessToken}`,
228
+ "X-Storefront-Key": config.storefrontApiKey,
229
+ "X-Business-ID": config.businessId
230
+ };
231
+ if (guestSessionId) {
232
+ headers["X-Guest-Session"] = guestSessionId;
233
+ }
234
+ const response = await fetch(`${config.backendUrls.store}/cart/merge`, {
235
+ method: "POST",
236
+ headers,
237
+ body: JSON.stringify({ items: payloadItems })
238
+ });
239
+ if (!response.ok) throw new Error("Failed to merge guest cart");
240
+ const data = await response.json();
241
+ return { ...data, items: parseItems(data.items || []) };
242
+ }
243
+ async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
244
+ try {
245
+ const guestItems = await getGuestCart(config, guestSessionId);
246
+ if (guestItems.length === 0) return;
247
+ await mergeGuestCart(config, accessToken, guestSessionId);
248
+ } catch (error) {
249
+ console.warn("[Cart] Failed to merge guest cart:", error);
250
+ }
251
+ }
252
+
253
+ // src/context/sdk-context.tsx
254
+ var import_react = require("react");
255
+ var import_jsx_runtime = require("react/jsx-runtime");
256
+ var SdkContext = (0, import_react.createContext)(null);
257
+ function SdkProvider({ config, accessToken, children }) {
258
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SdkContext.Provider, { value: { config, accessToken }, children });
259
+ }
260
+ function useSdkContext() {
261
+ return (0, import_react.useContext)(SdkContext);
262
+ }
263
+ function resolveHookArgs(explicitConfig, explicitToken, ctx) {
264
+ const config = explicitConfig ?? ctx?.config;
265
+ if (!config) {
266
+ throw new Error(
267
+ "[kasuvia-sdk] No SdkConfig found. Either pass config explicitly or wrap your app with <SdkProvider config={...}>."
268
+ );
269
+ }
270
+ const accessToken = explicitToken !== void 0 ? explicitToken : ctx?.accessToken ?? null;
271
+ return { config, accessToken };
272
+ }
273
+
274
+ // src/hooks/use-cart.ts
275
+ var CartCtx = import_react2.default.createContext ? import_react2.default.createContext(null) : null;
276
+ function CartProvider({ children }) {
277
+ const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
278
+ if (!CartCtx) return children;
279
+ return import_react2.default.createElement(CartCtx.Provider, { value: { isOpen, setOpen: setIsOpen } }, children);
280
+ }
281
+ function useCart(config, accessToken) {
282
+ const ctx = useSdkContext();
283
+ try {
284
+ const resolved = resolveHookArgs(config, accessToken, ctx);
285
+ const resolvedConfig = resolved.config;
286
+ const resolvedToken = resolved.accessToken;
287
+ const queryClient = (0, import_react_query.useQueryClient)();
288
+ const context = CartCtx ? (0, import_react2.useContext)(CartCtx) : null;
289
+ const isOpen = context ? context.isOpen : false;
290
+ const setOpen = context ? context.setOpen : () => {
291
+ };
292
+ const [productTypeMismatch, setProductTypeMismatch] = (0, import_react2.useState)(null);
293
+ const cartQuery = (0, import_react_query.useQuery)({
294
+ queryKey: ["cart"],
295
+ queryFn: async () => {
296
+ if (resolvedToken) {
297
+ return getCart(resolvedConfig, resolvedToken);
298
+ }
299
+ if (typeof window !== "undefined") {
300
+ const res = await fetch("/api/cart", { credentials: "include" });
301
+ if (!res.ok) throw new Error("Failed to fetch cart");
302
+ return res.json();
303
+ }
304
+ return void 0;
305
+ },
306
+ enabled: true
307
+ });
308
+ const addToCartMutation = (0, import_react_query.useMutation)({
309
+ mutationFn: async (item) => {
310
+ if (resolvedToken) {
311
+ return addToCart(resolvedConfig, resolvedToken, item);
312
+ }
313
+ if (typeof window !== "undefined") {
314
+ const res = await fetch("/api/cart", {
315
+ method: "POST",
316
+ headers: { "Content-Type": "application/json" },
317
+ credentials: "include",
318
+ body: JSON.stringify(item)
319
+ });
320
+ if (!res.ok) {
321
+ const data = await res.json().catch(() => ({}));
322
+ throw { status: res.status, data };
323
+ }
324
+ return res.json();
325
+ }
326
+ throw new Error("No access token and not in browser context");
327
+ },
328
+ onSuccess: () => {
329
+ setProductTypeMismatch(null);
330
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
331
+ },
332
+ onError: (error) => {
333
+ const err = error;
334
+ if (err.status === 409 && err.data?.detail?.code === "CART_PRODUCT_TYPE_MISMATCH") {
335
+ const errorDetail = err.data.detail;
336
+ setProductTypeMismatch({
337
+ message: errorDetail.message ?? "Your cart contains incompatible items.",
338
+ existing_type: errorDetail.existing_type ?? "physical",
339
+ new_type: errorDetail.new_type ?? "physical"
340
+ });
341
+ }
342
+ }
343
+ });
344
+ const updateCartItemMutation = (0, import_react_query.useMutation)({
345
+ mutationFn: async ({ itemId, quantity }) => {
346
+ if (resolvedToken) {
347
+ return updateCartItem(resolvedConfig, resolvedToken, itemId, quantity);
348
+ }
349
+ if (typeof window !== "undefined") {
350
+ const res = await fetch(`/api/cart/${itemId}`, {
351
+ method: "PATCH",
352
+ headers: { "Content-Type": "application/json" },
353
+ credentials: "include",
354
+ body: JSON.stringify({ quantity })
355
+ });
356
+ if (!res.ok) throw new Error("Failed to update cart item");
357
+ return res.json();
358
+ }
359
+ throw new Error("No access token");
360
+ },
361
+ onSuccess: () => {
362
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
363
+ }
364
+ });
365
+ const removeFromCartMutation = (0, import_react_query.useMutation)({
366
+ mutationFn: async (itemId) => {
367
+ if (resolvedToken) {
368
+ return removeFromCart(resolvedConfig, resolvedToken, itemId);
369
+ }
370
+ if (typeof window !== "undefined") {
371
+ const res = await fetch(`/api/cart/${itemId}`, {
372
+ method: "DELETE",
373
+ credentials: "include"
374
+ });
375
+ if (!res.ok) throw new Error("Failed to remove cart item");
376
+ return res.json();
377
+ }
378
+ throw new Error("No access token");
379
+ },
380
+ onSuccess: () => {
381
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
382
+ }
383
+ });
384
+ const clearCartMutation = (0, import_react_query.useMutation)({
385
+ mutationFn: async () => {
386
+ if (resolvedToken) {
387
+ return clearCart(resolvedConfig, resolvedToken);
388
+ }
389
+ if (typeof window !== "undefined") {
390
+ const res = await fetch("/api/cart/clear", {
391
+ method: "DELETE",
392
+ credentials: "include"
393
+ });
394
+ if (!res.ok) throw new Error("Failed to clear cart");
395
+ return res.json();
396
+ }
397
+ throw new Error("No access token");
398
+ },
399
+ onSuccess: () => {
400
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
401
+ }
402
+ });
403
+ const mergeGuestCartMutation = (0, import_react_query.useMutation)({
404
+ mutationFn: (guestSessionId) => resolvedToken ? mergeGuestCartIfPresent(resolvedConfig, resolvedToken, guestSessionId) : Promise.resolve(),
405
+ onSuccess: () => {
406
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
407
+ }
408
+ });
409
+ const addItem = (product, variantId, quantity = 1, customMeasurements) => {
410
+ const variant = variantId ? product.variants.find((v) => v.id === variantId) : void 0;
411
+ return addToCartMutation.mutate({
412
+ product_id: product.id,
413
+ product_slug: product.slug,
414
+ product_name: product.name,
415
+ image: product.images[0] || void 0,
416
+ variant_id: variantId,
417
+ variant_attributes: variant?.attributes ? JSON.stringify(variant.attributes) : void 0,
418
+ unit_price: variant?.price ?? product.base_price,
419
+ quantity,
420
+ custom_measurements: customMeasurements ? JSON.stringify(customMeasurements) : void 0,
421
+ is_bespoke: product.is_bespoke
422
+ });
423
+ };
424
+ const items = cartQuery.data?.items || [];
425
+ const subtotal = cartQuery.data?.subtotal || 0;
426
+ const count = items.reduce((total, item) => total + item.quantity, 0);
427
+ const updateQty = (itemId, quantity) => {
428
+ updateCartItemMutation.mutate({ itemId, quantity });
429
+ };
430
+ const removeItem = (itemId) => {
431
+ removeFromCartMutation.mutate(itemId);
432
+ };
433
+ const handleClearCartAndAdd = () => {
434
+ clearCartMutation.mutate();
435
+ setProductTypeMismatch(null);
436
+ };
437
+ const handleKeepCurrentCart = () => {
438
+ setProductTypeMismatch(null);
439
+ };
440
+ return {
441
+ cart: cartQuery.data,
442
+ items,
443
+ count,
444
+ isOpen,
445
+ setOpen,
446
+ isLoading: cartQuery.isLoading,
447
+ error: cartQuery.error,
448
+ addToCart: addToCartMutation.mutate,
449
+ updateCartItem: updateCartItemMutation.mutate,
450
+ removeFromCart: removeFromCartMutation.mutate,
451
+ clearCart: clearCartMutation.mutate,
452
+ clear: clearCartMutation.mutate,
453
+ // Alias for storefront compatibility
454
+ mergeGuestCart: mergeGuestCartMutation.mutate,
455
+ addItem,
456
+ updateQty,
457
+ removeItem,
458
+ subtotal,
459
+ productTypeMismatch,
460
+ handleClearCartAndAdd,
461
+ handleKeepCurrentCart
462
+ };
463
+ } catch (error) {
464
+ console.warn("[useCart] Called outside QueryClientProvider, returning empty cart");
465
+ const context = CartCtx ? (0, import_react2.useContext)(CartCtx) : null;
466
+ const isOpen = context ? context.isOpen : false;
467
+ const setOpen = context ? context.setOpen : () => {
468
+ };
469
+ return {
470
+ cart: void 0,
471
+ items: [],
472
+ count: 0,
473
+ isOpen,
474
+ setOpen,
475
+ isLoading: false,
476
+ error: null,
477
+ addToCart: () => {
478
+ },
479
+ updateCartItem: () => {
480
+ },
481
+ removeFromCart: () => {
482
+ },
483
+ clearCart: () => {
484
+ },
485
+ clear: () => {
486
+ },
487
+ mergeGuestCart: () => {
488
+ },
489
+ addItem: () => {
490
+ },
491
+ updateQty: () => {
492
+ },
493
+ removeItem: () => {
494
+ },
495
+ subtotal: 0,
496
+ productTypeMismatch: null,
497
+ handleClearCartAndAdd: () => {
498
+ },
499
+ handleKeepCurrentCart: () => {
500
+ }
501
+ };
502
+ }
503
+ }
504
+
505
+ // src/hooks/use-orders.ts
506
+ var import_react_query2 = require("@tanstack/react-query");
507
+
508
+ // src/services/order.service.ts
509
+ function deriveCustomerName(raw) {
510
+ if (raw.customer_name) return raw.customer_name;
511
+ if (raw.guest_name) return raw.guest_name;
512
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
513
+ if (addr) {
514
+ const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
515
+ if (full) return full;
516
+ }
517
+ const email = raw.guest_email ?? raw.customer_email ?? "";
518
+ if (email) return email.split("@")[0];
519
+ return "";
520
+ }
521
+ function normaliseStorefrontOrder(raw) {
522
+ const items = (raw.items ?? []).map((item) => ({
523
+ id: item.id,
524
+ productName: item.product_name ?? item.productName ?? "",
525
+ image: item.image ?? "",
526
+ quantity: item.quantity ?? 1,
527
+ price: item.unit_price ?? item.price ?? 0
528
+ }));
529
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
530
+ return {
531
+ id: raw.id,
532
+ display_id: raw.display_id,
533
+ items,
534
+ total: raw.total_amount ?? raw.total ?? 0,
535
+ status: raw.status,
536
+ customerEmail: raw.guest_email ?? raw.customer_email ?? "",
537
+ customerName: deriveCustomerName(raw),
538
+ createdAt: raw.created_at ? new Date(raw.created_at).getTime() : Date.now(),
539
+ updatedAt: raw.updated_at ? new Date(raw.updated_at).getTime() : Date.now(),
540
+ deliveryMethod: raw.delivery_method,
541
+ trackingNumber: raw.tracking_number,
542
+ deliveryAddress: typeof raw.shipping_address === "string" ? raw.shipping_address : addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
543
+ shippingAddress: addr ? {
544
+ first_name: addr.first_name ?? "",
545
+ last_name: addr.last_name ?? "",
546
+ phone: addr.phone ?? "",
547
+ street: addr.street ?? "",
548
+ city: addr.city ?? "",
549
+ state: addr.state ?? "",
550
+ lga: addr.lga ?? "",
551
+ country: addr.country ?? "",
552
+ postal: addr.postal ?? ""
553
+ } : void 0,
554
+ cancellationReason: raw.cancellation_reason,
555
+ hasBespoke: raw.product_type === "bespoke",
556
+ bespokeStage: raw.bespoke_stage,
557
+ bespokeBrief: raw.bespoke_brief,
558
+ deliveryStatus: raw.delivery_status,
559
+ carrierName: raw.carrier_name,
560
+ terminalShipmentId: raw.terminal_shipment_id,
561
+ guestToken: raw.guest_token,
562
+ guestEmail: raw.guest_email,
563
+ guestPhone: raw.guest_phone,
564
+ guestName: raw.guest_name
565
+ };
566
+ }
567
+ async function createOrder(config, accessToken, payload) {
568
+ const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
569
+ method: "POST",
570
+ headers: {
571
+ "Content-Type": "application/json",
572
+ "Authorization": `Bearer ${accessToken}`,
573
+ "X-Storefront-Key": config.storefrontApiKey,
574
+ "X-Business-ID": config.businessId
575
+ },
576
+ body: JSON.stringify(payload)
577
+ });
578
+ if (!response.ok) throw new Error("Failed to create order");
579
+ const data = await response.json();
580
+ return normaliseStorefrontOrder(data);
581
+ }
582
+ async function findOrder(config, params) {
583
+ const queryParams = new URLSearchParams();
584
+ if (params.email) queryParams.set("email", params.email);
585
+ if (params.order_id) queryParams.set("order_id", params.order_id);
586
+ if (params.guest_token) queryParams.set("guest_token", params.guest_token);
587
+ const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
588
+ headers: {
589
+ "X-Storefront-Key": config.storefrontApiKey,
590
+ "X-Business-ID": config.businessId
591
+ }
592
+ });
593
+ if (!response.ok) throw new Error("Failed to find order");
594
+ const data = await response.json();
595
+ return normaliseStorefrontOrder(data);
596
+ }
597
+ async function getOrders(config, accessToken, params) {
598
+ const queryParams = new URLSearchParams();
599
+ if (params?.email) queryParams.set("email", params.email);
600
+ if (params?.page) queryParams.set("page", params.page.toString());
601
+ if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
602
+ const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
603
+ headers: {
604
+ "Authorization": `Bearer ${accessToken}`,
605
+ "X-Storefront-Key": config.storefrontApiKey,
606
+ "X-Business-ID": config.businessId
607
+ }
608
+ });
609
+ if (!response.ok) throw new Error("Failed to get orders");
610
+ const data = await response.json();
611
+ const items = Array.isArray(data) ? data : data.items ?? [];
612
+ return items.map(normaliseStorefrontOrder);
613
+ }
614
+ async function cancelOrder(config, accessToken, orderId, reason) {
615
+ const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
616
+ method: "POST",
617
+ headers: {
618
+ "Content-Type": "application/json",
619
+ "Authorization": `Bearer ${accessToken}`,
620
+ "X-Storefront-Key": config.storefrontApiKey,
621
+ "X-Business-ID": config.businessId
622
+ },
623
+ body: JSON.stringify({ reason })
624
+ });
625
+ if (!response.ok) throw new Error("Failed to cancel order");
626
+ const data = await response.json();
627
+ return normaliseStorefrontOrder(data);
628
+ }
629
+ async function trackOrder(config, orderId, token) {
630
+ const queryParams = token ? `?token=${token}` : "";
631
+ const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
632
+ headers: {
633
+ "X-Storefront-Key": config.storefrontApiKey,
634
+ "X-Business-ID": config.businessId
635
+ }
636
+ });
637
+ if (!response.ok) throw new Error("Failed to track order");
638
+ const data = await response.json();
639
+ return normaliseStorefrontOrder(data);
640
+ }
641
+
642
+ // src/utils/cache.ts
643
+ var CACHE_TIERS = {
644
+ none: { staleTime: 0, gcTime: 0 },
645
+ infinity: { staleTime: Infinity, gcTime: 0 },
646
+ low: { staleTime: 1e3 * 30, gcTime: 1e3 * 60 },
647
+ // 30s / 1m
648
+ medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
649
+ // 5m / 10m
650
+ high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
651
+ // 30m / 1h
652
+ };
653
+ var isDevelopment = true;
654
+ var getCacheTier = (tier) => {
655
+ if (isDevelopment) return CACHE_TIERS.none;
656
+ return CACHE_TIERS[tier];
657
+ };
658
+
659
+ // src/utils/logger.ts
660
+ var isDevelopment2 = true;
661
+ var logger = {
662
+ log: (...args) => {
663
+ if (isDevelopment2) {
664
+ console.log(...args);
665
+ }
666
+ },
667
+ warn: (...args) => {
668
+ if (isDevelopment2) {
669
+ console.warn(...args);
670
+ }
671
+ },
672
+ /**
673
+ * Logs a warning to the console in development only.
674
+ * Alias for warn() for Python logging compatibility.
675
+ * In production, this is a no-op.
676
+ */
677
+ warning: (...args) => {
678
+ if (isDevelopment2) {
679
+ console.warn(...args);
680
+ }
681
+ },
682
+ error: (...args) => {
683
+ if (isDevelopment2) {
684
+ console.error(...args);
685
+ }
686
+ },
687
+ info: (...args) => {
688
+ if (isDevelopment2) {
689
+ console.info(...args);
690
+ }
691
+ },
692
+ createScope: (scope) => ({
693
+ log: (...args) => {
694
+ if (isDevelopment2) {
695
+ console.log(`[${scope}]`, ...args);
696
+ }
697
+ },
698
+ warn: (...args) => {
699
+ if (isDevelopment2) {
700
+ console.warn(`[${scope}]`, ...args);
701
+ }
702
+ },
703
+ warning: (...args) => {
704
+ if (isDevelopment2) {
705
+ console.warn(`[${scope}]`, ...args);
706
+ }
707
+ },
708
+ error: (...args) => {
709
+ if (isDevelopment2) {
710
+ console.error(`[${scope}]`, ...args);
711
+ }
712
+ },
713
+ info: (...args) => {
714
+ if (isDevelopment2) {
715
+ console.info(`[${scope}]`, ...args);
716
+ }
717
+ }
718
+ })
719
+ };
720
+
721
+ // src/hooks/use-orders.ts
722
+ function useOrders(arg1, arg2, arg3) {
723
+ const ctx = useSdkContext();
724
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
725
+ const explicitConfig = isArg1Config ? arg1 : void 0;
726
+ const explicitToken = isArg1Config ? arg2 : void 0;
727
+ const params = isArg1Config ? arg3 : arg1;
728
+ try {
729
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
730
+ return (0, import_react_query2.useQuery)({
731
+ queryKey: ["orders", params],
732
+ queryFn: () => token ? getOrders(cfg, token, params || {}) : Promise.resolve(void 0),
733
+ enabled: !!token
734
+ });
735
+ } catch (error) {
736
+ logger.warn("[useOrders] Called outside QueryClientProvider, returning empty list");
737
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
738
+ }
739
+ }
740
+ function useOrdersList(arg1, arg2, arg3) {
741
+ return useOrders(arg1, arg2, arg3);
742
+ }
743
+ function useFindOrder(arg1, arg2) {
744
+ const ctx = useSdkContext();
745
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
746
+ const explicitConfig = isArg1Config ? arg1 : void 0;
747
+ const params = isArg1Config ? arg2 : typeof arg1 === "string" ? { order_id: arg1, email: "" } : arg1;
748
+ try {
749
+ const { config: cfg } = resolveHookArgs(explicitConfig, void 0, ctx);
750
+ return (0, import_react_query2.useQuery)({
751
+ queryKey: ["order", params],
752
+ queryFn: () => params ? findOrder(cfg, params) : Promise.resolve(void 0),
753
+ enabled: !!params?.order_id
754
+ });
755
+ } catch (error) {
756
+ logger.warn("[useFindOrder] Called outside QueryClientProvider, returning undefined");
757
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
758
+ }
759
+ }
760
+ function useOrder(arg1, arg2) {
761
+ return useFindOrder(arg1, arg2);
762
+ }
763
+ function useOrderTracking(arg1, arg2, arg3) {
764
+ const ctx = useSdkContext();
765
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
766
+ const explicitConfig = isArg1Config ? arg1 : void 0;
767
+ const orderId = isArg1Config ? arg2 : typeof arg1 === "string" ? arg1 : void 0;
768
+ const guestToken = isArg1Config ? arg3 : typeof arg2 === "string" ? arg2 : void 0;
769
+ try {
770
+ const { config: cfg } = resolveHookArgs(explicitConfig, void 0, ctx);
771
+ return (0, import_react_query2.useQuery)({
772
+ queryKey: ["order-tracking", orderId, guestToken],
773
+ queryFn: () => trackOrder(cfg, orderId, guestToken),
774
+ enabled: !!orderId,
775
+ refetchInterval: 3e4
776
+ });
777
+ } catch (error) {
778
+ logger.warn("[useOrderTracking] Called outside QueryClientProvider, returning undefined");
779
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
780
+ }
781
+ }
782
+ function useCreateOrder(config, accessToken) {
783
+ const ctx = useSdkContext();
784
+ try {
785
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
786
+ const queryClient = (0, import_react_query2.useQueryClient)();
787
+ return (0, import_react_query2.useMutation)({
788
+ mutationFn: (payload) => createOrder(cfg, token || "", payload),
789
+ onSuccess: () => {
790
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
791
+ }
792
+ });
793
+ } catch (error) {
794
+ logger.warn("[useCreateOrder] Called outside QueryClientProvider, returning no-op mutation");
795
+ return { mutate: () => {
796
+ }, mutateAsync: () => Promise.resolve(void 0) };
797
+ }
798
+ }
799
+ function useCancelOrder(config, accessToken) {
800
+ const ctx = useSdkContext();
801
+ try {
802
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
803
+ const queryClient = (0, import_react_query2.useQueryClient)();
804
+ return (0, import_react_query2.useMutation)({
805
+ mutationFn: ({ orderId, reason = "" }) => token ? cancelOrder(cfg, token, orderId, reason) : Promise.reject("No access token"),
806
+ onSuccess: () => {
807
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
808
+ }
809
+ });
810
+ } catch (error) {
811
+ logger.warn("[useCancelOrder] Called outside QueryClientProvider, returning no-op mutation");
812
+ return { mutate: () => {
813
+ }, mutateAsync: () => Promise.resolve(void 0) };
814
+ }
815
+ }
816
+
817
+ // src/hooks/use-auth.ts
818
+ var import_react_query3 = require("@tanstack/react-query");
819
+
820
+ // src/services/auth.service.ts
821
+ async function loginCustomer(config, payload) {
822
+ const response = await fetch(`${config.backendUrls.auth}/auth/login/customer/`, {
823
+ method: "POST",
824
+ headers: {
825
+ "Content-Type": "application/json",
826
+ "X-Storefront-Key": config.storefrontApiKey,
827
+ "X-Business-ID": config.businessId
828
+ },
829
+ body: JSON.stringify({
830
+ ...payload,
831
+ tenant_id: config.businessId
832
+ })
833
+ });
834
+ if (!response.ok) {
835
+ throw new Error("Login failed");
836
+ }
837
+ const data = await response.json();
838
+ return data;
839
+ }
840
+ async function registerCustomer(config, payload) {
841
+ const response = await fetch(`${config.backendUrls.auth}/auth/register/customer/`, {
842
+ method: "POST",
843
+ headers: {
844
+ "Content-Type": "application/json",
845
+ "X-Storefront-Key": config.storefrontApiKey,
846
+ "X-Business-ID": config.businessId
847
+ },
848
+ body: JSON.stringify({
849
+ ...payload,
850
+ tenant_id: config.businessId
851
+ })
852
+ });
853
+ if (!response.ok) {
854
+ throw new Error("Registration failed");
855
+ }
856
+ const data = await response.json();
857
+ return data;
858
+ }
859
+ async function logout(config, refresh) {
860
+ const payload = refresh ? { refresh } : {};
861
+ try {
862
+ await fetch(`${config.backendUrls.auth}/auth/logout/`, {
863
+ method: "POST",
864
+ headers: {
865
+ "Content-Type": "application/json"
866
+ },
867
+ body: JSON.stringify(payload)
868
+ });
869
+ } catch {
870
+ }
871
+ }
872
+ function resolveProvider(data) {
873
+ if (data.is_google_auth_enabled) return "google";
874
+ if (data.is_facebook_auth_enabled) return "facebook";
875
+ return "email";
876
+ }
877
+ function resolveAvatar(profilePicture) {
878
+ if (!profilePicture) return null;
879
+ if (typeof profilePicture === "string") return profilePicture;
880
+ if (typeof profilePicture === "object" && profilePicture !== null && "url" in profilePicture) {
881
+ const url = profilePicture.url;
882
+ return typeof url === "string" ? url : null;
883
+ }
884
+ return null;
885
+ }
886
+ function mapAuthUserToCustomer(data, provider) {
887
+ const firstname = data.profile?.firstname?.trim() || void 0;
888
+ const lastname = data.profile?.lastname?.trim() || void 0;
889
+ const phone = data.profile?.phone?.trim() || void 0;
890
+ return {
891
+ id: String(data.id),
892
+ email: data.email,
893
+ firstname,
894
+ lastname,
895
+ phone,
896
+ full_name: buildFullName2(firstname, lastname),
897
+ avatar: resolveAvatar(data.profile?.profile_picture),
898
+ provider: provider ?? resolveProvider(data)
899
+ };
900
+ }
901
+ async function getAuthUser(config, accessToken) {
902
+ if (!config || !accessToken) {
903
+ const response2 = await fetch("/api/auth/me", { credentials: "include" });
904
+ if (!response2.ok) throw new Error("Failed to fetch auth user");
905
+ const data2 = await response2.json();
906
+ return data2.user;
907
+ }
908
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
909
+ headers: {
910
+ "Authorization": `Bearer ${accessToken}`
911
+ }
912
+ });
913
+ if (!response.ok) {
914
+ throw new Error("Failed to fetch auth user");
915
+ }
916
+ const data = await response.json();
917
+ return data;
918
+ }
919
+ async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
920
+ const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
921
+ if (!isArg1Config) {
922
+ const payload2 = configOrPayload;
923
+ const response2 = await fetch("/api/auth/profile", {
924
+ method: "PUT",
925
+ headers: { "Content-Type": "application/json" },
926
+ credentials: "include",
927
+ body: JSON.stringify(payload2)
928
+ });
929
+ if (!response2.ok) throw new Error("Failed to update profile");
930
+ return response2.json();
931
+ }
932
+ const config = configOrPayload;
933
+ const accessToken = accessTokenOrPayload;
934
+ const payload = payloadParam;
935
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
936
+ method: "PUT",
937
+ headers: {
938
+ "Content-Type": "application/json",
939
+ "Authorization": `Bearer ${accessToken}`
940
+ },
941
+ body: JSON.stringify(payload)
942
+ });
943
+ if (!response.ok) {
944
+ throw new Error("Failed to update profile");
945
+ }
946
+ const data = await response.json();
947
+ return mapAuthUserToCustomer(data);
948
+ }
949
+ function buildFullName2(firstname, lastname) {
950
+ if (firstname && lastname) return `${firstname} ${lastname}`;
951
+ return firstname || lastname || "";
952
+ }
953
+
954
+ // src/hooks/use-auth.ts
955
+ function useAuthUser(config, accessToken) {
956
+ const ctx = useSdkContext();
957
+ try {
958
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken ?? null, ctx);
959
+ return (0, import_react_query3.useQuery)({
960
+ queryKey: ["auth-user"],
961
+ queryFn: () => getAuthUser(cfg, token ?? ""),
962
+ enabled: !!token
963
+ });
964
+ } catch (error) {
965
+ logger.warn("[useAuthUser] Called outside QueryClientProvider, returning empty user");
966
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
967
+ }
968
+ }
969
+ function useLogin(config) {
970
+ const ctx = useSdkContext();
971
+ try {
972
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
973
+ const queryClient = (0, import_react_query3.useQueryClient)();
974
+ return (0, import_react_query3.useMutation)({
975
+ mutationFn: (payload) => loginCustomer(cfg, payload),
976
+ onSuccess: () => {
977
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
978
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
979
+ }
980
+ });
981
+ } catch (error) {
982
+ logger.warn("[useLogin] Called outside QueryClientProvider, returning no-op mutation");
983
+ return { mutate: () => {
984
+ }, mutateAsync: () => Promise.resolve(void 0) };
985
+ }
986
+ }
987
+ function useRegister(config) {
988
+ const ctx = useSdkContext();
989
+ try {
990
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
991
+ const queryClient = (0, import_react_query3.useQueryClient)();
992
+ return (0, import_react_query3.useMutation)({
993
+ mutationFn: (payload) => registerCustomer(cfg, payload),
994
+ onSuccess: () => {
995
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
996
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
997
+ }
998
+ });
999
+ } catch (error) {
1000
+ logger.warn("[useRegister] Called outside QueryClientProvider, returning no-op mutation");
1001
+ return { mutate: () => {
1002
+ }, mutateAsync: () => Promise.resolve(void 0) };
1003
+ }
1004
+ }
1005
+ function useUpdateProfile(config, accessToken) {
1006
+ const ctx = useSdkContext();
1007
+ try {
1008
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1009
+ const queryClient = (0, import_react_query3.useQueryClient)();
1010
+ return (0, import_react_query3.useMutation)({
1011
+ mutationFn: (payload) => token ? updateProfile(cfg, token, payload) : Promise.reject("No access token"),
1012
+ onSuccess: () => {
1013
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
1014
+ }
1015
+ });
1016
+ } catch (error) {
1017
+ logger.warn("[useUpdateProfile] Called outside QueryClientProvider, returning no-op mutation");
1018
+ return { mutate: () => {
1019
+ }, mutateAsync: () => Promise.resolve(void 0) };
1020
+ }
1021
+ }
1022
+ function useLogout(config, refreshToken) {
1023
+ const ctx = useSdkContext();
1024
+ try {
1025
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1026
+ const queryClient = (0, import_react_query3.useQueryClient)();
1027
+ return (0, import_react_query3.useMutation)({
1028
+ mutationFn: () => logout(cfg, refreshToken),
1029
+ onSuccess: () => {
1030
+ queryClient.clear();
1031
+ }
1032
+ });
1033
+ } catch (error) {
1034
+ logger.warn("[useLogout] Called outside QueryClientProvider, returning no-op mutation");
1035
+ return { mutate: () => {
1036
+ }, mutateAsync: () => Promise.resolve(void 0) };
1037
+ }
1038
+ }
1039
+
1040
+ // src/hooks/use-countries.ts
1041
+ var import_react_query4 = require("@tanstack/react-query");
1042
+ async function getCountries(config) {
1043
+ const response = await fetch(`${config.backendUrls.auth}/auth/countries/`, {
1044
+ headers: {
1045
+ "X-Storefront-Key": config.storefrontApiKey,
1046
+ "X-Business-ID": config.businessId
1047
+ }
1048
+ });
1049
+ if (!response.ok) throw new Error("Failed to fetch countries");
1050
+ return response.json();
1051
+ }
1052
+ function useCountries(config) {
1053
+ const ctx = useSdkContext();
1054
+ try {
1055
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1056
+ return (0, import_react_query4.useQuery)({
1057
+ queryKey: ["countries"],
1058
+ queryFn: () => getCountries(cfg),
1059
+ retry: 1,
1060
+ refetchOnWindowFocus: false,
1061
+ refetchOnReconnect: false,
1062
+ staleTime: 24 * 60 * 60 * 1e3
1063
+ });
1064
+ } catch (error) {
1065
+ logger.warn("[useCountries] Called outside QueryClientProvider, returning empty list");
1066
+ return {
1067
+ data: [],
1068
+ isLoading: false,
1069
+ error: null,
1070
+ isFetching: false,
1071
+ refetch: () => Promise.resolve({ data: [] })
1072
+ };
1073
+ }
1074
+ }
1075
+
1076
+ // src/hooks/use-states.ts
1077
+ var import_react_query5 = require("@tanstack/react-query");
1078
+ async function getStates(config, countryIso) {
1079
+ if (!countryIso) return [];
1080
+ const response = await fetch(`${config.backendUrls.auth}/auth/countries/?iso=${countryIso}`, {
1081
+ headers: {
1082
+ "X-Storefront-Key": config.storefrontApiKey,
1083
+ "X-Business-ID": config.businessId
1084
+ }
1085
+ });
1086
+ if (!response.ok) throw new Error("Failed to fetch states");
1087
+ return response.json();
1088
+ }
1089
+ function useStates(countryIso, config) {
1090
+ const ctx = useSdkContext();
1091
+ try {
1092
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1093
+ return (0, import_react_query5.useQuery)({
1094
+ queryKey: ["states", countryIso],
1095
+ queryFn: () => getStates(cfg, countryIso),
1096
+ enabled: !!countryIso,
1097
+ retry: 1,
1098
+ refetchOnWindowFocus: false,
1099
+ refetchOnReconnect: false,
1100
+ staleTime: 24 * 60 * 60 * 1e3
1101
+ });
1102
+ } catch (error) {
1103
+ logger.warn("[useStates] Called outside QueryClientProvider, returning empty list");
1104
+ return {
1105
+ data: [],
1106
+ isLoading: false,
1107
+ error: null,
1108
+ isFetching: false,
1109
+ refetch: () => Promise.resolve({ data: [] })
1110
+ };
1111
+ }
1112
+ }
1113
+
1114
+ // src/hooks/use-languages.ts
1115
+ var import_react_query6 = require("@tanstack/react-query");
1116
+
1117
+ // src/services/config.service.ts
1118
+ async function getSupportedLanguages(config) {
1119
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-languages`, {
1120
+ headers: {
1121
+ "X-Storefront-Key": config.storefrontApiKey,
1122
+ "X-Business-ID": config.businessId
1123
+ }
1124
+ });
1125
+ if (!response.ok) throw new Error("Failed to get supported languages");
1126
+ return response.json();
1127
+ }
1128
+ async function getSupportedCurrencies(config) {
1129
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-currencies`, {
1130
+ headers: {
1131
+ "X-Storefront-Key": config.storefrontApiKey,
1132
+ "X-Business-ID": config.businessId
1133
+ }
1134
+ });
1135
+ if (!response.ok) throw new Error("Failed to get supported currencies");
1136
+ return response.json();
1137
+ }
1138
+
1139
+ // src/hooks/use-languages.ts
1140
+ async function getSupportedLanguagesList(config) {
1141
+ const data = await getSupportedLanguages(config);
1142
+ return (data.languages || []).map((language) => ({
1143
+ code: language.code,
1144
+ appCode: language.code,
1145
+ label: language.label,
1146
+ native: language.label,
1147
+ flag: language.flag
1148
+ }));
1149
+ }
1150
+ function useSupportedLanguages(config) {
1151
+ const ctx = useSdkContext();
1152
+ try {
1153
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1154
+ return (0, import_react_query6.useQuery)({
1155
+ queryKey: ["supported-languages"],
1156
+ queryFn: () => getSupportedLanguagesList(cfg),
1157
+ retry: 1,
1158
+ ...getCacheTier("high")
1159
+ });
1160
+ } catch {
1161
+ return {
1162
+ data: [],
1163
+ isLoading: false,
1164
+ error: null,
1165
+ isFetching: false,
1166
+ isPending: false,
1167
+ isError: false,
1168
+ isSuccess: true,
1169
+ status: "success",
1170
+ fetchStatus: "idle",
1171
+ refetch: async () => ({
1172
+ data: [],
1173
+ isLoading: false,
1174
+ error: null,
1175
+ isFetching: false,
1176
+ isPending: false,
1177
+ isError: false,
1178
+ isSuccess: true,
1179
+ status: "success",
1180
+ fetchStatus: "idle"
1181
+ })
1182
+ };
1183
+ }
1184
+ }
1185
+
1186
+ // src/hooks/use-currencies.ts
1187
+ var import_react_query7 = require("@tanstack/react-query");
1188
+ async function getSupportedCurrenciesList(config) {
1189
+ const data = await getSupportedCurrencies(config);
1190
+ return data.currencies || [];
1191
+ }
1192
+ function useCurrencies(config) {
1193
+ const ctx = useSdkContext();
1194
+ try {
1195
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1196
+ return (0, import_react_query7.useQuery)({
1197
+ queryKey: ["supported-currencies"],
1198
+ queryFn: () => getSupportedCurrenciesList(cfg),
1199
+ retry: 1,
1200
+ ...getCacheTier("high")
1201
+ });
1202
+ } catch (error) {
1203
+ logger.warn("[useCurrencies] Called outside QueryClientProvider, returning empty list");
1204
+ return {
1205
+ data: [],
1206
+ isLoading: false,
1207
+ error: null,
1208
+ isFetching: false,
1209
+ refetch: () => Promise.resolve({ data: [] })
1210
+ };
1211
+ }
1212
+ }
1213
+
1214
+ // src/hooks/use-bespoke-availability.ts
1215
+ var import_react_query8 = require("@tanstack/react-query");
1216
+
1217
+ // src/services/bespoke.service.ts
1218
+ async function checkAvailability(config, product_id) {
1219
+ const response = await fetch(`${config.backendUrls.store}/bespoke/availability/${product_id}`, {
1220
+ headers: {
1221
+ "X-Storefront-Key": config.storefrontApiKey,
1222
+ "X-Business-ID": config.businessId
1223
+ }
1224
+ });
1225
+ if (!response.ok) throw new Error("Failed to check bespoke availability");
1226
+ return response.json();
1227
+ }
1228
+
1229
+ // src/hooks/use-bespoke-availability.ts
1230
+ function useBespokeAvailability(product_id, config) {
1231
+ const ctx = useSdkContext();
1232
+ try {
1233
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
1234
+ return (0, import_react_query8.useQuery)({
1235
+ queryKey: ["bespoke-availability", product_id],
1236
+ queryFn: () => checkAvailability(cfg, product_id),
1237
+ enabled: !!product_id,
1238
+ retry: false
1239
+ });
1240
+ } catch (error) {
1241
+ logger.warn("[useBespokeAvailability] Called outside QueryClientProvider, returning undefined");
1242
+ return {
1243
+ data: void 0,
1244
+ isLoading: false,
1245
+ error: null,
1246
+ isFetching: false,
1247
+ refetch: () => Promise.resolve({ data: void 0 })
1248
+ };
1249
+ }
1250
+ }
1251
+
1252
+ // src/hooks/use-collections.ts
1253
+ var import_react_query9 = require("@tanstack/react-query");
1254
+ var collectionKeys = {
1255
+ all: ["core", "collections"],
1256
+ list: (params) => ["core", "collections", "list", params ?? {}],
1257
+ slug: (slug) => ["core", "collections", "slug", slug]
1258
+ };
1259
+ function useStorefrontCollections(params) {
1260
+ try {
1261
+ const queryParams = new URLSearchParams();
1262
+ if (params?.page) queryParams.set("page", params.page.toString());
1263
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1264
+ return (0, import_react_query9.useQuery)({
1265
+ queryKey: collectionKeys.list(params),
1266
+ queryFn: async () => {
1267
+ const response = await fetch(`/api/collections?${queryParams.toString()}`);
1268
+ if (!response.ok) throw new Error("Failed to fetch collections");
1269
+ return response.json();
1270
+ },
1271
+ // medium — collections change infrequently
1272
+ ...getCacheTier("medium")
1273
+ });
1274
+ } catch (error) {
1275
+ logger.warn("[useStorefrontCollections] Called outside QueryClientProvider, returning empty list");
1276
+ return {
1277
+ data: void 0,
1278
+ isLoading: false,
1279
+ error: null,
1280
+ isFetching: false,
1281
+ refetch: () => Promise.resolve({ data: void 0 })
1282
+ };
1283
+ }
1284
+ }
1285
+ function useStorefrontCollection(slug) {
1286
+ try {
1287
+ return (0, import_react_query9.useQuery)({
1288
+ queryKey: collectionKeys.slug(slug),
1289
+ queryFn: async () => {
1290
+ const response = await fetch(`/api/collections/${slug}`);
1291
+ if (!response.ok) throw new Error("Failed to fetch collection");
1292
+ return response.json();
1293
+ },
1294
+ // medium — collection details change infrequently
1295
+ ...getCacheTier("medium"),
1296
+ enabled: !!slug
1297
+ });
1298
+ } catch (error) {
1299
+ logger.warn("[useStorefrontCollection] Called outside QueryClientProvider, returning undefined");
1300
+ return {
1301
+ data: void 0,
1302
+ isLoading: false,
1303
+ error: null,
1304
+ isFetching: false,
1305
+ refetch: () => Promise.resolve({ data: void 0 })
1306
+ };
1307
+ }
1308
+ }
1309
+
1310
+ // src/hooks/use-products.ts
1311
+ var import_react_query10 = require("@tanstack/react-query");
1312
+ var productKeys = {
1313
+ all: ["products"],
1314
+ list: (params) => [...productKeys.all, "list", params],
1315
+ detail: (slug) => [...productKeys.all, "detail", slug],
1316
+ recommended: (params) => [...productKeys.all, "recommended", params],
1317
+ latest: (params) => [...productKeys.all, "latest", params],
1318
+ popular: (params) => [...productKeys.all, "popular", params],
1319
+ featured: (params) => [...productKeys.all, "featured", params],
1320
+ new: (params) => [...productKeys.all, "new", params],
1321
+ onSale: (params) => [...productKeys.all, "onSale", params],
1322
+ lowStock: (params) => [...productKeys.all, "lowStock", params]
1323
+ };
1324
+ function useLatestProducts(params) {
1325
+ try {
1326
+ const queryParams = new URLSearchParams();
1327
+ if (params?.page) queryParams.set("page", params.page.toString());
1328
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1329
+ return (0, import_react_query10.useQuery)({
1330
+ queryKey: productKeys.latest(params),
1331
+ queryFn: async () => {
1332
+ const response = await fetch(`/api/products/latest?${queryParams.toString()}`);
1333
+ if (!response.ok) throw new Error("Failed to fetch latest products");
1334
+ return response.json();
1335
+ },
1336
+ // medium — latest products change infrequently
1337
+ ...getCacheTier("medium")
1338
+ });
1339
+ } catch (error) {
1340
+ logger.warn("[useLatestProducts] Called outside QueryClientProvider, returning empty list");
1341
+ return {
1342
+ data: void 0,
1343
+ isLoading: false,
1344
+ error: null,
1345
+ isFetching: false,
1346
+ refetch: () => Promise.resolve({ data: void 0 })
1347
+ };
1348
+ }
1349
+ }
1350
+ function usePopularProducts(params) {
1351
+ try {
1352
+ const queryParams = new URLSearchParams();
1353
+ if (params?.page) queryParams.set("page", params.page.toString());
1354
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1355
+ return (0, import_react_query10.useQuery)({
1356
+ queryKey: productKeys.popular(params),
1357
+ queryFn: async () => {
1358
+ const response = await fetch(`/api/products/popular?${queryParams.toString()}`);
1359
+ if (!response.ok) throw new Error("Failed to fetch popular products");
1360
+ return response.json();
1361
+ },
1362
+ // medium — popular products change infrequently
1363
+ ...getCacheTier("medium")
1364
+ });
1365
+ } catch (error) {
1366
+ logger.warn("[usePopularProducts] Called outside QueryClientProvider, returning empty list");
1367
+ return {
1368
+ data: void 0,
1369
+ isLoading: false,
1370
+ error: null,
1371
+ isFetching: false,
1372
+ refetch: () => Promise.resolve({ data: void 0 })
1373
+ };
1374
+ }
1375
+ }
1376
+ function useFeaturedProducts(params) {
1377
+ try {
1378
+ const queryParams = new URLSearchParams();
1379
+ if (params?.page) queryParams.set("page", params.page.toString());
1380
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1381
+ return (0, import_react_query10.useQuery)({
1382
+ queryKey: productKeys.featured(params),
1383
+ queryFn: async () => {
1384
+ const response = await fetch(`/api/products/featured?${queryParams.toString()}`);
1385
+ if (!response.ok) throw new Error("Failed to fetch featured products");
1386
+ return response.json();
1387
+ },
1388
+ // medium — featured products change infrequently
1389
+ ...getCacheTier("medium")
1390
+ });
1391
+ } catch (error) {
1392
+ logger.warn("[useFeaturedProducts] Called outside QueryClientProvider, returning empty list");
1393
+ return {
1394
+ data: void 0,
1395
+ isLoading: false,
1396
+ error: null,
1397
+ isFetching: false,
1398
+ refetch: () => Promise.resolve({ data: void 0 })
1399
+ };
1400
+ }
1401
+ }
1402
+ function useNewProducts(params) {
1403
+ try {
1404
+ const queryParams = new URLSearchParams();
1405
+ if (params?.page) queryParams.set("page", params.page.toString());
1406
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1407
+ return (0, import_react_query10.useQuery)({
1408
+ queryKey: productKeys.new(params),
1409
+ queryFn: async () => {
1410
+ const response = await fetch(`/api/products/new?${queryParams.toString()}`);
1411
+ if (!response.ok) throw new Error("Failed to fetch new products");
1412
+ return response.json();
1413
+ },
1414
+ // medium — new products change infrequently
1415
+ ...getCacheTier("medium")
1416
+ });
1417
+ } catch (error) {
1418
+ logger.warn("[useNewProducts] Called outside QueryClientProvider, returning empty list");
1419
+ return {
1420
+ data: void 0,
1421
+ isLoading: false,
1422
+ error: null,
1423
+ isFetching: false,
1424
+ refetch: () => Promise.resolve({ data: void 0 })
1425
+ };
1426
+ }
1427
+ }
1428
+ function useOnSaleProducts(params) {
1429
+ try {
1430
+ const queryParams = new URLSearchParams();
1431
+ if (params?.page) queryParams.set("page", params.page.toString());
1432
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1433
+ return (0, import_react_query10.useQuery)({
1434
+ queryKey: productKeys.onSale(params),
1435
+ queryFn: async () => {
1436
+ const response = await fetch(`/api/products/on-sale?${queryParams.toString()}`);
1437
+ if (!response.ok) throw new Error("Failed to fetch on-sale products");
1438
+ return response.json();
1439
+ },
1440
+ // medium — sale products change infrequently
1441
+ ...getCacheTier("medium")
1442
+ });
1443
+ } catch (error) {
1444
+ logger.warn("[useOnSaleProducts] Called outside QueryClientProvider, returning empty list");
1445
+ return {
1446
+ data: void 0,
1447
+ isLoading: false,
1448
+ error: null,
1449
+ isFetching: false,
1450
+ refetch: () => Promise.resolve({ data: void 0 })
1451
+ };
1452
+ }
1453
+ }
1454
+ function useLowStockProducts(params) {
1455
+ try {
1456
+ const queryParams = new URLSearchParams();
1457
+ if (params?.page) queryParams.set("page", params.page.toString());
1458
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1459
+ return (0, import_react_query10.useQuery)({
1460
+ queryKey: productKeys.lowStock(params),
1461
+ queryFn: async () => {
1462
+ const response = await fetch(`/api/products/low-stock?${queryParams.toString()}`);
1463
+ if (!response.ok) throw new Error("Failed to fetch low-stock products");
1464
+ return response.json();
1465
+ },
1466
+ // low — low stock status changes frequently
1467
+ ...getCacheTier("low")
1468
+ });
1469
+ } catch (error) {
1470
+ logger.warn("[useLowStockProducts] Called outside QueryClientProvider, returning empty list");
1471
+ return {
1472
+ data: void 0,
1473
+ isLoading: false,
1474
+ error: null,
1475
+ isFetching: false,
1476
+ refetch: () => Promise.resolve({ data: void 0 })
1477
+ };
1478
+ }
1479
+ }
1480
+ function useStorefrontProducts(params) {
1481
+ try {
1482
+ const queryParams = new URLSearchParams();
1483
+ if (params?.page) queryParams.set("page", params.page.toString());
1484
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1485
+ if (params?.collectionSlug) queryParams.set("collectionSlug", params.collectionSlug);
1486
+ if (params?.search) queryParams.set("search", params.search);
1487
+ return (0, import_react_query10.useQuery)({
1488
+ queryKey: productKeys.list(params),
1489
+ queryFn: async () => {
1490
+ const response = await fetch(`/api/products?${queryParams.toString()}`);
1491
+ if (!response.ok) throw new Error("Failed to fetch products");
1492
+ return response.json();
1493
+ },
1494
+ // medium — product catalog changes infrequently
1495
+ ...getCacheTier("medium")
1496
+ });
1497
+ } catch (error) {
1498
+ logger.warn("[useStorefrontProducts] Called outside QueryClientProvider, returning empty list");
1499
+ return {
1500
+ data: void 0,
1501
+ isLoading: false,
1502
+ error: null,
1503
+ isFetching: false,
1504
+ refetch: () => Promise.resolve({ data: void 0 })
1505
+ };
1506
+ }
1507
+ }
1508
+ function useProduct(slug) {
1509
+ try {
1510
+ return (0, import_react_query10.useQuery)({
1511
+ queryKey: productKeys.detail(slug),
1512
+ queryFn: async () => {
1513
+ const response = await fetch(`/api/products/${slug}`);
1514
+ if (!response.ok) throw new Error("Failed to fetch product");
1515
+ return response.json();
1516
+ },
1517
+ // medium — product details change infrequently
1518
+ ...getCacheTier("medium"),
1519
+ enabled: !!slug
1520
+ });
1521
+ } catch (error) {
1522
+ logger.warn("[useProduct] Called outside QueryClientProvider, returning undefined");
1523
+ return {
1524
+ data: void 0,
1525
+ isLoading: false,
1526
+ error: null,
1527
+ isFetching: false,
1528
+ refetch: () => Promise.resolve({ data: void 0 })
1529
+ };
1530
+ }
1531
+ }
1532
+ function useRecommendedProducts(params) {
1533
+ try {
1534
+ const queryParams = new URLSearchParams();
1535
+ if (params?.page) queryParams.set("page", params.page.toString());
1536
+ if (params?.pageSize) queryParams.set("pageSize", params.pageSize.toString());
1537
+ if (params?.excludeProductId) queryParams.set("excludeProductId", params.excludeProductId);
1538
+ return (0, import_react_query10.useQuery)({
1539
+ queryKey: productKeys.recommended(params),
1540
+ queryFn: async () => {
1541
+ const response = await fetch(`/api/products/recommended?${queryParams.toString()}`);
1542
+ if (!response.ok) throw new Error("Failed to fetch recommended products");
1543
+ return response.json();
1544
+ },
1545
+ // medium — recommendations change infrequently
1546
+ ...getCacheTier("medium")
1547
+ });
1548
+ } catch (error) {
1549
+ logger.warn("[useRecommendedProducts] Called outside QueryClientProvider, returning empty list");
1550
+ return {
1551
+ data: void 0,
1552
+ isLoading: false,
1553
+ error: null,
1554
+ isFetching: false,
1555
+ refetch: () => Promise.resolve({ data: void 0 })
1556
+ };
1557
+ }
1558
+ }
1559
+
1560
+ // src/hooks/use-wishlist.ts
1561
+ var import_react_query11 = require("@tanstack/react-query");
1562
+
1563
+ // src/services/wishlist.service.ts
1564
+ var import_graphql_request = require("graphql-request");
1565
+ var GET_STOREFRONT_WISHLIST = `
1566
+ query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
1567
+ storefront_wishlist(page: $page, pageSize: $pageSize) {
1568
+ items {
1569
+ id
1570
+ product_id
1571
+ notes
1572
+ created_at
1573
+ product_name
1574
+ product_slug
1575
+ product_price
1576
+ currency
1577
+ product_image
1578
+ }
1579
+ total
1580
+ page
1581
+ page_size
1582
+ total_pages
1583
+ }
1584
+ }
1585
+ `;
1586
+ var CHECK_IN_STOREFRONT_WISHLIST = `
1587
+ query CheckInStorefrontWishlist($productId: String!) {
1588
+ check_in_storefront_wishlist(productId: $productId) {
1589
+ in_wishlist
1590
+ }
1591
+ }
1592
+ `;
1593
+ function createGraphQLClient(config, accessToken) {
1594
+ const headers = {
1595
+ "Content-Type": "application/json",
1596
+ "Accept": "application/json",
1597
+ "X-Storefront-Key": config.storefrontApiKey,
1598
+ "X-Business-ID": config.businessId
1599
+ };
1600
+ if (accessToken) {
1601
+ headers["Authorization"] = `Bearer ${accessToken}`;
1602
+ }
1603
+ return new import_graphql_request.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
1604
+ }
1605
+ async function getWishlist(config, accessToken, params) {
1606
+ const client = createGraphQLClient(config, accessToken);
1607
+ const variables = {
1608
+ page: params?.page || 1,
1609
+ pageSize: params?.pageSize || 20
1610
+ };
1611
+ const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
1612
+ return data.storefront_wishlist;
1613
+ }
1614
+ async function checkInWishlist(config, accessToken, productId) {
1615
+ const client = createGraphQLClient(config, accessToken);
1616
+ const data = await client.request(CHECK_IN_STOREFRONT_WISHLIST, { productId });
1617
+ return data.check_in_storefront_wishlist;
1618
+ }
1619
+ async function addToWishlist(config, accessToken, productId, notes) {
1620
+ const response = await fetch(`${config.backendUrls.store}/wishlist/`, {
1621
+ method: "POST",
1622
+ headers: {
1623
+ "Content-Type": "application/json",
1624
+ "Authorization": `Bearer ${accessToken}`,
1625
+ "X-Storefront-Key": config.storefrontApiKey,
1626
+ "X-Business-ID": config.businessId
1627
+ },
1628
+ body: JSON.stringify({
1629
+ product_id: productId,
1630
+ notes: notes || void 0
1631
+ })
1632
+ });
1633
+ if (!response.ok) throw new Error("Failed to add to wishlist");
1634
+ return response.json();
1635
+ }
1636
+ async function removeFromWishlist(config, accessToken, itemId) {
1637
+ const response = await fetch(`${config.backendUrls.store}/wishlist/${itemId}`, {
1638
+ method: "DELETE",
1639
+ headers: {
1640
+ "Authorization": `Bearer ${accessToken}`,
1641
+ "X-Storefront-Key": config.storefrontApiKey,
1642
+ "X-Business-ID": config.businessId
1643
+ }
1644
+ });
1645
+ if (!response.ok) throw new Error("Failed to remove from wishlist");
1646
+ }
1647
+ async function removeProductFromWishlist(config, accessToken, productId) {
1648
+ const response = await fetch(`${config.backendUrls.store}/wishlist/product/${productId}`, {
1649
+ method: "DELETE",
1650
+ headers: {
1651
+ "Authorization": `Bearer ${accessToken}`,
1652
+ "X-Storefront-Key": config.storefrontApiKey,
1653
+ "X-Business-ID": config.businessId
1654
+ }
1655
+ });
1656
+ if (!response.ok) throw new Error("Failed to remove product from wishlist");
1657
+ }
1658
+
1659
+ // src/hooks/use-wishlist.ts
1660
+ var wishlistKeys = {
1661
+ all: ["wishlist"],
1662
+ list: () => [...wishlistKeys.all, "list"],
1663
+ check: (productId) => [...wishlistKeys.all, "check", productId]
1664
+ };
1665
+ function useWishlist(arg1, arg2, arg3) {
1666
+ const ctx = useSdkContext();
1667
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
1668
+ const explicitConfig = isArg1Config ? arg1 : void 0;
1669
+ const explicitToken = isArg1Config ? arg2 : void 0;
1670
+ const params = isArg1Config ? arg3 : arg1;
1671
+ try {
1672
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
1673
+ return (0, import_react_query11.useQuery)({
1674
+ queryKey: [...wishlistKeys.list(), params],
1675
+ queryFn: () => token ? getWishlist(cfg, token, params) : Promise.resolve(void 0),
1676
+ enabled: !!token,
1677
+ ...getCacheTier("medium")
1678
+ });
1679
+ } catch (error) {
1680
+ console.warn("[useWishlist] Called outside QueryClientProvider, returning empty wishlist");
1681
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
1682
+ }
1683
+ }
1684
+ function useCheckInWishlist(arg1, arg2, arg3) {
1685
+ const ctx = useSdkContext();
1686
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
1687
+ const explicitConfig = isArg1Config ? arg1 : void 0;
1688
+ const explicitToken = isArg1Config ? arg2 : void 0;
1689
+ const productId = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
1690
+ try {
1691
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
1692
+ return (0, import_react_query11.useQuery)({
1693
+ queryKey: wishlistKeys.check(productId ?? ""),
1694
+ queryFn: () => token && productId ? checkInWishlist(cfg, token, productId) : Promise.resolve({ in_wishlist: false }),
1695
+ ...getCacheTier("low"),
1696
+ enabled: !!productId && !!token
1697
+ });
1698
+ } catch (error) {
1699
+ console.warn("[useCheckInWishlist] Called outside QueryClientProvider, returning false");
1700
+ return { data: false, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: false }) };
1701
+ }
1702
+ }
1703
+ function useAddToWishlist(config, accessToken) {
1704
+ const ctx = useSdkContext();
1705
+ try {
1706
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1707
+ const queryClient = (0, import_react_query11.useQueryClient)();
1708
+ return (0, import_react_query11.useMutation)({
1709
+ mutationFn: ({ productId, notes }) => token ? addToWishlist(cfg, token, productId, notes) : Promise.reject("No access token"),
1710
+ onSuccess: () => {
1711
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
1712
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
1713
+ }
1714
+ });
1715
+ } catch (error) {
1716
+ console.warn("[useAddToWishlist] Called outside QueryClientProvider, returning no-op mutation");
1717
+ return { mutate: () => {
1718
+ }, mutateAsync: () => Promise.resolve(void 0) };
1719
+ }
1720
+ }
1721
+ function useRemoveFromWishlist(config, accessToken) {
1722
+ const ctx = useSdkContext();
1723
+ try {
1724
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1725
+ const queryClient = (0, import_react_query11.useQueryClient)();
1726
+ return (0, import_react_query11.useMutation)({
1727
+ mutationFn: (itemId) => token ? removeFromWishlist(cfg, token, itemId) : Promise.reject("No access token"),
1728
+ onSuccess: () => {
1729
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
1730
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
1731
+ }
1732
+ });
1733
+ } catch (error) {
1734
+ console.warn("[useRemoveFromWishlist] Called outside QueryClientProvider, returning no-op mutation");
1735
+ return { mutate: () => {
1736
+ }, mutateAsync: () => Promise.resolve(void 0) };
1737
+ }
1738
+ }
1739
+ function useRemoveProductFromWishlist(config, accessToken) {
1740
+ const ctx = useSdkContext();
1741
+ try {
1742
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1743
+ const queryClient = (0, import_react_query11.useQueryClient)();
1744
+ return (0, import_react_query11.useMutation)({
1745
+ mutationFn: (productId) => token ? removeProductFromWishlist(cfg, token, productId) : Promise.reject("No access token"),
1746
+ onSuccess: () => {
1747
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
1748
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
1749
+ }
1750
+ });
1751
+ } catch (error) {
1752
+ console.warn("[useRemoveProductFromWishlist] Called outside QueryClientProvider, returning no-op mutation");
1753
+ return { mutate: () => {
1754
+ }, mutateAsync: () => Promise.resolve(void 0) };
1755
+ }
1756
+ }
1757
+
1758
+ // src/hooks/use-service-booking.ts
1759
+ var import_react_query12 = require("@tanstack/react-query");
1760
+
1761
+ // src/services/service-booking.service.ts
1762
+ async function getAvailableSlots(config, product_id, date_from, date_to) {
1763
+ const response = await fetch(
1764
+ `${config.backendUrls.store}/service/available-slots/${product_id}?date_from=${date_from}&date_to=${date_to}`,
1765
+ {
1766
+ headers: {
1767
+ "X-Storefront-Key": config.storefrontApiKey,
1768
+ "X-Business-ID": config.businessId
1769
+ }
1770
+ }
1771
+ );
1772
+ if (!response.ok) throw new Error("Failed to get available slots");
1773
+ return response.json();
1774
+ }
1775
+ async function bookAppointment(config, accessToken, payload) {
1776
+ const response = await fetch(`${config.backendUrls.store}/service/appointments/`, {
1777
+ method: "POST",
1778
+ headers: {
1779
+ "Content-Type": "application/json",
1780
+ "Authorization": `Bearer ${accessToken}`,
1781
+ "X-Storefront-Key": config.storefrontApiKey,
1782
+ "X-Business-ID": config.businessId
1783
+ },
1784
+ body: JSON.stringify(payload)
1785
+ });
1786
+ if (!response.ok) throw new Error("Failed to book appointment");
1787
+ return response.json();
1788
+ }
1789
+ async function getAppointments(config, accessToken) {
1790
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/my`, {
1791
+ headers: {
1792
+ "Authorization": `Bearer ${accessToken}`,
1793
+ "X-Storefront-Key": config.storefrontApiKey,
1794
+ "X-Business-ID": config.businessId
1795
+ }
1796
+ });
1797
+ if (!response.ok) throw new Error("Failed to get appointments");
1798
+ return response.json();
1799
+ }
1800
+ async function getAppointment(config, accessToken, id) {
1801
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1802
+ headers: {
1803
+ "Authorization": `Bearer ${accessToken}`,
1804
+ "X-Storefront-Key": config.storefrontApiKey,
1805
+ "X-Business-ID": config.businessId
1806
+ }
1807
+ });
1808
+ if (!response.ok) throw new Error("Failed to get appointment");
1809
+ return response.json();
1810
+ }
1811
+ async function cancelAppointment(config, accessToken, id) {
1812
+ await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1813
+ method: "DELETE",
1814
+ headers: {
1815
+ "Authorization": `Bearer ${accessToken}`,
1816
+ "X-Storefront-Key": config.storefrontApiKey,
1817
+ "X-Business-ID": config.businessId
1818
+ }
1819
+ });
1820
+ }
1821
+ async function getDeliverables(config, accessToken, order_id) {
1822
+ const response = await fetch(`${config.backendUrls.store}/service/projects/${order_id}/deliverables/`, {
1823
+ headers: {
1824
+ "Authorization": `Bearer ${accessToken}`,
1825
+ "X-Storefront-Key": config.storefrontApiKey,
1826
+ "X-Business-ID": config.businessId
1827
+ }
1828
+ });
1829
+ if (!response.ok) throw new Error("Failed to get deliverables");
1830
+ return response.json();
1831
+ }
1832
+ async function approveDeliverable(config, accessToken, order_id, deliverable_id) {
1833
+ const response = await fetch(
1834
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
1835
+ {
1836
+ method: "POST",
1837
+ headers: {
1838
+ "Content-Type": "application/json",
1839
+ "Authorization": `Bearer ${accessToken}`,
1840
+ "X-Storefront-Key": config.storefrontApiKey,
1841
+ "X-Business-ID": config.businessId
1842
+ },
1843
+ body: JSON.stringify({ approved: true })
1844
+ }
1845
+ );
1846
+ if (!response.ok) throw new Error("Failed to approve deliverable");
1847
+ return response.json();
1848
+ }
1849
+ async function requestRevision(config, accessToken, order_id, deliverable_id, feedback) {
1850
+ const response = await fetch(
1851
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
1852
+ {
1853
+ method: "POST",
1854
+ headers: {
1855
+ "Content-Type": "application/json",
1856
+ "Authorization": `Bearer ${accessToken}`,
1857
+ "X-Storefront-Key": config.storefrontApiKey,
1858
+ "X-Business-ID": config.businessId
1859
+ },
1860
+ body: JSON.stringify({ approved: false, feedback })
1861
+ }
1862
+ );
1863
+ if (!response.ok) throw new Error("Failed to request revision");
1864
+ return response.json();
1865
+ }
1866
+
1867
+ // src/hooks/use-service-booking.ts
1868
+ function useAvailableSlots(arg1, arg2, arg3, arg4) {
1869
+ const ctx = useSdkContext();
1870
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
1871
+ const explicitConfig = isArg1Config ? arg1 : void 0;
1872
+ const product_id = isArg1Config ? arg2 : typeof arg1 === "string" ? arg1 : void 0;
1873
+ const date_from = isArg1Config ? arg3 : typeof arg2 === "string" ? arg2 : void 0;
1874
+ const date_to = isArg1Config ? arg4 : typeof arg3 === "string" ? arg3 : void 0;
1875
+ try {
1876
+ const { config: cfg } = resolveHookArgs(explicitConfig, void 0, ctx);
1877
+ return (0, import_react_query12.useQuery)({
1878
+ queryKey: ["available-slots", product_id, date_from, date_to],
1879
+ queryFn: () => getAvailableSlots(cfg, product_id, date_from, date_to),
1880
+ enabled: !!product_id && !!date_from && !!date_to
1881
+ });
1882
+ } catch (error) {
1883
+ logger.warn("[useAvailableSlots] Called outside QueryClientProvider, returning undefined");
1884
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
1885
+ }
1886
+ }
1887
+ function useBookAppointment(config, accessToken) {
1888
+ const ctx = useSdkContext();
1889
+ try {
1890
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1891
+ const queryClient = (0, import_react_query12.useQueryClient)();
1892
+ return (0, import_react_query12.useMutation)({
1893
+ mutationFn: (payload) => token ? bookAppointment(cfg, token, payload) : Promise.reject("No access token"),
1894
+ onSuccess: () => {
1895
+ queryClient.invalidateQueries({ queryKey: ["appointments"] });
1896
+ }
1897
+ });
1898
+ } catch (error) {
1899
+ logger.warn("[useBookAppointment] Called outside QueryClientProvider, returning no-op mutation");
1900
+ return { mutate: () => {
1901
+ }, mutateAsync: () => Promise.resolve(void 0) };
1902
+ }
1903
+ }
1904
+ function useAppointments(config, accessToken) {
1905
+ const ctx = useSdkContext();
1906
+ try {
1907
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1908
+ return (0, import_react_query12.useQuery)({
1909
+ queryKey: ["appointments"],
1910
+ queryFn: () => token ? getAppointments(cfg, token) : Promise.resolve([]),
1911
+ enabled: !!token
1912
+ });
1913
+ } catch (error) {
1914
+ logger.warn("[useAppointments] Called outside QueryClientProvider, returning empty list");
1915
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
1916
+ }
1917
+ }
1918
+ function useAppointment(arg1, arg2, arg3) {
1919
+ const ctx = useSdkContext();
1920
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
1921
+ const explicitConfig = isArg1Config ? arg1 : void 0;
1922
+ const explicitToken = isArg1Config ? arg2 : void 0;
1923
+ const id = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
1924
+ try {
1925
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
1926
+ return (0, import_react_query12.useQuery)({
1927
+ queryKey: ["appointment", id],
1928
+ queryFn: () => token && id ? getAppointment(cfg, token, id) : Promise.resolve(void 0),
1929
+ enabled: !!id && !!token
1930
+ });
1931
+ } catch (error) {
1932
+ logger.warn("[useAppointment] Called outside QueryClientProvider, returning undefined");
1933
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
1934
+ }
1935
+ }
1936
+ function useCancelAppointment(config, accessToken) {
1937
+ const ctx = useSdkContext();
1938
+ try {
1939
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1940
+ const queryClient = (0, import_react_query12.useQueryClient)();
1941
+ return (0, import_react_query12.useMutation)({
1942
+ mutationFn: (id) => token ? cancelAppointment(cfg, token, id) : Promise.reject("No access token"),
1943
+ onSuccess: () => {
1944
+ queryClient.invalidateQueries({ queryKey: ["appointments"] });
1945
+ }
1946
+ });
1947
+ } catch (error) {
1948
+ logger.warn("[useCancelAppointment] Called outside QueryClientProvider, returning no-op mutation");
1949
+ return { mutate: () => {
1950
+ }, mutateAsync: () => Promise.resolve(void 0) };
1951
+ }
1952
+ }
1953
+ function useDeliverables(arg1, arg2, arg3) {
1954
+ const ctx = useSdkContext();
1955
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
1956
+ const explicitConfig = isArg1Config ? arg1 : void 0;
1957
+ const explicitToken = isArg1Config ? arg2 : void 0;
1958
+ const order_id = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
1959
+ try {
1960
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
1961
+ return (0, import_react_query12.useQuery)({
1962
+ queryKey: ["deliverables", order_id],
1963
+ queryFn: () => token && order_id ? getDeliverables(cfg, token, order_id) : Promise.resolve([]),
1964
+ enabled: !!order_id && !!token
1965
+ });
1966
+ } catch (error) {
1967
+ logger.warn("[useDeliverables] Called outside QueryClientProvider, returning empty list");
1968
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
1969
+ }
1970
+ }
1971
+ function useApproveDeliverable(config, accessToken, order_id, deliverable_id) {
1972
+ const ctx = useSdkContext();
1973
+ try {
1974
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1975
+ const queryClient = (0, import_react_query12.useQueryClient)();
1976
+ return (0, import_react_query12.useMutation)({
1977
+ mutationFn: () => token && order_id && deliverable_id ? approveDeliverable(cfg, token, order_id, deliverable_id) : Promise.reject("No access token"),
1978
+ onSuccess: () => {
1979
+ queryClient.invalidateQueries({ queryKey: ["deliverables", order_id] });
1980
+ }
1981
+ });
1982
+ } catch (error) {
1983
+ logger.warn("[useApproveDeliverable] Called outside QueryClientProvider, returning no-op mutation");
1984
+ return { mutate: () => {
1985
+ }, mutateAsync: () => Promise.resolve(void 0) };
1986
+ }
1987
+ }
1988
+ function useRequestRevision(config, accessToken, order_id, deliverable_id) {
1989
+ const ctx = useSdkContext();
1990
+ try {
1991
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
1992
+ const queryClient = (0, import_react_query12.useQueryClient)();
1993
+ return (0, import_react_query12.useMutation)({
1994
+ mutationFn: (feedback) => token && order_id && deliverable_id ? requestRevision(cfg, token, order_id, deliverable_id, feedback) : Promise.reject("No access token"),
1995
+ onSuccess: () => {
1996
+ queryClient.invalidateQueries({ queryKey: ["deliverables", order_id] });
1997
+ }
1998
+ });
1999
+ } catch (error) {
2000
+ logger.warn("[useRequestRevision] Called outside QueryClientProvider, returning no-op mutation");
2001
+ return { mutate: () => {
2002
+ }, mutateAsync: () => Promise.resolve(void 0) };
2003
+ }
2004
+ }
2005
+
2006
+ // src/hooks/use-consultations.ts
2007
+ var import_react_query13 = require("@tanstack/react-query");
2008
+
2009
+ // src/services/consultation.service.ts
2010
+ async function createConsultation(config, accessToken, payload) {
2011
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
2012
+ method: "POST",
2013
+ headers: {
2014
+ "Content-Type": "application/json",
2015
+ "Authorization": `Bearer ${accessToken}`,
2016
+ "X-Storefront-Key": config.storefrontApiKey,
2017
+ "X-Business-ID": config.businessId
2018
+ },
2019
+ body: JSON.stringify(payload)
2020
+ });
2021
+ if (!response.ok) throw new Error("Failed to create consultation");
2022
+ return response.json();
2023
+ }
2024
+ async function getConsultations(config, accessToken) {
2025
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
2026
+ headers: {
2027
+ "Authorization": `Bearer ${accessToken}`,
2028
+ "X-Storefront-Key": config.storefrontApiKey,
2029
+ "X-Business-ID": config.businessId
2030
+ }
2031
+ });
2032
+ if (!response.ok) throw new Error("Failed to get consultations");
2033
+ return response.json();
2034
+ }
2035
+ async function getConsultation(config, accessToken, id) {
2036
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
2037
+ headers: {
2038
+ "Authorization": `Bearer ${accessToken}`,
2039
+ "X-Storefront-Key": config.storefrontApiKey,
2040
+ "X-Business-ID": config.businessId
2041
+ }
2042
+ });
2043
+ if (!response.ok) throw new Error("Failed to get consultation");
2044
+ return response.json();
2045
+ }
2046
+ async function sendMessage(config, accessToken, id, payload) {
2047
+ await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
2048
+ method: "POST",
2049
+ headers: {
2050
+ "Content-Type": "application/json",
2051
+ "Authorization": `Bearer ${accessToken}`,
2052
+ "X-Storefront-Key": config.storefrontApiKey,
2053
+ "X-Business-ID": config.businessId
2054
+ },
2055
+ body: JSON.stringify(payload)
2056
+ });
2057
+ }
2058
+ async function acceptQuote(config, accessToken, id, payload) {
2059
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
2060
+ method: "POST",
2061
+ headers: {
2062
+ "Content-Type": "application/json",
2063
+ "Authorization": `Bearer ${accessToken}`,
2064
+ "X-Storefront-Key": config.storefrontApiKey,
2065
+ "X-Business-ID": config.businessId
2066
+ },
2067
+ body: JSON.stringify(payload)
2068
+ });
2069
+ if (!response.ok) throw new Error("Failed to accept quote");
2070
+ return response.json();
2071
+ }
2072
+ async function rejectQuote(config, accessToken, id, reason) {
2073
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
2074
+ method: "POST",
2075
+ headers: {
2076
+ "Content-Type": "application/json",
2077
+ "Authorization": `Bearer ${accessToken}`,
2078
+ "X-Storefront-Key": config.storefrontApiKey,
2079
+ "X-Business-ID": config.businessId
2080
+ },
2081
+ body: JSON.stringify({ reason })
2082
+ });
2083
+ if (!response.ok) throw new Error("Failed to reject quote");
2084
+ return response.json();
2085
+ }
2086
+
2087
+ // src/hooks/use-consultations.ts
2088
+ function useConsultations(config, accessToken) {
2089
+ const ctx = useSdkContext();
2090
+ try {
2091
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2092
+ return (0, import_react_query13.useQuery)({
2093
+ queryKey: ["consultations"],
2094
+ queryFn: () => token ? getConsultations(cfg, token) : Promise.resolve([]),
2095
+ enabled: !!token
2096
+ });
2097
+ } catch (error) {
2098
+ logger.warn("[useConsultations] Called outside QueryClientProvider, returning empty list");
2099
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
2100
+ }
2101
+ }
2102
+ function useConsultation(arg1, arg2, arg3) {
2103
+ const ctx = useSdkContext();
2104
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null;
2105
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2106
+ const explicitToken = isArg1Config ? arg2 : void 0;
2107
+ const id = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
2108
+ try {
2109
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
2110
+ return (0, import_react_query13.useQuery)({
2111
+ queryKey: ["consultation", id],
2112
+ queryFn: () => token && id ? getConsultation(cfg, token, id) : Promise.resolve(void 0),
2113
+ enabled: !!id && !!token
2114
+ });
2115
+ } catch (error) {
2116
+ logger.warn("[useConsultation] Called outside QueryClientProvider, returning undefined");
2117
+ return { data: void 0, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: void 0 }) };
2118
+ }
2119
+ }
2120
+ function useCreateConsultation(config, accessToken) {
2121
+ const ctx = useSdkContext();
2122
+ try {
2123
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2124
+ const queryClient = (0, import_react_query13.useQueryClient)();
2125
+ return (0, import_react_query13.useMutation)({
2126
+ mutationFn: (payload) => token ? createConsultation(cfg, token, payload) : Promise.reject("No access token"),
2127
+ onSuccess: () => {
2128
+ queryClient.invalidateQueries({ queryKey: ["consultations"] });
2129
+ }
2130
+ });
2131
+ } catch (error) {
2132
+ logger.warn("[useCreateConsultation] Called outside QueryClientProvider, returning no-op mutation");
2133
+ return { mutate: () => {
2134
+ }, mutateAsync: () => Promise.resolve(void 0) };
2135
+ }
2136
+ }
2137
+ function useSendMessage(arg1, arg2, arg3) {
2138
+ const ctx = useSdkContext();
2139
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null;
2140
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2141
+ const explicitToken = isArg1Config ? arg2 : void 0;
2142
+ const consultationId = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
2143
+ try {
2144
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
2145
+ const queryClient = (0, import_react_query13.useQueryClient)();
2146
+ return (0, import_react_query13.useMutation)({
2147
+ mutationFn: (payload) => token && consultationId ? sendMessage(cfg, token, consultationId, payload) : Promise.reject("No access token"),
2148
+ onSuccess: () => {
2149
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2150
+ }
2151
+ });
2152
+ } catch (error) {
2153
+ logger.warn("[useSendMessage] Called outside QueryClientProvider, returning no-op mutation");
2154
+ return { mutate: () => {
2155
+ }, mutateAsync: () => Promise.resolve(void 0) };
2156
+ }
2157
+ }
2158
+ function useAcceptQuote(arg1, arg2, arg3) {
2159
+ const ctx = useSdkContext();
2160
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null;
2161
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2162
+ const explicitToken = isArg1Config ? arg2 : void 0;
2163
+ const consultationId = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
2164
+ try {
2165
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
2166
+ const queryClient = (0, import_react_query13.useQueryClient)();
2167
+ return (0, import_react_query13.useMutation)({
2168
+ mutationFn: (payload) => token && consultationId ? acceptQuote(cfg, token, consultationId, payload) : Promise.reject("No access token"),
2169
+ onSuccess: () => {
2170
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2171
+ }
2172
+ });
2173
+ } catch (error) {
2174
+ logger.warn("[useAcceptQuote] Called outside QueryClientProvider, returning no-op mutation");
2175
+ return { mutate: () => {
2176
+ }, mutateAsync: () => Promise.resolve(void 0) };
2177
+ }
2178
+ }
2179
+ function useRejectQuote(arg1, arg2, arg3) {
2180
+ const ctx = useSdkContext();
2181
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null;
2182
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2183
+ const explicitToken = isArg1Config ? arg2 : void 0;
2184
+ const consultationId = isArg1Config ? arg3 : typeof arg1 === "string" ? arg1 : void 0;
2185
+ try {
2186
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx);
2187
+ const queryClient = (0, import_react_query13.useQueryClient)();
2188
+ return (0, import_react_query13.useMutation)({
2189
+ mutationFn: (reason) => token && consultationId ? rejectQuote(cfg, token, consultationId, reason) : Promise.reject("No access token"),
2190
+ onSuccess: () => {
2191
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2192
+ }
2193
+ });
2194
+ } catch (error) {
2195
+ logger.warn("[useRejectQuote] Called outside QueryClientProvider, returning no-op mutation");
2196
+ return { mutate: () => {
2197
+ }, mutateAsync: () => Promise.resolve(void 0) };
2198
+ }
2199
+ }
2200
+
2201
+ // src/hooks/use-consultation-stream.ts
2202
+ var import_react3 = require("react");
2203
+ var import_fetch_event_source = require("@microsoft/fetch-event-source");
2204
+ function useConsultationStream({
2205
+ config,
2206
+ consultationId,
2207
+ onMessage,
2208
+ onQuote,
2209
+ onStatusChange,
2210
+ onError
2211
+ }) {
2212
+ const abortControllerRef = (0, import_react3.useRef)(null);
2213
+ const [isConnected, setIsConnected] = (0, import_react3.useState)(false);
2214
+ const [lastEvent, setLastEvent] = (0, import_react3.useState)(null);
2215
+ (0, import_react3.useEffect)(() => {
2216
+ if (!consultationId) {
2217
+ return;
2218
+ }
2219
+ const abortController = new AbortController();
2220
+ abortControllerRef.current = abortController;
2221
+ const streamUrl = `${config.backendUrls.payment}/events/stream/consultation/${consultationId}`;
2222
+ (0, import_fetch_event_source.fetchEventSource)(streamUrl, {
2223
+ method: "GET",
2224
+ signal: abortController.signal,
2225
+ onmessage: (event) => {
2226
+ try {
2227
+ if (!event.data || event.data.trim() === "") {
2228
+ return;
2229
+ }
2230
+ const data = JSON.parse(event.data);
2231
+ logger.log("[ConsultationStream] Received event:", data);
2232
+ setLastEvent(data);
2233
+ if (data.event === "consultation.message") {
2234
+ logger.log("[ConsultationStream] Message detected, calling onMessage");
2235
+ if (onMessage) {
2236
+ onMessage(data);
2237
+ }
2238
+ }
2239
+ if (data.event === "consultation.quote") {
2240
+ logger.log("[ConsultationStream] Quote detected, calling onQuote");
2241
+ if (onQuote) {
2242
+ onQuote(data);
2243
+ }
2244
+ }
2245
+ if (data.event === "consultation.status") {
2246
+ logger.log("[ConsultationStream] Status change detected, calling onStatusChange");
2247
+ if (onStatusChange) {
2248
+ onStatusChange(data);
2249
+ }
2250
+ }
2251
+ } catch (error) {
2252
+ logger.error("[ConsultationStream] Error parsing event:", error);
2253
+ }
2254
+ },
2255
+ onerror: (error) => {
2256
+ if (abortController.signal.aborted) {
2257
+ logger.log("[ConsultationStream] Connection closed via AbortController");
2258
+ return;
2259
+ }
2260
+ logger.error("[ConsultationStream] Connection error:", error);
2261
+ setIsConnected(false);
2262
+ if (onError) {
2263
+ onError(error);
2264
+ }
2265
+ },
2266
+ onopen: async (response) => {
2267
+ if (response.ok && response.headers.get("content-type")?.includes("text/event-stream")) {
2268
+ logger.log("[ConsultationStream] Connection established for consultation:", consultationId);
2269
+ setIsConnected(true);
2270
+ return;
2271
+ }
2272
+ throw new Error(`Unexpected response: ${response.status}`);
2273
+ }
2274
+ }).catch((error) => {
2275
+ if (abortController.signal.aborted || error.name === "AbortError") {
2276
+ return;
2277
+ }
2278
+ logger.error("[ConsultationStream] fetchEventSource failed:", error);
2279
+ });
2280
+ return () => {
2281
+ abortController.abort();
2282
+ setIsConnected(false);
2283
+ };
2284
+ }, [consultationId, onMessage, onQuote, onStatusChange, onError]);
2285
+ return { isConnected, lastEvent };
2286
+ }
2287
+
2288
+ // src/hooks/use-order-stream.ts
2289
+ var import_react4 = require("react");
2290
+ var import_fetch_event_source2 = require("@microsoft/fetch-event-source");
2291
+ function useOrderStream({
2292
+ config: explicitConfig,
2293
+ orderId,
2294
+ onPaymentComplete,
2295
+ onDigitalReady,
2296
+ onBespokeUpdate,
2297
+ onConsultationUpdate,
2298
+ onServiceBookingUpdate,
2299
+ onError
2300
+ }) {
2301
+ const ctx = useSdkContext();
2302
+ const config = explicitConfig ?? ctx?.config;
2303
+ const abortControllerRef = (0, import_react4.useRef)(null);
2304
+ (0, import_react4.useEffect)(() => {
2305
+ if (!orderId || !config) {
2306
+ return;
2307
+ }
2308
+ const abortController = new AbortController();
2309
+ abortControllerRef.current = abortController;
2310
+ const streamUrl = `${config.backendUrls.payment}/events/stream/order/${encodeURIComponent(orderId)}`;
2311
+ (0, import_fetch_event_source2.fetchEventSource)(streamUrl, {
2312
+ method: "GET",
2313
+ signal: abortController.signal,
2314
+ onmessage: (event) => {
2315
+ try {
2316
+ if (!event.data || event.data.trim() === "") {
2317
+ return;
2318
+ }
2319
+ const data = JSON.parse(event.data);
2320
+ logger.log("[OrderStream] Received event:", data);
2321
+ if (data.event === "payment.success") {
2322
+ logger.log("[OrderStream] Payment success detected, calling onPaymentComplete");
2323
+ if (onPaymentComplete) {
2324
+ onPaymentComplete(data);
2325
+ }
2326
+ abortController.abort();
2327
+ }
2328
+ if (data.event === "digital.ready") {
2329
+ logger.log("[OrderStream] Digital delivery ready detected, calling onDigitalReady");
2330
+ if (onDigitalReady) {
2331
+ onDigitalReady(data);
2332
+ }
2333
+ }
2334
+ if (data.event === "bespoke.update") {
2335
+ logger.log("[OrderStream] Bespoke update detected, calling onBespokeUpdate");
2336
+ if (onBespokeUpdate) {
2337
+ onBespokeUpdate(data);
2338
+ }
2339
+ }
2340
+ if (data.event === "consultation.update") {
2341
+ logger.log("[OrderStream] Consultation update detected, calling onConsultationUpdate");
2342
+ if (onConsultationUpdate) {
2343
+ onConsultationUpdate(data);
2344
+ }
2345
+ }
2346
+ if (data.event === "service_booking.update") {
2347
+ logger.log("[OrderStream] Service booking update detected, calling onServiceBookingUpdate");
2348
+ if (onServiceBookingUpdate) {
2349
+ onServiceBookingUpdate(data);
2350
+ }
2351
+ }
2352
+ } catch (error) {
2353
+ logger.error("[OrderStream] Error parsing event:", error);
2354
+ }
2355
+ },
2356
+ onerror: (error) => {
2357
+ if (abortController.signal.aborted) {
2358
+ logger.log("[OrderStream] Connection closed via AbortController");
2359
+ return;
2360
+ }
2361
+ if (error.message?.includes("404") || error.message?.includes("Not Found")) {
2362
+ logger.warn("[OrderStream] Stream endpoint unavailable for order:", orderId);
2363
+ return;
2364
+ }
2365
+ logger.error("[OrderStream] Connection error:", error);
2366
+ if (onError) {
2367
+ onError(error);
2368
+ }
2369
+ },
2370
+ onopen: async (response) => {
2371
+ if (response.ok && response.headers.get("content-type")?.includes("text/event-stream")) {
2372
+ logger.log("[OrderStream] Connection established for order:", orderId);
2373
+ return;
2374
+ }
2375
+ if (response.status === 404) {
2376
+ logger.warn("[OrderStream] Stream endpoint unavailable for order:", orderId);
2377
+ return;
2378
+ }
2379
+ throw new Error(`Unexpected response: ${response.status}`);
2380
+ }
2381
+ }).catch((error) => {
2382
+ if (abortController.signal.aborted || error.name === "AbortError") {
2383
+ return;
2384
+ }
2385
+ logger.error("[OrderStream] fetchEventSource failed:", error);
2386
+ });
2387
+ return () => {
2388
+ abortController.abort();
2389
+ };
2390
+ }, [orderId, onPaymentComplete, onDigitalReady, onBespokeUpdate, onConsultationUpdate, onServiceBookingUpdate, onError]);
2391
+ return null;
2392
+ }
2393
+
2394
+ // src/hooks/use-is-mounted.ts
2395
+ var import_react5 = require("react");
2396
+ function useIsMounted() {
2397
+ const [mounted, setMounted] = (0, import_react5.useState)(false);
2398
+ (0, import_react5.useEffect)(() => {
2399
+ setMounted(true);
2400
+ }, []);
2401
+ return mounted;
2402
+ }
2403
+
2404
+ // src/hooks/use-mobile.ts
2405
+ var import_react6 = require("react");
2406
+ var MOBILE_BREAKPOINT = 768;
2407
+ function useIsMobile() {
2408
+ const [isMobile, setIsMobile] = (0, import_react6.useState)(false);
2409
+ (0, import_react6.useEffect)(() => {
2410
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
2411
+ const onChange = () => setIsMobile(mql.matches);
2412
+ mql.addEventListener("change", onChange);
2413
+ setIsMobile(mql.matches);
2414
+ return () => mql.removeEventListener("change", onChange);
2415
+ }, []);
2416
+ return isMobile;
2417
+ }
2418
+
2419
+ // src/hooks/use-google-translate.ts
2420
+ var import_react7 = require("react");
2421
+ var SCRIPT_ID = "google-translate-script";
2422
+ var ELEMENT_ID = "google_translate_element";
2423
+ function fireChange(googleCode) {
2424
+ const combo = document.querySelector(".goog-te-combo");
2425
+ if (combo) {
2426
+ combo.value = googleCode;
2427
+ combo.dispatchEvent(new Event("change"));
2428
+ return true;
2429
+ }
2430
+ return false;
2431
+ }
2432
+ function useGoogleTranslate(configOrLang, appLang) {
2433
+ const ctx = useSdkContext();
2434
+ let cfg;
2435
+ let lang;
2436
+ if (typeof configOrLang === "string") {
2437
+ lang = configOrLang;
2438
+ cfg = resolveHookArgs(void 0, void 0, ctx).config;
2439
+ } else {
2440
+ lang = appLang ?? "en";
2441
+ cfg = resolveHookArgs(configOrLang, void 0, ctx).config;
2442
+ }
2443
+ const [isLoaded, setIsLoaded] = (0, import_react7.useState)(false);
2444
+ const initRef = (0, import_react7.useRef)(false);
2445
+ const { data: supportedLangs = [] } = useSupportedLanguages(cfg);
2446
+ const clearCookies = (0, import_react7.useCallback)(() => {
2447
+ if (typeof window === "undefined") return;
2448
+ const domains = [
2449
+ window.location.hostname,
2450
+ "." + window.location.hostname,
2451
+ "." + window.location.hostname.split(".").slice(-2).join(".")
2452
+ ];
2453
+ const path = "/";
2454
+ document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path};`;
2455
+ domains.forEach((domain) => {
2456
+ document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}; domain=${domain};`;
2457
+ });
2458
+ }, []);
2459
+ const resetToEnglish = (0, import_react7.useCallback)(() => {
2460
+ if (typeof window === "undefined") return;
2461
+ const googtrans = document.cookie.split("; ").find((row) => row.startsWith("googtrans="))?.split("=")[1];
2462
+ const domains = [
2463
+ window.location.hostname,
2464
+ "." + window.location.hostname,
2465
+ window.location.hostname.split(".").slice(-2).join("."),
2466
+ "." + window.location.hostname.split(".").slice(-2).join(".")
2467
+ ];
2468
+ const clear = (name) => {
2469
+ document.cookie = `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
2470
+ domains.forEach((d) => {
2471
+ document.cookie = `${name}=; Path=/; Domain=${d}; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
2472
+ });
2473
+ };
2474
+ clear("googtrans");
2475
+ if (googtrans || document.documentElement.classList.contains("translated-ltr") || document.querySelector(".goog-te-banner-frame")) {
2476
+ window.location.reload();
2477
+ return;
2478
+ }
2479
+ document.body.style.top = "0";
2480
+ document.documentElement.classList.remove("translated-ltr", "translated-rtl");
2481
+ const container = document.getElementById(":1.container");
2482
+ if (container) container.style.display = "none";
2483
+ }, []);
2484
+ const changeLanguage = (0, import_react7.useCallback)((nextAppCode) => {
2485
+ if (nextAppCode === "en") {
2486
+ resetToEnglish();
2487
+ return;
2488
+ }
2489
+ const googleCode = nextAppCode;
2490
+ const container = document.getElementById(":1.container");
2491
+ if (container) container.style.display = "block";
2492
+ let tries = 0;
2493
+ const tick = () => {
2494
+ if (fireChange(googleCode)) return;
2495
+ if (tries++ < 30) setTimeout(tick, 200);
2496
+ };
2497
+ tick();
2498
+ }, [resetToEnglish]);
2499
+ (0, import_react7.useEffect)(() => {
2500
+ if (typeof window === "undefined") return;
2501
+ if (lang === "en" && !initRef.current) return;
2502
+ if (initRef.current) return;
2503
+ if (supportedLangs.length === 0) return;
2504
+ initRef.current = true;
2505
+ if (!document.getElementById(ELEMENT_ID)) {
2506
+ const host = document.createElement("div");
2507
+ host.id = ELEMENT_ID;
2508
+ host.style.display = "none";
2509
+ document.body.appendChild(host);
2510
+ }
2511
+ const includedLanguages = supportedLangs.map((l) => l.code).join(",");
2512
+ window.googleTranslateElementInit = () => {
2513
+ if (window.google?.translate?.TranslateElement) {
2514
+ new window.google.translate.TranslateElement(
2515
+ { pageLanguage: "en", includedLanguages, autoDisplay: false },
2516
+ ELEMENT_ID
2517
+ );
2518
+ setIsLoaded(true);
2519
+ }
2520
+ };
2521
+ if (!document.getElementById(SCRIPT_ID)) {
2522
+ const script = document.createElement("script");
2523
+ script.id = SCRIPT_ID;
2524
+ script.src = "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
2525
+ script.async = true;
2526
+ document.body.appendChild(script);
2527
+ } else {
2528
+ if (window.google?.translate) window.googleTranslateElementInit?.();
2529
+ }
2530
+ }, [lang, supportedLangs]);
2531
+ (0, import_react7.useEffect)(() => {
2532
+ if (isLoaded || lang === "en" && initRef.current) {
2533
+ changeLanguage(lang);
2534
+ }
2535
+ }, [lang, isLoaded, changeLanguage]);
2536
+ return { isLoaded };
2537
+ }
2538
+
2539
+ // src/hooks/use-payment.ts
2540
+ var import_react_query14 = require("@tanstack/react-query");
2541
+
2542
+ // src/services/payment.service.ts
2543
+ async function createDedicatedAccount(config, accessToken, request) {
2544
+ const isValidUUID = (str) => {
2545
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2546
+ return uuidRegex.test(str);
2547
+ };
2548
+ const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
2549
+ method: "POST",
2550
+ headers: {
2551
+ "Content-Type": "application/json",
2552
+ "Authorization": `Bearer ${accessToken}`,
2553
+ "X-Storefront-Key": config.storefrontApiKey,
2554
+ "X-Business-ID": config.businessId
2555
+ },
2556
+ body: JSON.stringify({
2557
+ order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
2558
+ amount: request.amount,
2559
+ customer_email: request.customer_email,
2560
+ customer_name: request.customer_name,
2561
+ currency: request.currency,
2562
+ idempotency_key: request.idempotency_key
2563
+ })
2564
+ });
2565
+ if (!response.ok) throw new Error("Failed to create dedicated account");
2566
+ const data = await response.json();
2567
+ return data;
2568
+ }
2569
+ async function initiatePayment(config, accessToken, request) {
2570
+ const isValidUUID = (str) => {
2571
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2572
+ return uuidRegex.test(str);
2573
+ };
2574
+ const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
2575
+ const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
2576
+ method: "POST",
2577
+ headers: {
2578
+ "Content-Type": "application/json",
2579
+ "Authorization": `Bearer ${accessToken}`,
2580
+ "X-Storefront-Key": config.storefrontApiKey,
2581
+ "X-Business-ID": config.businessId
2582
+ },
2583
+ body: JSON.stringify({
2584
+ amount: request.amount,
2585
+ currency: request.currency,
2586
+ order_id: validOrderId,
2587
+ quote_id: request.quote_id,
2588
+ metadata_json: {
2589
+ customer_email: request.customer_email,
2590
+ customer_name: request.customer_name ?? "",
2591
+ order_id: validOrderId,
2592
+ ...request.metadata ?? {}
2593
+ },
2594
+ idempotency_key: request.idempotency_key
2595
+ })
2596
+ });
2597
+ if (!response.ok) throw new Error("Failed to initiate payment");
2598
+ const data = await response.json();
2599
+ return {
2600
+ id: data.id,
2601
+ gateway_ref: data.gateway_ref,
2602
+ gateway: data.gateway,
2603
+ status: data.status,
2604
+ checkout_url: data.metadata_json?.checkout_url ?? ""
2605
+ };
2606
+ }
2607
+ async function verifyTransaction(configOrReference, reference) {
2608
+ if (typeof configOrReference === "string") {
2609
+ const ref2 = configOrReference;
2610
+ const response2 = await fetch(`/api/payments/verify/${ref2}`, {
2611
+ method: "POST",
2612
+ headers: { "Content-Type": "application/json" }
2613
+ });
2614
+ if (!response2.ok) throw new Error("Failed to verify transaction");
2615
+ return response2.json();
2616
+ }
2617
+ const config = configOrReference;
2618
+ const ref = reference || "";
2619
+ const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
2620
+ method: "POST",
2621
+ headers: {
2622
+ "Content-Type": "application/json",
2623
+ "X-Storefront-Key": config.storefrontApiKey,
2624
+ "X-Business-ID": config.businessId
2625
+ }
2626
+ });
2627
+ if (!response.ok) throw new Error("Failed to verify transaction");
2628
+ const data = await response.json();
2629
+ return data;
2630
+ }
2631
+ async function getTransactionStatus(config, transactionId) {
2632
+ const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
2633
+ headers: {
2634
+ "X-Storefront-Key": config.storefrontApiKey,
2635
+ "X-Business-ID": config.businessId
2636
+ }
2637
+ });
2638
+ if (!response.ok) throw new Error("Failed to get transaction status");
2639
+ const data = await response.json();
2640
+ return data;
2641
+ }
2642
+
2643
+ // src/hooks/use-payment.ts
2644
+ function useCreateDVA(config, accessToken) {
2645
+ const ctx = useSdkContext();
2646
+ try {
2647
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2648
+ const queryClient = (0, import_react_query14.useQueryClient)();
2649
+ return (0, import_react_query14.useMutation)({
2650
+ mutationFn: (request) => token ? createDedicatedAccount(cfg, token, request) : Promise.reject("No access token"),
2651
+ onSuccess: () => {
2652
+ queryClient.invalidateQueries({ queryKey: ["payment"] });
2653
+ }
2654
+ });
2655
+ } catch (error) {
2656
+ logger.warn("[useCreateDVA] Called outside QueryClientProvider, returning no-op mutation");
2657
+ return {
2658
+ mutate: () => {
2659
+ },
2660
+ mutateAsync: () => Promise.resolve(void 0)
2661
+ };
2662
+ }
2663
+ }
2664
+ function useInitiatePayment(config, accessToken) {
2665
+ const ctx = useSdkContext();
2666
+ try {
2667
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2668
+ return (0, import_react_query14.useMutation)({
2669
+ mutationFn: (request) => token ? initiatePayment(cfg, token, request) : Promise.reject("No access token")
2670
+ });
2671
+ } catch (error) {
2672
+ logger.warn("[useInitiatePayment] Called outside QueryClientProvider, returning no-op mutation");
2673
+ return {
2674
+ mutate: () => {
2675
+ },
2676
+ mutateAsync: () => Promise.resolve(void 0)
2677
+ };
2678
+ }
2679
+ }
2680
+ function useVerifyTransaction(config) {
2681
+ const ctx = useSdkContext();
2682
+ try {
2683
+ const { config: cfg } = resolveHookArgs(config, void 0, ctx);
2684
+ return (0, import_react_query14.useMutation)({
2685
+ mutationFn: (reference) => verifyTransaction(cfg, reference)
2686
+ });
2687
+ } catch (error) {
2688
+ logger.warn("[useVerifyTransaction] Called outside QueryClientProvider, returning no-op mutation");
2689
+ return {
2690
+ mutate: () => {
2691
+ },
2692
+ mutateAsync: () => Promise.resolve(void 0)
2693
+ };
2694
+ }
2695
+ }
2696
+ function useTransactionStatus(arg1, arg2, arg3) {
2697
+ const ctx = useSdkContext();
2698
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
2699
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2700
+ const transactionId = isArg1Config ? arg2 : typeof arg1 === "string" ? arg1 : "";
2701
+ const enabled = isArg1Config ? arg3 ?? false : typeof arg2 === "boolean" ? arg2 : false;
2702
+ try {
2703
+ const { config: cfg } = resolveHookArgs(explicitConfig, void 0, ctx);
2704
+ return (0, import_react_query14.useQuery)({
2705
+ queryKey: ["transaction", "status", transactionId],
2706
+ queryFn: () => getTransactionStatus(cfg, transactionId),
2707
+ enabled: enabled && !!transactionId,
2708
+ refetchInterval: 3e3
2709
+ });
2710
+ } catch (error) {
2711
+ logger.warn("[useTransactionStatus] Called outside QueryClientProvider, returning undefined");
2712
+ return {
2713
+ data: void 0,
2714
+ isLoading: false,
2715
+ error: null,
2716
+ isFetching: false,
2717
+ refetch: () => Promise.resolve({ data: void 0 })
2718
+ };
2719
+ }
2720
+ }
2721
+ function usePollTransactionStatus(arg1, arg2, arg3) {
2722
+ const ctx = useSdkContext();
2723
+ const isArg1Config = typeof arg1 === "object" && arg1 !== null && "businessId" in arg1;
2724
+ const explicitConfig = isArg1Config ? arg1 : void 0;
2725
+ const reference = isArg1Config ? arg2 : typeof arg1 === "string" ? arg1 : "";
2726
+ const enabled = isArg1Config ? arg3 ?? false : typeof arg2 === "boolean" ? arg2 : false;
2727
+ try {
2728
+ const { config: cfg } = resolveHookArgs(explicitConfig, void 0, ctx);
2729
+ return (0, import_react_query14.useQuery)({
2730
+ queryKey: ["transaction", "poll", reference],
2731
+ queryFn: () => verifyTransaction(cfg, reference),
2732
+ enabled: enabled && !!reference,
2733
+ refetchInterval: 2e3,
2734
+ retry: 10
2735
+ });
2736
+ } catch (error) {
2737
+ logger.warn("[usePollTransactionStatus] Called outside QueryClientProvider, returning undefined");
2738
+ return {
2739
+ data: void 0,
2740
+ isLoading: false,
2741
+ error: null,
2742
+ isFetching: false,
2743
+ refetch: () => Promise.resolve({ data: void 0 })
2744
+ };
2745
+ }
2746
+ }
2747
+
2748
+ // src/hooks/use-cms.ts
2749
+ var import_react_query15 = require("@tanstack/react-query");
2750
+
2751
+ // src/services/cms.service.ts
2752
+ async function listCmsEntries(config, modelSlug, params) {
2753
+ const queryParams = new URLSearchParams();
2754
+ queryParams.set("page", (params?.page || 1).toString());
2755
+ queryParams.set("page_size", (params?.page_size || 50).toString());
2756
+ const response = await fetch(
2757
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries?${queryParams.toString()}`,
2758
+ {
2759
+ headers: {
2760
+ "X-Storefront-Key": config.storefrontApiKey,
2761
+ "X-Business-ID": config.businessId
2762
+ }
2763
+ }
2764
+ );
2765
+ if (!response.ok) throw new Error("Failed to list CMS entries");
2766
+ return response.json();
2767
+ }
2768
+ async function getCmsEntry(config, modelSlug, entryId) {
2769
+ const response = await fetch(
2770
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2771
+ {
2772
+ headers: {
2773
+ "X-Storefront-Key": config.storefrontApiKey,
2774
+ "X-Business-ID": config.businessId
2775
+ }
2776
+ }
2777
+ );
2778
+ if (!response.ok) throw new Error("Failed to get CMS entry");
2779
+ return response.json();
2780
+ }
2781
+ async function createCmsEntry(config, accessToken, modelSlug, params) {
2782
+ const response = await fetch(
2783
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries`,
2784
+ {
2785
+ method: "POST",
2786
+ headers: {
2787
+ "Content-Type": "application/json",
2788
+ "Authorization": `Bearer ${accessToken}`,
2789
+ "X-Storefront-Key": config.storefrontApiKey,
2790
+ "X-Business-ID": config.businessId
2791
+ },
2792
+ body: JSON.stringify(params)
2793
+ }
2794
+ );
2795
+ if (!response.ok) throw new Error("Failed to create CMS entry");
2796
+ return response.json();
2797
+ }
2798
+ async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
2799
+ const response = await fetch(
2800
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2801
+ {
2802
+ method: "PUT",
2803
+ headers: {
2804
+ "Content-Type": "application/json",
2805
+ "Authorization": `Bearer ${accessToken}`,
2806
+ "X-Storefront-Key": config.storefrontApiKey,
2807
+ "X-Business-ID": config.businessId
2808
+ },
2809
+ body: JSON.stringify(params)
2810
+ }
2811
+ );
2812
+ if (!response.ok) throw new Error("Failed to update CMS entry");
2813
+ return response.json();
2814
+ }
2815
+ async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
2816
+ const response = await fetch(
2817
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2818
+ {
2819
+ method: "DELETE",
2820
+ headers: {
2821
+ "Authorization": `Bearer ${accessToken}`,
2822
+ "X-Storefront-Key": config.storefrontApiKey,
2823
+ "X-Business-ID": config.businessId
2824
+ }
2825
+ }
2826
+ );
2827
+ if (!response.ok) throw new Error("Failed to delete CMS entry");
2828
+ }
2829
+
2830
+ // src/hooks/use-cms.ts
2831
+ function useCmsEntries(configOrModelSlug, modelSlugOrParams, maybeParams) {
2832
+ const ctx = useSdkContext();
2833
+ let cfg;
2834
+ let slug;
2835
+ let params;
2836
+ if (typeof configOrModelSlug === "string") {
2837
+ slug = configOrModelSlug;
2838
+ params = modelSlugOrParams;
2839
+ cfg = resolveHookArgs(void 0, void 0, ctx).config;
2840
+ } else {
2841
+ cfg = configOrModelSlug;
2842
+ slug = modelSlugOrParams;
2843
+ params = maybeParams;
2844
+ }
2845
+ try {
2846
+ const query = (0, import_react_query15.useQuery)({
2847
+ queryKey: ["cms-entries", slug, params],
2848
+ queryFn: () => listCmsEntries(cfg, slug, params),
2849
+ enabled: !!slug
2850
+ });
2851
+ return {
2852
+ entries: query.data?.entries || [],
2853
+ total: query.data?.total || 0,
2854
+ page: query.data?.page || 1,
2855
+ page_size: query.data?.page_size || 50,
2856
+ isLoading: query.isLoading,
2857
+ error: query.error,
2858
+ refetch: query.refetch
2859
+ };
2860
+ } catch (error) {
2861
+ logger.warn("[useCmsEntries] Called outside QueryClientProvider, returning empty list");
2862
+ return {
2863
+ entries: [],
2864
+ total: 0,
2865
+ page: 1,
2866
+ page_size: 50,
2867
+ isLoading: false,
2868
+ error: null,
2869
+ refetch: () => {
2870
+ }
2871
+ };
2872
+ }
2873
+ }
2874
+ function useCmsEntry(configOrModelSlug, modelSlugOrEntryId, maybeEntryId) {
2875
+ const ctx = useSdkContext();
2876
+ let cfg;
2877
+ let slug;
2878
+ let entryId;
2879
+ if (maybeEntryId !== void 0) {
2880
+ cfg = configOrModelSlug;
2881
+ slug = modelSlugOrEntryId;
2882
+ entryId = maybeEntryId;
2883
+ } else {
2884
+ cfg = resolveHookArgs(void 0, void 0, ctx).config;
2885
+ slug = configOrModelSlug;
2886
+ entryId = modelSlugOrEntryId;
2887
+ }
2888
+ try {
2889
+ const query = (0, import_react_query15.useQuery)({
2890
+ queryKey: ["cms-entry", slug, entryId],
2891
+ queryFn: () => getCmsEntry(cfg, slug, entryId),
2892
+ enabled: !!slug && !!entryId
2893
+ });
2894
+ return {
2895
+ entry: query.data,
2896
+ isLoading: query.isLoading,
2897
+ error: query.error,
2898
+ refetch: query.refetch
2899
+ };
2900
+ } catch (error) {
2901
+ logger.warn("[useCmsEntry] Called outside QueryClientProvider, returning undefined");
2902
+ return {
2903
+ entry: void 0,
2904
+ isLoading: false,
2905
+ error: null,
2906
+ refetch: () => {
2907
+ }
2908
+ };
2909
+ }
2910
+ }
2911
+ function useCreateCmsEntry(config, accessToken, modelSlug) {
2912
+ const ctx = useSdkContext();
2913
+ try {
2914
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2915
+ const queryClient = (0, import_react_query15.useQueryClient)();
2916
+ const mutation = (0, import_react_query15.useMutation)({
2917
+ mutationFn: (params) => token && modelSlug ? createCmsEntry(cfg, token, modelSlug, params) : Promise.reject("No access token or modelSlug"),
2918
+ onSuccess: () => {
2919
+ if (modelSlug) queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
2920
+ }
2921
+ });
2922
+ return {
2923
+ createEntry: mutation.mutate,
2924
+ isLoading: mutation.isPending,
2925
+ error: mutation.error
2926
+ };
2927
+ } catch (error) {
2928
+ logger.warn("[useCreateCmsEntry] Called outside QueryClientProvider, returning no-op mutation");
2929
+ return {
2930
+ createEntry: () => {
2931
+ },
2932
+ isLoading: false,
2933
+ error: null
2934
+ };
2935
+ }
2936
+ }
2937
+ function useUpdateCmsEntry(config, accessToken, modelSlug) {
2938
+ const ctx = useSdkContext();
2939
+ try {
2940
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2941
+ const queryClient = (0, import_react_query15.useQueryClient)();
2942
+ const mutation = (0, import_react_query15.useMutation)({
2943
+ mutationFn: ({ entryId, params }) => token && modelSlug ? updateCmsEntry(cfg, token, modelSlug, entryId, params) : Promise.reject("No access token or modelSlug"),
2944
+ onSuccess: () => {
2945
+ if (modelSlug) {
2946
+ queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
2947
+ queryClient.invalidateQueries({ queryKey: ["cms-entry", modelSlug] });
2948
+ }
2949
+ }
2950
+ });
2951
+ return {
2952
+ updateEntry: (entryId, params) => mutation.mutate({ entryId, params }),
2953
+ isLoading: mutation.isPending,
2954
+ error: mutation.error
2955
+ };
2956
+ } catch (error) {
2957
+ logger.warn("[useUpdateCmsEntry] Called outside QueryClientProvider, returning no-op mutation");
2958
+ return {
2959
+ updateEntry: () => {
2960
+ },
2961
+ isLoading: false,
2962
+ error: null
2963
+ };
2964
+ }
2965
+ }
2966
+ function useDeleteCmsEntry(config, accessToken, modelSlug) {
2967
+ const ctx = useSdkContext();
2968
+ try {
2969
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx);
2970
+ const queryClient = (0, import_react_query15.useQueryClient)();
2971
+ const mutation = (0, import_react_query15.useMutation)({
2972
+ mutationFn: (entryId) => token && modelSlug ? deleteCmsEntry(cfg, token, modelSlug, entryId) : Promise.reject("No access token or modelSlug"),
2973
+ onSuccess: () => {
2974
+ if (modelSlug) {
2975
+ queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
2976
+ queryClient.invalidateQueries({ queryKey: ["cms-entry", modelSlug] });
2977
+ }
2978
+ }
2979
+ });
2980
+ return {
2981
+ deleteEntry: mutation.mutate,
2982
+ isLoading: mutation.isPending,
2983
+ error: mutation.error
2984
+ };
2985
+ } catch (error) {
2986
+ logger.warn("[useDeleteCmsEntry] Called outside QueryClientProvider, returning no-op mutation");
2987
+ return {
2988
+ deleteEntry: () => {
2989
+ },
2990
+ isLoading: false,
2991
+ error: null
2992
+ };
2993
+ }
2994
+ }
2995
+ // Annotate the CommonJS export names for ESM import in node:
2996
+ 0 && (module.exports = {
2997
+ CartCtx,
2998
+ CartProvider,
2999
+ SdkProvider,
3000
+ collectionKeys,
3001
+ getCountries,
3002
+ getStates,
3003
+ getSupportedCurrenciesList,
3004
+ getSupportedLanguagesList,
3005
+ productKeys,
3006
+ resolveHookArgs,
3007
+ useAcceptQuote,
3008
+ useAddToWishlist,
3009
+ useAppointment,
3010
+ useAppointments,
3011
+ useApproveDeliverable,
3012
+ useAuthUser,
3013
+ useAvailableSlots,
3014
+ useBespokeAvailability,
3015
+ useBookAppointment,
3016
+ useCancelAppointment,
3017
+ useCancelOrder,
3018
+ useCart,
3019
+ useCheckInWishlist,
3020
+ useCmsEntries,
3021
+ useCmsEntry,
3022
+ useConsultation,
3023
+ useConsultationStream,
3024
+ useConsultations,
3025
+ useCountries,
3026
+ useCreateCmsEntry,
3027
+ useCreateConsultation,
3028
+ useCreateDVA,
3029
+ useCreateOrder,
3030
+ useCurrencies,
3031
+ useDeleteCmsEntry,
3032
+ useDeliverables,
3033
+ useFeaturedProducts,
3034
+ useFindOrder,
3035
+ useGoogleTranslate,
3036
+ useInitiatePayment,
3037
+ useIsMobile,
3038
+ useIsMounted,
3039
+ useLatestProducts,
3040
+ useLogin,
3041
+ useLogout,
3042
+ useLowStockProducts,
3043
+ useNewProducts,
3044
+ useOnSaleProducts,
3045
+ useOrder,
3046
+ useOrderStream,
3047
+ useOrderTracking,
3048
+ useOrders,
3049
+ useOrdersList,
3050
+ usePollTransactionStatus,
3051
+ usePopularProducts,
3052
+ useProduct,
3053
+ useRecommendedProducts,
3054
+ useRegister,
3055
+ useRejectQuote,
3056
+ useRemoveFromWishlist,
3057
+ useRemoveProductFromWishlist,
3058
+ useRequestRevision,
3059
+ useSdkContext,
3060
+ useSendMessage,
3061
+ useStates,
3062
+ useStorefrontCollection,
3063
+ useStorefrontCollections,
3064
+ useStorefrontProducts,
3065
+ useSupportedLanguages,
3066
+ useTransactionStatus,
3067
+ useUpdateCmsEntry,
3068
+ useUpdateProfile,
3069
+ useVerifyTransaction,
3070
+ useWishlist,
3071
+ wishlistKeys
3072
+ });
3073
+ //# sourceMappingURL=index.js.map