@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
package/dist/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,45 +15,34 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
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
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.ts
|
|
31
21
|
var index_exports = {};
|
|
32
22
|
__export(index_exports, {
|
|
33
|
-
AuthCtx: () => AuthCtx,
|
|
34
|
-
AuthProvider: () => AuthProvider,
|
|
35
|
-
CartCtx: () => CartCtx,
|
|
36
|
-
CartProvider: () => CartProvider,
|
|
37
23
|
InvalidBaseURLError: () => InvalidBaseURLError,
|
|
24
|
+
STORAGE_KEYS: () => STORAGE_KEYS,
|
|
25
|
+
SdkProvider: () => SdkProvider,
|
|
26
|
+
ServiceLocationTypeEnum: () => ServiceLocationTypeEnum,
|
|
27
|
+
ServiceRecurringIntervalEnum: () => ServiceRecurringIntervalEnum,
|
|
28
|
+
ServiceTypeEnum: () => ServiceTypeEnum,
|
|
38
29
|
acceptQuote: () => acceptQuote,
|
|
39
30
|
addToCart: () => addToCart,
|
|
40
31
|
addToGuestCart: () => addToGuestCart,
|
|
41
32
|
addToWishlist: () => addToWishlist,
|
|
42
33
|
approveDeliverable: () => approveDeliverable,
|
|
43
|
-
authAxios: () => authAxios,
|
|
44
34
|
bespokeService: () => bespokeService,
|
|
45
35
|
bookAppointment: () => bookAppointment,
|
|
46
36
|
buildDeliveryAddress: () => buildDeliveryAddress,
|
|
47
|
-
buildFullName: () =>
|
|
37
|
+
buildFullName: () => buildFullName2,
|
|
48
38
|
cancelAppointment: () => cancelAppointment,
|
|
49
39
|
cancelOrder: () => cancelOrder,
|
|
50
40
|
checkAvailability: () => checkAvailability,
|
|
51
41
|
checkInWishlist: () => checkInWishlist,
|
|
52
42
|
clearCart: () => clearCart,
|
|
53
43
|
clearGuestCart: () => clearGuestCart,
|
|
54
|
-
|
|
55
|
-
cmsAxios: () => cmsAxios,
|
|
56
|
-
collectionKeys: () => collectionKeys,
|
|
44
|
+
clearTokens: () => clearTokens,
|
|
57
45
|
configService: () => configService,
|
|
58
|
-
configureHttpClients: () => configureHttpClients,
|
|
59
46
|
consultationService: () => consultationService,
|
|
60
47
|
createCmsEntry: () => createCmsEntry,
|
|
61
48
|
createConsultation: () => createConsultation,
|
|
@@ -69,7 +56,6 @@ __export(index_exports, {
|
|
|
69
56
|
getAppointments: () => getAppointments,
|
|
70
57
|
getAuthUser: () => getAuthUser,
|
|
71
58
|
getAvailableSlots: () => getAvailableSlots,
|
|
72
|
-
getBackendUrl: () => getBackendUrl,
|
|
73
59
|
getBusinessConfig: () => getBusinessConfig,
|
|
74
60
|
getCacheTier: () => getCacheTier,
|
|
75
61
|
getCart: () => getCart,
|
|
@@ -77,43 +63,36 @@ __export(index_exports, {
|
|
|
77
63
|
getCmsEntry: () => getCmsEntry,
|
|
78
64
|
getConsultation: () => getConsultation,
|
|
79
65
|
getConsultations: () => getConsultations,
|
|
80
|
-
getCountries: () => getCountries,
|
|
81
66
|
getCustomerDisplayName: () => getCustomerDisplayName,
|
|
82
67
|
getDeliverables: () => getDeliverables,
|
|
83
68
|
getErrorMessage: () => getErrorMessage,
|
|
84
69
|
getFeaturedProducts: () => getFeaturedProducts,
|
|
85
|
-
getGraphQLClient: () => getGraphQLClient,
|
|
86
70
|
getGuestCart: () => getGuestCart,
|
|
87
71
|
getGuestCartCount: () => getGuestCartCount,
|
|
88
72
|
getGuestCartProductType: () => getGuestCartProductType,
|
|
89
73
|
getGuestCartSubtotal: () => getGuestCartSubtotal,
|
|
90
|
-
getGuestSessionId: () => getGuestSessionId,
|
|
91
74
|
getLatestProducts: () => getLatestProducts,
|
|
75
|
+
getLowStockProducts: () => getLowStockProducts,
|
|
92
76
|
getMe: () => getMe,
|
|
93
77
|
getNewProducts: () => getNewProducts,
|
|
94
|
-
|
|
78
|
+
getOnSaleProducts: () => getOnSaleProducts,
|
|
95
79
|
getOrders: () => getOrders,
|
|
96
80
|
getPopularProducts: () => getPopularProducts,
|
|
97
81
|
getRecommendedProducts: () => getRecommendedProducts,
|
|
98
|
-
getRuntimeConfig: () => getRuntimeConfig,
|
|
99
82
|
getSellerShippingAddress: () => getSellerShippingAddress,
|
|
100
83
|
getShippingRates: () => getShippingRates,
|
|
101
|
-
|
|
84
|
+
getStoredTokens: () => getStoredTokens,
|
|
102
85
|
getStorefrontCollectionBySlug: () => getStorefrontCollectionBySlug,
|
|
103
86
|
getStorefrontCollections: () => getStorefrontCollections,
|
|
104
87
|
getStorefrontProductBySlug: () => getStorefrontProductBySlug,
|
|
105
88
|
getStorefrontProducts: () => getStorefrontProducts,
|
|
106
89
|
getStorefrontUrl: () => getStorefrontUrl,
|
|
107
90
|
getSupportedCurrencies: () => getSupportedCurrencies,
|
|
108
|
-
getSupportedCurrenciesList: () => getSupportedCurrenciesList,
|
|
109
91
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
110
|
-
getSupportedLanguagesList: () => getSupportedLanguagesList,
|
|
111
92
|
getTransactionStatus: () => getTransactionStatus,
|
|
112
93
|
getWishlist: () => getWishlist,
|
|
113
94
|
googleTranslate: () => googleTranslate,
|
|
114
|
-
initSdk: () => initSdk,
|
|
115
95
|
initiatePayment: () => initiatePayment,
|
|
116
|
-
isInitialized: () => isInitialized,
|
|
117
96
|
listCmsEntries: () => listCmsEntries,
|
|
118
97
|
localStore: () => localStore,
|
|
119
98
|
logger: () => logger,
|
|
@@ -124,10 +103,7 @@ __export(index_exports, {
|
|
|
124
103
|
mergeGuestCart: () => mergeGuestCart,
|
|
125
104
|
mergeGuestCartIfPresent: () => mergeGuestCartIfPresent,
|
|
126
105
|
notificationsService: () => notificationsService,
|
|
127
|
-
paymentAxios: () => paymentAxios,
|
|
128
106
|
paymentService: () => paymentService,
|
|
129
|
-
productKeys: () => productKeys,
|
|
130
|
-
publicStoreAxios: () => publicStoreAxios,
|
|
131
107
|
refreshToken: () => refreshToken,
|
|
132
108
|
registerCustomer: () => registerCustomer,
|
|
133
109
|
rejectQuote: () => rejectQuote,
|
|
@@ -137,8 +113,6 @@ __export(index_exports, {
|
|
|
137
113
|
removeProductFromWishlist: () => removeProductFromWishlist,
|
|
138
114
|
requestQuote: () => requestQuote,
|
|
139
115
|
requestRevision: () => requestRevision,
|
|
140
|
-
resetConfig: () => resetConfig,
|
|
141
|
-
resetGraphQLClient: () => resetGraphQLClient,
|
|
142
116
|
sanitizeBaseUrl: () => sanitizeBaseUrl,
|
|
143
117
|
sendContactConfirmation: () => sendContactConfirmation,
|
|
144
118
|
sendContactEmail: () => sendContactEmail,
|
|
@@ -148,647 +122,65 @@ __export(index_exports, {
|
|
|
148
122
|
setEnvironmentMode: () => setEnvironmentMode,
|
|
149
123
|
setLoggerEnvironmentMode: () => setLoggerEnvironmentMode,
|
|
150
124
|
silentRefresh: () => silentRefresh,
|
|
151
|
-
splitFullName: () =>
|
|
152
|
-
storeManagementAxios: () => storeManagementAxios,
|
|
125
|
+
splitFullName: () => splitFullName2,
|
|
153
126
|
storeTokens: () => storeTokens,
|
|
154
|
-
tokenStore: () => tokenStore,
|
|
155
127
|
trackOrder: () => trackOrder,
|
|
156
128
|
updateCartItem: () => updateCartItem,
|
|
157
129
|
updateCmsEntry: () => updateCmsEntry,
|
|
158
130
|
updateGuestCartItemQuantity: () => updateGuestCartItemQuantity,
|
|
159
131
|
updateProfile: () => updateProfile,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
useAvailableSlots: () => useAvailableSlots,
|
|
168
|
-
useBespokeAvailability: () => useBespokeAvailability,
|
|
169
|
-
useBookAppointment: () => useBookAppointment,
|
|
170
|
-
useCancelAppointment: () => useCancelAppointment,
|
|
171
|
-
useCancelOrder: () => useCancelOrder,
|
|
172
|
-
useCart: () => useCart,
|
|
173
|
-
useCheckInWishlist: () => useCheckInWishlist,
|
|
174
|
-
useCmsEntries: () => useCmsEntries,
|
|
175
|
-
useCmsEntry: () => useCmsEntry,
|
|
176
|
-
useConsultation: () => useConsultation,
|
|
177
|
-
useConsultationStream: () => useConsultationStream,
|
|
178
|
-
useConsultations: () => useConsultations,
|
|
179
|
-
useCountries: () => useCountries,
|
|
180
|
-
useCreateCmsEntry: () => useCreateCmsEntry,
|
|
181
|
-
useCreateConsultation: () => useCreateConsultation,
|
|
182
|
-
useCreateDVA: () => useCreateDVA,
|
|
183
|
-
useCreateOrder: () => useCreateOrder,
|
|
184
|
-
useCurrencies: () => useCurrencies,
|
|
185
|
-
useDeleteCmsEntry: () => useDeleteCmsEntry,
|
|
186
|
-
useDeliverables: () => useDeliverables,
|
|
187
|
-
useFeaturedProducts: () => useFeaturedProducts,
|
|
188
|
-
useFindOrder: () => useFindOrder,
|
|
189
|
-
useGoogleTranslate: () => useGoogleTranslate,
|
|
190
|
-
useInitiatePayment: () => useInitiatePayment,
|
|
191
|
-
useIsMounted: () => useIsMounted,
|
|
192
|
-
useLatestProducts: () => useLatestProducts,
|
|
193
|
-
useLogin: () => useLogin,
|
|
194
|
-
useLogout: () => useLogout,
|
|
195
|
-
useNewProducts: () => useNewProducts,
|
|
196
|
-
useOrder: () => useOrder,
|
|
197
|
-
useOrderStream: () => useOrderStream,
|
|
198
|
-
useOrderTracking: () => useOrderTracking,
|
|
199
|
-
useOrders: () => useOrders,
|
|
200
|
-
useOrdersList: () => useOrdersList,
|
|
201
|
-
usePollTransactionStatus: () => usePollTransactionStatus,
|
|
202
|
-
usePopularProducts: () => usePopularProducts,
|
|
203
|
-
useProduct: () => useProduct,
|
|
204
|
-
useRecommendedProducts: () => useRecommendedProducts,
|
|
205
|
-
useRegister: () => useRegister,
|
|
206
|
-
useRejectQuote: () => useRejectQuote,
|
|
207
|
-
useRemoveFromWishlist: () => useRemoveFromWishlist,
|
|
208
|
-
useRemoveProductFromWishlist: () => useRemoveProductFromWishlist,
|
|
209
|
-
useRequestRevision: () => useRequestRevision,
|
|
210
|
-
useSendMessage: () => useSendMessage,
|
|
211
|
-
useStates: () => useStates,
|
|
212
|
-
useStorefrontCollection: () => useStorefrontCollection,
|
|
213
|
-
useStorefrontCollections: () => useStorefrontCollections,
|
|
214
|
-
useStorefrontProducts: () => useStorefrontProducts,
|
|
215
|
-
useSupportedLanguages: () => useSupportedLanguages,
|
|
216
|
-
useTransactionStatus: () => useTransactionStatus,
|
|
217
|
-
useUpdateCmsEntry: () => useUpdateCmsEntry,
|
|
218
|
-
useUpdateProfile: () => useUpdateProfile,
|
|
219
|
-
useVerifyTransaction: () => useVerifyTransaction,
|
|
220
|
-
useWishlist: () => useWishlist,
|
|
221
|
-
useWishlistCount: () => useWishlistCount,
|
|
132
|
+
useSdkContext: () => useSdkContext,
|
|
133
|
+
validateConfirmPassword: () => validateConfirmPassword,
|
|
134
|
+
validateEmail: () => validateEmail,
|
|
135
|
+
validateMessage: () => validateMessage,
|
|
136
|
+
validateName: () => validateName,
|
|
137
|
+
validatePassword: () => validatePassword,
|
|
138
|
+
validateRequired: () => validateRequired,
|
|
222
139
|
validateShippingAddress: () => validateShippingAddress,
|
|
223
140
|
verifySocialToken: () => verifySocialToken,
|
|
224
|
-
verifyTransaction: () => verifyTransaction
|
|
225
|
-
wishlistKeys: () => wishlistKeys
|
|
141
|
+
verifyTransaction: () => verifyTransaction
|
|
226
142
|
});
|
|
227
143
|
module.exports = __toCommonJS(index_exports);
|
|
228
144
|
|
|
229
|
-
// src/
|
|
230
|
-
var
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
|
|
236
|
-
// 5m / 10m
|
|
237
|
-
high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
|
|
238
|
-
// 30m / 1h
|
|
239
|
-
};
|
|
240
|
-
var isDevelopment = true;
|
|
241
|
-
function setEnvironmentMode(development) {
|
|
242
|
-
isDevelopment = development;
|
|
145
|
+
// src/context/sdk-context.tsx
|
|
146
|
+
var import_react = require("react");
|
|
147
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
148
|
+
var SdkContext = (0, import_react.createContext)(null);
|
|
149
|
+
function SdkProvider({ config, accessToken, children }) {
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SdkContext.Provider, { value: { config, accessToken }, children });
|
|
243
151
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return CACHE_TIERS[tier];
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
// src/utils/logger.ts
|
|
250
|
-
var isDevelopment2 = true;
|
|
251
|
-
function setLoggerEnvironmentMode(development) {
|
|
252
|
-
isDevelopment2 = development;
|
|
152
|
+
function useSdkContext() {
|
|
153
|
+
return (0, import_react.useContext)(SdkContext);
|
|
253
154
|
}
|
|
254
|
-
var logger = {
|
|
255
|
-
log: (...args) => {
|
|
256
|
-
if (isDevelopment2) {
|
|
257
|
-
console.log(...args);
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
warn: (...args) => {
|
|
261
|
-
if (isDevelopment2) {
|
|
262
|
-
console.warn(...args);
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
/**
|
|
266
|
-
* Logs a warning to the console in development only.
|
|
267
|
-
* Alias for warn() for Python logging compatibility.
|
|
268
|
-
* In production, this is a no-op.
|
|
269
|
-
*/
|
|
270
|
-
warning: (...args) => {
|
|
271
|
-
if (isDevelopment2) {
|
|
272
|
-
console.warn(...args);
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
error: (...args) => {
|
|
276
|
-
if (isDevelopment2) {
|
|
277
|
-
console.error(...args);
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
info: (...args) => {
|
|
281
|
-
if (isDevelopment2) {
|
|
282
|
-
console.info(...args);
|
|
283
|
-
}
|
|
284
|
-
},
|
|
285
|
-
createScope: (scope) => ({
|
|
286
|
-
log: (...args) => {
|
|
287
|
-
if (isDevelopment2) {
|
|
288
|
-
console.log(`[${scope}]`, ...args);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
warn: (...args) => {
|
|
292
|
-
if (isDevelopment2) {
|
|
293
|
-
console.warn(`[${scope}]`, ...args);
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
warning: (...args) => {
|
|
297
|
-
if (isDevelopment2) {
|
|
298
|
-
console.warn(`[${scope}]`, ...args);
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
error: (...args) => {
|
|
302
|
-
if (isDevelopment2) {
|
|
303
|
-
console.error(`[${scope}]`, ...args);
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
info: (...args) => {
|
|
307
|
-
if (isDevelopment2) {
|
|
308
|
-
console.info(`[${scope}]`, ...args);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
})
|
|
312
|
-
};
|
|
313
155
|
|
|
314
|
-
// src/
|
|
315
|
-
var
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
156
|
+
// src/constants.ts
|
|
157
|
+
var STORAGE_KEYS = {
|
|
158
|
+
ACCESS_TOKEN: "kasuvia_access_token",
|
|
159
|
+
REFRESH_TOKEN: "kasuvia_refresh_token",
|
|
160
|
+
CHECKOUT_STATE: "kasuvia_checkout_state",
|
|
161
|
+
ORDERS_LINKED: "kasuvia_orders_linked",
|
|
162
|
+
STOREFRONT_STATE: "storefront_state_v3"
|
|
320
163
|
};
|
|
321
|
-
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
|
|
322
|
-
function sanitizeBaseUrl(url, name = "URL") {
|
|
323
|
-
if (url == null) {
|
|
324
|
-
throw new InvalidBaseURLError(`${name} is not set`);
|
|
325
|
-
}
|
|
326
|
-
const cleaned0 = url.trim();
|
|
327
|
-
if (!cleaned0) {
|
|
328
|
-
throw new InvalidBaseURLError(`${name} is empty`);
|
|
329
|
-
}
|
|
330
|
-
const cleaned = cleaned0.replace(/\/+$/, "");
|
|
331
|
-
let parsed;
|
|
332
|
-
try {
|
|
333
|
-
parsed = new URL(cleaned);
|
|
334
|
-
} catch {
|
|
335
|
-
throw new InvalidBaseURLError(
|
|
336
|
-
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
|
|
340
|
-
throw new InvalidBaseURLError(
|
|
341
|
-
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
if (!parsed.hostname) {
|
|
345
|
-
throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
|
|
346
|
-
}
|
|
347
|
-
if (parsed.search || parsed.hash) {
|
|
348
|
-
throw new InvalidBaseURLError(
|
|
349
|
-
`${name} should not contain a query or fragment: ${url}`
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
return cleaned;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// src/utils/customer.ts
|
|
356
|
-
function buildFullName(firstname, lastname) {
|
|
357
|
-
const name = [firstname, lastname].filter(Boolean).join(" ").trim();
|
|
358
|
-
return name || void 0;
|
|
359
|
-
}
|
|
360
|
-
function splitFullName(fullName) {
|
|
361
|
-
if (!fullName?.trim()) return { firstname: "", lastname: "" };
|
|
362
|
-
const parts = fullName.trim().split(/\s+/);
|
|
363
|
-
return {
|
|
364
|
-
firstname: parts[0] ?? "",
|
|
365
|
-
lastname: parts.slice(1).join(" ")
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
function getCustomerDisplayName(user) {
|
|
369
|
-
const fromParts = buildFullName(user.firstname, user.lastname);
|
|
370
|
-
return fromParts || user.full_name || user.email.split("@")[0];
|
|
371
|
-
}
|
|
372
|
-
function getStorefrontUrl(businessId, customDomain) {
|
|
373
|
-
if (customDomain && customDomain.trim()) {
|
|
374
|
-
const cleanDomain = customDomain.trim().replace(/^https?:\/\//, "");
|
|
375
|
-
return `https://${cleanDomain}`;
|
|
376
|
-
}
|
|
377
|
-
const cleanBid = (businessId || "store").toLowerCase().trim();
|
|
378
|
-
return `https://${cleanBid}.kasuvia.com`;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// src/utils/checkout.ts
|
|
382
|
-
function buildDeliveryAddress(customer, location) {
|
|
383
|
-
return {
|
|
384
|
-
first_name: customer.first_name,
|
|
385
|
-
last_name: customer.last_name,
|
|
386
|
-
phone: customer.phone,
|
|
387
|
-
...location
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
function getCheckoutCustomerName(customer) {
|
|
391
|
-
return buildFullName(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
|
|
392
|
-
}
|
|
393
|
-
function enrichCompletedOrder(order, options) {
|
|
394
|
-
const customerName = getCheckoutCustomerName(options.customer);
|
|
395
|
-
return {
|
|
396
|
-
...order,
|
|
397
|
-
customerName: order.customerName || customerName,
|
|
398
|
-
customerEmail: order.customerEmail || options.customer.email,
|
|
399
|
-
shippingAddress: order.shippingAddress ?? (options.productType === "physical" && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
|
|
400
|
-
bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// src/utils/error-handler.ts
|
|
405
|
-
var import_axios = __toESM(require("axios"));
|
|
406
|
-
function getErrorMessage(error, fallback = "Something went wrong") {
|
|
407
|
-
if (import_axios.default.isAxiosError(error)) {
|
|
408
|
-
return error.response?.data?.detail || error.response?.data?.message || error.message || fallback;
|
|
409
|
-
}
|
|
410
|
-
if (error instanceof Error) {
|
|
411
|
-
return error.message;
|
|
412
|
-
}
|
|
413
|
-
return fallback;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// src/config/index.ts
|
|
417
|
-
var runtimeConfig = null;
|
|
418
|
-
var BACKEND_URLS = {
|
|
419
|
-
auth: "https://127.0.0.1:8000/api/v1",
|
|
420
|
-
store: "https://127.0.0.1:8001/api/v1",
|
|
421
|
-
payment: "https://127.0.0.1:8002/api/v1",
|
|
422
|
-
notifications: "https://127.0.0.1:8007/api/v1",
|
|
423
|
-
cms: "https://127.0.0.1:8009/api/v1"
|
|
424
|
-
};
|
|
425
|
-
function initSdk(config) {
|
|
426
|
-
runtimeConfig = {
|
|
427
|
-
businessId: config.businessId,
|
|
428
|
-
storefrontApiKey: config.storefrontApiKey
|
|
429
|
-
};
|
|
430
|
-
const isDevelopment3 = typeof window === "undefined" && globalThis.process?.env?.NODE_ENV === "development";
|
|
431
|
-
setEnvironmentMode(isDevelopment3);
|
|
432
|
-
setLoggerEnvironmentMode(isDevelopment3);
|
|
433
|
-
logger.log("SDK initialized with businessId:", config.businessId);
|
|
434
|
-
}
|
|
435
|
-
function getRuntimeConfig() {
|
|
436
|
-
if (!runtimeConfig) {
|
|
437
|
-
throw new Error("SDK not initialized. Call initSdk() before using SDK functions.");
|
|
438
|
-
}
|
|
439
|
-
return runtimeConfig;
|
|
440
|
-
}
|
|
441
|
-
function getBackendUrl(service) {
|
|
442
|
-
return BACKEND_URLS[service];
|
|
443
|
-
}
|
|
444
|
-
function isInitialized() {
|
|
445
|
-
return runtimeConfig !== null;
|
|
446
|
-
}
|
|
447
|
-
function resetConfig() {
|
|
448
|
-
runtimeConfig = null;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// src/client/httpClient.ts
|
|
452
|
-
var import_axios3 = __toESM(require("axios"));
|
|
453
|
-
|
|
454
|
-
// src/client/authClient.ts
|
|
455
|
-
var import_axios2 = __toESM(require("axios"));
|
|
456
|
-
var _accessToken = null;
|
|
457
|
-
var _isRefreshing = false;
|
|
458
|
-
var _pendingQueue = [];
|
|
459
|
-
function getStorageKey() {
|
|
460
|
-
if (!isInitialized()) return "kasuvia-sf-anon-refresh";
|
|
461
|
-
const config = getRuntimeConfig();
|
|
462
|
-
return `kasuvia-sf-${config.businessId}-refresh`;
|
|
463
|
-
}
|
|
464
|
-
function drainQueue(error, newToken = null) {
|
|
465
|
-
_pendingQueue.forEach(({ resolve, reject }) => {
|
|
466
|
-
if (newToken) resolve(newToken);
|
|
467
|
-
else reject(error);
|
|
468
|
-
});
|
|
469
|
-
_pendingQueue = [];
|
|
470
|
-
}
|
|
471
|
-
var tokenStore = {
|
|
472
|
-
getAccessToken: () => _accessToken,
|
|
473
|
-
setAccessToken: (token) => {
|
|
474
|
-
_accessToken = token;
|
|
475
|
-
},
|
|
476
|
-
getRefreshToken: () => {
|
|
477
|
-
if (typeof window === "undefined") return null;
|
|
478
|
-
const key = getStorageKey();
|
|
479
|
-
return localStorage.getItem(key) || sessionStorage.getItem(key);
|
|
480
|
-
},
|
|
481
|
-
setRefreshToken: (token, remember = true) => {
|
|
482
|
-
if (typeof window === "undefined") return;
|
|
483
|
-
const key = getStorageKey();
|
|
484
|
-
localStorage.removeItem(key);
|
|
485
|
-
sessionStorage.removeItem(key);
|
|
486
|
-
if (token) {
|
|
487
|
-
const store = remember ? localStorage : sessionStorage;
|
|
488
|
-
store.setItem(key, token);
|
|
489
|
-
}
|
|
490
|
-
},
|
|
491
|
-
clearAll: () => {
|
|
492
|
-
_accessToken = null;
|
|
493
|
-
if (typeof window !== "undefined") {
|
|
494
|
-
const key = getStorageKey();
|
|
495
|
-
localStorage.removeItem(key);
|
|
496
|
-
sessionStorage.removeItem(key);
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
hasSession: () => {
|
|
500
|
-
if (typeof window === "undefined") return false;
|
|
501
|
-
const key = getStorageKey();
|
|
502
|
-
return !!(localStorage.getItem(key) || sessionStorage.getItem(key));
|
|
503
|
-
},
|
|
504
|
-
isPersistent: () => {
|
|
505
|
-
if (typeof window === "undefined") return true;
|
|
506
|
-
const key = getStorageKey();
|
|
507
|
-
return !!localStorage.getItem(key);
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
var refreshAxios = import_axios2.default.create({
|
|
511
|
-
baseURL: getBackendUrl("auth"),
|
|
512
|
-
headers: {
|
|
513
|
-
"Content-Type": "application/json",
|
|
514
|
-
Accept: "application/json"
|
|
515
|
-
},
|
|
516
|
-
withCredentials: true,
|
|
517
|
-
timeout: 3e4
|
|
518
|
-
});
|
|
519
|
-
async function refreshToken() {
|
|
520
|
-
if (_isRefreshing) {
|
|
521
|
-
return new Promise((resolve, reject) => {
|
|
522
|
-
_pendingQueue.push({ resolve, reject });
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
_isRefreshing = true;
|
|
526
|
-
const refresh = tokenStore.getRefreshToken();
|
|
527
|
-
if (!refresh) {
|
|
528
|
-
_isRefreshing = false;
|
|
529
|
-
tokenStore.clearAll();
|
|
530
|
-
throw new Error("[kasuvia SDK] No refresh token available");
|
|
531
|
-
}
|
|
532
|
-
try {
|
|
533
|
-
const { data } = await refreshAxios.post("/auth/token/refresh/", { refresh });
|
|
534
|
-
const newAccess = data.access;
|
|
535
|
-
tokenStore.setAccessToken(newAccess);
|
|
536
|
-
if (data.refresh) {
|
|
537
|
-
tokenStore.setRefreshToken(data.refresh, tokenStore.isPersistent());
|
|
538
|
-
}
|
|
539
|
-
drainQueue(null, newAccess);
|
|
540
|
-
return newAccess;
|
|
541
|
-
} catch (err) {
|
|
542
|
-
drainQueue(err);
|
|
543
|
-
tokenStore.clearAll();
|
|
544
|
-
throw err;
|
|
545
|
-
} finally {
|
|
546
|
-
_isRefreshing = false;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// src/client/httpClient.ts
|
|
551
|
-
var _guestSessionId = null;
|
|
552
|
-
function getOrCreateGuestSessionId() {
|
|
553
|
-
if (_guestSessionId) return _guestSessionId;
|
|
554
|
-
const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
|
|
555
|
-
if (typeof window !== "undefined") {
|
|
556
|
-
_guestSessionId = sessionStorage.getItem(storageKey) || crypto.randomUUID();
|
|
557
|
-
sessionStorage.setItem(storageKey, _guestSessionId);
|
|
558
|
-
} else {
|
|
559
|
-
_guestSessionId = crypto.randomUUID();
|
|
560
|
-
}
|
|
561
|
-
return _guestSessionId;
|
|
562
|
-
}
|
|
563
|
-
function getGuestSessionId() {
|
|
564
|
-
if (!_guestSessionId && typeof window !== "undefined") {
|
|
565
|
-
const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
|
|
566
|
-
_guestSessionId = sessionStorage.getItem(storageKey);
|
|
567
|
-
}
|
|
568
|
-
return _guestSessionId;
|
|
569
|
-
}
|
|
570
|
-
function clearGuestSessionId() {
|
|
571
|
-
_guestSessionId = null;
|
|
572
|
-
if (typeof window !== "undefined") {
|
|
573
|
-
const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
|
|
574
|
-
sessionStorage.removeItem(storageKey);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
var storeManagementAxios = import_axios3.default.create({
|
|
578
|
-
baseURL: getBackendUrl("store"),
|
|
579
|
-
headers: {
|
|
580
|
-
"Content-Type": "application/json",
|
|
581
|
-
Accept: "application/json"
|
|
582
|
-
},
|
|
583
|
-
timeout: 3e4
|
|
584
|
-
});
|
|
585
|
-
storeManagementAxios.interceptors.request.use((cfg) => {
|
|
586
|
-
const config = getRuntimeConfig();
|
|
587
|
-
const token = tokenStore.getAccessToken();
|
|
588
|
-
if (token) {
|
|
589
|
-
cfg.headers = cfg.headers ?? {};
|
|
590
|
-
cfg.headers["Authorization"] = `Bearer ${token}`;
|
|
591
|
-
}
|
|
592
|
-
cfg.headers = cfg.headers ?? {};
|
|
593
|
-
cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
594
|
-
cfg.headers["X-Business-ID"] = config.businessId;
|
|
595
|
-
if (!token) {
|
|
596
|
-
const sid = getOrCreateGuestSessionId();
|
|
597
|
-
if (sid) cfg.headers["X-Guest-Session"] = sid;
|
|
598
|
-
}
|
|
599
|
-
return cfg;
|
|
600
|
-
});
|
|
601
|
-
storeManagementAxios.interceptors.response.use(
|
|
602
|
-
(res) => res,
|
|
603
|
-
async (err) => {
|
|
604
|
-
const originalRequest = err.config;
|
|
605
|
-
if (!originalRequest) return Promise.reject(err);
|
|
606
|
-
const status = err.response?.status;
|
|
607
|
-
const isUnauthorized = status === 401;
|
|
608
|
-
const isRefreshEndpoint = originalRequest.url?.includes("/auth/token/refresh/");
|
|
609
|
-
const alreadyRetried = originalRequest._retry === true;
|
|
610
|
-
if (isUnauthorized && isRefreshEndpoint) {
|
|
611
|
-
tokenStore.clearAll();
|
|
612
|
-
return Promise.reject(err);
|
|
613
|
-
}
|
|
614
|
-
if (!isUnauthorized || alreadyRetried) return Promise.reject(err);
|
|
615
|
-
try {
|
|
616
|
-
const newToken = await refreshToken();
|
|
617
|
-
originalRequest._retry = true;
|
|
618
|
-
if (originalRequest.headers) {
|
|
619
|
-
originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
|
|
620
|
-
}
|
|
621
|
-
return storeManagementAxios(originalRequest);
|
|
622
|
-
} catch (refreshErr) {
|
|
623
|
-
tokenStore.clearAll();
|
|
624
|
-
return Promise.reject(refreshErr);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
);
|
|
628
|
-
var publicStoreAxios = import_axios3.default.create({
|
|
629
|
-
baseURL: getBackendUrl("store"),
|
|
630
|
-
headers: {
|
|
631
|
-
"Content-Type": "application/json",
|
|
632
|
-
Accept: "application/json"
|
|
633
|
-
},
|
|
634
|
-
timeout: 3e4
|
|
635
|
-
});
|
|
636
|
-
publicStoreAxios.interceptors.request.use((cfg) => {
|
|
637
|
-
const config = getRuntimeConfig();
|
|
638
|
-
cfg.headers = cfg.headers ?? {};
|
|
639
|
-
cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
640
|
-
cfg.headers["X-Business-ID"] = config.businessId;
|
|
641
|
-
return cfg;
|
|
642
|
-
});
|
|
643
|
-
publicStoreAxios.interceptors.response.use(
|
|
644
|
-
(res) => res,
|
|
645
|
-
(err) => Promise.reject(err)
|
|
646
|
-
);
|
|
647
|
-
var authAxios = import_axios3.default.create({
|
|
648
|
-
baseURL: getBackendUrl("auth"),
|
|
649
|
-
headers: {
|
|
650
|
-
"Content-Type": "application/json",
|
|
651
|
-
Accept: "application/json"
|
|
652
|
-
},
|
|
653
|
-
withCredentials: true,
|
|
654
|
-
timeout: 3e4
|
|
655
|
-
});
|
|
656
|
-
authAxios.interceptors.request.use((cfg) => {
|
|
657
|
-
const config = getRuntimeConfig();
|
|
658
|
-
const token = tokenStore.getAccessToken();
|
|
659
|
-
if (token) {
|
|
660
|
-
cfg.headers = cfg.headers ?? {};
|
|
661
|
-
cfg.headers["Authorization"] = `Bearer ${token}`;
|
|
662
|
-
}
|
|
663
|
-
cfg.headers = cfg.headers ?? {};
|
|
664
|
-
cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
665
|
-
cfg.headers["X-Business-ID"] = config.businessId;
|
|
666
|
-
return cfg;
|
|
667
|
-
});
|
|
668
|
-
authAxios.interceptors.response.use(
|
|
669
|
-
(res) => res,
|
|
670
|
-
async (err) => {
|
|
671
|
-
const originalRequest = err.config;
|
|
672
|
-
if (!originalRequest) return Promise.reject(err);
|
|
673
|
-
const status = err.response?.status;
|
|
674
|
-
const isUnauthorized = status === 401;
|
|
675
|
-
const isRefreshEndpoint = originalRequest.url?.includes("/auth/token/refresh/");
|
|
676
|
-
const alreadyRetried = originalRequest._retry === true;
|
|
677
|
-
if (isUnauthorized && isRefreshEndpoint) {
|
|
678
|
-
tokenStore.clearAll();
|
|
679
|
-
return Promise.reject(err);
|
|
680
|
-
}
|
|
681
|
-
if (!isUnauthorized || alreadyRetried) return Promise.reject(err);
|
|
682
|
-
try {
|
|
683
|
-
const newToken = await refreshToken();
|
|
684
|
-
originalRequest._retry = true;
|
|
685
|
-
if (originalRequest.headers) {
|
|
686
|
-
originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
|
|
687
|
-
}
|
|
688
|
-
return authAxios(originalRequest);
|
|
689
|
-
} catch (refreshErr) {
|
|
690
|
-
tokenStore.clearAll();
|
|
691
|
-
return Promise.reject(refreshErr);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
);
|
|
695
|
-
var paymentAxios = import_axios3.default.create({
|
|
696
|
-
baseURL: getBackendUrl("payment"),
|
|
697
|
-
headers: {
|
|
698
|
-
"Content-Type": "application/json",
|
|
699
|
-
Accept: "application/json"
|
|
700
|
-
},
|
|
701
|
-
timeout: 3e4
|
|
702
|
-
});
|
|
703
|
-
paymentAxios.interceptors.request.use((cfg) => {
|
|
704
|
-
const config = getRuntimeConfig();
|
|
705
|
-
cfg.headers = cfg.headers ?? {};
|
|
706
|
-
cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
707
|
-
cfg.headers["X-Business-ID"] = config.businessId;
|
|
708
|
-
return cfg;
|
|
709
|
-
});
|
|
710
|
-
paymentAxios.interceptors.response.use(
|
|
711
|
-
(res) => res,
|
|
712
|
-
(err) => Promise.reject(err)
|
|
713
|
-
);
|
|
714
|
-
var notificationsAxios = import_axios3.default.create({
|
|
715
|
-
baseURL: getBackendUrl("notifications"),
|
|
716
|
-
headers: {
|
|
717
|
-
"Content-Type": "application/json",
|
|
718
|
-
Accept: "application/json"
|
|
719
|
-
},
|
|
720
|
-
timeout: 3e4
|
|
721
|
-
});
|
|
722
|
-
notificationsAxios.interceptors.response.use(
|
|
723
|
-
(res) => res,
|
|
724
|
-
(err) => Promise.reject(err)
|
|
725
|
-
);
|
|
726
|
-
var cmsAxios = import_axios3.default.create({
|
|
727
|
-
baseURL: getBackendUrl("cms"),
|
|
728
|
-
headers: {
|
|
729
|
-
"Content-Type": "application/json",
|
|
730
|
-
Accept: "application/json"
|
|
731
|
-
},
|
|
732
|
-
timeout: 3e4
|
|
733
|
-
});
|
|
734
|
-
cmsAxios.interceptors.request.use((cfg) => {
|
|
735
|
-
const config = getRuntimeConfig();
|
|
736
|
-
cfg.headers = cfg.headers ?? {};
|
|
737
|
-
cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
738
|
-
cfg.headers["X-Business-ID"] = config.businessId;
|
|
739
|
-
return cfg;
|
|
740
|
-
});
|
|
741
|
-
cmsAxios.interceptors.response.use(
|
|
742
|
-
(res) => res,
|
|
743
|
-
(err) => Promise.reject(err)
|
|
744
|
-
);
|
|
745
|
-
var refreshAxios2 = import_axios3.default.create({
|
|
746
|
-
baseURL: getBackendUrl("auth"),
|
|
747
|
-
headers: {
|
|
748
|
-
"Content-Type": "application/json",
|
|
749
|
-
Accept: "application/json"
|
|
750
|
-
},
|
|
751
|
-
withCredentials: true,
|
|
752
|
-
timeout: 3e4
|
|
753
|
-
});
|
|
754
|
-
function configureHttpClients() {
|
|
755
|
-
if (!isInitialized()) return;
|
|
756
|
-
const storeUrl = getBackendUrl("store");
|
|
757
|
-
const authUrl = getBackendUrl("auth");
|
|
758
|
-
const paymentUrl = getBackendUrl("payment");
|
|
759
|
-
const notificationsUrl = getBackendUrl("notifications");
|
|
760
|
-
const cmsUrl = getBackendUrl("cms");
|
|
761
|
-
storeManagementAxios.defaults.baseURL = storeUrl;
|
|
762
|
-
publicStoreAxios.defaults.baseURL = storeUrl;
|
|
763
|
-
authAxios.defaults.baseURL = authUrl;
|
|
764
|
-
paymentAxios.defaults.baseURL = paymentUrl;
|
|
765
|
-
notificationsAxios.defaults.baseURL = notificationsUrl;
|
|
766
|
-
cmsAxios.defaults.baseURL = cmsUrl;
|
|
767
|
-
refreshAxios2.defaults.baseURL = authUrl;
|
|
768
|
-
}
|
|
769
164
|
|
|
770
|
-
// src/
|
|
771
|
-
var
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
function resetGraphQLClient() {
|
|
791
|
-
}
|
|
165
|
+
// src/types/store/index.ts
|
|
166
|
+
var ServiceTypeEnum = /* @__PURE__ */ ((ServiceTypeEnum2) => {
|
|
167
|
+
ServiceTypeEnum2["APPOINTMENT"] = "appointment";
|
|
168
|
+
ServiceTypeEnum2["PROJECT"] = "project";
|
|
169
|
+
ServiceTypeEnum2["RECURRING"] = "recurring";
|
|
170
|
+
return ServiceTypeEnum2;
|
|
171
|
+
})(ServiceTypeEnum || {});
|
|
172
|
+
var ServiceLocationTypeEnum = /* @__PURE__ */ ((ServiceLocationTypeEnum2) => {
|
|
173
|
+
ServiceLocationTypeEnum2["REMOTE"] = "remote";
|
|
174
|
+
ServiceLocationTypeEnum2["PHYSICAL"] = "physical";
|
|
175
|
+
ServiceLocationTypeEnum2["BOTH"] = "both";
|
|
176
|
+
return ServiceLocationTypeEnum2;
|
|
177
|
+
})(ServiceLocationTypeEnum || {});
|
|
178
|
+
var ServiceRecurringIntervalEnum = /* @__PURE__ */ ((ServiceRecurringIntervalEnum2) => {
|
|
179
|
+
ServiceRecurringIntervalEnum2["WEEKLY"] = "weekly";
|
|
180
|
+
ServiceRecurringIntervalEnum2["MONTHLY"] = "monthly";
|
|
181
|
+
ServiceRecurringIntervalEnum2["YEARLY"] = "yearly";
|
|
182
|
+
return ServiceRecurringIntervalEnum2;
|
|
183
|
+
})(ServiceRecurringIntervalEnum || {});
|
|
792
184
|
|
|
793
185
|
// src/services/cart.service.ts
|
|
794
186
|
function parseItems(items) {
|
|
@@ -797,21 +189,25 @@ function parseItems(items) {
|
|
|
797
189
|
variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
|
|
798
190
|
}));
|
|
799
191
|
}
|
|
800
|
-
async function getGuestCart() {
|
|
801
|
-
|
|
802
|
-
if (!sid) return [];
|
|
192
|
+
async function getGuestCart(config, guestSessionId) {
|
|
193
|
+
if (!guestSessionId) return [];
|
|
803
194
|
try {
|
|
804
|
-
const
|
|
805
|
-
headers: {
|
|
195
|
+
const response = await fetch(`${config.backendUrls.store}/cart/`, {
|
|
196
|
+
headers: {
|
|
197
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
198
|
+
"X-Business-ID": config.businessId,
|
|
199
|
+
"X-Guest-Session": guestSessionId
|
|
200
|
+
}
|
|
806
201
|
});
|
|
202
|
+
if (!response.ok) return [];
|
|
203
|
+
const data = await response.json();
|
|
807
204
|
return parseItems(data.items || []);
|
|
808
205
|
} catch {
|
|
809
206
|
return [];
|
|
810
207
|
}
|
|
811
208
|
}
|
|
812
|
-
async function addToGuestCart(item) {
|
|
813
|
-
|
|
814
|
-
if (!sid) return [];
|
|
209
|
+
async function addToGuestCart(config, guestSessionId, item) {
|
|
210
|
+
if (!guestSessionId) return [];
|
|
815
211
|
const payload = {
|
|
816
212
|
product_id: item.product_id,
|
|
817
213
|
product_slug: item.product_slug,
|
|
@@ -824,66 +220,132 @@ async function addToGuestCart(item) {
|
|
|
824
220
|
custom_measurements: item.custom_measurements,
|
|
825
221
|
is_bespoke: item.is_bespoke
|
|
826
222
|
};
|
|
827
|
-
const
|
|
828
|
-
|
|
223
|
+
const response = await fetch(`${config.backendUrls.store}/cart/`, {
|
|
224
|
+
method: "POST",
|
|
225
|
+
headers: {
|
|
226
|
+
"Content-Type": "application/json",
|
|
227
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
228
|
+
"X-Business-ID": config.businessId,
|
|
229
|
+
"X-Guest-Session": guestSessionId
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify(payload)
|
|
829
232
|
});
|
|
233
|
+
if (!response.ok) return [];
|
|
234
|
+
const data = await response.json();
|
|
830
235
|
return parseItems(data.items || []);
|
|
831
236
|
}
|
|
832
|
-
async function updateGuestCartItemQuantity(itemId, quantity) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
237
|
+
async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
|
|
238
|
+
if (!guestSessionId) return [];
|
|
239
|
+
const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
|
|
240
|
+
method: "PATCH",
|
|
241
|
+
headers: {
|
|
242
|
+
"Content-Type": "application/json",
|
|
243
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
244
|
+
"X-Business-ID": config.businessId,
|
|
245
|
+
"X-Guest-Session": guestSessionId
|
|
246
|
+
},
|
|
247
|
+
body: JSON.stringify({ quantity })
|
|
248
|
+
});
|
|
249
|
+
if (!response.ok) return [];
|
|
250
|
+
const data = await response.json();
|
|
840
251
|
return parseItems(data.items || []);
|
|
841
252
|
}
|
|
842
|
-
async function removeFromGuestCart(itemId) {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
headers: {
|
|
253
|
+
async function removeFromGuestCart(config, guestSessionId, itemId) {
|
|
254
|
+
if (!guestSessionId) return [];
|
|
255
|
+
await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
|
|
256
|
+
method: "DELETE",
|
|
257
|
+
headers: {
|
|
258
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
259
|
+
"X-Business-ID": config.businessId,
|
|
260
|
+
"X-Guest-Session": guestSessionId
|
|
261
|
+
}
|
|
847
262
|
});
|
|
848
|
-
return getGuestCart();
|
|
263
|
+
return getGuestCart(config, guestSessionId);
|
|
849
264
|
}
|
|
850
|
-
async function clearGuestCart() {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
headers: {
|
|
265
|
+
async function clearGuestCart(config, guestSessionId) {
|
|
266
|
+
if (!guestSessionId) return;
|
|
267
|
+
await fetch(`${config.backendUrls.store}/cart/clear`, {
|
|
268
|
+
method: "DELETE",
|
|
269
|
+
headers: {
|
|
270
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
271
|
+
"X-Business-ID": config.businessId,
|
|
272
|
+
"X-Guest-Session": guestSessionId
|
|
273
|
+
}
|
|
855
274
|
});
|
|
856
275
|
}
|
|
857
|
-
async function getCart() {
|
|
858
|
-
|
|
276
|
+
async function getCart(config, accessToken) {
|
|
277
|
+
if (!accessToken) {
|
|
278
|
+
return { id: "", items: [], subtotal: 0, total: 0, product_type: "physical" };
|
|
279
|
+
}
|
|
280
|
+
const response = await fetch(`${config.backendUrls.store}/cart/`, {
|
|
281
|
+
headers: {
|
|
282
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
283
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
284
|
+
"X-Business-ID": config.businessId
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
if (!response.ok) throw new Error("Failed to fetch cart");
|
|
288
|
+
const data = await response.json();
|
|
859
289
|
const parsedItems = parseItems(data.items || []);
|
|
860
290
|
return { ...data, items: parsedItems };
|
|
861
291
|
}
|
|
862
|
-
async function addToCart(item) {
|
|
863
|
-
const
|
|
292
|
+
async function addToCart(config, accessToken, item) {
|
|
293
|
+
const response = await fetch(`${config.backendUrls.store}/cart/`, {
|
|
294
|
+
method: "POST",
|
|
295
|
+
headers: {
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
298
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
299
|
+
"X-Business-ID": config.businessId
|
|
300
|
+
},
|
|
301
|
+
body: JSON.stringify(item)
|
|
302
|
+
});
|
|
303
|
+
if (!response.ok) throw new Error("Failed to add to cart");
|
|
304
|
+
const data = await response.json();
|
|
864
305
|
const parsedItems = parseItems(data.items || []);
|
|
865
306
|
return { ...data, items: parsedItems };
|
|
866
307
|
}
|
|
867
|
-
async function updateCartItem(itemId, quantity) {
|
|
868
|
-
const
|
|
869
|
-
|
|
870
|
-
{
|
|
871
|
-
|
|
308
|
+
async function updateCartItem(config, accessToken, itemId, quantity) {
|
|
309
|
+
const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
|
|
310
|
+
method: "PATCH",
|
|
311
|
+
headers: {
|
|
312
|
+
"Content-Type": "application/json",
|
|
313
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
314
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
315
|
+
"X-Business-ID": config.businessId
|
|
316
|
+
},
|
|
317
|
+
body: JSON.stringify({ quantity })
|
|
318
|
+
});
|
|
319
|
+
if (!response.ok) throw new Error("Failed to update cart item");
|
|
320
|
+
const data = await response.json();
|
|
872
321
|
const parsedItems = parseItems(data.items || []);
|
|
873
322
|
return { ...data, items: parsedItems };
|
|
874
323
|
}
|
|
875
|
-
async function removeFromCart(itemId) {
|
|
876
|
-
await
|
|
877
|
-
|
|
324
|
+
async function removeFromCart(config, accessToken, itemId) {
|
|
325
|
+
await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
|
|
326
|
+
method: "DELETE",
|
|
327
|
+
headers: {
|
|
328
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
329
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
330
|
+
"X-Business-ID": config.businessId
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
return getCart(config, accessToken);
|
|
878
334
|
}
|
|
879
|
-
async function clearCart() {
|
|
880
|
-
await
|
|
335
|
+
async function clearCart(config, accessToken) {
|
|
336
|
+
await fetch(`${config.backendUrls.store}/cart/clear`, {
|
|
337
|
+
method: "DELETE",
|
|
338
|
+
headers: {
|
|
339
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
340
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
341
|
+
"X-Business-ID": config.businessId
|
|
342
|
+
}
|
|
343
|
+
});
|
|
881
344
|
}
|
|
882
|
-
async function mergeGuestCart() {
|
|
883
|
-
const
|
|
884
|
-
const guestItems = sid ? await getGuestCart() : [];
|
|
345
|
+
async function mergeGuestCart(config, accessToken, guestSessionId) {
|
|
346
|
+
const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
|
|
885
347
|
if (guestItems.length === 0) {
|
|
886
|
-
return getCart();
|
|
348
|
+
return getCart(config, accessToken);
|
|
887
349
|
}
|
|
888
350
|
const payloadItems = guestItems.map((item) => ({
|
|
889
351
|
product_id: item.product_id,
|
|
@@ -897,19 +359,29 @@ async function mergeGuestCart() {
|
|
|
897
359
|
custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
|
|
898
360
|
is_bespoke: item.is_bespoke
|
|
899
361
|
}));
|
|
900
|
-
const
|
|
901
|
-
"
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
362
|
+
const headers = {
|
|
363
|
+
"Content-Type": "application/json",
|
|
364
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
365
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
366
|
+
"X-Business-ID": config.businessId
|
|
367
|
+
};
|
|
368
|
+
if (guestSessionId) {
|
|
369
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
370
|
+
}
|
|
371
|
+
const response = await fetch(`${config.backendUrls.store}/cart/merge`, {
|
|
372
|
+
method: "POST",
|
|
373
|
+
headers,
|
|
374
|
+
body: JSON.stringify({ items: payloadItems })
|
|
375
|
+
});
|
|
376
|
+
if (!response.ok) throw new Error("Failed to merge guest cart");
|
|
377
|
+
const data = await response.json();
|
|
906
378
|
return { ...data, items: parseItems(data.items || []) };
|
|
907
379
|
}
|
|
908
|
-
async function mergeGuestCartIfPresent() {
|
|
380
|
+
async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
|
|
909
381
|
try {
|
|
910
|
-
const guestItems = await getGuestCart();
|
|
382
|
+
const guestItems = await getGuestCart(config, guestSessionId);
|
|
911
383
|
if (guestItems.length === 0) return;
|
|
912
|
-
await mergeGuestCart();
|
|
384
|
+
await mergeGuestCart(config, accessToken, guestSessionId);
|
|
913
385
|
} catch (error) {
|
|
914
386
|
console.warn("[Cart] Failed to merge guest cart:", error);
|
|
915
387
|
}
|
|
@@ -983,88 +455,173 @@ function normaliseStorefrontOrder(raw) {
|
|
|
983
455
|
guestName: raw.guest_name
|
|
984
456
|
};
|
|
985
457
|
}
|
|
986
|
-
async function createOrder(payload) {
|
|
987
|
-
const
|
|
458
|
+
async function createOrder(config, accessToken, payload) {
|
|
459
|
+
const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
|
|
460
|
+
method: "POST",
|
|
461
|
+
headers: {
|
|
462
|
+
"Content-Type": "application/json",
|
|
463
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
464
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
465
|
+
"X-Business-ID": config.businessId
|
|
466
|
+
},
|
|
467
|
+
body: JSON.stringify(payload)
|
|
468
|
+
});
|
|
469
|
+
if (!response.ok) throw new Error("Failed to create order");
|
|
470
|
+
const data = await response.json();
|
|
988
471
|
return normaliseStorefrontOrder(data);
|
|
989
472
|
}
|
|
990
|
-
async function findOrder(params) {
|
|
991
|
-
const
|
|
473
|
+
async function findOrder(config, params) {
|
|
474
|
+
const queryParams = new URLSearchParams();
|
|
475
|
+
if (params.email) queryParams.set("email", params.email);
|
|
476
|
+
if (params.order_id) queryParams.set("order_id", params.order_id);
|
|
477
|
+
if (params.guest_token) queryParams.set("guest_token", params.guest_token);
|
|
478
|
+
const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
|
|
479
|
+
headers: {
|
|
480
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
481
|
+
"X-Business-ID": config.businessId
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
if (!response.ok) throw new Error("Failed to find order");
|
|
485
|
+
const data = await response.json();
|
|
992
486
|
return normaliseStorefrontOrder(data);
|
|
993
487
|
}
|
|
994
|
-
async function findOrderByToken(token) {
|
|
995
|
-
const
|
|
996
|
-
|
|
488
|
+
async function findOrderByToken(config, token) {
|
|
489
|
+
const response = await fetch(`${config.backendUrls.store}/orders/find/?guest_token=${token}`, {
|
|
490
|
+
headers: {
|
|
491
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
492
|
+
"X-Business-ID": config.businessId
|
|
493
|
+
}
|
|
997
494
|
});
|
|
495
|
+
if (!response.ok) throw new Error("Failed to find order by token");
|
|
496
|
+
const data = await response.json();
|
|
998
497
|
return normaliseStorefrontOrder(data);
|
|
999
498
|
}
|
|
1000
|
-
async function getOrders(params) {
|
|
1001
|
-
const
|
|
499
|
+
async function getOrders(config, accessToken, params) {
|
|
500
|
+
const queryParams = new URLSearchParams();
|
|
501
|
+
if (params?.email) queryParams.set("email", params.email);
|
|
502
|
+
if (params?.page) queryParams.set("page", params.page.toString());
|
|
503
|
+
if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
|
|
504
|
+
const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
|
|
505
|
+
headers: {
|
|
506
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
507
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
508
|
+
"X-Business-ID": config.businessId
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
if (!response.ok) throw new Error("Failed to get orders");
|
|
512
|
+
const data = await response.json();
|
|
1002
513
|
const items = Array.isArray(data) ? data : data.items ?? [];
|
|
1003
514
|
return items.map(normaliseStorefrontOrder);
|
|
1004
515
|
}
|
|
1005
|
-
async function cancelOrder(orderId, reason) {
|
|
1006
|
-
const
|
|
516
|
+
async function cancelOrder(config, accessToken, orderId, reason) {
|
|
517
|
+
const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
|
|
518
|
+
method: "POST",
|
|
519
|
+
headers: {
|
|
520
|
+
"Content-Type": "application/json",
|
|
521
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
522
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
523
|
+
"X-Business-ID": config.businessId
|
|
524
|
+
},
|
|
525
|
+
body: JSON.stringify({ reason })
|
|
526
|
+
});
|
|
527
|
+
if (!response.ok) throw new Error("Failed to cancel order");
|
|
528
|
+
const data = await response.json();
|
|
1007
529
|
return normaliseStorefrontOrder(data);
|
|
1008
530
|
}
|
|
1009
|
-
async function trackOrder(orderId, token) {
|
|
1010
|
-
const
|
|
1011
|
-
|
|
531
|
+
async function trackOrder(config, orderId, token) {
|
|
532
|
+
const queryParams = token ? `?token=${token}` : "";
|
|
533
|
+
const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
|
|
534
|
+
headers: {
|
|
535
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
536
|
+
"X-Business-ID": config.businessId
|
|
537
|
+
}
|
|
1012
538
|
});
|
|
539
|
+
if (!response.ok) throw new Error("Failed to track order");
|
|
540
|
+
const data = await response.json();
|
|
1013
541
|
return normaliseStorefrontOrder(data);
|
|
1014
542
|
}
|
|
1015
543
|
|
|
1016
544
|
// src/services/auth.service.ts
|
|
1017
|
-
async function loginCustomer(payload) {
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
545
|
+
async function loginCustomer(config, payload) {
|
|
546
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/login/customer/`, {
|
|
547
|
+
method: "POST",
|
|
548
|
+
headers: {
|
|
549
|
+
"Content-Type": "application/json",
|
|
550
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
551
|
+
"X-Business-ID": config.businessId
|
|
552
|
+
},
|
|
553
|
+
body: JSON.stringify({
|
|
554
|
+
...payload,
|
|
555
|
+
tenant_id: config.businessId
|
|
556
|
+
})
|
|
1022
557
|
});
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
await
|
|
558
|
+
if (!response.ok) {
|
|
559
|
+
throw new Error("Login failed");
|
|
560
|
+
}
|
|
561
|
+
const data = await response.json();
|
|
1027
562
|
return data;
|
|
1028
563
|
}
|
|
1029
|
-
async function registerCustomer(payload) {
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
564
|
+
async function registerCustomer(config, payload) {
|
|
565
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/register/customer/`, {
|
|
566
|
+
method: "POST",
|
|
567
|
+
headers: {
|
|
568
|
+
"Content-Type": "application/json",
|
|
569
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
570
|
+
"X-Business-ID": config.businessId
|
|
571
|
+
},
|
|
572
|
+
body: JSON.stringify({
|
|
573
|
+
...payload,
|
|
574
|
+
tenant_id: config.businessId
|
|
575
|
+
})
|
|
1034
576
|
});
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
await
|
|
577
|
+
if (!response.ok) {
|
|
578
|
+
throw new Error("Registration failed");
|
|
579
|
+
}
|
|
580
|
+
const data = await response.json();
|
|
1039
581
|
return data;
|
|
1040
582
|
}
|
|
1041
|
-
async function
|
|
1042
|
-
const
|
|
583
|
+
async function refreshToken(config, refresh) {
|
|
584
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/token/refresh/`, {
|
|
585
|
+
method: "POST",
|
|
586
|
+
headers: {
|
|
587
|
+
"Content-Type": "application/json"
|
|
588
|
+
},
|
|
589
|
+
body: JSON.stringify({ refresh })
|
|
590
|
+
});
|
|
591
|
+
if (!response.ok) {
|
|
592
|
+
throw new Error("Token refresh failed");
|
|
593
|
+
}
|
|
594
|
+
const data = await response.json();
|
|
1043
595
|
return data;
|
|
1044
596
|
}
|
|
1045
|
-
async function logout() {
|
|
1046
|
-
const refresh = tokenStore.getRefreshToken();
|
|
597
|
+
async function logout(config, refresh) {
|
|
1047
598
|
const payload = refresh ? { refresh } : {};
|
|
1048
599
|
try {
|
|
1049
|
-
await
|
|
600
|
+
await fetch(`${config.backendUrls.auth}/auth/logout/`, {
|
|
601
|
+
method: "POST",
|
|
602
|
+
headers: {
|
|
603
|
+
"Content-Type": "application/json"
|
|
604
|
+
},
|
|
605
|
+
body: JSON.stringify(payload)
|
|
606
|
+
});
|
|
1050
607
|
} catch {
|
|
1051
|
-
} finally {
|
|
1052
|
-
tokenStore.clearAll();
|
|
1053
|
-
resetGraphQLClient();
|
|
1054
608
|
}
|
|
1055
609
|
}
|
|
1056
|
-
async function verifySocialToken(provider, token) {
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
610
|
+
async function verifySocialToken(config, provider, token) {
|
|
611
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
|
|
612
|
+
method: "POST",
|
|
613
|
+
headers: {
|
|
614
|
+
"Content-Type": "application/json"
|
|
615
|
+
},
|
|
616
|
+
body: JSON.stringify({
|
|
1061
617
|
id_token: token,
|
|
1062
618
|
storefront_key: config.storefrontApiKey
|
|
1063
|
-
}
|
|
1064
|
-
);
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
619
|
+
})
|
|
620
|
+
});
|
|
621
|
+
if (!response.ok) {
|
|
622
|
+
throw new Error("Social token verification failed");
|
|
623
|
+
}
|
|
624
|
+
const data = await response.json();
|
|
1068
625
|
return data;
|
|
1069
626
|
}
|
|
1070
627
|
function parseJwtPayload(token) {
|
|
@@ -1098,7 +655,7 @@ function mapAuthUserToCustomer(data, provider) {
|
|
|
1098
655
|
firstname,
|
|
1099
656
|
lastname,
|
|
1100
657
|
phone,
|
|
1101
|
-
full_name:
|
|
658
|
+
full_name: buildFullName(firstname, lastname),
|
|
1102
659
|
avatar: resolveAvatar(data.profile?.profile_picture),
|
|
1103
660
|
provider: provider ?? resolveProvider(data)
|
|
1104
661
|
};
|
|
@@ -1106,7 +663,7 @@ function mapAuthUserToCustomer(data, provider) {
|
|
|
1106
663
|
function buildCustomerFromClaims(claims) {
|
|
1107
664
|
const provider = claims.is_google_auth_enabled ? "google" : claims.is_facebook_auth_enabled ? "facebook" : "email";
|
|
1108
665
|
const jwtFullName = String(claims.full_name ?? claims.name ?? "").trim() || void 0;
|
|
1109
|
-
const { firstname: splitFirst, lastname: splitLast } =
|
|
666
|
+
const { firstname: splitFirst, lastname: splitLast } = splitFullName(jwtFullName);
|
|
1110
667
|
return {
|
|
1111
668
|
id: String(claims.user_id ?? claims.sub ?? ""),
|
|
1112
669
|
email: String(claims.email ?? ""),
|
|
@@ -1118,86 +675,91 @@ function buildCustomerFromClaims(claims) {
|
|
|
1118
675
|
provider
|
|
1119
676
|
};
|
|
1120
677
|
}
|
|
1121
|
-
async function getMe() {
|
|
1122
|
-
|
|
678
|
+
async function getMe(config, accessToken) {
|
|
679
|
+
if (!config || !accessToken) {
|
|
680
|
+
const response2 = await fetch("/api/auth/me", { credentials: "include" });
|
|
681
|
+
if (!response2.ok) throw new Error("Failed to fetch profile");
|
|
682
|
+
const data2 = await response2.json();
|
|
683
|
+
return data2.user;
|
|
684
|
+
}
|
|
685
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
|
|
686
|
+
headers: {
|
|
687
|
+
"Authorization": `Bearer ${accessToken}`
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
if (!response.ok) {
|
|
691
|
+
throw new Error("Failed to fetch profile");
|
|
692
|
+
}
|
|
693
|
+
const data = await response.json();
|
|
1123
694
|
return mapAuthUserToCustomer(data);
|
|
1124
695
|
}
|
|
1125
|
-
async function getAuthUser() {
|
|
1126
|
-
|
|
696
|
+
async function getAuthUser(config, accessToken) {
|
|
697
|
+
if (!config || !accessToken) {
|
|
698
|
+
const response2 = await fetch("/api/auth/me", { credentials: "include" });
|
|
699
|
+
if (!response2.ok) throw new Error("Failed to fetch auth user");
|
|
700
|
+
const data2 = await response2.json();
|
|
701
|
+
return data2.user;
|
|
702
|
+
}
|
|
703
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
|
|
704
|
+
headers: {
|
|
705
|
+
"Authorization": `Bearer ${accessToken}`
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
if (!response.ok) {
|
|
709
|
+
throw new Error("Failed to fetch auth user");
|
|
710
|
+
}
|
|
711
|
+
const data = await response.json();
|
|
1127
712
|
return data;
|
|
1128
713
|
}
|
|
1129
|
-
async function updateProfile(
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
async function retryWithBackoff(fn, maxRetries = 2, baseDelay = 1e3) {
|
|
1142
|
-
let lastError;
|
|
1143
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1144
|
-
try {
|
|
1145
|
-
return await fn();
|
|
1146
|
-
} catch (error) {
|
|
1147
|
-
lastError = error;
|
|
1148
|
-
const { isNetworkError, isAuthError } = classifyError(error);
|
|
1149
|
-
if (!isNetworkError || isAuthError) {
|
|
1150
|
-
throw error;
|
|
1151
|
-
}
|
|
1152
|
-
if (attempt === maxRetries) {
|
|
1153
|
-
throw error;
|
|
1154
|
-
}
|
|
1155
|
-
const delay = baseDelay * Math.pow(2, attempt);
|
|
1156
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1157
|
-
}
|
|
714
|
+
async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
|
|
715
|
+
const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
|
|
716
|
+
if (!isArg1Config) {
|
|
717
|
+
const payload2 = configOrPayload;
|
|
718
|
+
const response2 = await fetch("/api/auth/profile", {
|
|
719
|
+
method: "PUT",
|
|
720
|
+
headers: { "Content-Type": "application/json" },
|
|
721
|
+
credentials: "include",
|
|
722
|
+
body: JSON.stringify(payload2)
|
|
723
|
+
});
|
|
724
|
+
if (!response2.ok) throw new Error("Failed to update profile");
|
|
725
|
+
return response2.json();
|
|
1158
726
|
}
|
|
1159
|
-
|
|
727
|
+
const config = configOrPayload;
|
|
728
|
+
const accessToken = accessTokenOrPayload;
|
|
729
|
+
const payload = payloadParam;
|
|
730
|
+
const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
|
|
731
|
+
method: "PUT",
|
|
732
|
+
headers: {
|
|
733
|
+
"Content-Type": "application/json",
|
|
734
|
+
"Authorization": `Bearer ${accessToken}`
|
|
735
|
+
},
|
|
736
|
+
body: JSON.stringify(payload)
|
|
737
|
+
});
|
|
738
|
+
if (!response.ok) {
|
|
739
|
+
throw new Error("Failed to update profile");
|
|
740
|
+
}
|
|
741
|
+
const data = await response.json();
|
|
742
|
+
return mapAuthUserToCustomer(data);
|
|
1160
743
|
}
|
|
1161
|
-
async function silentRefresh() {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
refreshPromise = (async () => {
|
|
1166
|
-
try {
|
|
1167
|
-
const tokens = await retryWithBackoff(() => refreshToken2(refresh), 2, 1e3);
|
|
1168
|
-
tokenStore.setAccessToken(tokens.access);
|
|
1169
|
-
if (tokens.refresh) tokenStore.setRefreshToken(tokens.refresh, tokenStore.isPersistent());
|
|
1170
|
-
const claims = parseJwtPayload(tokens.access);
|
|
1171
|
-
const user = buildCustomerFromClaims(claims);
|
|
1172
|
-
return { user, provider: user.provider };
|
|
1173
|
-
} catch (error) {
|
|
1174
|
-
const { isNetworkError, isAuthError, isBlacklistedError } = classifyError(error);
|
|
1175
|
-
if (isNetworkError) {
|
|
1176
|
-
logger.warn("[silentRefresh] Network error during token refresh (offline/CORS), clearing session:", error);
|
|
1177
|
-
} else if (isBlacklistedError) {
|
|
1178
|
-
logger.log("[silentRefresh] Token was blacklisted (likely from logout), clearing session");
|
|
1179
|
-
} else if (isAuthError) {
|
|
1180
|
-
logger.log("[silentRefresh] Token refresh failed with auth error (expired/invalid), clearing session");
|
|
1181
|
-
} else {
|
|
1182
|
-
logger.error("[silentRefresh] Unexpected error during token refresh, clearing session:", error);
|
|
1183
|
-
}
|
|
1184
|
-
tokenStore.clearAll();
|
|
744
|
+
async function silentRefresh(config, refresh) {
|
|
745
|
+
try {
|
|
746
|
+
const data = await refreshToken(config, refresh);
|
|
747
|
+
if (!data.access || !data.refresh) {
|
|
1185
748
|
return null;
|
|
1186
|
-
} finally {
|
|
1187
|
-
refreshPromise = null;
|
|
1188
749
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
750
|
+
const claims = parseJwtPayload(data.access);
|
|
751
|
+
const user = buildCustomerFromClaims(claims);
|
|
752
|
+
const provider = user.provider;
|
|
753
|
+
return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
|
|
754
|
+
} catch {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
1195
757
|
}
|
|
1196
|
-
function
|
|
758
|
+
function buildFullName(firstname, lastname) {
|
|
1197
759
|
if (firstname && lastname) return `${firstname} ${lastname}`;
|
|
1198
760
|
return firstname || lastname || "";
|
|
1199
761
|
}
|
|
1200
|
-
function
|
|
762
|
+
function splitFullName(fullName) {
|
|
1201
763
|
if (!fullName) return { firstname: "", lastname: "" };
|
|
1202
764
|
const parts = fullName.trim().split(/\s+/);
|
|
1203
765
|
if (parts.length === 1) {
|
|
@@ -1208,8 +770,39 @@ function splitFullName2(fullName) {
|
|
|
1208
770
|
lastname: parts.slice(1).join(" ")
|
|
1209
771
|
};
|
|
1210
772
|
}
|
|
773
|
+
function storeTokens(accessToken, refreshToken2) {
|
|
774
|
+
if (typeof window !== "undefined") {
|
|
775
|
+
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
|
|
776
|
+
localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, refreshToken2);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function clearTokens() {
|
|
780
|
+
if (typeof window !== "undefined") {
|
|
781
|
+
localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
782
|
+
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
function getStoredTokens() {
|
|
786
|
+
if (typeof window === "undefined") {
|
|
787
|
+
return { accessToken: null, refreshToken: null };
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
accessToken: localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN),
|
|
791
|
+
refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
|
|
792
|
+
};
|
|
793
|
+
}
|
|
1211
794
|
|
|
1212
795
|
// src/services/product.service.ts
|
|
796
|
+
var import_graphql_request = require("graphql-request");
|
|
797
|
+
function createGraphQLClient(config) {
|
|
798
|
+
const headers = {
|
|
799
|
+
"Content-Type": "application/json",
|
|
800
|
+
"Accept": "application/json",
|
|
801
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
802
|
+
"X-Business-ID": config.businessId
|
|
803
|
+
};
|
|
804
|
+
return new import_graphql_request.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
805
|
+
}
|
|
1213
806
|
var GET_STOREFRONT_PRODUCTS = `
|
|
1214
807
|
query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
|
|
1215
808
|
storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
|
|
@@ -1226,7 +819,7 @@ var GET_STOREFRONT_PRODUCTS = `
|
|
|
1226
819
|
is_bespoke
|
|
1227
820
|
base_price
|
|
1228
821
|
currency
|
|
1229
|
-
images
|
|
822
|
+
images
|
|
1230
823
|
tags
|
|
1231
824
|
custom_fields { label unit required }
|
|
1232
825
|
is_published
|
|
@@ -1249,7 +842,7 @@ var GET_STOREFRONT_PRODUCTS = `
|
|
|
1249
842
|
sku
|
|
1250
843
|
attributes
|
|
1251
844
|
price
|
|
1252
|
-
images
|
|
845
|
+
images
|
|
1253
846
|
weight_kg
|
|
1254
847
|
is_active
|
|
1255
848
|
inventory {
|
|
@@ -1276,7 +869,7 @@ var GET_STOREFRONT_PRODUCTS = `
|
|
|
1276
869
|
name
|
|
1277
870
|
slug
|
|
1278
871
|
description
|
|
1279
|
-
image
|
|
872
|
+
image
|
|
1280
873
|
collection_type
|
|
1281
874
|
rules
|
|
1282
875
|
status
|
|
@@ -1307,7 +900,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
|
1307
900
|
is_bespoke
|
|
1308
901
|
base_price
|
|
1309
902
|
currency
|
|
1310
|
-
images
|
|
903
|
+
images
|
|
1311
904
|
tags
|
|
1312
905
|
custom_fields { label unit required }
|
|
1313
906
|
is_published
|
|
@@ -1330,7 +923,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
|
1330
923
|
sku
|
|
1331
924
|
attributes
|
|
1332
925
|
price
|
|
1333
|
-
images
|
|
926
|
+
images
|
|
1334
927
|
weight_kg
|
|
1335
928
|
is_active
|
|
1336
929
|
inventory {
|
|
@@ -1357,7 +950,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
|
1357
950
|
name
|
|
1358
951
|
slug
|
|
1359
952
|
description
|
|
1360
|
-
image
|
|
953
|
+
image
|
|
1361
954
|
collection_type
|
|
1362
955
|
rules
|
|
1363
956
|
status
|
|
@@ -1368,9 +961,173 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
|
1368
961
|
}
|
|
1369
962
|
}
|
|
1370
963
|
`;
|
|
1371
|
-
var GET_STOREFRONT_LATEST = `
|
|
1372
|
-
query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
|
|
1373
|
-
storefront_latest(page: $page, pageSize: $pageSize) {
|
|
964
|
+
var GET_STOREFRONT_LATEST = `
|
|
965
|
+
query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
|
|
966
|
+
storefront_latest(page: $page, pageSize: $pageSize) {
|
|
967
|
+
items {
|
|
968
|
+
id
|
|
969
|
+
business_id
|
|
970
|
+
name
|
|
971
|
+
slug
|
|
972
|
+
description
|
|
973
|
+
brand
|
|
974
|
+
product_type
|
|
975
|
+
requires_shipping
|
|
976
|
+
is_consumable
|
|
977
|
+
is_bespoke
|
|
978
|
+
base_price
|
|
979
|
+
currency
|
|
980
|
+
images
|
|
981
|
+
tags
|
|
982
|
+
custom_fields { label unit required }
|
|
983
|
+
is_published
|
|
984
|
+
is_featured
|
|
985
|
+
is_popular
|
|
986
|
+
is_new
|
|
987
|
+
is_temporary
|
|
988
|
+
digital_file_key
|
|
989
|
+
download_limit
|
|
990
|
+
download_expires_at
|
|
991
|
+
weight_kg
|
|
992
|
+
length_cm
|
|
993
|
+
width_cm
|
|
994
|
+
height_cm
|
|
995
|
+
created_at
|
|
996
|
+
updated_at
|
|
997
|
+
variants {
|
|
998
|
+
id
|
|
999
|
+
product_id
|
|
1000
|
+
sku
|
|
1001
|
+
attributes
|
|
1002
|
+
price
|
|
1003
|
+
images
|
|
1004
|
+
weight_kg
|
|
1005
|
+
is_active
|
|
1006
|
+
inventory {
|
|
1007
|
+
id
|
|
1008
|
+
product_id
|
|
1009
|
+
variant_id
|
|
1010
|
+
quantity
|
|
1011
|
+
reserved
|
|
1012
|
+
reorder_point
|
|
1013
|
+
reorder_quantity
|
|
1014
|
+
track_quantity
|
|
1015
|
+
allow_backorder
|
|
1016
|
+
available
|
|
1017
|
+
is_in_stock
|
|
1018
|
+
is_low_stock
|
|
1019
|
+
updated_at
|
|
1020
|
+
}
|
|
1021
|
+
created_at
|
|
1022
|
+
updated_at
|
|
1023
|
+
}
|
|
1024
|
+
collections {
|
|
1025
|
+
id
|
|
1026
|
+
business_id
|
|
1027
|
+
name
|
|
1028
|
+
slug
|
|
1029
|
+
description
|
|
1030
|
+
image
|
|
1031
|
+
collection_type
|
|
1032
|
+
rules
|
|
1033
|
+
status
|
|
1034
|
+
sort_order
|
|
1035
|
+
created_at
|
|
1036
|
+
updated_at
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
total
|
|
1040
|
+
page
|
|
1041
|
+
page_size
|
|
1042
|
+
total_pages
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
`;
|
|
1046
|
+
var GET_STOREFRONT_POPULAR = `
|
|
1047
|
+
query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
|
|
1048
|
+
storefront_popular(page: $page, pageSize: $pageSize) {
|
|
1049
|
+
items {
|
|
1050
|
+
id
|
|
1051
|
+
business_id
|
|
1052
|
+
name
|
|
1053
|
+
slug
|
|
1054
|
+
description
|
|
1055
|
+
brand
|
|
1056
|
+
product_type
|
|
1057
|
+
requires_shipping
|
|
1058
|
+
is_consumable
|
|
1059
|
+
is_bespoke
|
|
1060
|
+
base_price
|
|
1061
|
+
currency
|
|
1062
|
+
images
|
|
1063
|
+
tags
|
|
1064
|
+
custom_fields { label unit required }
|
|
1065
|
+
is_published
|
|
1066
|
+
is_featured
|
|
1067
|
+
is_popular
|
|
1068
|
+
is_new
|
|
1069
|
+
is_temporary
|
|
1070
|
+
digital_file_key
|
|
1071
|
+
download_limit
|
|
1072
|
+
download_expires_at
|
|
1073
|
+
weight_kg
|
|
1074
|
+
length_cm
|
|
1075
|
+
width_cm
|
|
1076
|
+
height_cm
|
|
1077
|
+
created_at
|
|
1078
|
+
updated_at
|
|
1079
|
+
variants {
|
|
1080
|
+
id
|
|
1081
|
+
product_id
|
|
1082
|
+
sku
|
|
1083
|
+
attributes
|
|
1084
|
+
price
|
|
1085
|
+
images
|
|
1086
|
+
weight_kg
|
|
1087
|
+
is_active
|
|
1088
|
+
inventory {
|
|
1089
|
+
id
|
|
1090
|
+
product_id
|
|
1091
|
+
variant_id
|
|
1092
|
+
quantity
|
|
1093
|
+
reserved
|
|
1094
|
+
reorder_point
|
|
1095
|
+
reorder_quantity
|
|
1096
|
+
track_quantity
|
|
1097
|
+
allow_backorder
|
|
1098
|
+
available
|
|
1099
|
+
is_in_stock
|
|
1100
|
+
is_low_stock
|
|
1101
|
+
updated_at
|
|
1102
|
+
}
|
|
1103
|
+
created_at
|
|
1104
|
+
updated_at
|
|
1105
|
+
}
|
|
1106
|
+
collections {
|
|
1107
|
+
id
|
|
1108
|
+
business_id
|
|
1109
|
+
name
|
|
1110
|
+
slug
|
|
1111
|
+
description
|
|
1112
|
+
image
|
|
1113
|
+
collection_type
|
|
1114
|
+
rules
|
|
1115
|
+
status
|
|
1116
|
+
sort_order
|
|
1117
|
+
created_at
|
|
1118
|
+
updated_at
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
total
|
|
1122
|
+
page
|
|
1123
|
+
page_size
|
|
1124
|
+
total_pages
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
`;
|
|
1128
|
+
var GET_STOREFRONT_FEATURED = `
|
|
1129
|
+
query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
|
|
1130
|
+
storefront_featured(page: $page, pageSize: $pageSize) {
|
|
1374
1131
|
items {
|
|
1375
1132
|
id
|
|
1376
1133
|
business_id
|
|
@@ -1384,7 +1141,7 @@ var GET_STOREFRONT_LATEST = `
|
|
|
1384
1141
|
is_bespoke
|
|
1385
1142
|
base_price
|
|
1386
1143
|
currency
|
|
1387
|
-
images
|
|
1144
|
+
images
|
|
1388
1145
|
tags
|
|
1389
1146
|
custom_fields { label unit required }
|
|
1390
1147
|
is_published
|
|
@@ -1407,7 +1164,7 @@ var GET_STOREFRONT_LATEST = `
|
|
|
1407
1164
|
sku
|
|
1408
1165
|
attributes
|
|
1409
1166
|
price
|
|
1410
|
-
images
|
|
1167
|
+
images
|
|
1411
1168
|
weight_kg
|
|
1412
1169
|
is_active
|
|
1413
1170
|
inventory {
|
|
@@ -1434,7 +1191,7 @@ var GET_STOREFRONT_LATEST = `
|
|
|
1434
1191
|
name
|
|
1435
1192
|
slug
|
|
1436
1193
|
description
|
|
1437
|
-
image
|
|
1194
|
+
image
|
|
1438
1195
|
collection_type
|
|
1439
1196
|
rules
|
|
1440
1197
|
status
|
|
@@ -1450,9 +1207,9 @@ var GET_STOREFRONT_LATEST = `
|
|
|
1450
1207
|
}
|
|
1451
1208
|
}
|
|
1452
1209
|
`;
|
|
1453
|
-
var
|
|
1454
|
-
query
|
|
1455
|
-
|
|
1210
|
+
var GET_STOREFRONT_NEW = `
|
|
1211
|
+
query GetStorefrontNew($page: Int!, $pageSize: Int!) {
|
|
1212
|
+
storefront_new(page: $page, pageSize: $pageSize) {
|
|
1456
1213
|
items {
|
|
1457
1214
|
id
|
|
1458
1215
|
business_id
|
|
@@ -1466,7 +1223,10 @@ var GET_STOREFRONT_POPULAR = `
|
|
|
1466
1223
|
is_bespoke
|
|
1467
1224
|
base_price
|
|
1468
1225
|
currency
|
|
1469
|
-
|
|
1226
|
+
sale_price
|
|
1227
|
+
sale_start
|
|
1228
|
+
sale_end
|
|
1229
|
+
images
|
|
1470
1230
|
tags
|
|
1471
1231
|
custom_fields { label unit required }
|
|
1472
1232
|
is_published
|
|
@@ -1489,7 +1249,7 @@ var GET_STOREFRONT_POPULAR = `
|
|
|
1489
1249
|
sku
|
|
1490
1250
|
attributes
|
|
1491
1251
|
price
|
|
1492
|
-
images
|
|
1252
|
+
images
|
|
1493
1253
|
weight_kg
|
|
1494
1254
|
is_active
|
|
1495
1255
|
inventory {
|
|
@@ -1516,7 +1276,7 @@ var GET_STOREFRONT_POPULAR = `
|
|
|
1516
1276
|
name
|
|
1517
1277
|
slug
|
|
1518
1278
|
description
|
|
1519
|
-
image
|
|
1279
|
+
image
|
|
1520
1280
|
collection_type
|
|
1521
1281
|
rules
|
|
1522
1282
|
status
|
|
@@ -1532,9 +1292,9 @@ var GET_STOREFRONT_POPULAR = `
|
|
|
1532
1292
|
}
|
|
1533
1293
|
}
|
|
1534
1294
|
`;
|
|
1535
|
-
var
|
|
1536
|
-
query
|
|
1537
|
-
|
|
1295
|
+
var GET_STOREFRONT_ON_SALE = `
|
|
1296
|
+
query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
|
|
1297
|
+
storefront_on_sale(page: $page, pageSize: $pageSize) {
|
|
1538
1298
|
items {
|
|
1539
1299
|
id
|
|
1540
1300
|
business_id
|
|
@@ -1548,7 +1308,10 @@ var GET_STOREFRONT_FEATURED = `
|
|
|
1548
1308
|
is_bespoke
|
|
1549
1309
|
base_price
|
|
1550
1310
|
currency
|
|
1551
|
-
|
|
1311
|
+
sale_price
|
|
1312
|
+
sale_start
|
|
1313
|
+
sale_end
|
|
1314
|
+
images
|
|
1552
1315
|
tags
|
|
1553
1316
|
custom_fields { label unit required }
|
|
1554
1317
|
is_published
|
|
@@ -1571,7 +1334,7 @@ var GET_STOREFRONT_FEATURED = `
|
|
|
1571
1334
|
sku
|
|
1572
1335
|
attributes
|
|
1573
1336
|
price
|
|
1574
|
-
images
|
|
1337
|
+
images
|
|
1575
1338
|
weight_kg
|
|
1576
1339
|
is_active
|
|
1577
1340
|
inventory {
|
|
@@ -1598,7 +1361,7 @@ var GET_STOREFRONT_FEATURED = `
|
|
|
1598
1361
|
name
|
|
1599
1362
|
slug
|
|
1600
1363
|
description
|
|
1601
|
-
image
|
|
1364
|
+
image
|
|
1602
1365
|
collection_type
|
|
1603
1366
|
rules
|
|
1604
1367
|
status
|
|
@@ -1614,9 +1377,9 @@ var GET_STOREFRONT_FEATURED = `
|
|
|
1614
1377
|
}
|
|
1615
1378
|
}
|
|
1616
1379
|
`;
|
|
1617
|
-
var
|
|
1618
|
-
query
|
|
1619
|
-
|
|
1380
|
+
var GET_STOREFRONT_LOW_STOCK = `
|
|
1381
|
+
query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
|
|
1382
|
+
storefront_low_stock(page: $page, pageSize: $pageSize) {
|
|
1620
1383
|
items {
|
|
1621
1384
|
id
|
|
1622
1385
|
business_id
|
|
@@ -1630,7 +1393,10 @@ var GET_STOREFRONT_NEW = `
|
|
|
1630
1393
|
is_bespoke
|
|
1631
1394
|
base_price
|
|
1632
1395
|
currency
|
|
1633
|
-
|
|
1396
|
+
sale_price
|
|
1397
|
+
sale_start
|
|
1398
|
+
sale_end
|
|
1399
|
+
images
|
|
1634
1400
|
tags
|
|
1635
1401
|
custom_fields { label unit required }
|
|
1636
1402
|
is_published
|
|
@@ -1653,7 +1419,7 @@ var GET_STOREFRONT_NEW = `
|
|
|
1653
1419
|
sku
|
|
1654
1420
|
attributes
|
|
1655
1421
|
price
|
|
1656
|
-
images
|
|
1422
|
+
images
|
|
1657
1423
|
weight_kg
|
|
1658
1424
|
is_active
|
|
1659
1425
|
inventory {
|
|
@@ -1680,7 +1446,7 @@ var GET_STOREFRONT_NEW = `
|
|
|
1680
1446
|
name
|
|
1681
1447
|
slug
|
|
1682
1448
|
description
|
|
1683
|
-
image
|
|
1449
|
+
image
|
|
1684
1450
|
collection_type
|
|
1685
1451
|
rules
|
|
1686
1452
|
status
|
|
@@ -1712,7 +1478,7 @@ var GET_STOREFRONT_RECOMMENDED = `
|
|
|
1712
1478
|
is_bespoke
|
|
1713
1479
|
base_price
|
|
1714
1480
|
currency
|
|
1715
|
-
images
|
|
1481
|
+
images
|
|
1716
1482
|
tags
|
|
1717
1483
|
custom_fields { label unit required }
|
|
1718
1484
|
is_published
|
|
@@ -1735,7 +1501,7 @@ var GET_STOREFRONT_RECOMMENDED = `
|
|
|
1735
1501
|
sku
|
|
1736
1502
|
attributes
|
|
1737
1503
|
price
|
|
1738
|
-
images
|
|
1504
|
+
images
|
|
1739
1505
|
weight_kg
|
|
1740
1506
|
is_active
|
|
1741
1507
|
inventory {
|
|
@@ -1762,7 +1528,7 @@ var GET_STOREFRONT_RECOMMENDED = `
|
|
|
1762
1528
|
name
|
|
1763
1529
|
slug
|
|
1764
1530
|
description
|
|
1765
|
-
image
|
|
1531
|
+
image
|
|
1766
1532
|
collection_type
|
|
1767
1533
|
rules
|
|
1768
1534
|
status
|
|
@@ -1778,8 +1544,8 @@ var GET_STOREFRONT_RECOMMENDED = `
|
|
|
1778
1544
|
}
|
|
1779
1545
|
}
|
|
1780
1546
|
`;
|
|
1781
|
-
async function getStorefrontProducts(params) {
|
|
1782
|
-
const client =
|
|
1547
|
+
async function getStorefrontProducts(config, params) {
|
|
1548
|
+
const client = createGraphQLClient(config);
|
|
1783
1549
|
const variables = {
|
|
1784
1550
|
page: params?.page || 1,
|
|
1785
1551
|
pageSize: params?.pageSize || 20,
|
|
@@ -1789,13 +1555,13 @@ async function getStorefrontProducts(params) {
|
|
|
1789
1555
|
const data = await client.request(GET_STOREFRONT_PRODUCTS, variables);
|
|
1790
1556
|
return data.storefront_products;
|
|
1791
1557
|
}
|
|
1792
|
-
async function getStorefrontProductBySlug(slug) {
|
|
1793
|
-
const client =
|
|
1558
|
+
async function getStorefrontProductBySlug(config, slug) {
|
|
1559
|
+
const client = createGraphQLClient(config);
|
|
1794
1560
|
const data = await client.request(GET_STOREFRONT_PRODUCT_BY_SLUG, { slug });
|
|
1795
1561
|
return data.storefront_product_by_slug;
|
|
1796
1562
|
}
|
|
1797
|
-
async function getLatestProducts(params) {
|
|
1798
|
-
const client =
|
|
1563
|
+
async function getLatestProducts(config, params) {
|
|
1564
|
+
const client = createGraphQLClient(config);
|
|
1799
1565
|
const variables = {
|
|
1800
1566
|
page: params?.page || 1,
|
|
1801
1567
|
pageSize: params?.pageSize || 4
|
|
@@ -1803,8 +1569,8 @@ async function getLatestProducts(params) {
|
|
|
1803
1569
|
const data = await client.request(GET_STOREFRONT_LATEST, variables);
|
|
1804
1570
|
return data.storefront_latest;
|
|
1805
1571
|
}
|
|
1806
|
-
async function getPopularProducts(params) {
|
|
1807
|
-
const client =
|
|
1572
|
+
async function getPopularProducts(config, params) {
|
|
1573
|
+
const client = createGraphQLClient(config);
|
|
1808
1574
|
const variables = {
|
|
1809
1575
|
page: params?.page || 1,
|
|
1810
1576
|
pageSize: params?.pageSize || 4
|
|
@@ -1812,8 +1578,8 @@ async function getPopularProducts(params) {
|
|
|
1812
1578
|
const data = await client.request(GET_STOREFRONT_POPULAR, variables);
|
|
1813
1579
|
return data.storefront_popular;
|
|
1814
1580
|
}
|
|
1815
|
-
async function getFeaturedProducts(params) {
|
|
1816
|
-
const client =
|
|
1581
|
+
async function getFeaturedProducts(config, params) {
|
|
1582
|
+
const client = createGraphQLClient(config);
|
|
1817
1583
|
const variables = {
|
|
1818
1584
|
page: params?.page || 1,
|
|
1819
1585
|
pageSize: params?.pageSize || 4
|
|
@@ -1821,8 +1587,8 @@ async function getFeaturedProducts(params) {
|
|
|
1821
1587
|
const data = await client.request(GET_STOREFRONT_FEATURED, variables);
|
|
1822
1588
|
return data.storefront_featured;
|
|
1823
1589
|
}
|
|
1824
|
-
async function getNewProducts(params) {
|
|
1825
|
-
const client =
|
|
1590
|
+
async function getNewProducts(config, params) {
|
|
1591
|
+
const client = createGraphQLClient(config);
|
|
1826
1592
|
const variables = {
|
|
1827
1593
|
page: params?.page || 1,
|
|
1828
1594
|
pageSize: params?.pageSize || 4
|
|
@@ -1830,8 +1596,26 @@ async function getNewProducts(params) {
|
|
|
1830
1596
|
const data = await client.request(GET_STOREFRONT_NEW, variables);
|
|
1831
1597
|
return data.storefront_new;
|
|
1832
1598
|
}
|
|
1833
|
-
async function
|
|
1834
|
-
const client =
|
|
1599
|
+
async function getOnSaleProducts(config, params) {
|
|
1600
|
+
const client = createGraphQLClient(config);
|
|
1601
|
+
const variables = {
|
|
1602
|
+
page: params?.page || 1,
|
|
1603
|
+
pageSize: params?.pageSize || 4
|
|
1604
|
+
};
|
|
1605
|
+
const data = await client.request(GET_STOREFRONT_ON_SALE, variables);
|
|
1606
|
+
return data.storefront_on_sale;
|
|
1607
|
+
}
|
|
1608
|
+
async function getLowStockProducts(config, params) {
|
|
1609
|
+
const client = createGraphQLClient(config);
|
|
1610
|
+
const variables = {
|
|
1611
|
+
page: params?.page || 1,
|
|
1612
|
+
pageSize: params?.pageSize || 4
|
|
1613
|
+
};
|
|
1614
|
+
const data = await client.request(GET_STOREFRONT_LOW_STOCK, variables);
|
|
1615
|
+
return data.storefront_low_stock;
|
|
1616
|
+
}
|
|
1617
|
+
async function getRecommendedProducts(config, params) {
|
|
1618
|
+
const client = createGraphQLClient(config);
|
|
1835
1619
|
const variables = {
|
|
1836
1620
|
page: params?.page || 1,
|
|
1837
1621
|
pageSize: params?.pageSize || 4,
|
|
@@ -1842,6 +1626,7 @@ async function getRecommendedProducts(params) {
|
|
|
1842
1626
|
}
|
|
1843
1627
|
|
|
1844
1628
|
// src/services/collection.service.ts
|
|
1629
|
+
var import_graphql_request2 = require("graphql-request");
|
|
1845
1630
|
var GET_STOREFRONT_COLLECTIONS = `
|
|
1846
1631
|
query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
|
|
1847
1632
|
storefront_collections(page: $page, pageSize: $pageSize) {
|
|
@@ -1851,7 +1636,7 @@ var GET_STOREFRONT_COLLECTIONS = `
|
|
|
1851
1636
|
name
|
|
1852
1637
|
slug
|
|
1853
1638
|
description
|
|
1854
|
-
image
|
|
1639
|
+
image
|
|
1855
1640
|
collection_type
|
|
1856
1641
|
rules
|
|
1857
1642
|
status
|
|
@@ -1874,7 +1659,7 @@ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
|
|
|
1874
1659
|
name
|
|
1875
1660
|
slug
|
|
1876
1661
|
description
|
|
1877
|
-
image
|
|
1662
|
+
image
|
|
1878
1663
|
collection_type
|
|
1879
1664
|
rules
|
|
1880
1665
|
status
|
|
@@ -1884,1501 +1669,889 @@ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
|
|
|
1884
1669
|
}
|
|
1885
1670
|
}
|
|
1886
1671
|
`;
|
|
1887
|
-
|
|
1888
|
-
const
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
return
|
|
1895
|
-
}
|
|
1896
|
-
async function getStorefrontCollectionBySlug(slug) {
|
|
1897
|
-
const client = getGraphQLClient();
|
|
1898
|
-
const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
|
|
1899
|
-
return data.storefront_collection_by_slug;
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
// src/services/wishlist.service.ts
|
|
1903
|
-
var GET_WISHLIST = `
|
|
1904
|
-
query GetWishlist($page: Int!, $pageSize: Int!) {
|
|
1905
|
-
wishlist(page: $page, pageSize: $pageSize) {
|
|
1906
|
-
items {
|
|
1907
|
-
id
|
|
1908
|
-
product_id
|
|
1909
|
-
notes
|
|
1910
|
-
created_at
|
|
1911
|
-
product_name
|
|
1912
|
-
product_slug
|
|
1913
|
-
product_price
|
|
1914
|
-
product_image
|
|
1915
|
-
}
|
|
1916
|
-
total
|
|
1917
|
-
page
|
|
1918
|
-
page_size
|
|
1919
|
-
total_pages
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
`;
|
|
1923
|
-
var CHECK_IN_WISHLIST = `
|
|
1924
|
-
query CheckInWishlist($productId: String!) {
|
|
1925
|
-
check_in_wishlist(productId: $productId) {
|
|
1926
|
-
in_wishlist
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
`;
|
|
1930
|
-
async function getWishlist(params) {
|
|
1931
|
-
const client = getGraphQLClient();
|
|
1932
|
-
const variables = {
|
|
1933
|
-
page: params?.page || 1,
|
|
1934
|
-
pageSize: params?.pageSize || 20
|
|
1935
|
-
};
|
|
1936
|
-
const data = await client.request(GET_WISHLIST, variables);
|
|
1937
|
-
return data.wishlist;
|
|
1938
|
-
}
|
|
1939
|
-
async function checkInWishlist(productId) {
|
|
1940
|
-
const client = getGraphQLClient();
|
|
1941
|
-
const data = await client.request(CHECK_IN_WISHLIST, { productId });
|
|
1942
|
-
return data.check_in_wishlist;
|
|
1943
|
-
}
|
|
1944
|
-
async function addToWishlist(productId, notes) {
|
|
1945
|
-
const { data } = await storeManagementAxios.post("wishlist/", {
|
|
1946
|
-
product_id: productId,
|
|
1947
|
-
notes: notes || void 0
|
|
1948
|
-
});
|
|
1949
|
-
return data;
|
|
1950
|
-
}
|
|
1951
|
-
async function removeFromWishlist(itemId) {
|
|
1952
|
-
await storeManagementAxios.delete(`wishlist/${itemId}`);
|
|
1953
|
-
}
|
|
1954
|
-
async function removeProductFromWishlist(productId) {
|
|
1955
|
-
await storeManagementAxios.delete(`wishlist/product/${productId}`);
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
// src/services/payment.service.ts
|
|
1959
|
-
async function createDedicatedAccount(request) {
|
|
1960
|
-
const isValidUUID = (str) => {
|
|
1961
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1962
|
-
return uuidRegex.test(str);
|
|
1963
|
-
};
|
|
1964
|
-
const { data } = await paymentAxios.post(
|
|
1965
|
-
"payments/dedicated-account",
|
|
1966
|
-
{
|
|
1967
|
-
order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
|
|
1968
|
-
amount: request.amount,
|
|
1969
|
-
customer_email: request.customer_email,
|
|
1970
|
-
customer_name: request.customer_name,
|
|
1971
|
-
currency: request.currency,
|
|
1972
|
-
idempotency_key: request.idempotency_key
|
|
1973
|
-
}
|
|
1974
|
-
);
|
|
1975
|
-
return data;
|
|
1976
|
-
}
|
|
1977
|
-
async function initiatePayment(request) {
|
|
1978
|
-
const isValidUUID = (str) => {
|
|
1979
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1980
|
-
return uuidRegex.test(str);
|
|
1981
|
-
};
|
|
1982
|
-
const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
|
|
1983
|
-
const { data } = await paymentAxios.post("payments/storefront/initiate", {
|
|
1984
|
-
amount: request.amount,
|
|
1985
|
-
currency: request.currency,
|
|
1986
|
-
order_id: validOrderId,
|
|
1987
|
-
quote_id: request.quote_id,
|
|
1988
|
-
metadata_json: {
|
|
1989
|
-
customer_email: request.customer_email,
|
|
1990
|
-
customer_name: request.customer_name ?? "",
|
|
1991
|
-
order_id: validOrderId,
|
|
1992
|
-
...request.metadata ?? {}
|
|
1993
|
-
},
|
|
1994
|
-
idempotency_key: request.idempotency_key
|
|
1995
|
-
});
|
|
1996
|
-
return {
|
|
1997
|
-
id: data.id,
|
|
1998
|
-
gateway_ref: data.gateway_ref,
|
|
1999
|
-
gateway: data.gateway,
|
|
2000
|
-
status: data.status,
|
|
2001
|
-
checkout_url: data.metadata_json?.checkout_url ?? ""
|
|
2002
|
-
};
|
|
2003
|
-
}
|
|
2004
|
-
async function requestQuote(amount) {
|
|
2005
|
-
const { data } = await paymentAxios.post("payments/quote", { amount });
|
|
2006
|
-
return data;
|
|
2007
|
-
}
|
|
2008
|
-
async function verifyTransaction(reference) {
|
|
2009
|
-
const { data } = await paymentAxios.post(
|
|
2010
|
-
`payments/verify/${reference}`
|
|
2011
|
-
);
|
|
2012
|
-
return data;
|
|
2013
|
-
}
|
|
2014
|
-
async function getTransactionStatus(transactionId) {
|
|
2015
|
-
const { data } = await paymentAxios.get(
|
|
2016
|
-
`payments/transactions/${transactionId}`
|
|
2017
|
-
);
|
|
2018
|
-
return data;
|
|
2019
|
-
}
|
|
2020
|
-
var paymentService = {
|
|
2021
|
-
createDedicatedAccount,
|
|
2022
|
-
initiatePayment,
|
|
2023
|
-
requestQuote,
|
|
2024
|
-
verifyTransaction,
|
|
2025
|
-
getTransactionStatus
|
|
2026
|
-
};
|
|
2027
|
-
|
|
2028
|
-
// src/services/consultation.service.ts
|
|
2029
|
-
async function createConsultation(payload) {
|
|
2030
|
-
const { data } = await storeManagementAxios.post("social/consultations/", payload);
|
|
2031
|
-
return data;
|
|
2032
|
-
}
|
|
2033
|
-
async function getConsultations() {
|
|
2034
|
-
const { data } = await storeManagementAxios.get("social/consultations/");
|
|
2035
|
-
return data;
|
|
2036
|
-
}
|
|
2037
|
-
async function getConsultation(id) {
|
|
2038
|
-
const { data } = await storeManagementAxios.get(`social/consultations/${id}`);
|
|
2039
|
-
return data;
|
|
2040
|
-
}
|
|
2041
|
-
async function sendMessage(id, payload) {
|
|
2042
|
-
await storeManagementAxios.post(`social/consultations/${id}/messages`, payload);
|
|
2043
|
-
}
|
|
2044
|
-
async function acceptQuote(id, payload) {
|
|
2045
|
-
const { data } = await storeManagementAxios.post(`social/consultations/${id}/accept-quote`, payload);
|
|
2046
|
-
return data;
|
|
2047
|
-
}
|
|
2048
|
-
async function rejectQuote(id, reason) {
|
|
2049
|
-
const { data } = await storeManagementAxios.post(`social/consultations/${id}/reject-quote`, { reason });
|
|
2050
|
-
return data;
|
|
2051
|
-
}
|
|
2052
|
-
var consultationService = {
|
|
2053
|
-
createConsultation,
|
|
2054
|
-
getConsultations,
|
|
2055
|
-
getConsultation,
|
|
2056
|
-
sendMessage,
|
|
2057
|
-
acceptQuote,
|
|
2058
|
-
rejectQuote
|
|
2059
|
-
};
|
|
2060
|
-
|
|
2061
|
-
// src/services/logistics.service.ts
|
|
2062
|
-
async function getShippingRates(payload) {
|
|
2063
|
-
const { data } = await storeManagementAxios.post(
|
|
2064
|
-
"logistics/shipping/rates",
|
|
2065
|
-
payload
|
|
2066
|
-
);
|
|
2067
|
-
return data;
|
|
2068
|
-
}
|
|
2069
|
-
async function getSellerShippingAddress() {
|
|
2070
|
-
const { data } = await storeManagementAxios.get("logistics/shipping-address");
|
|
2071
|
-
return data;
|
|
2072
|
-
}
|
|
2073
|
-
async function validateShippingAddress(payload) {
|
|
2074
|
-
const { data } = await storeManagementAxios.post("logistics/shipping-address/validate", payload);
|
|
2075
|
-
return data;
|
|
2076
|
-
}
|
|
2077
|
-
var logisticsService = {
|
|
2078
|
-
getShippingRates,
|
|
2079
|
-
getSellerShippingAddress,
|
|
2080
|
-
validateShippingAddress
|
|
2081
|
-
};
|
|
2082
|
-
|
|
2083
|
-
// src/services/bespoke.service.ts
|
|
2084
|
-
async function checkAvailability(product_id) {
|
|
2085
|
-
const { data } = await storeManagementAxios.get(`bespoke/availability/${product_id}`);
|
|
2086
|
-
return data;
|
|
2087
|
-
}
|
|
2088
|
-
var bespokeService = {
|
|
2089
|
-
checkAvailability
|
|
2090
|
-
};
|
|
2091
|
-
|
|
2092
|
-
// src/services/service-booking.service.ts
|
|
2093
|
-
async function getAvailableSlots(product_id, date_from, date_to) {
|
|
2094
|
-
const { data } = await storeManagementAxios.get(
|
|
2095
|
-
`service/available-slots/${product_id}`,
|
|
2096
|
-
{ params: { date_from, date_to } }
|
|
2097
|
-
);
|
|
2098
|
-
return data;
|
|
2099
|
-
}
|
|
2100
|
-
async function bookAppointment(payload) {
|
|
2101
|
-
const { data } = await storeManagementAxios.post("service/appointments/", payload);
|
|
2102
|
-
return data;
|
|
2103
|
-
}
|
|
2104
|
-
async function getAppointments() {
|
|
2105
|
-
const { data } = await storeManagementAxios.get("service/bookings/my");
|
|
2106
|
-
return data;
|
|
2107
|
-
}
|
|
2108
|
-
async function getAppointment(id) {
|
|
2109
|
-
const { data } = await storeManagementAxios.get(`service/bookings/${id}`);
|
|
2110
|
-
return data;
|
|
2111
|
-
}
|
|
2112
|
-
async function cancelAppointment(id) {
|
|
2113
|
-
await storeManagementAxios.delete(`service/bookings/${id}`);
|
|
2114
|
-
}
|
|
2115
|
-
async function getDeliverables(order_id) {
|
|
2116
|
-
const { data } = await storeManagementAxios.get(`service/projects/${order_id}/deliverables/`);
|
|
2117
|
-
return data;
|
|
2118
|
-
}
|
|
2119
|
-
async function approveDeliverable(order_id, deliverable_id) {
|
|
2120
|
-
const { data } = await storeManagementAxios.post(
|
|
2121
|
-
`service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
|
|
2122
|
-
{ approved: true }
|
|
2123
|
-
);
|
|
2124
|
-
return data;
|
|
2125
|
-
}
|
|
2126
|
-
async function requestRevision(order_id, deliverable_id, feedback) {
|
|
2127
|
-
const { data } = await storeManagementAxios.post(
|
|
2128
|
-
`service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
|
|
2129
|
-
{ approved: false, feedback }
|
|
2130
|
-
);
|
|
2131
|
-
return data;
|
|
2132
|
-
}
|
|
2133
|
-
var serviceBookingService = {
|
|
2134
|
-
getAvailableSlots,
|
|
2135
|
-
bookAppointment,
|
|
2136
|
-
getAppointments,
|
|
2137
|
-
getAppointment,
|
|
2138
|
-
cancelAppointment,
|
|
2139
|
-
getDeliverables,
|
|
2140
|
-
approveDeliverable,
|
|
2141
|
-
requestRevision
|
|
2142
|
-
};
|
|
2143
|
-
|
|
2144
|
-
// src/services/notifications.service.ts
|
|
2145
|
-
async function sendContactEmail(payload) {
|
|
2146
|
-
const { data } = await notificationsAxios.post(
|
|
2147
|
-
"contact/send-contact-email",
|
|
2148
|
-
payload
|
|
2149
|
-
);
|
|
2150
|
-
return data;
|
|
2151
|
-
}
|
|
2152
|
-
async function sendContactConfirmation(payload) {
|
|
2153
|
-
const { data } = await notificationsAxios.post(
|
|
2154
|
-
"contact/send-contact-confirmation",
|
|
2155
|
-
payload
|
|
2156
|
-
);
|
|
2157
|
-
return data;
|
|
2158
|
-
}
|
|
2159
|
-
var notificationsService = {
|
|
2160
|
-
sendContactEmail,
|
|
2161
|
-
sendContactConfirmation
|
|
2162
|
-
};
|
|
2163
|
-
|
|
2164
|
-
// src/services/app.service.ts
|
|
2165
|
-
async function googleTranslate(text, target, source = "en") {
|
|
2166
|
-
if (!text || target === source) return text;
|
|
2167
|
-
try {
|
|
2168
|
-
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${source}&tl=${target}&dt=t&q=${encodeURIComponent(text)}`;
|
|
2169
|
-
const res = await fetch(url);
|
|
2170
|
-
const data = await res.json();
|
|
2171
|
-
return (data?.[0] || []).map((s) => s[0]).join("");
|
|
2172
|
-
} catch {
|
|
2173
|
-
return text;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
// src/services/config.service.ts
|
|
2178
|
-
async function getSupportedLanguages() {
|
|
2179
|
-
const { data } = await paymentAxios.get("/config/supported-languages");
|
|
2180
|
-
return data;
|
|
2181
|
-
}
|
|
2182
|
-
async function getSupportedCurrencies() {
|
|
2183
|
-
const { data } = await paymentAxios.get("/config/supported-currencies");
|
|
2184
|
-
return data;
|
|
2185
|
-
}
|
|
2186
|
-
async function getBusinessConfig() {
|
|
2187
|
-
const { data } = await publicStoreAxios.get("business/profile");
|
|
2188
|
-
return data;
|
|
2189
|
-
}
|
|
2190
|
-
var configService = {
|
|
2191
|
-
getSupportedLanguages,
|
|
2192
|
-
getSupportedCurrencies,
|
|
2193
|
-
getBusinessConfig
|
|
2194
|
-
};
|
|
2195
|
-
|
|
2196
|
-
// src/services/cms.service.ts
|
|
2197
|
-
async function listCmsEntries(modelSlug, params) {
|
|
2198
|
-
const config = getRuntimeConfig();
|
|
2199
|
-
const { businessId } = config;
|
|
2200
|
-
const response = await cmsAxios.get(
|
|
2201
|
-
`/sdk/${businessId}/${modelSlug}/entries`,
|
|
2202
|
-
{
|
|
2203
|
-
params: {
|
|
2204
|
-
page: params?.page || 1,
|
|
2205
|
-
page_size: params?.page_size || 50
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
);
|
|
2209
|
-
return response.data;
|
|
2210
|
-
}
|
|
2211
|
-
async function getCmsEntry(modelSlug, entryId) {
|
|
2212
|
-
const config = getRuntimeConfig();
|
|
2213
|
-
const { businessId } = config;
|
|
2214
|
-
const response = await cmsAxios.get(
|
|
2215
|
-
`/sdk/${businessId}/${modelSlug}/entries/${entryId}`
|
|
2216
|
-
);
|
|
2217
|
-
return response.data;
|
|
2218
|
-
}
|
|
2219
|
-
async function createCmsEntry(modelSlug, params) {
|
|
2220
|
-
const config = getRuntimeConfig();
|
|
2221
|
-
const { businessId } = config;
|
|
2222
|
-
const response = await cmsAxios.post(
|
|
2223
|
-
`/sdk/${businessId}/${modelSlug}/entries`,
|
|
2224
|
-
params
|
|
2225
|
-
);
|
|
2226
|
-
return response.data;
|
|
2227
|
-
}
|
|
2228
|
-
async function updateCmsEntry(modelSlug, entryId, params) {
|
|
2229
|
-
const config = getRuntimeConfig();
|
|
2230
|
-
const { businessId } = config;
|
|
2231
|
-
const response = await cmsAxios.put(
|
|
2232
|
-
`/sdk/${businessId}/${modelSlug}/entries/${entryId}`,
|
|
2233
|
-
params
|
|
2234
|
-
);
|
|
2235
|
-
return response.data;
|
|
1672
|
+
function createGraphQLClient2(config) {
|
|
1673
|
+
const headers = {
|
|
1674
|
+
"Content-Type": "application/json",
|
|
1675
|
+
"Accept": "application/json",
|
|
1676
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1677
|
+
"X-Business-ID": config.businessId
|
|
1678
|
+
};
|
|
1679
|
+
return new import_graphql_request2.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
2236
1680
|
}
|
|
2237
|
-
async function
|
|
2238
|
-
const
|
|
2239
|
-
const
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
1681
|
+
async function getStorefrontCollections(config, params) {
|
|
1682
|
+
const client = createGraphQLClient2(config);
|
|
1683
|
+
const variables = {
|
|
1684
|
+
page: params?.page || 1,
|
|
1685
|
+
pageSize: params?.pageSize || 20
|
|
1686
|
+
};
|
|
1687
|
+
const data = await client.request(GET_STOREFRONT_COLLECTIONS, variables);
|
|
1688
|
+
return data.storefront_collections;
|
|
1689
|
+
}
|
|
1690
|
+
async function getStorefrontCollectionBySlug(config, slug) {
|
|
1691
|
+
const client = createGraphQLClient2(config);
|
|
1692
|
+
const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
|
|
1693
|
+
return data.storefront_collection_by_slug;
|
|
2243
1694
|
}
|
|
2244
1695
|
|
|
2245
|
-
// src/
|
|
2246
|
-
var
|
|
2247
|
-
var
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
};
|
|
2261
|
-
const [productTypeMismatch, setProductTypeMismatch] = (0, import_react.useState)(null);
|
|
2262
|
-
const cartQuery = (0, import_react_query.useQuery)({
|
|
2263
|
-
queryKey: ["cart"],
|
|
2264
|
-
queryFn: getCart,
|
|
2265
|
-
enabled: isInitialized()
|
|
2266
|
-
});
|
|
2267
|
-
const addToCartMutation = (0, import_react_query.useMutation)({
|
|
2268
|
-
mutationFn: addToCart,
|
|
2269
|
-
onSuccess: () => {
|
|
2270
|
-
setProductTypeMismatch(null);
|
|
2271
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
2272
|
-
},
|
|
2273
|
-
onError: (error) => {
|
|
2274
|
-
if (import_axios4.default.isAxiosError(error) && error.response?.status === 409) {
|
|
2275
|
-
const responseData = error.response?.data;
|
|
2276
|
-
const errorDetail = responseData?.detail;
|
|
2277
|
-
if (errorDetail?.code === "CART_PRODUCT_TYPE_MISMATCH") {
|
|
2278
|
-
setProductTypeMismatch({
|
|
2279
|
-
message: errorDetail.message ?? "Your cart contains incompatible items.",
|
|
2280
|
-
existing_type: errorDetail.existing_type ?? "physical",
|
|
2281
|
-
new_type: errorDetail.new_type ?? "physical"
|
|
2282
|
-
});
|
|
2283
|
-
}
|
|
1696
|
+
// src/services/wishlist.service.ts
|
|
1697
|
+
var import_graphql_request3 = require("graphql-request");
|
|
1698
|
+
var GET_STOREFRONT_WISHLIST = `
|
|
1699
|
+
query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
|
|
1700
|
+
storefront_wishlist(page: $page, pageSize: $pageSize) {
|
|
1701
|
+
items {
|
|
1702
|
+
id
|
|
1703
|
+
product_id
|
|
1704
|
+
notes
|
|
1705
|
+
created_at
|
|
1706
|
+
product_name
|
|
1707
|
+
product_slug
|
|
1708
|
+
product_price
|
|
1709
|
+
currency
|
|
1710
|
+
product_image
|
|
2284
1711
|
}
|
|
1712
|
+
total
|
|
1713
|
+
page
|
|
1714
|
+
page_size
|
|
1715
|
+
total_pages
|
|
2285
1716
|
}
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
});
|
|
2293
|
-
const removeFromCartMutation = (0, import_react_query.useMutation)({
|
|
2294
|
-
mutationFn: removeFromCart,
|
|
2295
|
-
onSuccess: () => {
|
|
2296
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
2297
|
-
}
|
|
2298
|
-
});
|
|
2299
|
-
const clearCartMutation = (0, import_react_query.useMutation)({
|
|
2300
|
-
mutationFn: clearCart,
|
|
2301
|
-
onSuccess: () => {
|
|
2302
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
2303
|
-
}
|
|
2304
|
-
});
|
|
2305
|
-
const mergeGuestCartMutation = (0, import_react_query.useMutation)({
|
|
2306
|
-
mutationFn: mergeGuestCartIfPresent,
|
|
2307
|
-
onSuccess: () => {
|
|
2308
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
1717
|
+
}
|
|
1718
|
+
`;
|
|
1719
|
+
var CHECK_IN_STOREFRONT_WISHLIST = `
|
|
1720
|
+
query CheckInStorefrontWishlist($productId: String!) {
|
|
1721
|
+
check_in_storefront_wishlist(productId: $productId) {
|
|
1722
|
+
in_wishlist
|
|
2309
1723
|
}
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
variant_id: variantId,
|
|
2319
|
-
variant_attributes: variant?.attributes ? JSON.stringify(variant.attributes) : void 0,
|
|
2320
|
-
unit_price: variant?.price ?? product.base_price,
|
|
2321
|
-
quantity,
|
|
2322
|
-
custom_measurements: customMeasurements ? JSON.stringify(customMeasurements) : void 0,
|
|
2323
|
-
is_bespoke: product.is_bespoke
|
|
2324
|
-
});
|
|
2325
|
-
};
|
|
2326
|
-
const items = cartQuery.data?.items || [];
|
|
2327
|
-
const subtotal = cartQuery.data?.subtotal || 0;
|
|
2328
|
-
const count = items.reduce((total, item) => total + item.quantity, 0);
|
|
2329
|
-
const updateQty = (itemId, quantity) => {
|
|
2330
|
-
updateCartItemMutation.mutate({ itemId, quantity });
|
|
2331
|
-
};
|
|
2332
|
-
const removeItem = (itemId) => {
|
|
2333
|
-
removeFromCartMutation.mutate(itemId);
|
|
2334
|
-
};
|
|
2335
|
-
const handleClearCartAndAdd = () => {
|
|
2336
|
-
clearCartMutation.mutate();
|
|
2337
|
-
setProductTypeMismatch(null);
|
|
2338
|
-
};
|
|
2339
|
-
const handleKeepCurrentCart = () => {
|
|
2340
|
-
setProductTypeMismatch(null);
|
|
2341
|
-
};
|
|
2342
|
-
return {
|
|
2343
|
-
cart: cartQuery.data,
|
|
2344
|
-
items,
|
|
2345
|
-
count,
|
|
2346
|
-
isOpen,
|
|
2347
|
-
setOpen,
|
|
2348
|
-
isLoading: cartQuery.isLoading,
|
|
2349
|
-
error: cartQuery.error,
|
|
2350
|
-
addToCart: addToCartMutation.mutate,
|
|
2351
|
-
updateCartItem: updateCartItemMutation.mutate,
|
|
2352
|
-
removeFromCart: removeFromCartMutation.mutate,
|
|
2353
|
-
clearCart: clearCartMutation.mutate,
|
|
2354
|
-
clear: clearCartMutation.mutate,
|
|
2355
|
-
// Alias for storefront compatibility
|
|
2356
|
-
mergeGuestCart: mergeGuestCartMutation.mutate,
|
|
2357
|
-
addItem,
|
|
2358
|
-
updateQty,
|
|
2359
|
-
removeItem,
|
|
2360
|
-
subtotal,
|
|
2361
|
-
productTypeMismatch,
|
|
2362
|
-
handleClearCartAndAdd,
|
|
2363
|
-
handleKeepCurrentCart
|
|
1724
|
+
}
|
|
1725
|
+
`;
|
|
1726
|
+
function createGraphQLClient3(config, accessToken) {
|
|
1727
|
+
const headers = {
|
|
1728
|
+
"Content-Type": "application/json",
|
|
1729
|
+
"Accept": "application/json",
|
|
1730
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1731
|
+
"X-Business-ID": config.businessId
|
|
2364
1732
|
};
|
|
1733
|
+
if (accessToken) {
|
|
1734
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1735
|
+
}
|
|
1736
|
+
return new import_graphql_request3.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
2365
1737
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
}
|
|
2375
|
-
function
|
|
2376
|
-
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
refetchInterval: 3e4
|
|
2394
|
-
// Refetch every 30 seconds for tracking updates
|
|
1738
|
+
async function getWishlist(config, accessToken, params) {
|
|
1739
|
+
const client = createGraphQLClient3(config, accessToken);
|
|
1740
|
+
const variables = {
|
|
1741
|
+
page: params?.page || 1,
|
|
1742
|
+
pageSize: params?.pageSize || 20
|
|
1743
|
+
};
|
|
1744
|
+
const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
|
|
1745
|
+
return data.storefront_wishlist;
|
|
1746
|
+
}
|
|
1747
|
+
async function checkInWishlist(config, accessToken, productId) {
|
|
1748
|
+
const client = createGraphQLClient3(config, accessToken);
|
|
1749
|
+
const data = await client.request(CHECK_IN_STOREFRONT_WISHLIST, { productId });
|
|
1750
|
+
return data.check_in_storefront_wishlist;
|
|
1751
|
+
}
|
|
1752
|
+
async function addToWishlist(config, accessToken, productId, notes) {
|
|
1753
|
+
const response = await fetch(`${config.backendUrls.store}/wishlist/`, {
|
|
1754
|
+
method: "POST",
|
|
1755
|
+
headers: {
|
|
1756
|
+
"Content-Type": "application/json",
|
|
1757
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1758
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1759
|
+
"X-Business-ID": config.businessId
|
|
1760
|
+
},
|
|
1761
|
+
body: JSON.stringify({
|
|
1762
|
+
product_id: productId,
|
|
1763
|
+
notes: notes || void 0
|
|
1764
|
+
})
|
|
2395
1765
|
});
|
|
1766
|
+
if (!response.ok) throw new Error("Failed to add to wishlist");
|
|
1767
|
+
return response.json();
|
|
2396
1768
|
}
|
|
2397
|
-
function
|
|
2398
|
-
const
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
1769
|
+
async function removeFromWishlist(config, accessToken, itemId) {
|
|
1770
|
+
const response = await fetch(`${config.backendUrls.store}/wishlist/${itemId}`, {
|
|
1771
|
+
method: "DELETE",
|
|
1772
|
+
headers: {
|
|
1773
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1774
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1775
|
+
"X-Business-ID": config.businessId
|
|
2403
1776
|
}
|
|
2404
1777
|
});
|
|
1778
|
+
if (!response.ok) throw new Error("Failed to remove from wishlist");
|
|
2405
1779
|
}
|
|
2406
|
-
function
|
|
2407
|
-
const
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
1780
|
+
async function removeProductFromWishlist(config, accessToken, productId) {
|
|
1781
|
+
const response = await fetch(`${config.backendUrls.store}/wishlist/product/${productId}`, {
|
|
1782
|
+
method: "DELETE",
|
|
1783
|
+
headers: {
|
|
1784
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1785
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1786
|
+
"X-Business-ID": config.businessId
|
|
2412
1787
|
}
|
|
2413
1788
|
});
|
|
1789
|
+
if (!response.ok) throw new Error("Failed to remove product from wishlist");
|
|
2414
1790
|
}
|
|
2415
1791
|
|
|
2416
|
-
// src/
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
const [customer, setCustomer] = (0, import_react2.useState)(null);
|
|
2422
|
-
const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
|
|
2423
|
-
const [isModalOpen, setIsModalOpen] = (0, import_react2.useState)(false);
|
|
2424
|
-
(0, import_react2.useEffect)(() => {
|
|
2425
|
-
let voided = false;
|
|
2426
|
-
(async () => {
|
|
2427
|
-
setIsLoading(true);
|
|
2428
|
-
try {
|
|
2429
|
-
const result = await silentRefresh();
|
|
2430
|
-
if (!voided && result) {
|
|
2431
|
-
setCustomer(result.user);
|
|
2432
|
-
resetGraphQLClient();
|
|
2433
|
-
}
|
|
2434
|
-
} catch (error) {
|
|
2435
|
-
logger.error("[AuthProvider] Session restore failed:", error);
|
|
2436
|
-
if (!voided) setCustomer(null);
|
|
2437
|
-
} finally {
|
|
2438
|
-
if (!voided) setIsLoading(false);
|
|
2439
|
-
}
|
|
2440
|
-
})();
|
|
2441
|
-
return () => {
|
|
2442
|
-
voided = true;
|
|
2443
|
-
};
|
|
2444
|
-
}, []);
|
|
2445
|
-
const openModal = (0, import_react2.useCallback)(() => setIsModalOpen(true), []);
|
|
2446
|
-
const closeModal = (0, import_react2.useCallback)(() => {
|
|
2447
|
-
setIsModalOpen(false);
|
|
2448
|
-
if (typeof window !== "undefined" && (window.location.hash === "#login" || window.location.hash === "#signup")) {
|
|
2449
|
-
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
2450
|
-
}
|
|
2451
|
-
}, []);
|
|
2452
|
-
(0, import_react2.useEffect)(() => {
|
|
2453
|
-
const handleHash = () => {
|
|
2454
|
-
if (typeof window === "undefined") return;
|
|
2455
|
-
if (window.location.hash === "#login" || window.location.hash === "#signup") {
|
|
2456
|
-
if (!isLoading && customer) {
|
|
2457
|
-
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
2458
|
-
} else if (!isLoading && !customer) {
|
|
2459
|
-
setIsModalOpen(true);
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
};
|
|
2463
|
-
handleHash();
|
|
2464
|
-
window.addEventListener("hashchange", handleHash);
|
|
2465
|
-
return () => window.removeEventListener("hashchange", handleHash);
|
|
2466
|
-
}, [customer, isLoading]);
|
|
2467
|
-
(0, import_react2.useEffect)(() => {
|
|
2468
|
-
resetGraphQLClient();
|
|
2469
|
-
}, [customer]);
|
|
2470
|
-
const handleLogout = (0, import_react2.useCallback)(async () => {
|
|
2471
|
-
await logout();
|
|
2472
|
-
setCustomer(null);
|
|
2473
|
-
setIsModalOpen(false);
|
|
2474
|
-
resetGraphQLClient();
|
|
2475
|
-
}, []);
|
|
2476
|
-
const value = {
|
|
2477
|
-
customer,
|
|
2478
|
-
isLoading,
|
|
2479
|
-
isModalOpen,
|
|
2480
|
-
openModal,
|
|
2481
|
-
closeModal,
|
|
2482
|
-
setCustomer,
|
|
2483
|
-
logout: handleLogout
|
|
1792
|
+
// src/services/payment.service.ts
|
|
1793
|
+
async function createDedicatedAccount(config, accessToken, request) {
|
|
1794
|
+
const isValidUUID = (str) => {
|
|
1795
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1796
|
+
return uuidRegex.test(str);
|
|
2484
1797
|
};
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
2502
|
-
}
|
|
2503
|
-
});
|
|
2504
|
-
}
|
|
2505
|
-
function useRegister() {
|
|
2506
|
-
const queryClient = (0, import_react_query3.useQueryClient)();
|
|
2507
|
-
return (0, import_react_query3.useMutation)({
|
|
2508
|
-
mutationFn: registerCustomer,
|
|
2509
|
-
onSuccess: () => {
|
|
2510
|
-
queryClient.invalidateQueries({ queryKey: ["auth-user"] });
|
|
2511
|
-
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
2512
|
-
}
|
|
2513
|
-
});
|
|
2514
|
-
}
|
|
2515
|
-
function useUpdateProfile() {
|
|
2516
|
-
const queryClient = (0, import_react_query3.useQueryClient)();
|
|
2517
|
-
return (0, import_react_query3.useMutation)({
|
|
2518
|
-
mutationFn: updateProfile,
|
|
2519
|
-
onSuccess: () => {
|
|
2520
|
-
queryClient.invalidateQueries({ queryKey: ["auth-user"] });
|
|
2521
|
-
}
|
|
1798
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
|
|
1799
|
+
method: "POST",
|
|
1800
|
+
headers: {
|
|
1801
|
+
"Content-Type": "application/json",
|
|
1802
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1803
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1804
|
+
"X-Business-ID": config.businessId
|
|
1805
|
+
},
|
|
1806
|
+
body: JSON.stringify({
|
|
1807
|
+
order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
|
|
1808
|
+
amount: request.amount,
|
|
1809
|
+
customer_email: request.customer_email,
|
|
1810
|
+
customer_name: request.customer_name,
|
|
1811
|
+
currency: request.currency,
|
|
1812
|
+
idempotency_key: request.idempotency_key
|
|
1813
|
+
})
|
|
2522
1814
|
});
|
|
1815
|
+
if (!response.ok) throw new Error("Failed to create dedicated account");
|
|
1816
|
+
const data = await response.json();
|
|
1817
|
+
return data;
|
|
2523
1818
|
}
|
|
2524
|
-
function
|
|
2525
|
-
const
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
1819
|
+
async function initiatePayment(config, accessToken, request) {
|
|
1820
|
+
const isValidUUID = (str) => {
|
|
1821
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1822
|
+
return uuidRegex.test(str);
|
|
1823
|
+
};
|
|
1824
|
+
const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
|
|
1825
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
|
|
1826
|
+
method: "POST",
|
|
1827
|
+
headers: {
|
|
1828
|
+
"Content-Type": "application/json",
|
|
1829
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1830
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1831
|
+
"X-Business-ID": config.businessId
|
|
1832
|
+
},
|
|
1833
|
+
body: JSON.stringify({
|
|
1834
|
+
amount: request.amount,
|
|
1835
|
+
currency: request.currency,
|
|
1836
|
+
order_id: validOrderId,
|
|
1837
|
+
quote_id: request.quote_id,
|
|
1838
|
+
metadata_json: {
|
|
1839
|
+
customer_email: request.customer_email,
|
|
1840
|
+
customer_name: request.customer_name ?? "",
|
|
1841
|
+
order_id: validOrderId,
|
|
1842
|
+
...request.metadata ?? {}
|
|
1843
|
+
},
|
|
1844
|
+
idempotency_key: request.idempotency_key
|
|
1845
|
+
})
|
|
2531
1846
|
});
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
const context = AuthCtx ? (0, import_react2.useContext)(AuthCtx) : null;
|
|
2535
|
-
if (context) return context;
|
|
2536
|
-
const authUserQuery = useAuthUser();
|
|
2537
|
-
const logoutMutation = useLogout();
|
|
1847
|
+
if (!response.ok) throw new Error("Failed to initiate payment");
|
|
1848
|
+
const data = await response.json();
|
|
2538
1849
|
return {
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
closeModal: () => {
|
|
2545
|
-
},
|
|
2546
|
-
setCustomer: () => {
|
|
2547
|
-
},
|
|
2548
|
-
logout: async () => {
|
|
2549
|
-
await logoutMutation.mutateAsync();
|
|
2550
|
-
}
|
|
1850
|
+
id: data.id,
|
|
1851
|
+
gateway_ref: data.gateway_ref,
|
|
1852
|
+
gateway: data.gateway,
|
|
1853
|
+
status: data.status,
|
|
1854
|
+
checkout_url: data.metadata_json?.checkout_url ?? ""
|
|
2551
1855
|
};
|
|
2552
1856
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
queryKey: ["countries"],
|
|
2563
|
-
queryFn: () => getCountries(),
|
|
2564
|
-
retry: 1,
|
|
2565
|
-
refetchOnWindowFocus: false,
|
|
2566
|
-
refetchOnReconnect: false,
|
|
2567
|
-
staleTime: 24 * 60 * 60 * 1e3
|
|
2568
|
-
// 24 hours
|
|
2569
|
-
});
|
|
2570
|
-
}
|
|
2571
|
-
|
|
2572
|
-
// src/hooks/use-states.ts
|
|
2573
|
-
var import_react_query5 = require("@tanstack/react-query");
|
|
2574
|
-
async function getStates(countryIso) {
|
|
2575
|
-
if (!countryIso) return [];
|
|
2576
|
-
const { data } = await authAxios.get("auth/countries/", {
|
|
2577
|
-
params: { iso: countryIso }
|
|
1857
|
+
async function requestQuote(config, amount) {
|
|
1858
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/quote`, {
|
|
1859
|
+
method: "POST",
|
|
1860
|
+
headers: {
|
|
1861
|
+
"Content-Type": "application/json",
|
|
1862
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1863
|
+
"X-Business-ID": config.businessId
|
|
1864
|
+
},
|
|
1865
|
+
body: JSON.stringify({ amount })
|
|
2578
1866
|
});
|
|
1867
|
+
if (!response.ok) throw new Error("Failed to request quote");
|
|
1868
|
+
const data = await response.json();
|
|
2579
1869
|
return data;
|
|
2580
1870
|
}
|
|
2581
|
-
function
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
}));
|
|
2605
|
-
}
|
|
2606
|
-
function useSupportedLanguages() {
|
|
2607
|
-
return (0, import_react_query6.useQuery)({
|
|
2608
|
-
queryKey: ["supported-languages"],
|
|
2609
|
-
queryFn: () => getSupportedLanguagesList(),
|
|
2610
|
-
enabled: isInitialized(),
|
|
2611
|
-
retry: 1,
|
|
2612
|
-
...getCacheTier("high")
|
|
2613
|
-
});
|
|
2614
|
-
}
|
|
2615
|
-
|
|
2616
|
-
// src/hooks/use-currencies.ts
|
|
2617
|
-
var import_react_query7 = require("@tanstack/react-query");
|
|
2618
|
-
async function getSupportedCurrenciesList() {
|
|
2619
|
-
const data = await getSupportedCurrencies();
|
|
2620
|
-
return data.currencies || [];
|
|
2621
|
-
}
|
|
2622
|
-
function useCurrencies() {
|
|
2623
|
-
return (0, import_react_query7.useQuery)({
|
|
2624
|
-
queryKey: ["supported-currencies"],
|
|
2625
|
-
queryFn: () => getSupportedCurrenciesList(),
|
|
2626
|
-
enabled: isInitialized(),
|
|
2627
|
-
retry: 1,
|
|
2628
|
-
...getCacheTier("high")
|
|
2629
|
-
});
|
|
1871
|
+
async function verifyTransaction(configOrReference, reference) {
|
|
1872
|
+
if (typeof configOrReference === "string") {
|
|
1873
|
+
const ref2 = configOrReference;
|
|
1874
|
+
const response2 = await fetch(`/api/payments/verify/${ref2}`, {
|
|
1875
|
+
method: "POST",
|
|
1876
|
+
headers: { "Content-Type": "application/json" }
|
|
1877
|
+
});
|
|
1878
|
+
if (!response2.ok) throw new Error("Failed to verify transaction");
|
|
1879
|
+
return response2.json();
|
|
1880
|
+
}
|
|
1881
|
+
const config = configOrReference;
|
|
1882
|
+
const ref = reference || "";
|
|
1883
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
|
|
1884
|
+
method: "POST",
|
|
1885
|
+
headers: {
|
|
1886
|
+
"Content-Type": "application/json",
|
|
1887
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1888
|
+
"X-Business-ID": config.businessId
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
if (!response.ok) throw new Error("Failed to verify transaction");
|
|
1892
|
+
const data = await response.json();
|
|
1893
|
+
return data;
|
|
2630
1894
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
queryFn: () => bespokeService.checkAvailability(product_id),
|
|
2638
|
-
enabled: !!product_id,
|
|
2639
|
-
retry: false
|
|
2640
|
-
// Don't retry if no config exists (returns 404)
|
|
1895
|
+
async function getTransactionStatus(config, transactionId) {
|
|
1896
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
|
|
1897
|
+
headers: {
|
|
1898
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1899
|
+
"X-Business-ID": config.businessId
|
|
1900
|
+
}
|
|
2641
1901
|
});
|
|
1902
|
+
if (!response.ok) throw new Error("Failed to get transaction status");
|
|
1903
|
+
const data = await response.json();
|
|
1904
|
+
return data;
|
|
2642
1905
|
}
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
slug: (slug) => ["core", "collections", "slug", slug]
|
|
1906
|
+
var paymentService = {
|
|
1907
|
+
createDedicatedAccount,
|
|
1908
|
+
initiatePayment,
|
|
1909
|
+
requestQuote,
|
|
1910
|
+
verifyTransaction,
|
|
1911
|
+
getTransactionStatus
|
|
2650
1912
|
};
|
|
2651
|
-
function useStorefrontCollections(params) {
|
|
2652
|
-
return (0, import_react_query9.useQuery)({
|
|
2653
|
-
queryKey: collectionKeys.list(params),
|
|
2654
|
-
queryFn: () => getStorefrontCollections(params),
|
|
2655
|
-
// medium — collections change infrequently
|
|
2656
|
-
...getCacheTier("medium")
|
|
2657
|
-
});
|
|
2658
|
-
}
|
|
2659
|
-
function useStorefrontCollection(slug) {
|
|
2660
|
-
return (0, import_react_query9.useQuery)({
|
|
2661
|
-
queryKey: collectionKeys.slug(slug),
|
|
2662
|
-
queryFn: () => getStorefrontCollectionBySlug(slug),
|
|
2663
|
-
// medium — collection details change infrequently
|
|
2664
|
-
...getCacheTier("medium"),
|
|
2665
|
-
enabled: !!slug
|
|
2666
|
-
});
|
|
2667
|
-
}
|
|
2668
1913
|
|
|
2669
|
-
// src/
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
};
|
|
2681
|
-
function useLatestProducts(params) {
|
|
2682
|
-
return (0, import_react_query10.useQuery)({
|
|
2683
|
-
queryKey: productKeys.latest(params),
|
|
2684
|
-
queryFn: () => getLatestProducts(params),
|
|
2685
|
-
// medium — latest products change infrequently
|
|
2686
|
-
...getCacheTier("medium")
|
|
2687
|
-
});
|
|
2688
|
-
}
|
|
2689
|
-
function usePopularProducts(params) {
|
|
2690
|
-
return (0, import_react_query10.useQuery)({
|
|
2691
|
-
queryKey: productKeys.popular(params),
|
|
2692
|
-
queryFn: () => getPopularProducts(params),
|
|
2693
|
-
// medium — popular products change infrequently
|
|
2694
|
-
...getCacheTier("medium")
|
|
2695
|
-
});
|
|
2696
|
-
}
|
|
2697
|
-
function useFeaturedProducts(params) {
|
|
2698
|
-
return (0, import_react_query10.useQuery)({
|
|
2699
|
-
queryKey: productKeys.featured(params),
|
|
2700
|
-
queryFn: () => getFeaturedProducts(params),
|
|
2701
|
-
// medium — featured products change infrequently
|
|
2702
|
-
...getCacheTier("medium")
|
|
1914
|
+
// src/services/consultation.service.ts
|
|
1915
|
+
async function createConsultation(config, accessToken, payload) {
|
|
1916
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
|
|
1917
|
+
method: "POST",
|
|
1918
|
+
headers: {
|
|
1919
|
+
"Content-Type": "application/json",
|
|
1920
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1921
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1922
|
+
"X-Business-ID": config.businessId
|
|
1923
|
+
},
|
|
1924
|
+
body: JSON.stringify(payload)
|
|
2703
1925
|
});
|
|
1926
|
+
if (!response.ok) throw new Error("Failed to create consultation");
|
|
1927
|
+
return response.json();
|
|
2704
1928
|
}
|
|
2705
|
-
function
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
1929
|
+
async function getConsultations(config, accessToken) {
|
|
1930
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
|
|
1931
|
+
headers: {
|
|
1932
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1933
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1934
|
+
"X-Business-ID": config.businessId
|
|
1935
|
+
}
|
|
2711
1936
|
});
|
|
1937
|
+
if (!response.ok) throw new Error("Failed to get consultations");
|
|
1938
|
+
return response.json();
|
|
2712
1939
|
}
|
|
2713
|
-
function
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
1940
|
+
async function getConsultation(config, accessToken, id) {
|
|
1941
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
|
|
1942
|
+
headers: {
|
|
1943
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1944
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1945
|
+
"X-Business-ID": config.businessId
|
|
1946
|
+
}
|
|
2719
1947
|
});
|
|
1948
|
+
if (!response.ok) throw new Error("Failed to get consultation");
|
|
1949
|
+
return response.json();
|
|
2720
1950
|
}
|
|
2721
|
-
function
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
1951
|
+
async function sendMessage(config, accessToken, id, payload) {
|
|
1952
|
+
await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
|
|
1953
|
+
method: "POST",
|
|
1954
|
+
headers: {
|
|
1955
|
+
"Content-Type": "application/json",
|
|
1956
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1957
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1958
|
+
"X-Business-ID": config.businessId
|
|
1959
|
+
},
|
|
1960
|
+
body: JSON.stringify(payload)
|
|
2728
1961
|
});
|
|
2729
1962
|
}
|
|
2730
|
-
function
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
1963
|
+
async function acceptQuote(config, accessToken, id, payload) {
|
|
1964
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
|
|
1965
|
+
method: "POST",
|
|
1966
|
+
headers: {
|
|
1967
|
+
"Content-Type": "application/json",
|
|
1968
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1969
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1970
|
+
"X-Business-ID": config.businessId
|
|
1971
|
+
},
|
|
1972
|
+
body: JSON.stringify(payload)
|
|
1973
|
+
});
|
|
1974
|
+
if (!response.ok) throw new Error("Failed to accept quote");
|
|
1975
|
+
return response.json();
|
|
1976
|
+
}
|
|
1977
|
+
async function rejectQuote(config, accessToken, id, reason) {
|
|
1978
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
|
|
1979
|
+
method: "POST",
|
|
1980
|
+
headers: {
|
|
1981
|
+
"Content-Type": "application/json",
|
|
1982
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1983
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
1984
|
+
"X-Business-ID": config.businessId
|
|
1985
|
+
},
|
|
1986
|
+
body: JSON.stringify({ reason })
|
|
2736
1987
|
});
|
|
1988
|
+
if (!response.ok) throw new Error("Failed to reject quote");
|
|
1989
|
+
return response.json();
|
|
2737
1990
|
}
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
1991
|
+
var consultationService = {
|
|
1992
|
+
createConsultation,
|
|
1993
|
+
getConsultations,
|
|
1994
|
+
getConsultation,
|
|
1995
|
+
sendMessage,
|
|
1996
|
+
acceptQuote,
|
|
1997
|
+
rejectQuote
|
|
2745
1998
|
};
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
return (0, import_react_query11.useQuery)({
|
|
2756
|
-
queryKey: wishlistKeys.check(productId),
|
|
2757
|
-
queryFn: () => checkInWishlist(productId),
|
|
2758
|
-
// low — wishlist check changes frequently
|
|
2759
|
-
...getCacheTier("low"),
|
|
2760
|
-
enabled: !!productId
|
|
2761
|
-
});
|
|
2762
|
-
}
|
|
2763
|
-
function useAddToWishlist() {
|
|
2764
|
-
const queryClient = (0, import_react_query11.useQueryClient)();
|
|
2765
|
-
return (0, import_react_query11.useMutation)({
|
|
2766
|
-
mutationFn: ({ productId, notes }) => {
|
|
2767
|
-
return addToWishlist(productId, notes);
|
|
1999
|
+
|
|
2000
|
+
// src/services/logistics.service.ts
|
|
2001
|
+
async function getShippingRates(config, payload) {
|
|
2002
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
2003
|
+
method: "POST",
|
|
2004
|
+
headers: {
|
|
2005
|
+
"Content-Type": "application/json",
|
|
2006
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2007
|
+
"X-Business-ID": config.businessId
|
|
2768
2008
|
},
|
|
2769
|
-
|
|
2770
|
-
queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
|
|
2771
|
-
queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
|
|
2772
|
-
}
|
|
2009
|
+
body: JSON.stringify(payload)
|
|
2773
2010
|
});
|
|
2011
|
+
if (!response.ok) throw new Error("Failed to get shipping rates");
|
|
2012
|
+
return response.json();
|
|
2774
2013
|
}
|
|
2775
|
-
function
|
|
2776
|
-
const
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
},
|
|
2781
|
-
onSuccess: () => {
|
|
2782
|
-
queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
|
|
2783
|
-
queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
|
|
2014
|
+
async function getSellerShippingAddress(config) {
|
|
2015
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
|
|
2016
|
+
headers: {
|
|
2017
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2018
|
+
"X-Business-ID": config.businessId
|
|
2784
2019
|
}
|
|
2785
2020
|
});
|
|
2021
|
+
if (!response.ok) throw new Error("Failed to get seller shipping address");
|
|
2022
|
+
return response.json();
|
|
2786
2023
|
}
|
|
2787
|
-
function
|
|
2788
|
-
const
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2024
|
+
async function validateShippingAddress(config, payload) {
|
|
2025
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
|
|
2026
|
+
method: "POST",
|
|
2027
|
+
headers: {
|
|
2028
|
+
"Content-Type": "application/json",
|
|
2029
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2030
|
+
"X-Business-ID": config.businessId
|
|
2792
2031
|
},
|
|
2793
|
-
|
|
2794
|
-
queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
|
|
2795
|
-
queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
|
|
2796
|
-
}
|
|
2032
|
+
body: JSON.stringify(payload)
|
|
2797
2033
|
});
|
|
2034
|
+
if (!response.ok) throw new Error("Failed to validate shipping address");
|
|
2035
|
+
return response.json();
|
|
2798
2036
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
...getCacheTier("low"),
|
|
2805
|
-
select: (data) => data.total
|
|
2806
|
-
});
|
|
2807
|
-
return backendQuery;
|
|
2808
|
-
}
|
|
2037
|
+
var logisticsService = {
|
|
2038
|
+
getShippingRates,
|
|
2039
|
+
getSellerShippingAddress,
|
|
2040
|
+
validateShippingAddress
|
|
2041
|
+
};
|
|
2809
2042
|
|
|
2810
|
-
// src/
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2043
|
+
// src/services/bespoke.service.ts
|
|
2044
|
+
async function checkAvailability(config, product_id) {
|
|
2045
|
+
const response = await fetch(`${config.backendUrls.store}/bespoke/availability/${product_id}`, {
|
|
2046
|
+
headers: {
|
|
2047
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2048
|
+
"X-Business-ID": config.businessId
|
|
2049
|
+
}
|
|
2817
2050
|
});
|
|
2051
|
+
if (!response.ok) throw new Error("Failed to check bespoke availability");
|
|
2052
|
+
return response.json();
|
|
2818
2053
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2054
|
+
var bespokeService = {
|
|
2055
|
+
checkAvailability
|
|
2056
|
+
};
|
|
2057
|
+
|
|
2058
|
+
// src/services/service-booking.service.ts
|
|
2059
|
+
async function getAvailableSlots(config, product_id, date_from, date_to) {
|
|
2060
|
+
const response = await fetch(
|
|
2061
|
+
`${config.backendUrls.store}/service/available-slots/${product_id}?date_from=${date_from}&date_to=${date_to}`,
|
|
2062
|
+
{
|
|
2063
|
+
headers: {
|
|
2064
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2065
|
+
"X-Business-ID": config.businessId
|
|
2066
|
+
}
|
|
2825
2067
|
}
|
|
2068
|
+
);
|
|
2069
|
+
if (!response.ok) throw new Error("Failed to get available slots");
|
|
2070
|
+
return response.json();
|
|
2071
|
+
}
|
|
2072
|
+
async function bookAppointment(config, accessToken, payload) {
|
|
2073
|
+
const response = await fetch(`${config.backendUrls.store}/service/appointments/`, {
|
|
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(payload)
|
|
2826
2082
|
});
|
|
2083
|
+
if (!response.ok) throw new Error("Failed to book appointment");
|
|
2084
|
+
return response.json();
|
|
2827
2085
|
}
|
|
2828
|
-
function
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2086
|
+
async function getAppointments(config, accessToken) {
|
|
2087
|
+
const response = await fetch(`${config.backendUrls.store}/service/bookings/my`, {
|
|
2088
|
+
headers: {
|
|
2089
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2090
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2091
|
+
"X-Business-ID": config.businessId
|
|
2092
|
+
}
|
|
2832
2093
|
});
|
|
2094
|
+
if (!response.ok) throw new Error("Failed to get appointments");
|
|
2095
|
+
return response.json();
|
|
2833
2096
|
}
|
|
2834
|
-
function
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2097
|
+
async function getAppointment(config, accessToken, id) {
|
|
2098
|
+
const response = await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
|
|
2099
|
+
headers: {
|
|
2100
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2101
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2102
|
+
"X-Business-ID": config.businessId
|
|
2103
|
+
}
|
|
2839
2104
|
});
|
|
2105
|
+
if (!response.ok) throw new Error("Failed to get appointment");
|
|
2106
|
+
return response.json();
|
|
2840
2107
|
}
|
|
2841
|
-
function
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2108
|
+
async function cancelAppointment(config, accessToken, id) {
|
|
2109
|
+
await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
|
|
2110
|
+
method: "DELETE",
|
|
2111
|
+
headers: {
|
|
2112
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2113
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2114
|
+
"X-Business-ID": config.businessId
|
|
2847
2115
|
}
|
|
2848
2116
|
});
|
|
2849
2117
|
}
|
|
2850
|
-
function
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2118
|
+
async function getDeliverables(config, accessToken, order_id) {
|
|
2119
|
+
const response = await fetch(`${config.backendUrls.store}/service/projects/${order_id}/deliverables/`, {
|
|
2120
|
+
headers: {
|
|
2121
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2122
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2123
|
+
"X-Business-ID": config.businessId
|
|
2124
|
+
}
|
|
2855
2125
|
});
|
|
2126
|
+
if (!response.ok) throw new Error("Failed to get deliverables");
|
|
2127
|
+
return response.json();
|
|
2856
2128
|
}
|
|
2857
|
-
function
|
|
2858
|
-
const
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2129
|
+
async function approveDeliverable(config, accessToken, order_id, deliverable_id) {
|
|
2130
|
+
const response = await fetch(
|
|
2131
|
+
`${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
|
|
2132
|
+
{
|
|
2133
|
+
method: "POST",
|
|
2134
|
+
headers: {
|
|
2135
|
+
"Content-Type": "application/json",
|
|
2136
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2137
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2138
|
+
"X-Business-ID": config.businessId
|
|
2139
|
+
},
|
|
2140
|
+
body: JSON.stringify({ approved: true })
|
|
2863
2141
|
}
|
|
2864
|
-
|
|
2142
|
+
);
|
|
2143
|
+
if (!response.ok) throw new Error("Failed to approve deliverable");
|
|
2144
|
+
return response.json();
|
|
2865
2145
|
}
|
|
2866
|
-
function
|
|
2867
|
-
const
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2146
|
+
async function requestRevision(config, accessToken, order_id, deliverable_id, feedback) {
|
|
2147
|
+
const response = await fetch(
|
|
2148
|
+
`${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
|
|
2149
|
+
{
|
|
2150
|
+
method: "POST",
|
|
2151
|
+
headers: {
|
|
2152
|
+
"Content-Type": "application/json",
|
|
2153
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2154
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2155
|
+
"X-Business-ID": config.businessId
|
|
2156
|
+
},
|
|
2157
|
+
body: JSON.stringify({ approved: false, feedback })
|
|
2872
2158
|
}
|
|
2873
|
-
|
|
2159
|
+
);
|
|
2160
|
+
if (!response.ok) throw new Error("Failed to request revision");
|
|
2161
|
+
return response.json();
|
|
2874
2162
|
}
|
|
2163
|
+
var serviceBookingService = {
|
|
2164
|
+
getAvailableSlots,
|
|
2165
|
+
bookAppointment,
|
|
2166
|
+
getAppointments,
|
|
2167
|
+
getAppointment,
|
|
2168
|
+
cancelAppointment,
|
|
2169
|
+
getDeliverables,
|
|
2170
|
+
approveDeliverable,
|
|
2171
|
+
requestRevision
|
|
2172
|
+
};
|
|
2875
2173
|
|
|
2876
|
-
// src/
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2174
|
+
// src/services/notifications.service.ts
|
|
2175
|
+
async function sendContactEmail(config, payload) {
|
|
2176
|
+
const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-email`, {
|
|
2177
|
+
method: "POST",
|
|
2178
|
+
headers: {
|
|
2179
|
+
"Content-Type": "application/json",
|
|
2180
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2181
|
+
"X-Business-ID": config.businessId
|
|
2182
|
+
},
|
|
2183
|
+
body: JSON.stringify(payload)
|
|
2184
|
+
});
|
|
2185
|
+
if (!response.ok) throw new Error("Failed to send contact email");
|
|
2186
|
+
return response.json();
|
|
2187
|
+
}
|
|
2188
|
+
async function sendContactConfirmation(config, payload) {
|
|
2189
|
+
const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
|
|
2190
|
+
method: "POST",
|
|
2191
|
+
headers: {
|
|
2192
|
+
"Content-Type": "application/json",
|
|
2193
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2194
|
+
"X-Business-ID": config.businessId
|
|
2195
|
+
},
|
|
2196
|
+
body: JSON.stringify(payload)
|
|
2889
2197
|
});
|
|
2198
|
+
if (!response.ok) throw new Error("Failed to send contact confirmation");
|
|
2199
|
+
return response.json();
|
|
2890
2200
|
}
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2201
|
+
var notificationsService = {
|
|
2202
|
+
sendContactEmail,
|
|
2203
|
+
sendContactConfirmation
|
|
2204
|
+
};
|
|
2205
|
+
|
|
2206
|
+
// src/services/app.service.ts
|
|
2207
|
+
async function googleTranslate(text, target, source = "en") {
|
|
2208
|
+
if (!text || target === source) return text;
|
|
2209
|
+
try {
|
|
2210
|
+
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${source}&tl=${target}&dt=t&q=${encodeURIComponent(text)}`;
|
|
2211
|
+
const res = await fetch(url);
|
|
2212
|
+
const data = await res.json();
|
|
2213
|
+
return (data?.[0] || []).map((s) => s[0]).join("");
|
|
2214
|
+
} catch {
|
|
2215
|
+
return text;
|
|
2216
|
+
}
|
|
2899
2217
|
}
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2218
|
+
|
|
2219
|
+
// src/services/config.service.ts
|
|
2220
|
+
async function getSupportedLanguages(config) {
|
|
2221
|
+
const response = await fetch(`${config.backendUrls.payment}/config/supported-languages`, {
|
|
2222
|
+
headers: {
|
|
2223
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2224
|
+
"X-Business-ID": config.businessId
|
|
2906
2225
|
}
|
|
2907
2226
|
});
|
|
2227
|
+
if (!response.ok) throw new Error("Failed to get supported languages");
|
|
2228
|
+
return response.json();
|
|
2908
2229
|
}
|
|
2909
|
-
function
|
|
2910
|
-
const
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
|
|
2230
|
+
async function getSupportedCurrencies(config) {
|
|
2231
|
+
const response = await fetch(`${config.backendUrls.payment}/config/supported-currencies`, {
|
|
2232
|
+
headers: {
|
|
2233
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2234
|
+
"X-Business-ID": config.businessId
|
|
2915
2235
|
}
|
|
2916
2236
|
});
|
|
2237
|
+
if (!response.ok) throw new Error("Failed to get supported currencies");
|
|
2238
|
+
return response.json();
|
|
2917
2239
|
}
|
|
2918
|
-
function
|
|
2919
|
-
const
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
|
|
2240
|
+
async function getBusinessConfig(config) {
|
|
2241
|
+
const response = await fetch(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
|
|
2242
|
+
headers: {
|
|
2243
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2244
|
+
"X-Business-ID": config.businessId
|
|
2924
2245
|
}
|
|
2925
2246
|
});
|
|
2247
|
+
if (!response.ok) throw new Error("Failed to get business config");
|
|
2248
|
+
return response.json();
|
|
2926
2249
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
const
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
}
|
|
2945
|
-
const abortController = new AbortController();
|
|
2946
|
-
abortControllerRef.current = abortController;
|
|
2947
|
-
const paymentUrl = getBackendUrl("payment");
|
|
2948
|
-
const streamUrl = `${paymentUrl}/events/stream/consultation/${consultationId}`;
|
|
2949
|
-
(0, import_fetch_event_source.fetchEventSource)(streamUrl, {
|
|
2950
|
-
method: "GET",
|
|
2951
|
-
signal: abortController.signal,
|
|
2952
|
-
onmessage: (event) => {
|
|
2953
|
-
try {
|
|
2954
|
-
if (!event.data || event.data.trim() === "") {
|
|
2955
|
-
return;
|
|
2956
|
-
}
|
|
2957
|
-
const data = JSON.parse(event.data);
|
|
2958
|
-
logger.log("[ConsultationStream] Received event:", data);
|
|
2959
|
-
setLastEvent(data);
|
|
2960
|
-
if (data.event === "consultation.message") {
|
|
2961
|
-
logger.log("[ConsultationStream] Message detected, calling onMessage");
|
|
2962
|
-
if (onMessage) {
|
|
2963
|
-
onMessage(data);
|
|
2964
|
-
}
|
|
2965
|
-
}
|
|
2966
|
-
if (data.event === "consultation.quote") {
|
|
2967
|
-
logger.log("[ConsultationStream] Quote detected, calling onQuote");
|
|
2968
|
-
if (onQuote) {
|
|
2969
|
-
onQuote(data);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
if (data.event === "consultation.status") {
|
|
2973
|
-
logger.log("[ConsultationStream] Status change detected, calling onStatusChange");
|
|
2974
|
-
if (onStatusChange) {
|
|
2975
|
-
onStatusChange(data);
|
|
2976
|
-
}
|
|
2977
|
-
}
|
|
2978
|
-
} catch (error) {
|
|
2979
|
-
logger.error("[ConsultationStream] Error parsing event:", error);
|
|
2980
|
-
}
|
|
2981
|
-
},
|
|
2982
|
-
onerror: (error) => {
|
|
2983
|
-
if (abortController.signal.aborted) {
|
|
2984
|
-
logger.log("[ConsultationStream] Connection closed via AbortController");
|
|
2985
|
-
return;
|
|
2986
|
-
}
|
|
2987
|
-
logger.error("[ConsultationStream] Connection error:", error);
|
|
2988
|
-
setIsConnected(false);
|
|
2989
|
-
if (onError) {
|
|
2990
|
-
onError(error);
|
|
2991
|
-
}
|
|
2992
|
-
},
|
|
2993
|
-
onopen: async (response) => {
|
|
2994
|
-
if (response.ok && response.headers.get("content-type")?.includes("text/event-stream")) {
|
|
2995
|
-
logger.log("[ConsultationStream] Connection established for consultation:", consultationId);
|
|
2996
|
-
setIsConnected(true);
|
|
2997
|
-
return;
|
|
2998
|
-
}
|
|
2999
|
-
throw new Error(`Unexpected response: ${response.status}`);
|
|
3000
|
-
}
|
|
3001
|
-
}).catch((error) => {
|
|
3002
|
-
if (abortController.signal.aborted || error.name === "AbortError") {
|
|
3003
|
-
return;
|
|
2250
|
+
var configService = {
|
|
2251
|
+
getSupportedLanguages,
|
|
2252
|
+
getSupportedCurrencies,
|
|
2253
|
+
getBusinessConfig
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
// src/services/cms.service.ts
|
|
2257
|
+
async function listCmsEntries(config, modelSlug, params) {
|
|
2258
|
+
const queryParams = new URLSearchParams();
|
|
2259
|
+
queryParams.set("page", (params?.page || 1).toString());
|
|
2260
|
+
queryParams.set("page_size", (params?.page_size || 50).toString());
|
|
2261
|
+
const response = await fetch(
|
|
2262
|
+
`${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries?${queryParams.toString()}`,
|
|
2263
|
+
{
|
|
2264
|
+
headers: {
|
|
2265
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2266
|
+
"X-Business-ID": config.businessId
|
|
3004
2267
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
setIsConnected(false);
|
|
3010
|
-
};
|
|
3011
|
-
}, [consultationId, onMessage, onQuote, onStatusChange, onError]);
|
|
3012
|
-
return { isConnected, lastEvent };
|
|
2268
|
+
}
|
|
2269
|
+
);
|
|
2270
|
+
if (!response.ok) throw new Error("Failed to list CMS entries");
|
|
2271
|
+
return response.json();
|
|
3013
2272
|
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
onBespokeUpdate,
|
|
3023
|
-
onConsultationUpdate,
|
|
3024
|
-
onServiceBookingUpdate,
|
|
3025
|
-
onError
|
|
3026
|
-
}) {
|
|
3027
|
-
const abortControllerRef = (0, import_react4.useRef)(null);
|
|
3028
|
-
(0, import_react4.useEffect)(() => {
|
|
3029
|
-
if (!orderId) {
|
|
3030
|
-
return;
|
|
2273
|
+
async function getCmsEntry(config, modelSlug, entryId) {
|
|
2274
|
+
const response = await fetch(
|
|
2275
|
+
`${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
|
|
2276
|
+
{
|
|
2277
|
+
headers: {
|
|
2278
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2279
|
+
"X-Business-ID": config.businessId
|
|
2280
|
+
}
|
|
3031
2281
|
}
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
if (data.event === "payment.success") {
|
|
3047
|
-
logger.log("[OrderStream] Payment success detected, calling onPaymentComplete");
|
|
3048
|
-
if (onPaymentComplete) {
|
|
3049
|
-
onPaymentComplete(data);
|
|
3050
|
-
}
|
|
3051
|
-
abortController.abort();
|
|
3052
|
-
}
|
|
3053
|
-
if (data.event === "digital.ready") {
|
|
3054
|
-
logger.log("[OrderStream] Digital delivery ready detected, calling onDigitalReady");
|
|
3055
|
-
if (onDigitalReady) {
|
|
3056
|
-
onDigitalReady(data);
|
|
3057
|
-
}
|
|
3058
|
-
}
|
|
3059
|
-
if (data.event === "bespoke.update") {
|
|
3060
|
-
logger.log("[OrderStream] Bespoke update detected, calling onBespokeUpdate");
|
|
3061
|
-
if (onBespokeUpdate) {
|
|
3062
|
-
onBespokeUpdate(data);
|
|
3063
|
-
}
|
|
3064
|
-
}
|
|
3065
|
-
if (data.event === "consultation.update") {
|
|
3066
|
-
logger.log("[OrderStream] Consultation update detected, calling onConsultationUpdate");
|
|
3067
|
-
if (onConsultationUpdate) {
|
|
3068
|
-
onConsultationUpdate(data);
|
|
3069
|
-
}
|
|
3070
|
-
}
|
|
3071
|
-
if (data.event === "service_booking.update") {
|
|
3072
|
-
logger.log("[OrderStream] Service booking update detected, calling onServiceBookingUpdate");
|
|
3073
|
-
if (onServiceBookingUpdate) {
|
|
3074
|
-
onServiceBookingUpdate(data);
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
} catch (error) {
|
|
3078
|
-
logger.error("[OrderStream] Error parsing event:", error);
|
|
3079
|
-
}
|
|
2282
|
+
);
|
|
2283
|
+
if (!response.ok) throw new Error("Failed to get CMS entry");
|
|
2284
|
+
return response.json();
|
|
2285
|
+
}
|
|
2286
|
+
async function createCmsEntry(config, accessToken, modelSlug, params) {
|
|
2287
|
+
const response = await fetch(
|
|
2288
|
+
`${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries`,
|
|
2289
|
+
{
|
|
2290
|
+
method: "POST",
|
|
2291
|
+
headers: {
|
|
2292
|
+
"Content-Type": "application/json",
|
|
2293
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2294
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2295
|
+
"X-Business-ID": config.businessId
|
|
3080
2296
|
},
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
2297
|
+
body: JSON.stringify(params)
|
|
2298
|
+
}
|
|
2299
|
+
);
|
|
2300
|
+
if (!response.ok) throw new Error("Failed to create CMS entry");
|
|
2301
|
+
return response.json();
|
|
2302
|
+
}
|
|
2303
|
+
async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
|
|
2304
|
+
const response = await fetch(
|
|
2305
|
+
`${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
|
|
2306
|
+
{
|
|
2307
|
+
method: "PUT",
|
|
2308
|
+
headers: {
|
|
2309
|
+
"Content-Type": "application/json",
|
|
2310
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2311
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2312
|
+
"X-Business-ID": config.businessId
|
|
3094
2313
|
},
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
2314
|
+
body: JSON.stringify(params)
|
|
2315
|
+
}
|
|
2316
|
+
);
|
|
2317
|
+
if (!response.ok) throw new Error("Failed to update CMS entry");
|
|
2318
|
+
return response.json();
|
|
2319
|
+
}
|
|
2320
|
+
async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
|
|
2321
|
+
const response = await fetch(
|
|
2322
|
+
`${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
|
|
2323
|
+
{
|
|
2324
|
+
method: "DELETE",
|
|
2325
|
+
headers: {
|
|
2326
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2327
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
2328
|
+
"X-Business-ID": config.businessId
|
|
3109
2329
|
}
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
abortController.abort();
|
|
3114
|
-
};
|
|
3115
|
-
}, [orderId, onPaymentComplete, onDigitalReady, onBespokeUpdate, onConsultationUpdate, onServiceBookingUpdate, onError]);
|
|
3116
|
-
return null;
|
|
2330
|
+
}
|
|
2331
|
+
);
|
|
2332
|
+
if (!response.ok) throw new Error("Failed to delete CMS entry");
|
|
3117
2333
|
}
|
|
3118
2334
|
|
|
3119
|
-
// src/
|
|
3120
|
-
var
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
},
|
|
3126
|
-
|
|
2335
|
+
// src/utils/cache.ts
|
|
2336
|
+
var CACHE_TIERS = {
|
|
2337
|
+
none: { staleTime: 0, gcTime: 0 },
|
|
2338
|
+
infinity: { staleTime: Infinity, gcTime: 0 },
|
|
2339
|
+
low: { staleTime: 1e3 * 30, gcTime: 1e3 * 60 },
|
|
2340
|
+
// 30s / 1m
|
|
2341
|
+
medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
|
|
2342
|
+
// 5m / 10m
|
|
2343
|
+
high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
|
|
2344
|
+
// 30m / 1h
|
|
2345
|
+
};
|
|
2346
|
+
var isDevelopment = true;
|
|
2347
|
+
function setEnvironmentMode(development) {
|
|
2348
|
+
isDevelopment = development;
|
|
3127
2349
|
}
|
|
2350
|
+
var getCacheTier = (tier) => {
|
|
2351
|
+
if (isDevelopment) return CACHE_TIERS.none;
|
|
2352
|
+
return CACHE_TIERS[tier];
|
|
2353
|
+
};
|
|
3128
2354
|
|
|
3129
|
-
// src/
|
|
3130
|
-
var
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
return true;
|
|
3139
|
-
}
|
|
3140
|
-
return false;
|
|
3141
|
-
}
|
|
3142
|
-
function useGoogleTranslate(appLang) {
|
|
3143
|
-
const [isLoaded, setIsLoaded] = (0, import_react6.useState)(false);
|
|
3144
|
-
const initRef = (0, import_react6.useRef)(false);
|
|
3145
|
-
const { data: supportedLangs = [] } = useSupportedLanguages();
|
|
3146
|
-
const clearCookies = (0, import_react6.useCallback)(() => {
|
|
3147
|
-
if (typeof window === "undefined") return;
|
|
3148
|
-
const domains = [
|
|
3149
|
-
window.location.hostname,
|
|
3150
|
-
"." + window.location.hostname,
|
|
3151
|
-
"." + window.location.hostname.split(".").slice(-2).join(".")
|
|
3152
|
-
];
|
|
3153
|
-
const path = "/";
|
|
3154
|
-
document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path};`;
|
|
3155
|
-
domains.forEach((domain) => {
|
|
3156
|
-
document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}; domain=${domain};`;
|
|
3157
|
-
});
|
|
3158
|
-
}, []);
|
|
3159
|
-
const resetToEnglish = (0, import_react6.useCallback)(() => {
|
|
3160
|
-
if (typeof window === "undefined") return;
|
|
3161
|
-
const googtrans = document.cookie.split("; ").find((row) => row.startsWith("googtrans="))?.split("=")[1];
|
|
3162
|
-
const domains = [
|
|
3163
|
-
window.location.hostname,
|
|
3164
|
-
"." + window.location.hostname,
|
|
3165
|
-
window.location.hostname.split(".").slice(-2).join("."),
|
|
3166
|
-
"." + window.location.hostname.split(".").slice(-2).join(".")
|
|
3167
|
-
];
|
|
3168
|
-
const clear = (name) => {
|
|
3169
|
-
document.cookie = `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
|
|
3170
|
-
domains.forEach((d) => {
|
|
3171
|
-
document.cookie = `${name}=; Path=/; Domain=${d}; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
|
|
3172
|
-
});
|
|
3173
|
-
};
|
|
3174
|
-
clear("googtrans");
|
|
3175
|
-
if (googtrans || document.documentElement.classList.contains("translated-ltr") || document.querySelector(".goog-te-banner-frame")) {
|
|
3176
|
-
window.location.reload();
|
|
3177
|
-
return;
|
|
2355
|
+
// src/utils/logger.ts
|
|
2356
|
+
var isDevelopment2 = true;
|
|
2357
|
+
function setLoggerEnvironmentMode(development) {
|
|
2358
|
+
isDevelopment2 = development;
|
|
2359
|
+
}
|
|
2360
|
+
var logger = {
|
|
2361
|
+
log: (...args) => {
|
|
2362
|
+
if (isDevelopment2) {
|
|
2363
|
+
console.log(...args);
|
|
3178
2364
|
}
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
}, []);
|
|
3184
|
-
const changeLanguage = (0, import_react6.useCallback)((nextAppCode) => {
|
|
3185
|
-
if (nextAppCode === "en") {
|
|
3186
|
-
resetToEnglish();
|
|
3187
|
-
return;
|
|
2365
|
+
},
|
|
2366
|
+
warn: (...args) => {
|
|
2367
|
+
if (isDevelopment2) {
|
|
2368
|
+
console.warn(...args);
|
|
3188
2369
|
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
}, [resetToEnglish]);
|
|
3199
|
-
(0, import_react6.useEffect)(() => {
|
|
3200
|
-
if (typeof window === "undefined") return;
|
|
3201
|
-
if (appLang === "en" && !initRef.current) return;
|
|
3202
|
-
if (initRef.current) return;
|
|
3203
|
-
if (supportedLangs.length === 0) return;
|
|
3204
|
-
initRef.current = true;
|
|
3205
|
-
if (!document.getElementById(ELEMENT_ID)) {
|
|
3206
|
-
const host = document.createElement("div");
|
|
3207
|
-
host.id = ELEMENT_ID;
|
|
3208
|
-
host.style.display = "none";
|
|
3209
|
-
document.body.appendChild(host);
|
|
2370
|
+
},
|
|
2371
|
+
/**
|
|
2372
|
+
* Logs a warning to the console in development only.
|
|
2373
|
+
* Alias for warn() for Python logging compatibility.
|
|
2374
|
+
* In production, this is a no-op.
|
|
2375
|
+
*/
|
|
2376
|
+
warning: (...args) => {
|
|
2377
|
+
if (isDevelopment2) {
|
|
2378
|
+
console.warn(...args);
|
|
3210
2379
|
}
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
{ pageLanguage: "en", includedLanguages, autoDisplay: false },
|
|
3216
|
-
ELEMENT_ID
|
|
3217
|
-
);
|
|
3218
|
-
setIsLoaded(true);
|
|
3219
|
-
}
|
|
3220
|
-
};
|
|
3221
|
-
if (!document.getElementById(SCRIPT_ID)) {
|
|
3222
|
-
const script = document.createElement("script");
|
|
3223
|
-
script.id = SCRIPT_ID;
|
|
3224
|
-
script.src = "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
|
|
3225
|
-
script.async = true;
|
|
3226
|
-
document.body.appendChild(script);
|
|
3227
|
-
} else {
|
|
3228
|
-
if (window.google?.translate) window.googleTranslateElementInit?.();
|
|
2380
|
+
},
|
|
2381
|
+
error: (...args) => {
|
|
2382
|
+
if (isDevelopment2) {
|
|
2383
|
+
console.error(...args);
|
|
3229
2384
|
}
|
|
3230
|
-
},
|
|
3231
|
-
|
|
3232
|
-
if (
|
|
3233
|
-
|
|
2385
|
+
},
|
|
2386
|
+
info: (...args) => {
|
|
2387
|
+
if (isDevelopment2) {
|
|
2388
|
+
console.info(...args);
|
|
3234
2389
|
}
|
|
3235
|
-
},
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
2390
|
+
},
|
|
2391
|
+
createScope: (scope) => ({
|
|
2392
|
+
log: (...args) => {
|
|
2393
|
+
if (isDevelopment2) {
|
|
2394
|
+
console.log(`[${scope}]`, ...args);
|
|
2395
|
+
}
|
|
2396
|
+
},
|
|
2397
|
+
warn: (...args) => {
|
|
2398
|
+
if (isDevelopment2) {
|
|
2399
|
+
console.warn(`[${scope}]`, ...args);
|
|
2400
|
+
}
|
|
2401
|
+
},
|
|
2402
|
+
warning: (...args) => {
|
|
2403
|
+
if (isDevelopment2) {
|
|
2404
|
+
console.warn(`[${scope}]`, ...args);
|
|
2405
|
+
}
|
|
2406
|
+
},
|
|
2407
|
+
error: (...args) => {
|
|
2408
|
+
if (isDevelopment2) {
|
|
2409
|
+
console.error(`[${scope}]`, ...args);
|
|
2410
|
+
}
|
|
2411
|
+
},
|
|
2412
|
+
info: (...args) => {
|
|
2413
|
+
if (isDevelopment2) {
|
|
2414
|
+
console.info(`[${scope}]`, ...args);
|
|
2415
|
+
}
|
|
3247
2416
|
}
|
|
3248
|
-
})
|
|
2417
|
+
})
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
// src/utils/sanitize-url.ts
|
|
2421
|
+
var InvalidBaseURLError = class extends Error {
|
|
2422
|
+
constructor(message) {
|
|
2423
|
+
super(message);
|
|
2424
|
+
this.name = "InvalidBaseURLError";
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
|
|
2428
|
+
function sanitizeBaseUrl(url, name = "URL") {
|
|
2429
|
+
if (url == null) {
|
|
2430
|
+
throw new InvalidBaseURLError(`${name} is not set`);
|
|
2431
|
+
}
|
|
2432
|
+
const cleaned0 = url.trim();
|
|
2433
|
+
if (!cleaned0) {
|
|
2434
|
+
throw new InvalidBaseURLError(`${name} is empty`);
|
|
2435
|
+
}
|
|
2436
|
+
const cleaned = cleaned0.replace(/\/+$/, "");
|
|
2437
|
+
let parsed;
|
|
2438
|
+
try {
|
|
2439
|
+
parsed = new URL(cleaned);
|
|
2440
|
+
} catch {
|
|
2441
|
+
throw new InvalidBaseURLError(
|
|
2442
|
+
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
|
|
2446
|
+
throw new InvalidBaseURLError(
|
|
2447
|
+
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
if (!parsed.hostname) {
|
|
2451
|
+
throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
|
|
2452
|
+
}
|
|
2453
|
+
if (parsed.search || parsed.hash) {
|
|
2454
|
+
throw new InvalidBaseURLError(
|
|
2455
|
+
`${name} should not contain a query or fragment: ${url}`
|
|
2456
|
+
);
|
|
2457
|
+
}
|
|
2458
|
+
return cleaned;
|
|
3249
2459
|
}
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
2460
|
+
|
|
2461
|
+
// src/utils/customer.ts
|
|
2462
|
+
function buildFullName2(firstname, lastname) {
|
|
2463
|
+
const name = [firstname, lastname].filter(Boolean).join(" ").trim();
|
|
2464
|
+
return name || void 0;
|
|
3254
2465
|
}
|
|
3255
|
-
function
|
|
3256
|
-
return
|
|
3257
|
-
|
|
3258
|
-
|
|
2466
|
+
function splitFullName2(fullName) {
|
|
2467
|
+
if (!fullName?.trim()) return { firstname: "", lastname: "" };
|
|
2468
|
+
const parts = fullName.trim().split(/\s+/);
|
|
2469
|
+
return {
|
|
2470
|
+
firstname: parts[0] ?? "",
|
|
2471
|
+
lastname: parts.slice(1).join(" ")
|
|
2472
|
+
};
|
|
3259
2473
|
}
|
|
3260
|
-
function
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
queryFn: () => paymentService.getTransactionStatus(transactionId),
|
|
3264
|
-
enabled: isInitialized() && enabled,
|
|
3265
|
-
...getCacheTier("none"),
|
|
3266
|
-
refetchInterval: 3e3
|
|
3267
|
-
// Poll every 3 seconds
|
|
3268
|
-
});
|
|
2474
|
+
function getCustomerDisplayName(user) {
|
|
2475
|
+
const fromParts = buildFullName2(user.firstname, user.lastname);
|
|
2476
|
+
return fromParts || user.full_name || user.email.split("@")[0];
|
|
3269
2477
|
}
|
|
3270
|
-
function
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
// Poll every 2 seconds
|
|
3278
|
-
retry: 10
|
|
3279
|
-
// Retry up to 10 times
|
|
3280
|
-
});
|
|
2478
|
+
function getStorefrontUrl(businessId, customDomain) {
|
|
2479
|
+
if (customDomain && customDomain.trim()) {
|
|
2480
|
+
const cleanDomain = customDomain.trim().replace(/^https?:\/\//, "");
|
|
2481
|
+
return `https://${cleanDomain}`;
|
|
2482
|
+
}
|
|
2483
|
+
const cleanBid = (businessId || "store").toLowerCase().trim();
|
|
2484
|
+
return `https://${cleanBid}.kasuvia.com`;
|
|
3281
2485
|
}
|
|
3282
2486
|
|
|
3283
|
-
// src/
|
|
3284
|
-
|
|
3285
|
-
function useCmsEntries(modelSlug, params) {
|
|
3286
|
-
const query = (0, import_react_query15.useQuery)({
|
|
3287
|
-
queryKey: ["cms-entries", modelSlug, params],
|
|
3288
|
-
queryFn: () => listCmsEntries(modelSlug, params),
|
|
3289
|
-
enabled: isInitialized() && !!modelSlug
|
|
3290
|
-
});
|
|
3291
|
-
return {
|
|
3292
|
-
entries: query.data?.entries || [],
|
|
3293
|
-
total: query.data?.total || 0,
|
|
3294
|
-
page: query.data?.page || 1,
|
|
3295
|
-
page_size: query.data?.page_size || 50,
|
|
3296
|
-
isLoading: query.isLoading,
|
|
3297
|
-
error: query.error,
|
|
3298
|
-
refetch: query.refetch
|
|
3299
|
-
};
|
|
3300
|
-
}
|
|
3301
|
-
function useCmsEntry(modelSlug, entryId) {
|
|
3302
|
-
const query = (0, import_react_query15.useQuery)({
|
|
3303
|
-
queryKey: ["cms-entry", modelSlug, entryId],
|
|
3304
|
-
queryFn: () => getCmsEntry(modelSlug, entryId),
|
|
3305
|
-
enabled: isInitialized() && !!modelSlug && !!entryId
|
|
3306
|
-
});
|
|
2487
|
+
// src/utils/checkout.ts
|
|
2488
|
+
function buildDeliveryAddress(customer, location) {
|
|
3307
2489
|
return {
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
2490
|
+
first_name: customer.first_name,
|
|
2491
|
+
last_name: customer.last_name,
|
|
2492
|
+
phone: customer.phone,
|
|
2493
|
+
...location
|
|
3312
2494
|
};
|
|
3313
2495
|
}
|
|
3314
|
-
function
|
|
3315
|
-
|
|
3316
|
-
const mutation = (0, import_react_query15.useMutation)({
|
|
3317
|
-
mutationFn: (params) => createCmsEntry(modelSlug, params),
|
|
3318
|
-
onSuccess: () => {
|
|
3319
|
-
queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
|
|
3320
|
-
}
|
|
3321
|
-
});
|
|
3322
|
-
return {
|
|
3323
|
-
createEntry: mutation.mutate,
|
|
3324
|
-
isLoading: mutation.isPending,
|
|
3325
|
-
error: mutation.error
|
|
3326
|
-
};
|
|
2496
|
+
function getCheckoutCustomerName(customer) {
|
|
2497
|
+
return buildFullName2(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
|
|
3327
2498
|
}
|
|
3328
|
-
function
|
|
3329
|
-
const
|
|
3330
|
-
const mutation = (0, import_react_query15.useMutation)({
|
|
3331
|
-
mutationFn: ({ entryId, params }) => updateCmsEntry(modelSlug, entryId, params),
|
|
3332
|
-
onSuccess: () => {
|
|
3333
|
-
queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
|
|
3334
|
-
queryClient.invalidateQueries({ queryKey: ["cms-entry", modelSlug] });
|
|
3335
|
-
}
|
|
3336
|
-
});
|
|
2499
|
+
function enrichCompletedOrder(order, options) {
|
|
2500
|
+
const customerName = getCheckoutCustomerName(options.customer);
|
|
3337
2501
|
return {
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
2502
|
+
...order,
|
|
2503
|
+
customerName: order.customerName || customerName,
|
|
2504
|
+
customerEmail: order.customerEmail || options.customer.email,
|
|
2505
|
+
shippingAddress: order.shippingAddress ?? (options.productType === "physical" && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
|
|
2506
|
+
bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
|
|
3341
2507
|
};
|
|
3342
2508
|
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
2509
|
+
|
|
2510
|
+
// src/utils/error-handler.ts
|
|
2511
|
+
function getErrorMessage(error, fallback = "Something went wrong") {
|
|
2512
|
+
if (error instanceof Error) {
|
|
2513
|
+
return error.message;
|
|
2514
|
+
}
|
|
2515
|
+
if (error instanceof Response) {
|
|
2516
|
+
return `HTTP ${error.status}: ${error.statusText}`;
|
|
2517
|
+
}
|
|
2518
|
+
if (typeof error === "object" && error !== null) {
|
|
2519
|
+
const err = error;
|
|
2520
|
+
return err.detail || err.message || fallback;
|
|
2521
|
+
}
|
|
2522
|
+
return fallback;
|
|
3357
2523
|
}
|
|
3358
2524
|
|
|
3359
2525
|
// src/utils/storage.ts
|
|
3360
|
-
function getPrefixedKey(key) {
|
|
3361
|
-
const
|
|
3362
|
-
|
|
3363
|
-
const cleanKey = key.startsWith("luxe_") ? key.substring(5) : key;
|
|
3364
|
-
return bid ? `luxe-sf-${bid}-${cleanKey}` : `luxe-sf-anon-${cleanKey}`;
|
|
2526
|
+
function getPrefixedKey(businessId, key) {
|
|
2527
|
+
const cleanKey = key.startsWith("kasuvia_") ? key.substring(5) : key;
|
|
2528
|
+
return businessId ? `kasuvia-sf-${businessId}-${cleanKey}` : `kasuvia-sf-anon-${cleanKey}`;
|
|
3365
2529
|
}
|
|
3366
2530
|
var sessionStore = {
|
|
3367
|
-
get: (key) => {
|
|
2531
|
+
get: (businessIdOrKey, key) => {
|
|
3368
2532
|
if (typeof window === "undefined") return null;
|
|
3369
|
-
|
|
2533
|
+
const bId = key ? businessIdOrKey : "";
|
|
2534
|
+
const k = key || businessIdOrKey;
|
|
2535
|
+
return sessionStorage.getItem(getPrefixedKey(bId, k));
|
|
3370
2536
|
},
|
|
3371
|
-
set: (
|
|
2537
|
+
set: (businessIdOrKey, keyOrVal, val) => {
|
|
3372
2538
|
if (typeof window === "undefined") return;
|
|
3373
|
-
|
|
2539
|
+
const bId = val !== void 0 ? businessIdOrKey : "";
|
|
2540
|
+
const k = val !== void 0 ? keyOrVal : businessIdOrKey;
|
|
2541
|
+
const v = val !== void 0 ? val : keyOrVal;
|
|
2542
|
+
sessionStorage.setItem(getPrefixedKey(bId, k), v);
|
|
3374
2543
|
},
|
|
3375
|
-
remove: (key) => {
|
|
2544
|
+
remove: (businessIdOrKey, key) => {
|
|
3376
2545
|
if (typeof window === "undefined") return;
|
|
3377
|
-
|
|
2546
|
+
const bId = key ? businessIdOrKey : "";
|
|
2547
|
+
const k = key || businessIdOrKey;
|
|
2548
|
+
sessionStorage.removeItem(getPrefixedKey(bId, k));
|
|
3378
2549
|
},
|
|
3379
|
-
getJSON: (key) => {
|
|
2550
|
+
getJSON: (businessIdOrKey, key) => {
|
|
3380
2551
|
if (typeof window === "undefined") return null;
|
|
3381
|
-
const
|
|
2552
|
+
const bId = key ? businessIdOrKey : "";
|
|
2553
|
+
const k = key || businessIdOrKey;
|
|
2554
|
+
const value = sessionStorage.getItem(getPrefixedKey(bId, k));
|
|
3382
2555
|
if (!value) return null;
|
|
3383
2556
|
try {
|
|
3384
2557
|
return JSON.parse(value);
|
|
@@ -3386,27 +2559,39 @@ var sessionStore = {
|
|
|
3386
2559
|
return null;
|
|
3387
2560
|
}
|
|
3388
2561
|
},
|
|
3389
|
-
setJSON: (
|
|
2562
|
+
setJSON: (businessIdOrKey, keyOrVal, val) => {
|
|
3390
2563
|
if (typeof window === "undefined") return;
|
|
3391
|
-
|
|
2564
|
+
const bId = val !== void 0 ? businessIdOrKey : "";
|
|
2565
|
+
const k = val !== void 0 ? keyOrVal : businessIdOrKey;
|
|
2566
|
+
const v = val !== void 0 ? val : keyOrVal;
|
|
2567
|
+
sessionStorage.setItem(getPrefixedKey(bId, k), JSON.stringify(v));
|
|
3392
2568
|
}
|
|
3393
2569
|
};
|
|
3394
2570
|
var localStore = {
|
|
3395
|
-
get: (key) => {
|
|
2571
|
+
get: (businessIdOrKey, key) => {
|
|
3396
2572
|
if (typeof window === "undefined") return null;
|
|
3397
|
-
|
|
2573
|
+
const bId = key ? businessIdOrKey : "";
|
|
2574
|
+
const k = key || businessIdOrKey;
|
|
2575
|
+
return localStorage.getItem(getPrefixedKey(bId, k));
|
|
3398
2576
|
},
|
|
3399
|
-
set: (
|
|
2577
|
+
set: (businessIdOrKey, keyOrVal, val) => {
|
|
3400
2578
|
if (typeof window === "undefined") return;
|
|
3401
|
-
|
|
2579
|
+
const bId = val !== void 0 ? businessIdOrKey : "";
|
|
2580
|
+
const k = val !== void 0 ? keyOrVal : businessIdOrKey;
|
|
2581
|
+
const v = val !== void 0 ? val : keyOrVal;
|
|
2582
|
+
localStorage.setItem(getPrefixedKey(bId, k), v);
|
|
3402
2583
|
},
|
|
3403
|
-
remove: (key) => {
|
|
2584
|
+
remove: (businessIdOrKey, key) => {
|
|
3404
2585
|
if (typeof window === "undefined") return;
|
|
3405
|
-
|
|
2586
|
+
const bId = key ? businessIdOrKey : "";
|
|
2587
|
+
const k = key || businessIdOrKey;
|
|
2588
|
+
localStorage.removeItem(getPrefixedKey(bId, k));
|
|
3406
2589
|
},
|
|
3407
|
-
getJSON: (key) => {
|
|
2590
|
+
getJSON: (businessIdOrKey, key) => {
|
|
3408
2591
|
if (typeof window === "undefined") return null;
|
|
3409
|
-
const
|
|
2592
|
+
const bId = key ? businessIdOrKey : "";
|
|
2593
|
+
const k = key || businessIdOrKey;
|
|
2594
|
+
const value = localStorage.getItem(getPrefixedKey(bId, k));
|
|
3410
2595
|
if (!value) return null;
|
|
3411
2596
|
try {
|
|
3412
2597
|
return JSON.parse(value);
|
|
@@ -3414,24 +2599,98 @@ var localStore = {
|
|
|
3414
2599
|
return null;
|
|
3415
2600
|
}
|
|
3416
2601
|
},
|
|
3417
|
-
setJSON: (
|
|
2602
|
+
setJSON: (businessIdOrKey, keyOrVal, val) => {
|
|
3418
2603
|
if (typeof window === "undefined") return;
|
|
3419
|
-
|
|
2604
|
+
const bId = val !== void 0 ? businessIdOrKey : "";
|
|
2605
|
+
const k = val !== void 0 ? keyOrVal : businessIdOrKey;
|
|
2606
|
+
const v = val !== void 0 ? val : keyOrVal;
|
|
2607
|
+
localStorage.setItem(getPrefixedKey(bId, k), JSON.stringify(v));
|
|
3420
2608
|
}
|
|
3421
2609
|
};
|
|
2610
|
+
|
|
2611
|
+
// src/utils/validators.ts
|
|
2612
|
+
function validateEmail(email) {
|
|
2613
|
+
if (!email || email.trim() === "") {
|
|
2614
|
+
return "Email is required";
|
|
2615
|
+
}
|
|
2616
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2617
|
+
if (!emailRegex.test(email)) {
|
|
2618
|
+
return "Please enter a valid email address";
|
|
2619
|
+
}
|
|
2620
|
+
return null;
|
|
2621
|
+
}
|
|
2622
|
+
function validatePassword(password) {
|
|
2623
|
+
if (!password || password.trim() === "") {
|
|
2624
|
+
return "Password is required";
|
|
2625
|
+
}
|
|
2626
|
+
if (password.length < 8) {
|
|
2627
|
+
return "Password must be at least 8 characters";
|
|
2628
|
+
}
|
|
2629
|
+
if (password.length > 72) {
|
|
2630
|
+
return "Password cannot exceed 72 characters";
|
|
2631
|
+
}
|
|
2632
|
+
if (!/[A-Z]/.test(password)) {
|
|
2633
|
+
return "Password must contain at least one uppercase letter";
|
|
2634
|
+
}
|
|
2635
|
+
if (!/[a-z]/.test(password)) {
|
|
2636
|
+
return "Password must contain at least one lowercase letter";
|
|
2637
|
+
}
|
|
2638
|
+
if (!/[0-9]/.test(password)) {
|
|
2639
|
+
return "Password must contain at least one number";
|
|
2640
|
+
}
|
|
2641
|
+
return null;
|
|
2642
|
+
}
|
|
2643
|
+
function validateName(name, fieldName = "Name") {
|
|
2644
|
+
if (!name || name.trim() === "") {
|
|
2645
|
+
return `${fieldName} is required`;
|
|
2646
|
+
}
|
|
2647
|
+
if (name.trim().length < 2) {
|
|
2648
|
+
return `${fieldName} must be at least 2 characters`;
|
|
2649
|
+
}
|
|
2650
|
+
if (name.trim().length > 50) {
|
|
2651
|
+
return `${fieldName} cannot exceed 50 characters`;
|
|
2652
|
+
}
|
|
2653
|
+
const nameRegex = /^[a-zA-Z\s\-'\u00C0-\u017F]+$/;
|
|
2654
|
+
if (!nameRegex.test(name.trim())) {
|
|
2655
|
+
return `${fieldName} can only contain letters, spaces, hyphens, and apostrophes`;
|
|
2656
|
+
}
|
|
2657
|
+
return null;
|
|
2658
|
+
}
|
|
2659
|
+
function validateRequired(value, fieldName) {
|
|
2660
|
+
if (!value || value.trim() === "") {
|
|
2661
|
+
return `${fieldName} is required`;
|
|
2662
|
+
}
|
|
2663
|
+
return null;
|
|
2664
|
+
}
|
|
2665
|
+
function validateConfirmPassword(password, confirmPassword) {
|
|
2666
|
+
if (!confirmPassword) return null;
|
|
2667
|
+
if (confirmPassword !== password) {
|
|
2668
|
+
return "Passwords do not match";
|
|
2669
|
+
}
|
|
2670
|
+
return null;
|
|
2671
|
+
}
|
|
2672
|
+
function validateMessage(message) {
|
|
2673
|
+
if (!message || message.trim() === "") {
|
|
2674
|
+
return "Message is required";
|
|
2675
|
+
}
|
|
2676
|
+
if (message.trim().length < 10) {
|
|
2677
|
+
return "Message must be at least 10 characters";
|
|
2678
|
+
}
|
|
2679
|
+
return null;
|
|
2680
|
+
}
|
|
3422
2681
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3423
2682
|
0 && (module.exports = {
|
|
3424
|
-
AuthCtx,
|
|
3425
|
-
AuthProvider,
|
|
3426
|
-
CartCtx,
|
|
3427
|
-
CartProvider,
|
|
3428
2683
|
InvalidBaseURLError,
|
|
2684
|
+
STORAGE_KEYS,
|
|
2685
|
+
SdkProvider,
|
|
2686
|
+
ServiceLocationTypeEnum,
|
|
2687
|
+
ServiceRecurringIntervalEnum,
|
|
2688
|
+
ServiceTypeEnum,
|
|
3429
2689
|
acceptQuote,
|
|
3430
2690
|
addToCart,
|
|
3431
2691
|
addToGuestCart,
|
|
3432
2692
|
addToWishlist,
|
|
3433
2693
|
approveDeliverable,
|
|
3434
|
-
authAxios,
|
|
3435
2694
|
bespokeService,
|
|
3436
2695
|
bookAppointment,
|
|
3437
2696
|
buildDeliveryAddress,
|
|
@@ -3442,11 +2701,8 @@ var localStore = {
|
|
|
3442
2701
|
checkInWishlist,
|
|
3443
2702
|
clearCart,
|
|
3444
2703
|
clearGuestCart,
|
|
3445
|
-
|
|
3446
|
-
cmsAxios,
|
|
3447
|
-
collectionKeys,
|
|
2704
|
+
clearTokens,
|
|
3448
2705
|
configService,
|
|
3449
|
-
configureHttpClients,
|
|
3450
2706
|
consultationService,
|
|
3451
2707
|
createCmsEntry,
|
|
3452
2708
|
createConsultation,
|
|
@@ -3460,7 +2716,6 @@ var localStore = {
|
|
|
3460
2716
|
getAppointments,
|
|
3461
2717
|
getAuthUser,
|
|
3462
2718
|
getAvailableSlots,
|
|
3463
|
-
getBackendUrl,
|
|
3464
2719
|
getBusinessConfig,
|
|
3465
2720
|
getCacheTier,
|
|
3466
2721
|
getCart,
|
|
@@ -3468,43 +2723,36 @@ var localStore = {
|
|
|
3468
2723
|
getCmsEntry,
|
|
3469
2724
|
getConsultation,
|
|
3470
2725
|
getConsultations,
|
|
3471
|
-
getCountries,
|
|
3472
2726
|
getCustomerDisplayName,
|
|
3473
2727
|
getDeliverables,
|
|
3474
2728
|
getErrorMessage,
|
|
3475
2729
|
getFeaturedProducts,
|
|
3476
|
-
getGraphQLClient,
|
|
3477
2730
|
getGuestCart,
|
|
3478
2731
|
getGuestCartCount,
|
|
3479
2732
|
getGuestCartProductType,
|
|
3480
2733
|
getGuestCartSubtotal,
|
|
3481
|
-
getGuestSessionId,
|
|
3482
2734
|
getLatestProducts,
|
|
2735
|
+
getLowStockProducts,
|
|
3483
2736
|
getMe,
|
|
3484
2737
|
getNewProducts,
|
|
3485
|
-
|
|
2738
|
+
getOnSaleProducts,
|
|
3486
2739
|
getOrders,
|
|
3487
2740
|
getPopularProducts,
|
|
3488
2741
|
getRecommendedProducts,
|
|
3489
|
-
getRuntimeConfig,
|
|
3490
2742
|
getSellerShippingAddress,
|
|
3491
2743
|
getShippingRates,
|
|
3492
|
-
|
|
2744
|
+
getStoredTokens,
|
|
3493
2745
|
getStorefrontCollectionBySlug,
|
|
3494
2746
|
getStorefrontCollections,
|
|
3495
2747
|
getStorefrontProductBySlug,
|
|
3496
2748
|
getStorefrontProducts,
|
|
3497
2749
|
getStorefrontUrl,
|
|
3498
2750
|
getSupportedCurrencies,
|
|
3499
|
-
getSupportedCurrenciesList,
|
|
3500
2751
|
getSupportedLanguages,
|
|
3501
|
-
getSupportedLanguagesList,
|
|
3502
2752
|
getTransactionStatus,
|
|
3503
2753
|
getWishlist,
|
|
3504
2754
|
googleTranslate,
|
|
3505
|
-
initSdk,
|
|
3506
2755
|
initiatePayment,
|
|
3507
|
-
isInitialized,
|
|
3508
2756
|
listCmsEntries,
|
|
3509
2757
|
localStore,
|
|
3510
2758
|
logger,
|
|
@@ -3515,10 +2763,7 @@ var localStore = {
|
|
|
3515
2763
|
mergeGuestCart,
|
|
3516
2764
|
mergeGuestCartIfPresent,
|
|
3517
2765
|
notificationsService,
|
|
3518
|
-
paymentAxios,
|
|
3519
2766
|
paymentService,
|
|
3520
|
-
productKeys,
|
|
3521
|
-
publicStoreAxios,
|
|
3522
2767
|
refreshToken,
|
|
3523
2768
|
registerCustomer,
|
|
3524
2769
|
rejectQuote,
|
|
@@ -3528,8 +2773,6 @@ var localStore = {
|
|
|
3528
2773
|
removeProductFromWishlist,
|
|
3529
2774
|
requestQuote,
|
|
3530
2775
|
requestRevision,
|
|
3531
|
-
resetConfig,
|
|
3532
|
-
resetGraphQLClient,
|
|
3533
2776
|
sanitizeBaseUrl,
|
|
3534
2777
|
sendContactConfirmation,
|
|
3535
2778
|
sendContactEmail,
|
|
@@ -3540,79 +2783,21 @@ var localStore = {
|
|
|
3540
2783
|
setLoggerEnvironmentMode,
|
|
3541
2784
|
silentRefresh,
|
|
3542
2785
|
splitFullName,
|
|
3543
|
-
storeManagementAxios,
|
|
3544
2786
|
storeTokens,
|
|
3545
|
-
tokenStore,
|
|
3546
2787
|
trackOrder,
|
|
3547
2788
|
updateCartItem,
|
|
3548
2789
|
updateCmsEntry,
|
|
3549
2790
|
updateGuestCartItemQuantity,
|
|
3550
2791
|
updateProfile,
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
useAvailableSlots,
|
|
3559
|
-
useBespokeAvailability,
|
|
3560
|
-
useBookAppointment,
|
|
3561
|
-
useCancelAppointment,
|
|
3562
|
-
useCancelOrder,
|
|
3563
|
-
useCart,
|
|
3564
|
-
useCheckInWishlist,
|
|
3565
|
-
useCmsEntries,
|
|
3566
|
-
useCmsEntry,
|
|
3567
|
-
useConsultation,
|
|
3568
|
-
useConsultationStream,
|
|
3569
|
-
useConsultations,
|
|
3570
|
-
useCountries,
|
|
3571
|
-
useCreateCmsEntry,
|
|
3572
|
-
useCreateConsultation,
|
|
3573
|
-
useCreateDVA,
|
|
3574
|
-
useCreateOrder,
|
|
3575
|
-
useCurrencies,
|
|
3576
|
-
useDeleteCmsEntry,
|
|
3577
|
-
useDeliverables,
|
|
3578
|
-
useFeaturedProducts,
|
|
3579
|
-
useFindOrder,
|
|
3580
|
-
useGoogleTranslate,
|
|
3581
|
-
useInitiatePayment,
|
|
3582
|
-
useIsMounted,
|
|
3583
|
-
useLatestProducts,
|
|
3584
|
-
useLogin,
|
|
3585
|
-
useLogout,
|
|
3586
|
-
useNewProducts,
|
|
3587
|
-
useOrder,
|
|
3588
|
-
useOrderStream,
|
|
3589
|
-
useOrderTracking,
|
|
3590
|
-
useOrders,
|
|
3591
|
-
useOrdersList,
|
|
3592
|
-
usePollTransactionStatus,
|
|
3593
|
-
usePopularProducts,
|
|
3594
|
-
useProduct,
|
|
3595
|
-
useRecommendedProducts,
|
|
3596
|
-
useRegister,
|
|
3597
|
-
useRejectQuote,
|
|
3598
|
-
useRemoveFromWishlist,
|
|
3599
|
-
useRemoveProductFromWishlist,
|
|
3600
|
-
useRequestRevision,
|
|
3601
|
-
useSendMessage,
|
|
3602
|
-
useStates,
|
|
3603
|
-
useStorefrontCollection,
|
|
3604
|
-
useStorefrontCollections,
|
|
3605
|
-
useStorefrontProducts,
|
|
3606
|
-
useSupportedLanguages,
|
|
3607
|
-
useTransactionStatus,
|
|
3608
|
-
useUpdateCmsEntry,
|
|
3609
|
-
useUpdateProfile,
|
|
3610
|
-
useVerifyTransaction,
|
|
3611
|
-
useWishlist,
|
|
3612
|
-
useWishlistCount,
|
|
2792
|
+
useSdkContext,
|
|
2793
|
+
validateConfirmPassword,
|
|
2794
|
+
validateEmail,
|
|
2795
|
+
validateMessage,
|
|
2796
|
+
validateName,
|
|
2797
|
+
validatePassword,
|
|
2798
|
+
validateRequired,
|
|
3613
2799
|
validateShippingAddress,
|
|
3614
2800
|
verifySocialToken,
|
|
3615
|
-
verifyTransaction
|
|
3616
|
-
wishlistKeys
|
|
2801
|
+
verifyTransaction
|
|
3617
2802
|
});
|
|
3618
2803
|
//# sourceMappingURL=index.js.map
|