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