@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.
- package/dist/hooks/index.d.mts +430 -0
- package/dist/hooks/index.d.ts +430 -0
- package/dist/hooks/index.js +3073 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/index.mjs +2962 -0
- package/dist/hooks/index.mjs.map +1 -0
- package/dist/index-CxNLI4nw.d.ts +786 -0
- package/dist/index-CzVMyUs4.d.mts +492 -0
- package/dist/index-CzVMyUs4.d.ts +492 -0
- package/dist/index-Dowl5224.d.mts +786 -0
- package/dist/index.d.mts +48 -1739
- package/dist/index.d.ts +48 -1739
- package/dist/index.js +1544 -2359
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1527 -2258
- package/dist/index.mjs.map +1 -1
- package/dist/sdk-context-BuarJbeb.d.ts +75 -0
- package/dist/sdk-context-Db8kf1Tv.d.mts +75 -0
- package/dist/services/index.d.mts +2 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +2369 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/index.mjs +2252 -0
- package/dist/services/index.mjs.map +1 -0
- package/package.json +11 -2
- package/src/config/index.ts +10 -91
- package/src/constants.ts +13 -0
- package/src/context/sdk-context.tsx +70 -0
- package/src/graphql/collections.graphql.ts +2 -10
- package/src/graphql/products.graphql.ts +215 -65
- package/src/graphql/wishlist.graphql.ts +7 -6
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-auth.ts +82 -158
- package/src/hooks/use-bespoke-availability.ts +25 -8
- package/src/hooks/use-cart.ts +222 -119
- package/src/hooks/use-cms.ts +179 -86
- package/src/hooks/use-collections.ts +52 -15
- package/src/hooks/use-consultation-stream.ts +4 -3
- package/src/hooks/use-consultations.ts +120 -51
- package/src/hooks/use-countries.ts +35 -13
- package/src/hooks/use-currencies.ts +26 -13
- package/src/hooks/use-google-translate.ts +22 -8
- package/src/hooks/use-languages.ts +40 -20
- package/src/hooks/use-mobile.ts +23 -0
- package/src/hooks/use-order-stream.ts +9 -5
- package/src/hooks/use-orders.ts +99 -44
- package/src/hooks/use-payment.ts +108 -40
- package/src/hooks/use-products.ts +251 -53
- package/src/hooks/use-service-booking.ts +152 -90
- package/src/hooks/use-states.ts +35 -15
- package/src/hooks/use-wishlist.ts +92 -91
- package/src/index.ts +26 -30
- package/src/services/auth.service.ts +209 -167
- package/src/services/bespoke.service.ts +12 -4
- package/src/services/cart.service.ts +172 -70
- package/src/services/cms.service.ts +70 -35
- package/src/services/collection.service.ts +22 -5
- package/src/services/config.service.ts +34 -14
- package/src/services/consultation.service.ts +72 -18
- package/src/services/logistics.service.ts +35 -11
- package/src/services/notifications.service.ts +27 -12
- package/src/services/order.service.ts +74 -15
- package/src/services/payment.service.ts +86 -31
- package/src/services/product.service.ts +279 -39
- package/src/services/service-booking.service.ts +98 -26
- package/src/services/wishlist.service.ts +69 -25
- package/src/types/auth/index.ts +6 -4
- package/src/types/business/index.ts +7 -2
- package/src/types/payments/index.ts +3 -3
- package/src/types/services/index.ts +2 -5
- package/src/types/store/index.ts +38 -3
- package/src/utils/error-handler.ts +10 -5
- package/src/utils/storage.ts +48 -26
- package/src/utils/validators.ts +85 -0
- package/src/client/authClient.ts +0 -135
- package/src/client/graphqlClient.ts +0 -53
- 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
|