@kasuvia/sdk 0.0.8 → 0.0.9
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 +42 -15
- package/dist/AddressAutocomplete-CjcqPElD.d.mts +46 -0
- package/dist/AddressAutocomplete-CvJHuRkf.d.ts +46 -0
- package/dist/components/index.d.mts +497 -0
- package/dist/components/index.d.ts +497 -0
- package/dist/components/index.js +4217 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +4194 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/server.d.mts +26 -0
- package/dist/config/server.d.ts +26 -0
- package/dist/config/server.js +38 -0
- package/dist/config/server.js.map +1 -0
- package/dist/config/server.mjs +13 -0
- package/dist/config/server.mjs.map +1 -0
- package/dist/hooks/index.d.mts +393 -160
- package/dist/hooks/index.d.ts +393 -160
- package/dist/hooks/index.js +2792 -2137
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +2734 -2121
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index-CNW_LINy.d.mts +578 -0
- package/dist/index-CNW_LINy.d.ts +578 -0
- package/dist/{index-C1chUA3P.d.mts → index-F7N6UItS.d.mts} +1 -1
- package/dist/{index-C1chUA3P.d.ts → index-F7N6UItS.d.ts} +1 -1
- package/dist/index-NkI10J_E.d.mts +40 -0
- package/dist/index-NkI10J_E.d.ts +40 -0
- package/dist/index.d.mts +20437 -103
- package/dist/index.d.ts +20437 -103
- package/dist/index.js +2111 -1802
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2006 -1786
- package/dist/index.mjs.map +1 -1
- package/dist/media.service-Cx7dQjzX.d.mts +1393 -0
- package/dist/media.service-mrBFJ2UQ.d.ts +1393 -0
- package/dist/services/index.d.mts +908 -2
- package/dist/services/index.d.ts +908 -2
- package/dist/services/index.js +1492 -1686
- package/dist/services/index.js.map +1 -1
- package/dist/services/index.mjs +1431 -1670
- package/dist/services/index.mjs.map +1 -1
- package/package.json +46 -6
- package/src/components/bespoke/BespokeAvailabilityBadge.tsx +32 -0
- package/src/components/bespoke/BespokeProgressTracker.tsx +58 -0
- package/src/components/bespoke/index.ts +3 -0
- package/src/components/booking/SlotPicker.tsx +97 -0
- package/src/components/booking/index.ts +1 -0
- package/src/components/cart/CartItem.tsx +81 -0
- package/src/components/cart/CartSidebar.tsx +115 -0
- package/src/components/cart/CartTypeMismatchBanner.tsx +55 -0
- package/src/components/cart/index.ts +3 -0
- package/src/components/index.ts +8 -0
- package/src/components/orders/DeliverableReviewer.tsx +139 -0
- package/src/components/orders/index.ts +1 -0
- package/src/components/product/ProductCard.tsx +350 -0
- package/src/components/product/ProductGrid.tsx +84 -0
- package/src/components/product/index.ts +2 -0
- package/src/components/shared/AddressAutocomplete.tsx +212 -0
- package/src/components/shared/AnalyticsScripts.tsx +56 -0
- package/src/components/shared/CookieConsentBanner.tsx +98 -0
- package/src/components/shared/ImageEditorModal.tsx +1066 -0
- package/src/components/shared/ImageViewerModal.tsx +598 -0
- package/src/components/shared/LucideReactIcon.tsx +52 -0
- package/src/components/shared/MapPinDrop.tsx +101 -0
- package/src/components/shared/MultiSelectPicker.tsx +193 -0
- package/src/components/shared/OfflineBanner.tsx +46 -0
- package/src/components/shared/SearchableInput.tsx +153 -0
- package/src/components/shared/SearchablePopover.tsx +166 -0
- package/src/components/shared/SmartImage.tsx +311 -0
- package/src/components/shared/TruncatedValue.tsx +27 -0
- package/src/components/shared/UnsavedChangesGuard.tsx +138 -0
- package/src/components/shared/index.ts +15 -0
- package/src/components/skeletons/CardSkeleton.tsx +26 -0
- package/src/components/skeletons/CartItemSkeleton.tsx +26 -0
- package/src/components/skeletons/OrderItemSkeleton.tsx +26 -0
- package/src/components/skeletons/ProductCardSkeleton.tsx +26 -0
- package/src/components/skeletons/TableSkeleton.tsx +42 -0
- package/src/components/skeletons/index.ts +5 -0
- package/src/config/index.ts +22 -4
- package/src/config/server.ts +45 -0
- package/src/context/sdk-context.tsx +5 -2
- package/src/generated/auth-openapi.ts +2935 -0
- package/src/generated/cart-openapi.ts +652 -0
- package/src/generated/cms-openapi.ts +1668 -0
- package/src/generated/crm-openapi.ts +986 -0
- package/src/generated/graphql.ts +126 -0
- package/src/generated/index.ts +11 -0
- package/src/generated/media-openapi.ts +613 -0
- package/src/generated/notification-openapi.ts +862 -0
- package/src/generated/payment-openapi.ts +2713 -0
- package/src/generated/store-openapi.ts +9510 -0
- package/src/graphql/operations/collections.graphql +32 -0
- package/src/graphql/operations/products.graphql +197 -0
- package/src/graphql/operations/wishlist.graphql +25 -0
- package/src/hooks/index.ts +9 -2
- package/src/hooks/use-auth.ts +163 -69
- package/src/hooks/use-bespoke-availability.ts +39 -22
- package/src/hooks/use-business-config.ts +51 -0
- package/src/hooks/use-cart.ts +310 -238
- package/src/hooks/use-cms.ts +107 -127
- package/src/hooks/use-collections.ts +35 -55
- package/src/hooks/use-consultations.ts +9 -136
- package/src/hooks/use-countries.ts +19 -28
- package/src/hooks/use-currencies.ts +8 -20
- package/src/hooks/use-customer-address.ts +64 -0
- package/src/hooks/use-feedback.ts +34 -0
- package/src/hooks/use-languages.ts +26 -39
- package/src/hooks/use-media-upload.ts +23 -0
- package/src/hooks/use-notification-stream.ts +88 -0
- package/src/hooks/use-notifications.ts +163 -0
- package/src/hooks/use-order-stream.ts +29 -29
- package/src/hooks/use-orders.ts +91 -73
- package/src/hooks/use-payment.ts +116 -84
- package/src/hooks/use-products.ts +65 -269
- package/src/hooks/use-push-notifications.ts +122 -0
- package/src/hooks/use-reviews.ts +175 -0
- package/src/hooks/use-service-booking.ts +109 -132
- package/src/hooks/use-states.ts +16 -30
- package/src/hooks/use-wishlist.ts +44 -69
- package/src/index.ts +15 -11
- package/src/services/auth.service.ts +422 -132
- package/src/services/bespoke.service.ts +69 -10
- package/src/services/cart.service.ts +155 -186
- package/src/services/cms.service.ts +41 -50
- package/src/services/collection.service.ts +25 -63
- package/src/services/config.service.ts +10 -21
- package/src/services/consultation.service.ts +36 -93
- package/src/services/feedback.service.ts +76 -0
- package/src/services/index.ts +7 -1
- package/src/services/legal.service.ts +62 -0
- package/src/services/logistics.service.ts +235 -53
- package/src/services/media.service.ts +115 -0
- package/src/services/notifications.service.ts +204 -20
- package/src/services/order.service.ts +498 -127
- package/src/services/payment.service.ts +149 -100
- package/src/services/product.service.ts +157 -814
- package/src/services/review.service.ts +211 -0
- package/src/services/service-booking.service.ts +198 -99
- package/src/services/wishlist.service.ts +27 -74
- package/src/types/auth/index.ts +161 -18
- package/src/types/business/index.ts +9 -1
- package/src/types/cms/index.ts +91 -6
- package/src/types/cms/legal.ts +18 -0
- package/src/types/consultations/index.ts +60 -68
- package/src/types/index.ts +5 -3
- package/src/types/media/index.ts +35 -3
- package/src/types/payments/index.ts +80 -16
- package/src/types/reviews/index.ts +116 -0
- package/src/types/services/index.ts +113 -38
- package/src/types/store/checkout.ts +53 -0
- package/src/types/store/index.ts +273 -52
- package/src/types/store/invoice.ts +31 -0
- package/src/types/store/shipping.ts +84 -3
- package/src/types/ui/index.ts +1 -1
- package/src/utils/checkout.ts +19 -3
- package/src/utils/cookieConsent.ts +34 -0
- package/src/utils/format.ts +408 -0
- package/src/utils/geolocation.ts +134 -0
- package/src/utils/graphql-url.ts +47 -0
- package/src/utils/guest-session.ts +59 -0
- package/src/utils/http-client.ts +147 -0
- package/src/utils/index.ts +11 -4
- package/src/utils/status-colors.ts +79 -0
- package/src/utils/token-refresh.ts +115 -0
- package/src/utils/validators.ts +13 -0
- package/src/utils/youtube.ts +18 -0
- package/dist/index-C5YO9gTl.d.mts +0 -507
- package/dist/index-C5YO9gTl.d.ts +0 -507
- package/dist/index-CefG7_xq.d.mts +0 -793
- package/dist/index-DeHCf3zI.d.ts +0 -793
- package/src/graphql/collections.graphql.ts +0 -48
- package/src/graphql/index.ts +0 -7
- package/src/graphql/products.graphql.ts +0 -860
- package/src/graphql/wishlist.graphql.ts +0 -34
- package/src/hooks/use-consultation-stream.ts +0 -142
- package/src/types/bespoke/index.ts +0 -39
package/dist/index.js
CHANGED
|
@@ -20,68 +20,115 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ApiError: () => ApiError,
|
|
24
|
+
COOKIE_CONSENT_CHANGED_EVENT: () => COOKIE_CONSENT_CHANGED_EVENT,
|
|
23
25
|
InvalidBaseURLError: () => InvalidBaseURLError,
|
|
26
|
+
JSON_HEADERS: () => JSON_HEADERS,
|
|
27
|
+
ModerationStatus: () => ModerationStatus,
|
|
24
28
|
PAYMENT_URLS: () => PAYMENT_URLS,
|
|
29
|
+
PaymentGatewayEnum: () => PaymentGatewayEnum,
|
|
30
|
+
PaymentMethodTypeEnum: () => PaymentMethodTypeEnum,
|
|
31
|
+
ProductTypeEnum: () => ProductTypeEnum,
|
|
25
32
|
STORAGE_KEYS: () => STORAGE_KEYS,
|
|
26
33
|
ServiceLocationTypeEnum: () => ServiceLocationTypeEnum,
|
|
27
34
|
ServiceRecurringIntervalEnum: () => ServiceRecurringIntervalEnum,
|
|
28
35
|
ServiceTypeEnum: () => ServiceTypeEnum,
|
|
29
|
-
acceptQuote: () => acceptQuote,
|
|
30
36
|
addToCart: () => addToCart,
|
|
31
37
|
addToGuestCart: () => addToGuestCart,
|
|
32
38
|
addToWishlist: () => addToWishlist,
|
|
33
|
-
|
|
39
|
+
apiRequest: () => apiRequest,
|
|
40
|
+
applyAddressSuggestion: () => applyAddressSuggestion,
|
|
41
|
+
appointmentStatusColors: () => appointmentStatusColors,
|
|
42
|
+
approveBespokeDeliverable: () => approveBespokeDeliverable,
|
|
43
|
+
approveMilestone: () => approveMilestone,
|
|
44
|
+
authHeaders: () => authHeaders,
|
|
45
|
+
autocompleteAddress: () => autocompleteAddress,
|
|
34
46
|
bespokeService: () => bespokeService,
|
|
35
47
|
bookAppointment: () => bookAppointment,
|
|
36
48
|
buildDeliveryAddress: () => buildDeliveryAddress,
|
|
37
|
-
buildFullName: () =>
|
|
49
|
+
buildFullName: () => buildFullName,
|
|
50
|
+
bytes: () => bytes,
|
|
38
51
|
cancelAppointment: () => cancelAppointment,
|
|
39
52
|
cancelOrder: () => cancelOrder,
|
|
53
|
+
changePassword: () => changePassword,
|
|
40
54
|
checkAvailability: () => checkAvailability,
|
|
41
55
|
checkInWishlist: () => checkInWishlist,
|
|
56
|
+
claimWalletCredit: () => claimWalletCredit,
|
|
42
57
|
clearCart: () => clearCart,
|
|
43
58
|
clearGuestCart: () => clearGuestCart,
|
|
59
|
+
clearGuestSessionId: () => clearGuestSessionId,
|
|
44
60
|
clearTokens: () => clearTokens,
|
|
61
|
+
compact: () => compact,
|
|
62
|
+
compactFull: () => compactFull,
|
|
63
|
+
compactLower: () => compactLower,
|
|
45
64
|
configService: () => configService,
|
|
46
|
-
|
|
65
|
+
confirmAppointmentCompletion: () => confirmAppointmentCompletion,
|
|
66
|
+
confirmMediaUpload: () => confirmMediaUpload,
|
|
67
|
+
createBespokeOrder: () => createBespokeOrder,
|
|
47
68
|
createCmsEntry: () => createCmsEntry,
|
|
69
|
+
createComment: () => createComment,
|
|
48
70
|
createConsultation: () => createConsultation,
|
|
71
|
+
createCustomerAddress: () => createCustomerAddress,
|
|
49
72
|
createDedicatedAccount: () => createDedicatedAccount,
|
|
73
|
+
createFeedback: () => createFeedback,
|
|
74
|
+
createGraphQLClient: () => createGraphQLClient,
|
|
50
75
|
createOrder: () => createOrder,
|
|
76
|
+
createReview: () => createReview,
|
|
77
|
+
createServiceBookingOrder: () => createServiceBookingOrder,
|
|
78
|
+
currencyCompact: () => currencyCompact,
|
|
79
|
+
currencyFormat: () => currencyFormat,
|
|
80
|
+
deactivateCustomerAccount: () => deactivateCustomerAccount,
|
|
81
|
+
decimal: () => decimal,
|
|
82
|
+
decodePlusCode: () => decodePlusCode,
|
|
51
83
|
deleteCmsEntry: () => deleteCmsEntry,
|
|
84
|
+
deleteCustomerAddress: () => deleteCustomerAddress,
|
|
85
|
+
disputeAppointment: () => disputeAppointment,
|
|
52
86
|
enrichCompletedOrder: () => enrichCompletedOrder,
|
|
87
|
+
extractApiErrorMessage: () => extractApiErrorMessage,
|
|
53
88
|
findOrder: () => findOrder,
|
|
54
|
-
|
|
89
|
+
forgotPasswordCustomer: () => forgotPasswordCustomer,
|
|
90
|
+
formatCompactPrice: () => formatCompactPrice,
|
|
91
|
+
formatNumber: () => formatNumber,
|
|
92
|
+
formatPrice: () => formatPrice,
|
|
93
|
+
formatTimeString: () => formatTimeString,
|
|
55
94
|
getAppointment: () => getAppointment,
|
|
56
95
|
getAppointments: () => getAppointments,
|
|
57
96
|
getAuthUser: () => getAuthUser,
|
|
97
|
+
getAvailablePaymentMethods: () => getAvailablePaymentMethods,
|
|
58
98
|
getAvailableSlots: () => getAvailableSlots,
|
|
59
99
|
getBusinessConfig: () => getBusinessConfig,
|
|
60
100
|
getCacheTier: () => getCacheTier,
|
|
61
101
|
getCart: () => getCart,
|
|
62
102
|
getCheckoutCustomerName: () => getCheckoutCustomerName,
|
|
63
103
|
getCmsEntry: () => getCmsEntry,
|
|
64
|
-
|
|
65
|
-
|
|
104
|
+
getCookieConsent: () => getCookieConsent,
|
|
105
|
+
getCurrencySymbol: () => getCurrencySymbol,
|
|
106
|
+
getCustomerAddresses: () => getCustomerAddresses,
|
|
66
107
|
getCustomerDisplayName: () => getCustomerDisplayName,
|
|
67
|
-
getDeliverables: () => getDeliverables,
|
|
68
108
|
getErrorMessage: () => getErrorMessage,
|
|
69
109
|
getFeaturedProducts: () => getFeaturedProducts,
|
|
70
110
|
getGuestCart: () => getGuestCart,
|
|
71
|
-
getGuestCartCount: () => getGuestCartCount,
|
|
72
111
|
getGuestCartProductType: () => getGuestCartProductType,
|
|
73
|
-
getGuestCartSubtotal: () => getGuestCartSubtotal,
|
|
74
|
-
getLatestProducts: () => getLatestProducts,
|
|
75
|
-
getLowStockProducts: () => getLowStockProducts,
|
|
76
112
|
getMe: () => getMe,
|
|
113
|
+
getMerchantLegalDocument: () => getMerchantLegalDocument,
|
|
114
|
+
getMilestones: () => getMilestones,
|
|
115
|
+
getMyFeedback: () => getMyFeedback,
|
|
77
116
|
getNewProducts: () => getNewProducts,
|
|
117
|
+
getNotificationInbox: () => getNotificationInbox,
|
|
118
|
+
getNotificationPreferences: () => getNotificationPreferences,
|
|
78
119
|
getOnSaleProducts: () => getOnSaleProducts,
|
|
120
|
+
getOrCreateGuestSessionId: () => getOrCreateGuestSessionId,
|
|
79
121
|
getOrders: () => getOrders,
|
|
122
|
+
getPendingComments: () => getPendingComments,
|
|
123
|
+
getPendingReviews: () => getPendingReviews,
|
|
80
124
|
getPopularProducts: () => getPopularProducts,
|
|
125
|
+
getPresignedUploadUrl: () => getPresignedUploadUrl,
|
|
126
|
+
getProductComments: () => getProductComments,
|
|
127
|
+
getProductReviews: () => getProductReviews,
|
|
81
128
|
getRecommendedProducts: () => getRecommendedProducts,
|
|
82
|
-
getSellerShippingAddress: () => getSellerShippingAddress,
|
|
83
129
|
getShippingRates: () => getShippingRates,
|
|
84
130
|
getStoredTokens: () => getStoredTokens,
|
|
131
|
+
getStorefrontBusinessInfo: () => getStorefrontBusinessInfo,
|
|
85
132
|
getStorefrontCollectionBySlug: () => getStorefrontCollectionBySlug,
|
|
86
133
|
getStorefrontCollections: () => getStorefrontCollections,
|
|
87
134
|
getStorefrontProductBySlug: () => getStorefrontProductBySlug,
|
|
@@ -90,52 +137,94 @@ __export(index_exports, {
|
|
|
90
137
|
getSupportedCurrencies: () => getSupportedCurrencies,
|
|
91
138
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
92
139
|
getTransactionStatus: () => getTransactionStatus,
|
|
140
|
+
getVapidPublicKey: () => getVapidPublicKey,
|
|
141
|
+
getWalletBalance: () => getWalletBalance,
|
|
142
|
+
getWalletLedger: () => getWalletLedger,
|
|
93
143
|
getWishlist: () => getWishlist,
|
|
144
|
+
getYouTubeID: () => getYouTubeID,
|
|
94
145
|
googleTranslate: () => googleTranslate,
|
|
146
|
+
handlePinDrop: () => handlePinDrop,
|
|
147
|
+
handlePlusCodeChange: () => handlePlusCodeChange,
|
|
148
|
+
hasRefreshHandler: () => hasRefreshHandler,
|
|
95
149
|
initiatePayment: () => initiatePayment,
|
|
150
|
+
isValidCountryCode: () => isValidCountryCode,
|
|
151
|
+
listBusinessLocations: () => listBusinessLocations,
|
|
96
152
|
listCmsEntries: () => listCmsEntries,
|
|
153
|
+
listPickupLocations: () => listPickupLocations,
|
|
97
154
|
localStore: () => localStore,
|
|
98
155
|
logger: () => logger,
|
|
99
156
|
loginCustomer: () => loginCustomer,
|
|
100
157
|
logisticsService: () => logisticsService,
|
|
101
158
|
logout: () => logout,
|
|
102
159
|
mapAuthUserToCustomer: () => mapAuthUserToCustomer,
|
|
160
|
+
markAllNotificationsRead: () => markAllNotificationsRead,
|
|
161
|
+
markNotificationRead: () => markNotificationRead,
|
|
162
|
+
merchantReplyToReview: () => merchantReplyToReview,
|
|
103
163
|
mergeGuestCart: () => mergeGuestCart,
|
|
104
164
|
mergeGuestCartIfPresent: () => mergeGuestCartIfPresent,
|
|
165
|
+
milestoneStatusColors: () => milestoneStatusColors,
|
|
166
|
+
moderateComment: () => moderateComment,
|
|
167
|
+
moderateReview: () => moderateReview,
|
|
105
168
|
notificationsService: () => notificationsService,
|
|
169
|
+
orderStatusColors: () => orderStatusColors,
|
|
170
|
+
orderStatusLabels: () => orderStatusLabels,
|
|
171
|
+
ordinal: () => ordinal,
|
|
106
172
|
paymentService: () => paymentService,
|
|
173
|
+
percent: () => percent,
|
|
174
|
+
refreshAccessToken: () => refreshAccessToken,
|
|
107
175
|
refreshToken: () => refreshToken,
|
|
108
176
|
registerCustomer: () => registerCustomer,
|
|
109
|
-
|
|
177
|
+
registerRefreshHandler: () => registerRefreshHandler,
|
|
110
178
|
removeFromCart: () => removeFromCart,
|
|
111
179
|
removeFromGuestCart: () => removeFromGuestCart,
|
|
112
180
|
removeFromWishlist: () => removeFromWishlist,
|
|
113
181
|
removeProductFromWishlist: () => removeProductFromWishlist,
|
|
114
|
-
|
|
115
|
-
|
|
182
|
+
requestBespokeRevision: () => requestBespokeRevision,
|
|
183
|
+
requestCustomerOtp: () => requestCustomerOtp,
|
|
184
|
+
requestCustomerReactivation: () => requestCustomerReactivation,
|
|
185
|
+
rescheduleAppointment: () => rescheduleAppointment,
|
|
186
|
+
resetPasswordCustomer: () => resetPasswordCustomer,
|
|
187
|
+
resolveDigitalDownload: () => resolveDigitalDownload,
|
|
188
|
+
resolveDigitalDownloadFile: () => resolveDigitalDownloadFile,
|
|
189
|
+
resolveGraphQLEndpoint: () => resolveGraphQLEndpoint,
|
|
190
|
+
reverseGeocode: () => reverseGeocode,
|
|
191
|
+
roman: () => roman,
|
|
116
192
|
sanitizeBaseUrl: () => sanitizeBaseUrl,
|
|
117
193
|
sendContactConfirmation: () => sendContactConfirmation,
|
|
118
194
|
sendContactEmail: () => sendContactEmail,
|
|
119
|
-
sendMessage: () => sendMessage,
|
|
120
195
|
serviceBookingService: () => serviceBookingService,
|
|
121
196
|
sessionStore: () => sessionStore,
|
|
197
|
+
setCookieConsent: () => setCookieConsent,
|
|
122
198
|
setEnvironmentMode: () => setEnvironmentMode,
|
|
123
199
|
setLoggerEnvironmentMode: () => setLoggerEnvironmentMode,
|
|
124
200
|
silentRefresh: () => silentRefresh,
|
|
125
|
-
splitFullName: () =>
|
|
201
|
+
splitFullName: () => splitFullName,
|
|
126
202
|
storeTokens: () => storeTokens,
|
|
203
|
+
storefrontHeaders: () => storefrontHeaders,
|
|
204
|
+
subscribeToPush: () => subscribeToPush,
|
|
205
|
+
trackNotificationClick: () => trackNotificationClick,
|
|
127
206
|
trackOrder: () => trackOrder,
|
|
207
|
+
unsubscribeFromPush: () => unsubscribeFromPush,
|
|
128
208
|
updateCartItem: () => updateCartItem,
|
|
129
209
|
updateCmsEntry: () => updateCmsEntry,
|
|
210
|
+
updateComment: () => updateComment,
|
|
211
|
+
updateCustomerAddress: () => updateCustomerAddress,
|
|
130
212
|
updateGuestCartItemQuantity: () => updateGuestCartItemQuantity,
|
|
213
|
+
updateNotificationPreferences: () => updateNotificationPreferences,
|
|
131
214
|
updateProfile: () => updateProfile,
|
|
215
|
+
updateReview: () => updateReview,
|
|
216
|
+
uploadMediaFile: () => uploadMediaFile,
|
|
217
|
+
uploadMediaFiles: () => uploadMediaFiles,
|
|
132
218
|
validateConfirmPassword: () => validateConfirmPassword,
|
|
133
219
|
validateEmail: () => validateEmail,
|
|
134
220
|
validateMessage: () => validateMessage,
|
|
135
221
|
validateName: () => validateName,
|
|
136
222
|
validatePassword: () => validatePassword,
|
|
223
|
+
validatePromoCode: () => validatePromoCode,
|
|
137
224
|
validateRequired: () => validateRequired,
|
|
138
225
|
validateShippingAddress: () => validateShippingAddress,
|
|
226
|
+
verifyCustomerOtp: () => verifyCustomerOtp,
|
|
227
|
+
verifyCustomerReactivation: () => verifyCustomerReactivation,
|
|
139
228
|
verifySocialToken: () => verifySocialToken,
|
|
140
229
|
verifyTransaction: () => verifyTransaction
|
|
141
230
|
});
|
|
@@ -155,6 +244,13 @@ var PAYMENT_URLS = {
|
|
|
155
244
|
};
|
|
156
245
|
|
|
157
246
|
// src/types/store/index.ts
|
|
247
|
+
var ProductTypeEnum = /* @__PURE__ */ ((ProductTypeEnum2) => {
|
|
248
|
+
ProductTypeEnum2["PHYSICAL"] = "physical";
|
|
249
|
+
ProductTypeEnum2["DIGITAL"] = "digital";
|
|
250
|
+
ProductTypeEnum2["SERVICE"] = "service";
|
|
251
|
+
ProductTypeEnum2["BESPOKE"] = "bespoke";
|
|
252
|
+
return ProductTypeEnum2;
|
|
253
|
+
})(ProductTypeEnum || {});
|
|
158
254
|
var ServiceTypeEnum = /* @__PURE__ */ ((ServiceTypeEnum2) => {
|
|
159
255
|
ServiceTypeEnum2["APPOINTMENT"] = "appointment";
|
|
160
256
|
ServiceTypeEnum2["PROJECT"] = "project";
|
|
@@ -163,8 +259,8 @@ var ServiceTypeEnum = /* @__PURE__ */ ((ServiceTypeEnum2) => {
|
|
|
163
259
|
})(ServiceTypeEnum || {});
|
|
164
260
|
var ServiceLocationTypeEnum = /* @__PURE__ */ ((ServiceLocationTypeEnum2) => {
|
|
165
261
|
ServiceLocationTypeEnum2["REMOTE"] = "remote";
|
|
166
|
-
ServiceLocationTypeEnum2["
|
|
167
|
-
ServiceLocationTypeEnum2["
|
|
262
|
+
ServiceLocationTypeEnum2["AT_BUSINESS"] = "at_business";
|
|
263
|
+
ServiceLocationTypeEnum2["CUSTOMER_LOCATION"] = "customer_location";
|
|
168
264
|
return ServiceLocationTypeEnum2;
|
|
169
265
|
})(ServiceLocationTypeEnum || {});
|
|
170
266
|
var ServiceRecurringIntervalEnum = /* @__PURE__ */ ((ServiceRecurringIntervalEnum2) => {
|
|
@@ -174,6 +270,130 @@ var ServiceRecurringIntervalEnum = /* @__PURE__ */ ((ServiceRecurringIntervalEnu
|
|
|
174
270
|
return ServiceRecurringIntervalEnum2;
|
|
175
271
|
})(ServiceRecurringIntervalEnum || {});
|
|
176
272
|
|
|
273
|
+
// src/types/payments/index.ts
|
|
274
|
+
var PaymentGatewayEnum = /* @__PURE__ */ ((PaymentGatewayEnum2) => {
|
|
275
|
+
PaymentGatewayEnum2["MONNIFY"] = "monnify";
|
|
276
|
+
PaymentGatewayEnum2["FLUTTERWAVE"] = "flutterwave";
|
|
277
|
+
PaymentGatewayEnum2["PAYSTACK"] = "paystack";
|
|
278
|
+
return PaymentGatewayEnum2;
|
|
279
|
+
})(PaymentGatewayEnum || {});
|
|
280
|
+
var PaymentMethodTypeEnum = /* @__PURE__ */ ((PaymentMethodTypeEnum2) => {
|
|
281
|
+
PaymentMethodTypeEnum2["CARD"] = "card";
|
|
282
|
+
PaymentMethodTypeEnum2["TRANSFER"] = "transfer";
|
|
283
|
+
PaymentMethodTypeEnum2["BANK_TRANSFER"] = "bank_transfer";
|
|
284
|
+
PaymentMethodTypeEnum2["ACCOUNT"] = "account";
|
|
285
|
+
PaymentMethodTypeEnum2["USSD"] = "ussd";
|
|
286
|
+
return PaymentMethodTypeEnum2;
|
|
287
|
+
})(PaymentMethodTypeEnum || {});
|
|
288
|
+
|
|
289
|
+
// src/types/reviews/index.ts
|
|
290
|
+
var ModerationStatus = /* @__PURE__ */ ((ModerationStatus2) => {
|
|
291
|
+
ModerationStatus2["PENDING"] = "pending";
|
|
292
|
+
ModerationStatus2["APPROVED"] = "approved";
|
|
293
|
+
ModerationStatus2["REJECTED"] = "rejected";
|
|
294
|
+
return ModerationStatus2;
|
|
295
|
+
})(ModerationStatus || {});
|
|
296
|
+
|
|
297
|
+
// src/utils/token-refresh.ts
|
|
298
|
+
var GLOBAL_KEY = "__kasuviaSdkTokenRefreshRegistry__";
|
|
299
|
+
function getRegistry() {
|
|
300
|
+
const g = globalThis;
|
|
301
|
+
if (!g[GLOBAL_KEY]) {
|
|
302
|
+
g[GLOBAL_KEY] = { handler: null, inFlight: null };
|
|
303
|
+
}
|
|
304
|
+
return g[GLOBAL_KEY];
|
|
305
|
+
}
|
|
306
|
+
function registerRefreshHandler(handler) {
|
|
307
|
+
getRegistry().handler = handler;
|
|
308
|
+
}
|
|
309
|
+
async function refreshAccessToken() {
|
|
310
|
+
const registry = getRegistry();
|
|
311
|
+
if (!registry.handler) return null;
|
|
312
|
+
if (registry.inFlight) return registry.inFlight;
|
|
313
|
+
registry.inFlight = registry.handler().finally(() => {
|
|
314
|
+
registry.inFlight = null;
|
|
315
|
+
});
|
|
316
|
+
return registry.inFlight;
|
|
317
|
+
}
|
|
318
|
+
function hasRefreshHandler() {
|
|
319
|
+
return getRegistry().handler !== null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/utils/http-client.ts
|
|
323
|
+
var ApiError = class extends Error {
|
|
324
|
+
constructor(message, status, body) {
|
|
325
|
+
super(message);
|
|
326
|
+
this.name = "ApiError";
|
|
327
|
+
this.status = status;
|
|
328
|
+
this.body = body;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
function extractApiErrorMessage(body, fallback) {
|
|
332
|
+
if (typeof body !== "object" || body === null) return fallback;
|
|
333
|
+
const record = body;
|
|
334
|
+
if (typeof record.detail === "string") return record.detail;
|
|
335
|
+
if (Array.isArray(record.detail) && record.detail.length > 0) {
|
|
336
|
+
const first = record.detail[0];
|
|
337
|
+
if (first && typeof first.msg === "string") {
|
|
338
|
+
const loc = first.loc;
|
|
339
|
+
const field = Array.isArray(loc) ? loc[loc.length - 1] : void 0;
|
|
340
|
+
return typeof field === "string" || typeof field === "number" ? `${field}: ${first.msg}` : first.msg;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const firstStringOrArrayItem = (value) => {
|
|
344
|
+
if (typeof value === "string") return value;
|
|
345
|
+
if (Array.isArray(value) && typeof value[0] === "string") return value[0];
|
|
346
|
+
return void 0;
|
|
347
|
+
};
|
|
348
|
+
const nonFieldMessage = firstStringOrArrayItem(record.non_field_errors);
|
|
349
|
+
if (nonFieldMessage) return nonFieldMessage;
|
|
350
|
+
for (const [key, value] of Object.entries(record)) {
|
|
351
|
+
if (key === "detail" || key === "non_field_errors") continue;
|
|
352
|
+
const message = firstStringOrArrayItem(value);
|
|
353
|
+
if (message) return message;
|
|
354
|
+
}
|
|
355
|
+
return fallback;
|
|
356
|
+
}
|
|
357
|
+
function storefrontHeaders(config) {
|
|
358
|
+
return {
|
|
359
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
360
|
+
"X-Business-ID": config.businessId
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function authHeaders(config, accessToken) {
|
|
364
|
+
return {
|
|
365
|
+
...storefrontHeaders(config),
|
|
366
|
+
Authorization: `Bearer ${accessToken}`
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
370
|
+
async function apiRequest(url, options = {}) {
|
|
371
|
+
const { fallbackErrorMessage = "Request failed", ...init } = options;
|
|
372
|
+
const headers = new Headers(init.headers);
|
|
373
|
+
const hadBearerToken = headers.get("Authorization")?.startsWith("Bearer ") ?? false;
|
|
374
|
+
const response = await fetch(url, { ...init, headers });
|
|
375
|
+
if (response.status === 401 && hadBearerToken && hasRefreshHandler()) {
|
|
376
|
+
const freshToken = await refreshAccessToken();
|
|
377
|
+
if (freshToken) {
|
|
378
|
+
const retryHeaders = new Headers(headers);
|
|
379
|
+
retryHeaders.set("Authorization", `Bearer ${freshToken}`);
|
|
380
|
+
const retryResponse = await fetch(url, { ...init, headers: retryHeaders });
|
|
381
|
+
if (retryResponse.ok) {
|
|
382
|
+
const retryText = await retryResponse.text();
|
|
383
|
+
return retryText ? JSON.parse(retryText) : void 0;
|
|
384
|
+
}
|
|
385
|
+
const retryBody = await retryResponse.json().catch(() => ({}));
|
|
386
|
+
throw new ApiError(extractApiErrorMessage(retryBody, fallbackErrorMessage), retryResponse.status, retryBody);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (!response.ok) {
|
|
390
|
+
const body = await response.json().catch(() => ({}));
|
|
391
|
+
throw new ApiError(extractApiErrorMessage(body, fallbackErrorMessage), response.status, body);
|
|
392
|
+
}
|
|
393
|
+
const text = await response.text();
|
|
394
|
+
return text ? JSON.parse(text) : void 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
177
397
|
// src/services/cart.service.ts
|
|
178
398
|
function parseItems(items) {
|
|
179
399
|
return items.map((item) => ({
|
|
@@ -181,218 +401,148 @@ function parseItems(items) {
|
|
|
181
401
|
variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
|
|
182
402
|
}));
|
|
183
403
|
}
|
|
404
|
+
function guestHeaders(config, guestSessionId, extra) {
|
|
405
|
+
return { ...extra, ...storefrontHeaders(config), "X-Guest-Session": guestSessionId };
|
|
406
|
+
}
|
|
184
407
|
async function getGuestCart(config, guestSessionId) {
|
|
185
|
-
if (!guestSessionId)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"X-Guest-Session": guestSessionId
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
if (!response.ok) return [];
|
|
195
|
-
const data = await response.json();
|
|
196
|
-
return parseItems(data.items || []);
|
|
197
|
-
} catch {
|
|
198
|
-
return [];
|
|
199
|
-
}
|
|
408
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to fetch guest cart");
|
|
409
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
410
|
+
headers: guestHeaders(config, guestSessionId),
|
|
411
|
+
fallbackErrorMessage: "Failed to fetch guest cart"
|
|
412
|
+
});
|
|
413
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
200
414
|
}
|
|
201
415
|
async function addToGuestCart(config, guestSessionId, item) {
|
|
202
|
-
if (!guestSessionId)
|
|
416
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to add to guest cart");
|
|
203
417
|
const payload = {
|
|
204
418
|
product_id: item.product_id,
|
|
205
|
-
|
|
206
|
-
product_name: item.product_name,
|
|
207
|
-
image: item.image,
|
|
208
|
-
variant_id: item.variant_id,
|
|
209
|
-
variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes),
|
|
210
|
-
unit_price: item.unit_price,
|
|
419
|
+
variant_id: item.variant_id ?? void 0,
|
|
211
420
|
quantity: item.quantity,
|
|
212
|
-
custom_measurements: item.custom_measurements
|
|
213
|
-
is_bespoke: item.is_bespoke
|
|
421
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
214
422
|
};
|
|
215
|
-
const
|
|
423
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
216
424
|
method: "POST",
|
|
217
|
-
headers:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"X-Business-ID": config.businessId,
|
|
221
|
-
"X-Guest-Session": guestSessionId
|
|
222
|
-
},
|
|
223
|
-
body: JSON.stringify(payload)
|
|
425
|
+
headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
|
|
426
|
+
body: JSON.stringify(payload),
|
|
427
|
+
fallbackErrorMessage: "Failed to add to guest cart"
|
|
224
428
|
});
|
|
225
|
-
|
|
226
|
-
const data = await response.json();
|
|
227
|
-
return parseItems(data.items || []);
|
|
429
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
228
430
|
}
|
|
229
431
|
async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
|
|
230
|
-
if (!guestSessionId)
|
|
231
|
-
const
|
|
432
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to update guest cart item");
|
|
433
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
232
434
|
method: "PATCH",
|
|
233
|
-
headers:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
"X-Business-ID": config.businessId,
|
|
237
|
-
"X-Guest-Session": guestSessionId
|
|
238
|
-
},
|
|
239
|
-
body: JSON.stringify({ quantity })
|
|
435
|
+
headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
|
|
436
|
+
body: JSON.stringify({ quantity }),
|
|
437
|
+
fallbackErrorMessage: "Failed to update guest cart item"
|
|
240
438
|
});
|
|
241
|
-
|
|
242
|
-
const data = await response.json();
|
|
243
|
-
return parseItems(data.items || []);
|
|
439
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
244
440
|
}
|
|
245
441
|
async function removeFromGuestCart(config, guestSessionId, itemId) {
|
|
246
|
-
if (!guestSessionId)
|
|
247
|
-
await
|
|
442
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to remove from guest cart");
|
|
443
|
+
await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
248
444
|
method: "DELETE",
|
|
249
|
-
headers:
|
|
250
|
-
|
|
251
|
-
"X-Business-ID": config.businessId,
|
|
252
|
-
"X-Guest-Session": guestSessionId
|
|
253
|
-
}
|
|
445
|
+
headers: guestHeaders(config, guestSessionId),
|
|
446
|
+
fallbackErrorMessage: "Failed to remove item from guest cart"
|
|
254
447
|
});
|
|
255
|
-
return getGuestCart(config, guestSessionId);
|
|
256
448
|
}
|
|
257
449
|
async function clearGuestCart(config, guestSessionId) {
|
|
258
|
-
if (!guestSessionId)
|
|
259
|
-
await
|
|
450
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to clear guest cart");
|
|
451
|
+
await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
|
|
260
452
|
method: "DELETE",
|
|
261
|
-
headers:
|
|
262
|
-
|
|
263
|
-
"X-Business-ID": config.businessId,
|
|
264
|
-
"X-Guest-Session": guestSessionId
|
|
265
|
-
}
|
|
453
|
+
headers: guestHeaders(config, guestSessionId),
|
|
454
|
+
fallbackErrorMessage: "Failed to clear guest cart"
|
|
266
455
|
});
|
|
267
456
|
}
|
|
268
457
|
async function getCart(config, accessToken) {
|
|
269
458
|
if (!accessToken) {
|
|
270
|
-
|
|
459
|
+
throw new Error("Access token is required to fetch authenticated cart");
|
|
271
460
|
}
|
|
272
|
-
const
|
|
273
|
-
headers:
|
|
274
|
-
|
|
275
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
276
|
-
"X-Business-ID": config.businessId
|
|
277
|
-
}
|
|
461
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
462
|
+
headers: authHeaders(config, accessToken),
|
|
463
|
+
fallbackErrorMessage: "Failed to fetch cart"
|
|
278
464
|
});
|
|
279
|
-
|
|
280
|
-
const data = await response.json();
|
|
281
|
-
const parsedItems = parseItems(data.items || []);
|
|
282
|
-
return { ...data, items: parsedItems };
|
|
465
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
283
466
|
}
|
|
284
467
|
async function addToCart(config, accessToken, item) {
|
|
285
|
-
const
|
|
468
|
+
const payload = {
|
|
469
|
+
product_id: item.product_id,
|
|
470
|
+
variant_id: item.variant_id ?? void 0,
|
|
471
|
+
quantity: item.quantity,
|
|
472
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
473
|
+
};
|
|
474
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
286
475
|
method: "POST",
|
|
287
|
-
headers: {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
291
|
-
"X-Business-ID": config.businessId
|
|
292
|
-
},
|
|
293
|
-
body: JSON.stringify(item)
|
|
476
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
477
|
+
body: JSON.stringify(payload),
|
|
478
|
+
fallbackErrorMessage: "Failed to add to cart"
|
|
294
479
|
});
|
|
295
|
-
|
|
296
|
-
const data = await response.json();
|
|
297
|
-
const parsedItems = parseItems(data.items || []);
|
|
298
|
-
return { ...data, items: parsedItems };
|
|
480
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
299
481
|
}
|
|
300
482
|
async function updateCartItem(config, accessToken, itemId, quantity) {
|
|
301
|
-
const
|
|
483
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
302
484
|
method: "PATCH",
|
|
303
|
-
headers: {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
307
|
-
"X-Business-ID": config.businessId
|
|
308
|
-
},
|
|
309
|
-
body: JSON.stringify({ quantity })
|
|
485
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
486
|
+
body: JSON.stringify({ quantity }),
|
|
487
|
+
fallbackErrorMessage: "Failed to update cart item"
|
|
310
488
|
});
|
|
311
|
-
|
|
312
|
-
const data = await response.json();
|
|
313
|
-
const parsedItems = parseItems(data.items || []);
|
|
314
|
-
return { ...data, items: parsedItems };
|
|
489
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
315
490
|
}
|
|
316
491
|
async function removeFromCart(config, accessToken, itemId) {
|
|
317
|
-
await
|
|
492
|
+
await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
318
493
|
method: "DELETE",
|
|
319
|
-
headers:
|
|
320
|
-
|
|
321
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
322
|
-
"X-Business-ID": config.businessId
|
|
323
|
-
}
|
|
494
|
+
headers: authHeaders(config, accessToken),
|
|
495
|
+
fallbackErrorMessage: "Failed to remove cart item"
|
|
324
496
|
});
|
|
325
|
-
return getCart(config, accessToken);
|
|
326
497
|
}
|
|
327
498
|
async function clearCart(config, accessToken) {
|
|
328
|
-
await
|
|
499
|
+
await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
|
|
329
500
|
method: "DELETE",
|
|
330
|
-
headers:
|
|
331
|
-
|
|
332
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
333
|
-
"X-Business-ID": config.businessId
|
|
334
|
-
}
|
|
501
|
+
headers: authHeaders(config, accessToken),
|
|
502
|
+
fallbackErrorMessage: "Failed to clear cart"
|
|
335
503
|
});
|
|
336
504
|
}
|
|
337
|
-
async function mergeGuestCart(config, accessToken, guestSessionId) {
|
|
338
|
-
const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
|
|
339
|
-
if (guestItems.length === 0) {
|
|
340
|
-
return getCart(config, accessToken);
|
|
341
|
-
}
|
|
505
|
+
async function mergeGuestCart(config, accessToken, guestSessionId, guestItems) {
|
|
342
506
|
const payloadItems = guestItems.map((item) => ({
|
|
343
507
|
product_id: item.product_id,
|
|
344
|
-
|
|
345
|
-
product_name: item.product_name,
|
|
346
|
-
image: item.image,
|
|
347
|
-
variant_id: item.variant_id,
|
|
348
|
-
variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
|
|
349
|
-
unit_price: item.unit_price,
|
|
508
|
+
variant_id: item.variant_id ?? void 0,
|
|
350
509
|
quantity: item.quantity,
|
|
351
|
-
custom_measurements:
|
|
352
|
-
is_bespoke: item.is_bespoke
|
|
510
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
353
511
|
}));
|
|
354
|
-
const headers = {
|
|
355
|
-
"Content-Type": "application/json",
|
|
356
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
357
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
358
|
-
"X-Business-ID": config.businessId
|
|
359
|
-
};
|
|
512
|
+
const headers = { ...JSON_HEADERS, ...authHeaders(config, accessToken) };
|
|
360
513
|
if (guestSessionId) {
|
|
361
514
|
headers["X-Guest-Session"] = guestSessionId;
|
|
362
515
|
}
|
|
363
|
-
const
|
|
516
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/merge`, {
|
|
364
517
|
method: "POST",
|
|
365
518
|
headers,
|
|
366
|
-
body: JSON.stringify({ items: payloadItems })
|
|
519
|
+
body: JSON.stringify({ items: payloadItems }),
|
|
520
|
+
fallbackErrorMessage: "Failed to merge guest cart"
|
|
367
521
|
});
|
|
368
|
-
if (!response.ok) throw new Error("Failed to merge guest cart");
|
|
369
|
-
const data = await response.json();
|
|
370
522
|
return { ...data, items: parseItems(data.items || []) };
|
|
371
523
|
}
|
|
372
524
|
async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
await mergeGuestCart(config, accessToken, guestSessionId);
|
|
377
|
-
} catch (error) {
|
|
378
|
-
console.warn("[Cart] Failed to merge guest cart:", error);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
function getGuestCartCount() {
|
|
382
|
-
return 0;
|
|
525
|
+
const guestCart = await getGuestCart(config, guestSessionId);
|
|
526
|
+
if (!guestCart.items.length) return;
|
|
527
|
+
await mergeGuestCart(config, accessToken, guestSessionId, guestCart.items);
|
|
383
528
|
}
|
|
384
|
-
function
|
|
385
|
-
return
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return
|
|
529
|
+
function getGuestCartProductType(items) {
|
|
530
|
+
if (!items || !items.length) return null;
|
|
531
|
+
const types = new Set(items.map((i) => i.product_type).filter(Boolean));
|
|
532
|
+
if (types.size === 0) return null;
|
|
533
|
+
if (types.size === 1) return [...types][0] ?? null;
|
|
534
|
+
return "physical" /* PHYSICAL */;
|
|
389
535
|
}
|
|
390
536
|
|
|
391
537
|
// src/services/order.service.ts
|
|
538
|
+
function extractShippingAddress(raw) {
|
|
539
|
+
const val = raw.physical_fulfillment?.shipping_address;
|
|
540
|
+
return typeof val === "object" && val !== null ? val : null;
|
|
541
|
+
}
|
|
392
542
|
function deriveCustomerName(raw) {
|
|
393
543
|
if (raw.customer_name) return raw.customer_name;
|
|
394
544
|
if (raw.guest_name) return raw.guest_name;
|
|
395
|
-
const addr =
|
|
545
|
+
const addr = extractShippingAddress(raw);
|
|
396
546
|
if (addr) {
|
|
397
547
|
const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
|
|
398
548
|
if (full) return full;
|
|
@@ -404,25 +554,123 @@ function deriveCustomerName(raw) {
|
|
|
404
554
|
function normaliseStorefrontOrder(raw) {
|
|
405
555
|
const items = (raw.items ?? []).map((item) => ({
|
|
406
556
|
id: item.id,
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
557
|
+
order_id: item.order_id,
|
|
558
|
+
product_id: item.product_id ?? void 0,
|
|
559
|
+
variant_id: item.variant_id ?? void 0,
|
|
560
|
+
product_name: item.product_name ?? "",
|
|
561
|
+
quantity: item.quantity,
|
|
562
|
+
unit_price: item.unit_price,
|
|
563
|
+
variant_details: item.variant_details,
|
|
564
|
+
custom_measurements: item.custom_measurements,
|
|
565
|
+
image_url: item.image_url ?? void 0
|
|
411
566
|
}));
|
|
412
|
-
const addr =
|
|
567
|
+
const addr = extractShippingAddress(raw);
|
|
568
|
+
const customerName = deriveCustomerName(raw);
|
|
569
|
+
const customerEmail = raw.guest_email ?? raw.customer_email ?? "";
|
|
570
|
+
const physical = raw.physical_fulfillment;
|
|
571
|
+
if (!raw.currency) {
|
|
572
|
+
throw new Error(`Order ${raw.id} response is missing a currency field.`);
|
|
573
|
+
}
|
|
574
|
+
if (!raw.created_at) {
|
|
575
|
+
throw new Error(`Order ${raw.id} response is missing a created_at field.`);
|
|
576
|
+
}
|
|
577
|
+
if (!raw.updated_at) {
|
|
578
|
+
throw new Error(`Order ${raw.id} response is missing an updated_at field.`);
|
|
579
|
+
}
|
|
580
|
+
if (!raw.business_id) {
|
|
581
|
+
throw new Error(`Order ${raw.id} response is missing a business_id field.`);
|
|
582
|
+
}
|
|
413
583
|
return {
|
|
414
584
|
id: raw.id,
|
|
415
|
-
display_id: raw.display_id,
|
|
585
|
+
display_id: raw.display_id || raw.id,
|
|
586
|
+
business_id: raw.business_id,
|
|
587
|
+
customer_id: raw.customer_id ?? void 0,
|
|
416
588
|
items,
|
|
417
|
-
total: raw.total_amount ?? raw.total ?? 0,
|
|
418
589
|
status: raw.status,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
590
|
+
payment_status: raw.payment_status || "pending",
|
|
591
|
+
product_type: raw.product_type ?? void 0,
|
|
592
|
+
// Canonical backend fields
|
|
593
|
+
total_amount: raw.total_amount,
|
|
594
|
+
currency: raw.currency,
|
|
595
|
+
subtotal_amount: raw.subtotal_amount ?? void 0,
|
|
596
|
+
shipping_amount: raw.shipping_amount ?? void 0,
|
|
597
|
+
discount_amount: raw.discount_amount ?? void 0,
|
|
598
|
+
tax_amount: raw.tax_amount ?? void 0,
|
|
599
|
+
customer_name: customerName,
|
|
600
|
+
customer_email: customerEmail,
|
|
601
|
+
// REAL BUG FIXED (2026-09-23) via the REST codegen initiative: every
|
|
602
|
+
// field below this point used to read a flat `raw.<field>` that does
|
|
603
|
+
// NOT exist anywhere on the real OrderResponse - confirmed by reading
|
|
604
|
+
// the actual Pydantic classes, not just the generated types. They
|
|
605
|
+
// genuinely live nested under `physical_fulfillment` (shipping/
|
|
606
|
+
// tracking/carrier/pickup/surcharge/weight) or `digital_fulfillment`
|
|
607
|
+
// (buyer_country) - "One nested block per product type, instead of
|
|
608
|
+
// ~35 flat fields on OrderBase" per that schema file's own Order
|
|
609
|
+
// Schema Refactor comment. Every one of these was silently `undefined`
|
|
610
|
+
// on every real order: a customer's tracking number, carrier, delivery
|
|
611
|
+
// status, and shipping address never actually rendered anywhere on the
|
|
612
|
+
// storefront's order tracking page.
|
|
613
|
+
tracking_number: physical?.tracking_number ?? void 0,
|
|
614
|
+
delivery_status: physical?.delivery_status ?? void 0,
|
|
615
|
+
carrier_name: physical?.carrier_name ?? void 0,
|
|
616
|
+
carrier_slug: physical?.carrier_slug ?? void 0,
|
|
617
|
+
terminal_rate_id: physical?.terminal_rate_id ?? void 0,
|
|
618
|
+
guest_token: raw.guest_token ?? void 0,
|
|
619
|
+
guest_email: raw.guest_email ?? void 0,
|
|
620
|
+
guest_phone: raw.guest_phone ?? void 0,
|
|
621
|
+
guest_name: raw.guest_name ?? void 0,
|
|
622
|
+
buyer_country: raw.digital_fulfillment?.buyer_country ?? void 0,
|
|
623
|
+
created_at: raw.created_at,
|
|
624
|
+
updated_at: raw.updated_at,
|
|
625
|
+
// Weight discrepancy & surcharge fields (Task 2) — physical_fulfillment
|
|
626
|
+
shipping_surcharge_amount: physical?.shipping_surcharge_amount ?? void 0,
|
|
627
|
+
shipping_surcharge_reason: physical?.shipping_surcharge_reason ?? void 0,
|
|
628
|
+
shipping_surcharge_description: physical?.shipping_surcharge_description ?? void 0,
|
|
629
|
+
shipping_surcharge_applied_at: physical?.shipping_surcharge_applied_at ?? void 0,
|
|
630
|
+
declared_weight_kg: physical?.declared_weight_kg ?? void 0,
|
|
631
|
+
actual_weight_kg: physical?.actual_weight_kg ?? void 0,
|
|
632
|
+
// Self-pickup verification fields (Task 3) — physical_fulfillment
|
|
633
|
+
pickup_verification_code: physical?.pickup_verification_code ?? void 0,
|
|
634
|
+
pickup_verification_code_generated_at: physical?.pickup_verification_code_generated_at ?? void 0,
|
|
635
|
+
pickup_verification_code_used_at: physical?.pickup_verification_code_used_at ?? void 0,
|
|
636
|
+
pickup_verification_failed_attempts: physical?.pickup_verification_failed_attempts,
|
|
637
|
+
pickup_verification_locked_until: physical?.pickup_verification_locked_until ?? void 0,
|
|
638
|
+
pickup_qr_payload: physical?.pickup_qr_payload ?? void 0,
|
|
639
|
+
// Bespoke fields — real backend nests these under `bespoke_fulfillment`.
|
|
640
|
+
bespoke_brief: raw.bespoke_fulfillment?.brief ?? void 0,
|
|
641
|
+
bespoke_reference_images: raw.bespoke_fulfillment?.reference_images ?? void 0,
|
|
642
|
+
bespoke_measurements: raw.bespoke_fulfillment?.measurements ?? void 0,
|
|
643
|
+
bespoke_preferred_timeline: raw.bespoke_fulfillment?.preferred_timeline ?? void 0,
|
|
644
|
+
bespoke_special_instructions: raw.bespoke_fulfillment?.special_instructions ?? void 0,
|
|
645
|
+
bespoke_deposit_ratio: raw.bespoke_fulfillment?.deposit_ratio ?? void 0,
|
|
646
|
+
bespoke_deposit_amount: raw.bespoke_fulfillment?.deposit_amount ?? void 0,
|
|
647
|
+
bespoke_balance_amount: raw.bespoke_fulfillment?.balance_amount ?? void 0,
|
|
648
|
+
bespoke_status: raw.bespoke_fulfillment?.status ?? void 0,
|
|
649
|
+
bespoke_deliverable_submitted_at: raw.bespoke_fulfillment?.deliverable_submitted_at ?? void 0,
|
|
650
|
+
bespoke_deliverable_url: raw.bespoke_fulfillment?.deliverable_url ?? void 0,
|
|
651
|
+
bespoke_deliverable_notes: raw.bespoke_fulfillment?.deliverable_notes ?? void 0,
|
|
652
|
+
bespoke_buyer_approved_at: raw.bespoke_fulfillment?.buyer_approved_at ?? void 0,
|
|
653
|
+
bespoke_revision_count: raw.bespoke_fulfillment?.revision_count ?? 0,
|
|
654
|
+
bespoke_revision_notes: raw.bespoke_fulfillment?.revision_notes ?? void 0,
|
|
655
|
+
// SDK camelCase convenience aliases
|
|
656
|
+
total: raw.total_amount ?? void 0,
|
|
657
|
+
shippingAmount: raw.shipping_amount ?? void 0,
|
|
658
|
+
discountAmount: raw.discount_amount ?? void 0,
|
|
659
|
+
customerEmail,
|
|
660
|
+
customerName,
|
|
661
|
+
createdAt: new Date(raw.created_at).getTime(),
|
|
662
|
+
updatedAt: new Date(raw.updated_at).getTime(),
|
|
663
|
+
// REAL BUG FIXED (2026-09-23), found alongside the nesting bug above:
|
|
664
|
+
// `deliveryMethod` reads physical_fulfillment.shipping_method now
|
|
665
|
+
// (was reading a flat `delivery_method` field that never existed at
|
|
666
|
+
// all, anywhere - not even nested). The real value is "carrier" or
|
|
667
|
+
// "self_pickup" (PhysicalFulfillmentCreate.shipping_method's own
|
|
668
|
+
// docstring) - see the matching fix in kasuvia-storefront's
|
|
669
|
+
// OrderDeliveryInfo.tsx, which used to compare against the wrong
|
|
670
|
+
// string "pickup".
|
|
671
|
+
deliveryMethod: physical?.shipping_method ?? void 0,
|
|
672
|
+
trackingNumber: physical?.tracking_number ?? void 0,
|
|
673
|
+
deliveryAddress: addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
|
|
426
674
|
shippingAddress: addr ? {
|
|
427
675
|
first_name: addr.first_name ?? "",
|
|
428
676
|
last_name: addr.last_name ?? "",
|
|
@@ -430,62 +678,85 @@ function normaliseStorefrontOrder(raw) {
|
|
|
430
678
|
street: addr.street ?? "",
|
|
431
679
|
city: addr.city ?? "",
|
|
432
680
|
state: addr.state ?? "",
|
|
433
|
-
lga: addr.lga
|
|
681
|
+
lga: addr.lga,
|
|
434
682
|
country: addr.country ?? "",
|
|
435
|
-
postal: addr.postal
|
|
683
|
+
postal: addr.postal
|
|
436
684
|
} : void 0,
|
|
437
|
-
|
|
685
|
+
// REAL GAP (2026-09-23), NOT fixed here: confirmed cancellation_reason
|
|
686
|
+
// does not exist anywhere in OrderResponse or any of its fulfillment
|
|
687
|
+
// sub-schemas (kasuvia-store-management's app/schemas/order.py) - the
|
|
688
|
+
// cancel-order endpoint accepts a `reason` in its request body but the
|
|
689
|
+
// backend never persists/returns it back on the order. Permanently
|
|
690
|
+
// undefined until the backend adds real storage for it; kept as a
|
|
691
|
+
// field on the public Order type rather than silently removed, since
|
|
692
|
+
// deleting a public SDK field is a breaking change this fix's scope
|
|
693
|
+
// doesn't cover.
|
|
694
|
+
cancellationReason: void 0,
|
|
438
695
|
hasBespoke: raw.product_type === "bespoke",
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
696
|
+
// REAL GAP (2026-09-23), NOT fixed here: same as cancellationReason -
|
|
697
|
+
// confirmed no `bespoke_stage` field exists anywhere; the real,
|
|
698
|
+
// equivalent concept is bespoke_fulfillment.status (already exposed
|
|
699
|
+
// above as `bespoke_status`). Reads that here rather than staying
|
|
700
|
+
// permanently undefined, since it's genuinely the same real data the
|
|
701
|
+
// consuming components (BespokeProgress) want to key off of.
|
|
702
|
+
bespokeStage: raw.bespoke_fulfillment?.status ?? void 0,
|
|
703
|
+
bespokeBrief: raw.bespoke_fulfillment?.brief ?? void 0,
|
|
704
|
+
deliveryStatus: physical?.delivery_status ?? void 0,
|
|
705
|
+
carrierName: physical?.carrier_name ?? void 0,
|
|
706
|
+
terminalShipmentId: physical?.terminal_shipment_id ?? void 0,
|
|
707
|
+
guestToken: raw.guest_token ?? void 0,
|
|
708
|
+
guestEmail: raw.guest_email ?? void 0,
|
|
709
|
+
guestPhone: raw.guest_phone ?? void 0,
|
|
710
|
+
guestName: raw.guest_name ?? void 0
|
|
448
711
|
};
|
|
449
712
|
}
|
|
450
|
-
async function createOrder(config, accessToken, payload) {
|
|
451
|
-
const
|
|
713
|
+
async function createOrder(config, accessToken, payload, guestSessionId) {
|
|
714
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
715
|
+
if (accessToken) {
|
|
716
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
717
|
+
} else if (guestSessionId) {
|
|
718
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
719
|
+
}
|
|
720
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront`, {
|
|
721
|
+
method: "POST",
|
|
722
|
+
headers,
|
|
723
|
+
body: JSON.stringify(payload),
|
|
724
|
+
fallbackErrorMessage: "Failed to create order"
|
|
725
|
+
});
|
|
726
|
+
return normaliseStorefrontOrder(data);
|
|
727
|
+
}
|
|
728
|
+
async function createBespokeOrder(config, accessToken, payload) {
|
|
729
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
730
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
731
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/bespoke`, {
|
|
452
732
|
method: "POST",
|
|
453
|
-
headers
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
457
|
-
"X-Business-ID": config.businessId
|
|
458
|
-
},
|
|
459
|
-
body: JSON.stringify(payload)
|
|
733
|
+
headers,
|
|
734
|
+
body: JSON.stringify(payload),
|
|
735
|
+
fallbackErrorMessage: "Failed to create bespoke order"
|
|
460
736
|
});
|
|
461
|
-
if (!response.ok) throw new Error("Failed to create order");
|
|
462
|
-
const data = await response.json();
|
|
463
737
|
return normaliseStorefrontOrder(data);
|
|
464
738
|
}
|
|
465
|
-
async function
|
|
466
|
-
const
|
|
467
|
-
if (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
"X-Business-ID": config.businessId
|
|
474
|
-
}
|
|
739
|
+
async function createServiceBookingOrder(config, accessToken, payload) {
|
|
740
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
741
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
742
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/service`, {
|
|
743
|
+
method: "POST",
|
|
744
|
+
headers,
|
|
745
|
+
body: JSON.stringify(payload),
|
|
746
|
+
fallbackErrorMessage: "Failed to create service booking order"
|
|
475
747
|
});
|
|
476
|
-
if (!response.ok) throw new Error("Failed to find order");
|
|
477
|
-
const data = await response.json();
|
|
478
748
|
return normaliseStorefrontOrder(data);
|
|
479
749
|
}
|
|
480
|
-
async function
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
750
|
+
async function findOrder(config, params) {
|
|
751
|
+
if (!params.email || !params.order_id) {
|
|
752
|
+
throw new Error("Both email and order_id are required to find an order.");
|
|
753
|
+
}
|
|
754
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/track`, {
|
|
755
|
+
method: "POST",
|
|
756
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
757
|
+
body: JSON.stringify({ order_id: params.order_id, email: params.email }),
|
|
758
|
+
fallbackErrorMessage: "Failed to find order"
|
|
486
759
|
});
|
|
487
|
-
if (!response.ok) throw new Error("Failed to find order by token");
|
|
488
|
-
const data = await response.json();
|
|
489
760
|
return normaliseStorefrontOrder(data);
|
|
490
761
|
}
|
|
491
762
|
async function getOrders(config, accessToken, params) {
|
|
@@ -493,128 +764,262 @@ async function getOrders(config, accessToken, params) {
|
|
|
493
764
|
if (params?.email) queryParams.set("email", params.email);
|
|
494
765
|
if (params?.page) queryParams.set("page", params.page.toString());
|
|
495
766
|
if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
|
|
496
|
-
const
|
|
497
|
-
headers:
|
|
498
|
-
|
|
499
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
500
|
-
"X-Business-ID": config.businessId
|
|
501
|
-
}
|
|
767
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
|
|
768
|
+
headers: authHeaders(config, accessToken),
|
|
769
|
+
fallbackErrorMessage: "Failed to get orders"
|
|
502
770
|
});
|
|
503
|
-
if (!response.ok) throw new Error("Failed to get orders");
|
|
504
|
-
const data = await response.json();
|
|
505
771
|
const items = Array.isArray(data) ? data : data.items ?? [];
|
|
506
772
|
return items.map(normaliseStorefrontOrder);
|
|
507
773
|
}
|
|
508
774
|
async function cancelOrder(config, accessToken, orderId, reason) {
|
|
509
|
-
const
|
|
775
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
|
|
510
776
|
method: "POST",
|
|
511
|
-
headers: {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
515
|
-
"X-Business-ID": config.businessId
|
|
516
|
-
},
|
|
517
|
-
body: JSON.stringify({ reason })
|
|
777
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
778
|
+
body: JSON.stringify({ reason }),
|
|
779
|
+
fallbackErrorMessage: "Failed to cancel order"
|
|
518
780
|
});
|
|
519
|
-
if (!response.ok) throw new Error("Failed to cancel order");
|
|
520
|
-
const data = await response.json();
|
|
521
781
|
return normaliseStorefrontOrder(data);
|
|
522
782
|
}
|
|
523
|
-
async function trackOrder(config, orderId,
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
528
|
-
"X-Business-ID": config.businessId
|
|
529
|
-
}
|
|
783
|
+
async function trackOrder(config, orderId, accessToken) {
|
|
784
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}`, {
|
|
785
|
+
headers: authHeaders(config, accessToken),
|
|
786
|
+
fallbackErrorMessage: "Failed to track order"
|
|
530
787
|
});
|
|
531
|
-
if (!response.ok) throw new Error("Failed to track order");
|
|
532
|
-
const data = await response.json();
|
|
533
788
|
return normaliseStorefrontOrder(data);
|
|
534
789
|
}
|
|
790
|
+
async function validatePromoCode(config, code, cartTotal) {
|
|
791
|
+
try {
|
|
792
|
+
return await apiRequest(`${config.backendUrls.store}/sales/discounts/validate`, {
|
|
793
|
+
method: "POST",
|
|
794
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
795
|
+
body: JSON.stringify({ code, cart_total: cartTotal }),
|
|
796
|
+
fallbackErrorMessage: "Invalid promo code"
|
|
797
|
+
});
|
|
798
|
+
} catch (err) {
|
|
799
|
+
const message = err instanceof ApiError ? err.message : "Invalid promo code";
|
|
800
|
+
return { valid: false, discount_amount: 0, discount_type: "fixed", message };
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
async function resolveRedirectOrJson(url, fallbackErrorMessage) {
|
|
804
|
+
const response = await fetch(url, { redirect: "manual" });
|
|
805
|
+
if (response.status >= 300 && response.status < 400) {
|
|
806
|
+
const location = response.headers.get("location");
|
|
807
|
+
if (!location) {
|
|
808
|
+
throw new Error(`${fallbackErrorMessage}: server redirected with no destination URL.`);
|
|
809
|
+
}
|
|
810
|
+
return { type: "redirect", url: location };
|
|
811
|
+
}
|
|
812
|
+
const body = await response.json().catch(() => ({}));
|
|
813
|
+
if (!response.ok) {
|
|
814
|
+
throw new ApiError(extractDigitalDownloadError(body, fallbackErrorMessage), response.status, body);
|
|
815
|
+
}
|
|
816
|
+
return { type: "json", data: body };
|
|
817
|
+
}
|
|
818
|
+
function extractDigitalDownloadError(body, fallback) {
|
|
819
|
+
if (typeof body === "object" && body !== null && "detail" in body && typeof body.detail === "string") {
|
|
820
|
+
return body.detail;
|
|
821
|
+
}
|
|
822
|
+
return fallback;
|
|
823
|
+
}
|
|
824
|
+
async function resolveDigitalDownload(config, orderId, token) {
|
|
825
|
+
const result = await resolveRedirectOrJson(
|
|
826
|
+
`${config.backendUrls.store}/orders/${orderId}/download/${token}`,
|
|
827
|
+
"Failed to resolve digital download link"
|
|
828
|
+
);
|
|
829
|
+
if (result.type === "redirect") return result;
|
|
830
|
+
return { type: "listing", ...result.data };
|
|
831
|
+
}
|
|
832
|
+
async function resolveDigitalDownloadFile(config, orderId, token, fileId) {
|
|
833
|
+
const result = await resolveRedirectOrJson(
|
|
834
|
+
`${config.backendUrls.store}/orders/${orderId}/download/${token}/${fileId}`,
|
|
835
|
+
"Failed to resolve this file's download link"
|
|
836
|
+
);
|
|
837
|
+
if (result.type !== "redirect") {
|
|
838
|
+
throw new Error("Failed to resolve this file's download link: server did not return a redirect.");
|
|
839
|
+
}
|
|
840
|
+
return result.url;
|
|
841
|
+
}
|
|
535
842
|
|
|
536
|
-
// src/services/
|
|
537
|
-
async function
|
|
538
|
-
|
|
843
|
+
// src/services/consultation.service.ts
|
|
844
|
+
async function createConsultation(config, accessToken, params) {
|
|
845
|
+
return apiRequest(`${config.backendUrls.crm}/consultations/`, {
|
|
539
846
|
method: "POST",
|
|
540
|
-
headers: {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
"X-Business-ID": config.businessId
|
|
544
|
-
},
|
|
545
|
-
body: JSON.stringify({
|
|
546
|
-
...payload,
|
|
547
|
-
tenant_id: config.businessId
|
|
548
|
-
})
|
|
847
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
848
|
+
body: JSON.stringify(params),
|
|
849
|
+
fallbackErrorMessage: "Failed to submit your request"
|
|
549
850
|
});
|
|
550
|
-
|
|
551
|
-
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// src/services/feedback.service.ts
|
|
854
|
+
async function createFeedback(config, accessToken, params) {
|
|
855
|
+
return apiRequest(`${config.backendUrls.crm}/feedback/`, {
|
|
856
|
+
method: "POST",
|
|
857
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
858
|
+
body: JSON.stringify(params),
|
|
859
|
+
fallbackErrorMessage: "Failed to submit your message"
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
async function getMyFeedback(config, accessToken, params) {
|
|
863
|
+
const query = new URLSearchParams();
|
|
864
|
+
if (params?.page) query.set("page", String(params.page));
|
|
865
|
+
if (params?.page_size) query.set("page_size", String(params.page_size));
|
|
866
|
+
return apiRequest(`${config.backendUrls.crm}/feedback/my?${query.toString()}`, {
|
|
867
|
+
headers: authHeaders(config, accessToken),
|
|
868
|
+
fallbackErrorMessage: "Failed to load your requests"
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// src/utils/customer.ts
|
|
873
|
+
function buildFullName(firstname, lastname) {
|
|
874
|
+
const name = [firstname, lastname].filter(Boolean).join(" ").trim();
|
|
875
|
+
return name || void 0;
|
|
876
|
+
}
|
|
877
|
+
function splitFullName(fullName) {
|
|
878
|
+
if (!fullName?.trim()) return { firstname: "", lastname: "" };
|
|
879
|
+
const parts = fullName.trim().split(/\s+/);
|
|
880
|
+
return {
|
|
881
|
+
firstname: parts[0] ?? "",
|
|
882
|
+
lastname: parts.slice(1).join(" ")
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function getCustomerDisplayName(user) {
|
|
886
|
+
const fromParts = buildFullName(user.firstname, user.lastname);
|
|
887
|
+
return fromParts || user.full_name || user.email.split("@")[0];
|
|
888
|
+
}
|
|
889
|
+
function getStorefrontUrl(businessId, customDomain) {
|
|
890
|
+
if (customDomain && customDomain.trim()) {
|
|
891
|
+
const cleanDomain = customDomain.trim().replace(/^https?:\/\//, "");
|
|
892
|
+
return `https://${cleanDomain}`;
|
|
552
893
|
}
|
|
553
|
-
const
|
|
554
|
-
return
|
|
894
|
+
const cleanBid = (businessId || "store").toLowerCase().trim();
|
|
895
|
+
return `https://${cleanBid}.kasuvia.com`;
|
|
555
896
|
}
|
|
556
|
-
|
|
557
|
-
|
|
897
|
+
|
|
898
|
+
// src/services/auth.service.ts
|
|
899
|
+
async function loginCustomer(config, payload, guestSessionId) {
|
|
900
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
901
|
+
if (guestSessionId) {
|
|
902
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
903
|
+
}
|
|
904
|
+
return apiRequest(`${config.backendUrls.auth}/auth/login/customer/`, {
|
|
558
905
|
method: "POST",
|
|
559
|
-
headers
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
"X-Business-ID": config.businessId
|
|
563
|
-
},
|
|
564
|
-
body: JSON.stringify({
|
|
565
|
-
...payload,
|
|
566
|
-
tenant_id: config.businessId
|
|
567
|
-
})
|
|
906
|
+
headers,
|
|
907
|
+
body: JSON.stringify(payload),
|
|
908
|
+
fallbackErrorMessage: "Login failed"
|
|
568
909
|
});
|
|
569
|
-
|
|
570
|
-
|
|
910
|
+
}
|
|
911
|
+
async function registerCustomer(config, payload, guestSessionId) {
|
|
912
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
913
|
+
if (guestSessionId) {
|
|
914
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
571
915
|
}
|
|
572
|
-
|
|
573
|
-
|
|
916
|
+
return apiRequest(`${config.backendUrls.auth}/auth/register/customer/`, {
|
|
917
|
+
method: "POST",
|
|
918
|
+
headers,
|
|
919
|
+
body: JSON.stringify(payload),
|
|
920
|
+
fallbackErrorMessage: "Registration failed"
|
|
921
|
+
});
|
|
574
922
|
}
|
|
575
923
|
async function refreshToken(config, refresh) {
|
|
576
|
-
|
|
924
|
+
return apiRequest(`${config.backendUrls.auth}/auth/token/refresh/`, {
|
|
577
925
|
method: "POST",
|
|
578
|
-
headers:
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
body: JSON.stringify({ refresh })
|
|
926
|
+
headers: JSON_HEADERS,
|
|
927
|
+
body: JSON.stringify({ refresh }),
|
|
928
|
+
fallbackErrorMessage: "Token refresh failed"
|
|
582
929
|
});
|
|
583
|
-
if (!response.ok) {
|
|
584
|
-
throw new Error("Token refresh failed");
|
|
585
|
-
}
|
|
586
|
-
const data = await response.json();
|
|
587
|
-
return data;
|
|
588
930
|
}
|
|
589
931
|
async function logout(config, refresh) {
|
|
590
932
|
const payload = refresh ? { refresh } : {};
|
|
591
933
|
try {
|
|
592
|
-
await
|
|
934
|
+
await apiRequest(`${config.backendUrls.auth}/auth/logout/`, {
|
|
593
935
|
method: "POST",
|
|
594
|
-
headers:
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
body: JSON.stringify(payload)
|
|
936
|
+
headers: JSON_HEADERS,
|
|
937
|
+
body: JSON.stringify(payload),
|
|
938
|
+
fallbackErrorMessage: "Server-side logout failed"
|
|
598
939
|
});
|
|
599
|
-
} catch {
|
|
940
|
+
} catch (err) {
|
|
941
|
+
if (err instanceof ApiError) {
|
|
942
|
+
console.error(`[auth.service] Server-side logout failed with status ${err.status}; local session will still be cleared.`);
|
|
943
|
+
} else {
|
|
944
|
+
console.error("[auth.service] Server-side logout request failed; local session will still be cleared.", err);
|
|
945
|
+
}
|
|
600
946
|
}
|
|
601
947
|
}
|
|
602
948
|
async function verifySocialToken(config, provider, token) {
|
|
603
|
-
|
|
949
|
+
return apiRequest(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
|
|
604
950
|
method: "POST",
|
|
605
|
-
headers: {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
body: JSON.stringify({
|
|
609
|
-
id_token: token,
|
|
610
|
-
storefront_key: config.storefrontApiKey
|
|
611
|
-
})
|
|
951
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
952
|
+
body: JSON.stringify({ id_token: token }),
|
|
953
|
+
fallbackErrorMessage: "Social token verification failed"
|
|
612
954
|
});
|
|
613
|
-
|
|
614
|
-
|
|
955
|
+
}
|
|
956
|
+
async function requestCustomerOtp(config, payload) {
|
|
957
|
+
await apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/request/`, {
|
|
958
|
+
method: "POST",
|
|
959
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
960
|
+
body: JSON.stringify(payload),
|
|
961
|
+
fallbackErrorMessage: "Failed to send login code"
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
async function verifyCustomerOtp(config, payload, guestSessionId) {
|
|
965
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
966
|
+
if (guestSessionId) {
|
|
967
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
968
|
+
}
|
|
969
|
+
return apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/verify/`, {
|
|
970
|
+
method: "POST",
|
|
971
|
+
headers,
|
|
972
|
+
body: JSON.stringify(payload),
|
|
973
|
+
fallbackErrorMessage: "Invalid or expired code"
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
async function forgotPasswordCustomer(config, payload) {
|
|
977
|
+
return apiRequest(`${config.backendUrls.auth}/auth/forgot-password/customer/`, {
|
|
978
|
+
method: "POST",
|
|
979
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
980
|
+
body: JSON.stringify(payload),
|
|
981
|
+
fallbackErrorMessage: "Failed to request password reset"
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
async function resetPasswordCustomer(config, payload) {
|
|
985
|
+
return apiRequest(`${config.backendUrls.auth}/auth/reset-password/customer/`, {
|
|
986
|
+
method: "POST",
|
|
987
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
988
|
+
body: JSON.stringify(payload),
|
|
989
|
+
fallbackErrorMessage: "Invalid or expired reset code"
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
async function deactivateCustomerAccount(config, accessToken, payload) {
|
|
993
|
+
try {
|
|
994
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/customer/deactivate/`, {
|
|
995
|
+
method: "POST",
|
|
996
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
997
|
+
body: JSON.stringify(payload || {}),
|
|
998
|
+
fallbackErrorMessage: "Failed to deactivate account"
|
|
999
|
+
});
|
|
1000
|
+
return { status: "success", detail: data.detail };
|
|
1001
|
+
} catch (err) {
|
|
1002
|
+
if (err instanceof ApiError && err.status === 409) {
|
|
1003
|
+
return { status: "confirmation_required", data: err.body };
|
|
1004
|
+
}
|
|
1005
|
+
throw err;
|
|
615
1006
|
}
|
|
616
|
-
|
|
617
|
-
|
|
1007
|
+
}
|
|
1008
|
+
async function requestCustomerReactivation(config, payload) {
|
|
1009
|
+
return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/`, {
|
|
1010
|
+
method: "POST",
|
|
1011
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1012
|
+
body: JSON.stringify(payload),
|
|
1013
|
+
fallbackErrorMessage: "Failed to request reactivation"
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
async function verifyCustomerReactivation(config, payload) {
|
|
1017
|
+
return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/verify/`, {
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1020
|
+
body: JSON.stringify(payload),
|
|
1021
|
+
fallbackErrorMessage: "Invalid or expired reactivation code"
|
|
1022
|
+
});
|
|
618
1023
|
}
|
|
619
1024
|
function parseJwtPayload(token) {
|
|
620
1025
|
try {
|
|
@@ -669,70 +1074,94 @@ function buildCustomerFromClaims(claims) {
|
|
|
669
1074
|
}
|
|
670
1075
|
async function getMe(config, accessToken) {
|
|
671
1076
|
if (!config || !accessToken) {
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
|
|
678
|
-
headers: {
|
|
679
|
-
"Authorization": `Bearer ${accessToken}`
|
|
680
|
-
}
|
|
681
|
-
});
|
|
682
|
-
if (!response.ok) {
|
|
683
|
-
throw new Error("Failed to fetch profile");
|
|
1077
|
+
const data2 = await apiRequest("/api/auth/me", {
|
|
1078
|
+
credentials: "include",
|
|
1079
|
+
fallbackErrorMessage: "Failed to fetch profile"
|
|
1080
|
+
});
|
|
1081
|
+
return mapAuthUserToCustomer(data2.user);
|
|
684
1082
|
}
|
|
685
|
-
const data = await
|
|
1083
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
1084
|
+
headers: authHeaders(config, accessToken),
|
|
1085
|
+
fallbackErrorMessage: "Failed to fetch profile"
|
|
1086
|
+
});
|
|
686
1087
|
return mapAuthUserToCustomer(data);
|
|
687
1088
|
}
|
|
688
1089
|
async function getAuthUser(config, accessToken) {
|
|
689
1090
|
if (!config || !accessToken) {
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
|
|
696
|
-
headers: {
|
|
697
|
-
"Authorization": `Bearer ${accessToken}`
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
|
-
if (!response.ok) {
|
|
701
|
-
throw new Error("Failed to fetch auth user");
|
|
1091
|
+
const data = await apiRequest("/api/auth/me", {
|
|
1092
|
+
credentials: "include",
|
|
1093
|
+
fallbackErrorMessage: "Failed to fetch auth user"
|
|
1094
|
+
});
|
|
1095
|
+
return data.user;
|
|
702
1096
|
}
|
|
703
|
-
|
|
704
|
-
|
|
1097
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
1098
|
+
headers: authHeaders(config, accessToken),
|
|
1099
|
+
fallbackErrorMessage: "Failed to fetch auth user"
|
|
1100
|
+
});
|
|
705
1101
|
}
|
|
706
1102
|
async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
|
|
707
1103
|
const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
|
|
708
1104
|
if (!isArg1Config) {
|
|
709
1105
|
const payload2 = configOrPayload;
|
|
710
|
-
|
|
1106
|
+
return apiRequest("/api/auth/profile", {
|
|
711
1107
|
method: "PUT",
|
|
712
|
-
headers:
|
|
1108
|
+
headers: JSON_HEADERS,
|
|
713
1109
|
credentials: "include",
|
|
714
|
-
body: JSON.stringify(payload2)
|
|
1110
|
+
body: JSON.stringify(payload2),
|
|
1111
|
+
fallbackErrorMessage: "Failed to update profile"
|
|
715
1112
|
});
|
|
716
|
-
if (!response2.ok) throw new Error("Failed to update profile");
|
|
717
|
-
return response2.json();
|
|
718
1113
|
}
|
|
719
1114
|
const config = configOrPayload;
|
|
720
1115
|
const accessToken = accessTokenOrPayload;
|
|
721
1116
|
const payload = payloadParam;
|
|
722
|
-
const
|
|
1117
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
723
1118
|
method: "PUT",
|
|
724
|
-
headers: {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
},
|
|
728
|
-
body: JSON.stringify(payload)
|
|
1119
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1120
|
+
body: JSON.stringify(payload),
|
|
1121
|
+
fallbackErrorMessage: "Failed to update profile"
|
|
729
1122
|
});
|
|
730
|
-
if (!response.ok) {
|
|
731
|
-
throw new Error("Failed to update profile");
|
|
732
|
-
}
|
|
733
|
-
const data = await response.json();
|
|
734
1123
|
return mapAuthUserToCustomer(data);
|
|
735
1124
|
}
|
|
1125
|
+
async function changePassword(config, accessToken, payload) {
|
|
1126
|
+
return apiRequest(`${config.backendUrls.auth}/auth/change-password/`, {
|
|
1127
|
+
method: "POST",
|
|
1128
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1129
|
+
body: JSON.stringify(payload),
|
|
1130
|
+
fallbackErrorMessage: "Failed to change password"
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
async function getStorefrontBusinessInfo(config) {
|
|
1134
|
+
return apiRequest(`${config.backendUrls.auth}/auth/storefront/business-info/`, {
|
|
1135
|
+
headers: storefrontHeaders(config),
|
|
1136
|
+
fallbackErrorMessage: "Failed to fetch business info"
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
async function getPresignedUploadUrl(config, accessToken, params) {
|
|
1140
|
+
const query = new URLSearchParams(
|
|
1141
|
+
Object.entries(params).filter(([, v]) => v !== void 0)
|
|
1142
|
+
);
|
|
1143
|
+
return apiRequest(
|
|
1144
|
+
`${config.backendUrls.auth}/auth/media/presigned-url/?${query.toString()}`,
|
|
1145
|
+
{
|
|
1146
|
+
method: "POST",
|
|
1147
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
1148
|
+
fallbackErrorMessage: "Failed to get presigned upload URL"
|
|
1149
|
+
}
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
async function confirmMediaUpload(config, accessToken, params) {
|
|
1153
|
+
const query = new URLSearchParams(
|
|
1154
|
+
Object.entries(params).filter(([, v]) => v !== void 0)
|
|
1155
|
+
);
|
|
1156
|
+
return apiRequest(
|
|
1157
|
+
`${config.backendUrls.auth}/auth/media/confirm-upload/?${query.toString()}`,
|
|
1158
|
+
{
|
|
1159
|
+
method: "POST",
|
|
1160
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
1161
|
+
fallbackErrorMessage: "Failed to confirm upload"
|
|
1162
|
+
}
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
736
1165
|
async function silentRefresh(config, refresh) {
|
|
737
1166
|
try {
|
|
738
1167
|
const data = await refreshToken(config, refresh);
|
|
@@ -743,25 +1172,11 @@ async function silentRefresh(config, refresh) {
|
|
|
743
1172
|
const user = buildCustomerFromClaims(claims);
|
|
744
1173
|
const provider = user.provider;
|
|
745
1174
|
return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
|
|
746
|
-
} catch {
|
|
1175
|
+
} catch (err) {
|
|
1176
|
+
console.error("[auth.service] Silent token refresh failed:", err);
|
|
747
1177
|
return null;
|
|
748
1178
|
}
|
|
749
1179
|
}
|
|
750
|
-
function buildFullName(firstname, lastname) {
|
|
751
|
-
if (firstname && lastname) return `${firstname} ${lastname}`;
|
|
752
|
-
return firstname || lastname || "";
|
|
753
|
-
}
|
|
754
|
-
function splitFullName(fullName) {
|
|
755
|
-
if (!fullName) return { firstname: "", lastname: "" };
|
|
756
|
-
const parts = fullName.trim().split(/\s+/);
|
|
757
|
-
if (parts.length === 1) {
|
|
758
|
-
return { firstname: parts[0], lastname: "" };
|
|
759
|
-
}
|
|
760
|
-
return {
|
|
761
|
-
firstname: parts[0],
|
|
762
|
-
lastname: parts.slice(1).join(" ")
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
1180
|
function storeTokens(accessToken, refreshToken2) {
|
|
766
1181
|
if (typeof window !== "undefined") {
|
|
767
1182
|
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
|
|
@@ -783,1061 +1198,369 @@ function getStoredTokens() {
|
|
|
783
1198
|
refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
|
|
784
1199
|
};
|
|
785
1200
|
}
|
|
1201
|
+
async function getCustomerAddresses(config, accessToken) {
|
|
1202
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
|
|
1203
|
+
headers: authHeaders(config, accessToken),
|
|
1204
|
+
fallbackErrorMessage: "Failed to fetch saved addresses"
|
|
1205
|
+
});
|
|
1206
|
+
return data.results;
|
|
1207
|
+
}
|
|
1208
|
+
async function createCustomerAddress(config, accessToken, payload) {
|
|
1209
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1212
|
+
body: JSON.stringify(payload),
|
|
1213
|
+
fallbackErrorMessage: "Failed to save address"
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
async function updateCustomerAddress(config, accessToken, addressId, payload) {
|
|
1217
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
|
|
1218
|
+
method: "PATCH",
|
|
1219
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1220
|
+
body: JSON.stringify(payload),
|
|
1221
|
+
fallbackErrorMessage: "Failed to update address"
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
async function deleteCustomerAddress(config, accessToken, addressId) {
|
|
1225
|
+
await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
|
|
1226
|
+
method: "DELETE",
|
|
1227
|
+
headers: authHeaders(config, accessToken),
|
|
1228
|
+
fallbackErrorMessage: "Failed to delete address"
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
786
1231
|
|
|
787
|
-
// src/
|
|
1232
|
+
// src/utils/graphql-url.ts
|
|
788
1233
|
var import_graphql_request = require("graphql-request");
|
|
789
|
-
function
|
|
1234
|
+
function resolveGraphQLEndpoint(url) {
|
|
1235
|
+
if (typeof window === "undefined") return url;
|
|
1236
|
+
try {
|
|
1237
|
+
new URL(url);
|
|
1238
|
+
return url;
|
|
1239
|
+
} catch {
|
|
1240
|
+
return `${window.location.origin}${url}`;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function createGraphQLClient(config, accessToken) {
|
|
790
1244
|
const headers = {
|
|
791
1245
|
"Content-Type": "application/json",
|
|
792
1246
|
"Accept": "application/json",
|
|
793
1247
|
"X-Storefront-Key": config.storefrontApiKey,
|
|
794
1248
|
"X-Business-ID": config.businessId
|
|
795
1249
|
};
|
|
796
|
-
|
|
797
|
-
}
|
|
798
|
-
var GET_STOREFRONT_PRODUCTS = `
|
|
799
|
-
query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
|
|
800
|
-
storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
|
|
801
|
-
items {
|
|
802
|
-
id
|
|
803
|
-
business_id
|
|
804
|
-
name
|
|
805
|
-
slug
|
|
806
|
-
description
|
|
807
|
-
brand
|
|
808
|
-
product_type
|
|
809
|
-
requires_shipping
|
|
810
|
-
is_consumable
|
|
811
|
-
is_bespoke
|
|
812
|
-
base_price
|
|
813
|
-
currency
|
|
814
|
-
images
|
|
815
|
-
tags
|
|
816
|
-
custom_fields { label unit required }
|
|
817
|
-
is_published
|
|
818
|
-
is_featured
|
|
819
|
-
is_popular
|
|
820
|
-
is_new
|
|
821
|
-
is_temporary
|
|
822
|
-
digital_file_key
|
|
823
|
-
download_limit
|
|
824
|
-
download_expires_at
|
|
825
|
-
weight_kg
|
|
826
|
-
length_cm
|
|
827
|
-
width_cm
|
|
828
|
-
height_cm
|
|
829
|
-
created_at
|
|
830
|
-
updated_at
|
|
831
|
-
variants {
|
|
832
|
-
id
|
|
833
|
-
product_id
|
|
834
|
-
sku
|
|
835
|
-
attributes
|
|
836
|
-
price
|
|
837
|
-
images
|
|
838
|
-
weight_kg
|
|
839
|
-
is_active
|
|
840
|
-
inventory {
|
|
841
|
-
id
|
|
842
|
-
product_id
|
|
843
|
-
variant_id
|
|
844
|
-
quantity
|
|
845
|
-
reserved
|
|
846
|
-
reorder_point
|
|
847
|
-
reorder_quantity
|
|
848
|
-
track_quantity
|
|
849
|
-
allow_backorder
|
|
850
|
-
available
|
|
851
|
-
is_in_stock
|
|
852
|
-
is_low_stock
|
|
853
|
-
updated_at
|
|
854
|
-
}
|
|
855
|
-
created_at
|
|
856
|
-
updated_at
|
|
857
|
-
}
|
|
858
|
-
collections {
|
|
859
|
-
id
|
|
860
|
-
business_id
|
|
861
|
-
name
|
|
862
|
-
slug
|
|
863
|
-
description
|
|
864
|
-
image
|
|
865
|
-
collection_type
|
|
866
|
-
rules
|
|
867
|
-
status
|
|
868
|
-
sort_order
|
|
869
|
-
created_at
|
|
870
|
-
updated_at
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
total
|
|
874
|
-
page
|
|
875
|
-
page_size
|
|
876
|
-
total_pages
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
`;
|
|
880
|
-
var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
881
|
-
query GetStorefrontProductBySlug($slug: String!) {
|
|
882
|
-
storefront_product_by_slug(slug: $slug) {
|
|
883
|
-
id
|
|
884
|
-
business_id
|
|
885
|
-
name
|
|
886
|
-
slug
|
|
887
|
-
description
|
|
888
|
-
brand
|
|
889
|
-
product_type
|
|
890
|
-
requires_shipping
|
|
891
|
-
is_consumable
|
|
892
|
-
is_bespoke
|
|
893
|
-
base_price
|
|
894
|
-
currency
|
|
895
|
-
images
|
|
896
|
-
tags
|
|
897
|
-
custom_fields { label unit required }
|
|
898
|
-
is_published
|
|
899
|
-
is_featured
|
|
900
|
-
is_popular
|
|
901
|
-
is_new
|
|
902
|
-
is_temporary
|
|
903
|
-
digital_file_key
|
|
904
|
-
download_limit
|
|
905
|
-
download_expires_at
|
|
906
|
-
weight_kg
|
|
907
|
-
length_cm
|
|
908
|
-
width_cm
|
|
909
|
-
height_cm
|
|
910
|
-
created_at
|
|
911
|
-
updated_at
|
|
912
|
-
variants {
|
|
913
|
-
id
|
|
914
|
-
product_id
|
|
915
|
-
sku
|
|
916
|
-
attributes
|
|
917
|
-
price
|
|
918
|
-
images
|
|
919
|
-
weight_kg
|
|
920
|
-
is_active
|
|
921
|
-
inventory {
|
|
922
|
-
id
|
|
923
|
-
product_id
|
|
924
|
-
variant_id
|
|
925
|
-
quantity
|
|
926
|
-
reserved
|
|
927
|
-
reorder_point
|
|
928
|
-
reorder_quantity
|
|
929
|
-
track_quantity
|
|
930
|
-
allow_backorder
|
|
931
|
-
available
|
|
932
|
-
is_in_stock
|
|
933
|
-
is_low_stock
|
|
934
|
-
updated_at
|
|
935
|
-
}
|
|
936
|
-
created_at
|
|
937
|
-
updated_at
|
|
938
|
-
}
|
|
939
|
-
collections {
|
|
940
|
-
id
|
|
941
|
-
business_id
|
|
942
|
-
name
|
|
943
|
-
slug
|
|
944
|
-
description
|
|
945
|
-
image
|
|
946
|
-
collection_type
|
|
947
|
-
rules
|
|
948
|
-
status
|
|
949
|
-
sort_order
|
|
950
|
-
created_at
|
|
951
|
-
updated_at
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
`;
|
|
956
|
-
var GET_STOREFRONT_LATEST = `
|
|
957
|
-
query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
|
|
958
|
-
storefront_latest(page: $page, pageSize: $pageSize) {
|
|
959
|
-
items {
|
|
960
|
-
id
|
|
961
|
-
business_id
|
|
962
|
-
name
|
|
963
|
-
slug
|
|
964
|
-
description
|
|
965
|
-
brand
|
|
966
|
-
product_type
|
|
967
|
-
requires_shipping
|
|
968
|
-
is_consumable
|
|
969
|
-
is_bespoke
|
|
970
|
-
base_price
|
|
971
|
-
currency
|
|
972
|
-
images
|
|
973
|
-
tags
|
|
974
|
-
custom_fields { label unit required }
|
|
975
|
-
is_published
|
|
976
|
-
is_featured
|
|
977
|
-
is_popular
|
|
978
|
-
is_new
|
|
979
|
-
is_temporary
|
|
980
|
-
digital_file_key
|
|
981
|
-
download_limit
|
|
982
|
-
download_expires_at
|
|
983
|
-
weight_kg
|
|
984
|
-
length_cm
|
|
985
|
-
width_cm
|
|
986
|
-
height_cm
|
|
987
|
-
created_at
|
|
988
|
-
updated_at
|
|
989
|
-
variants {
|
|
990
|
-
id
|
|
991
|
-
product_id
|
|
992
|
-
sku
|
|
993
|
-
attributes
|
|
994
|
-
price
|
|
995
|
-
images
|
|
996
|
-
weight_kg
|
|
997
|
-
is_active
|
|
998
|
-
inventory {
|
|
999
|
-
id
|
|
1000
|
-
product_id
|
|
1001
|
-
variant_id
|
|
1002
|
-
quantity
|
|
1003
|
-
reserved
|
|
1004
|
-
reorder_point
|
|
1005
|
-
reorder_quantity
|
|
1006
|
-
track_quantity
|
|
1007
|
-
allow_backorder
|
|
1008
|
-
available
|
|
1009
|
-
is_in_stock
|
|
1010
|
-
is_low_stock
|
|
1011
|
-
updated_at
|
|
1012
|
-
}
|
|
1013
|
-
created_at
|
|
1014
|
-
updated_at
|
|
1015
|
-
}
|
|
1016
|
-
collections {
|
|
1017
|
-
id
|
|
1018
|
-
business_id
|
|
1019
|
-
name
|
|
1020
|
-
slug
|
|
1021
|
-
description
|
|
1022
|
-
image
|
|
1023
|
-
collection_type
|
|
1024
|
-
rules
|
|
1025
|
-
status
|
|
1026
|
-
sort_order
|
|
1027
|
-
created_at
|
|
1028
|
-
updated_at
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
total
|
|
1032
|
-
page
|
|
1033
|
-
page_size
|
|
1034
|
-
total_pages
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
`;
|
|
1038
|
-
var GET_STOREFRONT_POPULAR = `
|
|
1039
|
-
query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
|
|
1040
|
-
storefront_popular(page: $page, pageSize: $pageSize) {
|
|
1041
|
-
items {
|
|
1042
|
-
id
|
|
1043
|
-
business_id
|
|
1044
|
-
name
|
|
1045
|
-
slug
|
|
1046
|
-
description
|
|
1047
|
-
brand
|
|
1048
|
-
product_type
|
|
1049
|
-
requires_shipping
|
|
1050
|
-
is_consumable
|
|
1051
|
-
is_bespoke
|
|
1052
|
-
base_price
|
|
1053
|
-
currency
|
|
1054
|
-
images
|
|
1055
|
-
tags
|
|
1056
|
-
custom_fields { label unit required }
|
|
1057
|
-
is_published
|
|
1058
|
-
is_featured
|
|
1059
|
-
is_popular
|
|
1060
|
-
is_new
|
|
1061
|
-
is_temporary
|
|
1062
|
-
digital_file_key
|
|
1063
|
-
download_limit
|
|
1064
|
-
download_expires_at
|
|
1065
|
-
weight_kg
|
|
1066
|
-
length_cm
|
|
1067
|
-
width_cm
|
|
1068
|
-
height_cm
|
|
1069
|
-
created_at
|
|
1070
|
-
updated_at
|
|
1071
|
-
variants {
|
|
1072
|
-
id
|
|
1073
|
-
product_id
|
|
1074
|
-
sku
|
|
1075
|
-
attributes
|
|
1076
|
-
price
|
|
1077
|
-
images
|
|
1078
|
-
weight_kg
|
|
1079
|
-
is_active
|
|
1080
|
-
inventory {
|
|
1081
|
-
id
|
|
1082
|
-
product_id
|
|
1083
|
-
variant_id
|
|
1084
|
-
quantity
|
|
1085
|
-
reserved
|
|
1086
|
-
reorder_point
|
|
1087
|
-
reorder_quantity
|
|
1088
|
-
track_quantity
|
|
1089
|
-
allow_backorder
|
|
1090
|
-
available
|
|
1091
|
-
is_in_stock
|
|
1092
|
-
is_low_stock
|
|
1093
|
-
updated_at
|
|
1094
|
-
}
|
|
1095
|
-
created_at
|
|
1096
|
-
updated_at
|
|
1097
|
-
}
|
|
1098
|
-
collections {
|
|
1099
|
-
id
|
|
1100
|
-
business_id
|
|
1101
|
-
name
|
|
1102
|
-
slug
|
|
1103
|
-
description
|
|
1104
|
-
image
|
|
1105
|
-
collection_type
|
|
1106
|
-
rules
|
|
1107
|
-
status
|
|
1108
|
-
sort_order
|
|
1109
|
-
created_at
|
|
1110
|
-
updated_at
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
total
|
|
1114
|
-
page
|
|
1115
|
-
page_size
|
|
1116
|
-
total_pages
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
`;
|
|
1120
|
-
var GET_STOREFRONT_FEATURED = `
|
|
1121
|
-
query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
|
|
1122
|
-
storefront_featured(page: $page, pageSize: $pageSize) {
|
|
1123
|
-
items {
|
|
1124
|
-
id
|
|
1125
|
-
business_id
|
|
1126
|
-
name
|
|
1127
|
-
slug
|
|
1128
|
-
description
|
|
1129
|
-
brand
|
|
1130
|
-
product_type
|
|
1131
|
-
requires_shipping
|
|
1132
|
-
is_consumable
|
|
1133
|
-
is_bespoke
|
|
1134
|
-
base_price
|
|
1135
|
-
currency
|
|
1136
|
-
images
|
|
1137
|
-
tags
|
|
1138
|
-
custom_fields { label unit required }
|
|
1139
|
-
is_published
|
|
1140
|
-
is_featured
|
|
1141
|
-
is_popular
|
|
1142
|
-
is_new
|
|
1143
|
-
is_temporary
|
|
1144
|
-
digital_file_key
|
|
1145
|
-
download_limit
|
|
1146
|
-
download_expires_at
|
|
1147
|
-
weight_kg
|
|
1148
|
-
length_cm
|
|
1149
|
-
width_cm
|
|
1150
|
-
height_cm
|
|
1151
|
-
created_at
|
|
1152
|
-
updated_at
|
|
1153
|
-
variants {
|
|
1154
|
-
id
|
|
1155
|
-
product_id
|
|
1156
|
-
sku
|
|
1157
|
-
attributes
|
|
1158
|
-
price
|
|
1159
|
-
images
|
|
1160
|
-
weight_kg
|
|
1161
|
-
is_active
|
|
1162
|
-
inventory {
|
|
1163
|
-
id
|
|
1164
|
-
product_id
|
|
1165
|
-
variant_id
|
|
1166
|
-
quantity
|
|
1167
|
-
reserved
|
|
1168
|
-
reorder_point
|
|
1169
|
-
reorder_quantity
|
|
1170
|
-
track_quantity
|
|
1171
|
-
allow_backorder
|
|
1172
|
-
available
|
|
1173
|
-
is_in_stock
|
|
1174
|
-
is_low_stock
|
|
1175
|
-
updated_at
|
|
1176
|
-
}
|
|
1177
|
-
created_at
|
|
1178
|
-
updated_at
|
|
1179
|
-
}
|
|
1180
|
-
collections {
|
|
1181
|
-
id
|
|
1182
|
-
business_id
|
|
1183
|
-
name
|
|
1184
|
-
slug
|
|
1185
|
-
description
|
|
1186
|
-
image
|
|
1187
|
-
collection_type
|
|
1188
|
-
rules
|
|
1189
|
-
status
|
|
1190
|
-
sort_order
|
|
1191
|
-
created_at
|
|
1192
|
-
updated_at
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
total
|
|
1196
|
-
page
|
|
1197
|
-
page_size
|
|
1198
|
-
total_pages
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
`;
|
|
1202
|
-
var GET_STOREFRONT_NEW = `
|
|
1203
|
-
query GetStorefrontNew($page: Int!, $pageSize: Int!) {
|
|
1204
|
-
storefront_new(page: $page, pageSize: $pageSize) {
|
|
1205
|
-
items {
|
|
1206
|
-
id
|
|
1207
|
-
business_id
|
|
1208
|
-
name
|
|
1209
|
-
slug
|
|
1210
|
-
description
|
|
1211
|
-
brand
|
|
1212
|
-
product_type
|
|
1213
|
-
requires_shipping
|
|
1214
|
-
is_consumable
|
|
1215
|
-
is_bespoke
|
|
1216
|
-
base_price
|
|
1217
|
-
currency
|
|
1218
|
-
sale_price
|
|
1219
|
-
sale_start
|
|
1220
|
-
sale_end
|
|
1221
|
-
images
|
|
1222
|
-
tags
|
|
1223
|
-
custom_fields { label unit required }
|
|
1224
|
-
is_published
|
|
1225
|
-
is_featured
|
|
1226
|
-
is_popular
|
|
1227
|
-
is_new
|
|
1228
|
-
is_temporary
|
|
1229
|
-
digital_file_key
|
|
1230
|
-
download_limit
|
|
1231
|
-
download_expires_at
|
|
1232
|
-
weight_kg
|
|
1233
|
-
length_cm
|
|
1234
|
-
width_cm
|
|
1235
|
-
height_cm
|
|
1236
|
-
created_at
|
|
1237
|
-
updated_at
|
|
1238
|
-
variants {
|
|
1239
|
-
id
|
|
1240
|
-
product_id
|
|
1241
|
-
sku
|
|
1242
|
-
attributes
|
|
1243
|
-
price
|
|
1244
|
-
images
|
|
1245
|
-
weight_kg
|
|
1246
|
-
is_active
|
|
1247
|
-
inventory {
|
|
1248
|
-
id
|
|
1249
|
-
product_id
|
|
1250
|
-
variant_id
|
|
1251
|
-
quantity
|
|
1252
|
-
reserved
|
|
1253
|
-
reorder_point
|
|
1254
|
-
reorder_quantity
|
|
1255
|
-
track_quantity
|
|
1256
|
-
allow_backorder
|
|
1257
|
-
available
|
|
1258
|
-
is_in_stock
|
|
1259
|
-
is_low_stock
|
|
1260
|
-
updated_at
|
|
1261
|
-
}
|
|
1262
|
-
created_at
|
|
1263
|
-
updated_at
|
|
1264
|
-
}
|
|
1265
|
-
collections {
|
|
1266
|
-
id
|
|
1267
|
-
business_id
|
|
1268
|
-
name
|
|
1269
|
-
slug
|
|
1270
|
-
description
|
|
1271
|
-
image
|
|
1272
|
-
collection_type
|
|
1273
|
-
rules
|
|
1274
|
-
status
|
|
1275
|
-
sort_order
|
|
1276
|
-
created_at
|
|
1277
|
-
updated_at
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
total
|
|
1281
|
-
page
|
|
1282
|
-
page_size
|
|
1283
|
-
total_pages
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
`;
|
|
1287
|
-
var GET_STOREFRONT_ON_SALE = `
|
|
1288
|
-
query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
|
|
1289
|
-
storefront_on_sale(page: $page, pageSize: $pageSize) {
|
|
1290
|
-
items {
|
|
1291
|
-
id
|
|
1292
|
-
business_id
|
|
1293
|
-
name
|
|
1294
|
-
slug
|
|
1295
|
-
description
|
|
1296
|
-
brand
|
|
1297
|
-
product_type
|
|
1298
|
-
requires_shipping
|
|
1299
|
-
is_consumable
|
|
1300
|
-
is_bespoke
|
|
1301
|
-
base_price
|
|
1302
|
-
currency
|
|
1303
|
-
sale_price
|
|
1304
|
-
sale_start
|
|
1305
|
-
sale_end
|
|
1306
|
-
images
|
|
1307
|
-
tags
|
|
1308
|
-
custom_fields { label unit required }
|
|
1309
|
-
is_published
|
|
1310
|
-
is_featured
|
|
1311
|
-
is_popular
|
|
1312
|
-
is_new
|
|
1313
|
-
is_temporary
|
|
1314
|
-
digital_file_key
|
|
1315
|
-
download_limit
|
|
1316
|
-
download_expires_at
|
|
1317
|
-
weight_kg
|
|
1318
|
-
length_cm
|
|
1319
|
-
width_cm
|
|
1320
|
-
height_cm
|
|
1321
|
-
created_at
|
|
1322
|
-
updated_at
|
|
1323
|
-
variants {
|
|
1324
|
-
id
|
|
1325
|
-
product_id
|
|
1326
|
-
sku
|
|
1327
|
-
attributes
|
|
1328
|
-
price
|
|
1329
|
-
images
|
|
1330
|
-
weight_kg
|
|
1331
|
-
is_active
|
|
1332
|
-
inventory {
|
|
1333
|
-
id
|
|
1334
|
-
product_id
|
|
1335
|
-
variant_id
|
|
1336
|
-
quantity
|
|
1337
|
-
reserved
|
|
1338
|
-
reorder_point
|
|
1339
|
-
reorder_quantity
|
|
1340
|
-
track_quantity
|
|
1341
|
-
allow_backorder
|
|
1342
|
-
available
|
|
1343
|
-
is_in_stock
|
|
1344
|
-
is_low_stock
|
|
1345
|
-
updated_at
|
|
1346
|
-
}
|
|
1347
|
-
created_at
|
|
1348
|
-
updated_at
|
|
1349
|
-
}
|
|
1350
|
-
collections {
|
|
1351
|
-
id
|
|
1352
|
-
business_id
|
|
1353
|
-
name
|
|
1354
|
-
slug
|
|
1355
|
-
description
|
|
1356
|
-
image
|
|
1357
|
-
collection_type
|
|
1358
|
-
rules
|
|
1359
|
-
status
|
|
1360
|
-
sort_order
|
|
1361
|
-
created_at
|
|
1362
|
-
updated_at
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
total
|
|
1366
|
-
page
|
|
1367
|
-
page_size
|
|
1368
|
-
total_pages
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
`;
|
|
1372
|
-
var GET_STOREFRONT_LOW_STOCK = `
|
|
1373
|
-
query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
|
|
1374
|
-
storefront_low_stock(page: $page, pageSize: $pageSize) {
|
|
1375
|
-
items {
|
|
1376
|
-
id
|
|
1377
|
-
business_id
|
|
1378
|
-
name
|
|
1379
|
-
slug
|
|
1380
|
-
description
|
|
1381
|
-
brand
|
|
1382
|
-
product_type
|
|
1383
|
-
requires_shipping
|
|
1384
|
-
is_consumable
|
|
1385
|
-
is_bespoke
|
|
1386
|
-
base_price
|
|
1387
|
-
currency
|
|
1388
|
-
sale_price
|
|
1389
|
-
sale_start
|
|
1390
|
-
sale_end
|
|
1391
|
-
images
|
|
1392
|
-
tags
|
|
1393
|
-
custom_fields { label unit required }
|
|
1394
|
-
is_published
|
|
1395
|
-
is_featured
|
|
1396
|
-
is_popular
|
|
1397
|
-
is_new
|
|
1398
|
-
is_temporary
|
|
1399
|
-
digital_file_key
|
|
1400
|
-
download_limit
|
|
1401
|
-
download_expires_at
|
|
1402
|
-
weight_kg
|
|
1403
|
-
length_cm
|
|
1404
|
-
width_cm
|
|
1405
|
-
height_cm
|
|
1406
|
-
created_at
|
|
1407
|
-
updated_at
|
|
1408
|
-
variants {
|
|
1409
|
-
id
|
|
1410
|
-
product_id
|
|
1411
|
-
sku
|
|
1412
|
-
attributes
|
|
1413
|
-
price
|
|
1414
|
-
images
|
|
1415
|
-
weight_kg
|
|
1416
|
-
is_active
|
|
1417
|
-
inventory {
|
|
1418
|
-
id
|
|
1419
|
-
product_id
|
|
1420
|
-
variant_id
|
|
1421
|
-
quantity
|
|
1422
|
-
reserved
|
|
1423
|
-
reorder_point
|
|
1424
|
-
reorder_quantity
|
|
1425
|
-
track_quantity
|
|
1426
|
-
allow_backorder
|
|
1427
|
-
available
|
|
1428
|
-
is_in_stock
|
|
1429
|
-
is_low_stock
|
|
1430
|
-
updated_at
|
|
1431
|
-
}
|
|
1432
|
-
created_at
|
|
1433
|
-
updated_at
|
|
1434
|
-
}
|
|
1435
|
-
collections {
|
|
1436
|
-
id
|
|
1437
|
-
business_id
|
|
1438
|
-
name
|
|
1439
|
-
slug
|
|
1440
|
-
description
|
|
1441
|
-
image
|
|
1442
|
-
collection_type
|
|
1443
|
-
rules
|
|
1444
|
-
status
|
|
1445
|
-
sort_order
|
|
1446
|
-
created_at
|
|
1447
|
-
updated_at
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
total
|
|
1451
|
-
page
|
|
1452
|
-
page_size
|
|
1453
|
-
total_pages
|
|
1454
|
-
}
|
|
1250
|
+
if (accessToken) {
|
|
1251
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1455
1252
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
business_id
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
width_cm
|
|
1487
|
-
height_cm
|
|
1488
|
-
created_at
|
|
1489
|
-
updated_at
|
|
1490
|
-
variants {
|
|
1491
|
-
id
|
|
1492
|
-
product_id
|
|
1493
|
-
sku
|
|
1494
|
-
attributes
|
|
1495
|
-
price
|
|
1496
|
-
images
|
|
1497
|
-
weight_kg
|
|
1498
|
-
is_active
|
|
1499
|
-
inventory {
|
|
1500
|
-
id
|
|
1501
|
-
product_id
|
|
1502
|
-
variant_id
|
|
1503
|
-
quantity
|
|
1504
|
-
reserved
|
|
1505
|
-
reorder_point
|
|
1506
|
-
reorder_quantity
|
|
1507
|
-
track_quantity
|
|
1508
|
-
allow_backorder
|
|
1509
|
-
available
|
|
1510
|
-
is_in_stock
|
|
1511
|
-
is_low_stock
|
|
1512
|
-
updated_at
|
|
1513
|
-
}
|
|
1514
|
-
created_at
|
|
1515
|
-
updated_at
|
|
1516
|
-
}
|
|
1517
|
-
collections {
|
|
1518
|
-
id
|
|
1519
|
-
business_id
|
|
1520
|
-
name
|
|
1521
|
-
slug
|
|
1522
|
-
description
|
|
1523
|
-
image
|
|
1524
|
-
collection_type
|
|
1525
|
-
rules
|
|
1526
|
-
status
|
|
1527
|
-
sort_order
|
|
1528
|
-
created_at
|
|
1529
|
-
updated_at
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
total
|
|
1533
|
-
page
|
|
1534
|
-
page_size
|
|
1535
|
-
total_pages
|
|
1253
|
+
return new import_graphql_request.GraphQLClient(resolveGraphQLEndpoint(`${config.backendUrls.store}/graphql`), { headers });
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
// src/generated/graphql.ts
|
|
1257
|
+
var GetStorefrontCollectionsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontCollections" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_collections" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "CollectionFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "CollectionFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Collection" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] };
|
|
1258
|
+
var GetStorefrontCollectionBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontCollectionBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_collection_by_slug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "CollectionFields" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "CollectionFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Collection" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] };
|
|
1259
|
+
var GetStorefrontProductsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontProducts" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "collectionSlug" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "search" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "productType" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_products" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "collectionSlug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "collectionSlug" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "search" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "search" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "productType" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "productType" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1260
|
+
var GetStorefrontProductBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontProductBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_product_by_slug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1261
|
+
var GetStorefrontPopularDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontPopular" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_popular" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1262
|
+
var GetStorefrontFeaturedDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontFeatured" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_featured" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1263
|
+
var GetStorefrontNewDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontNew" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_new" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1264
|
+
var GetStorefrontOnSaleDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontOnSale" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_on_sale" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1265
|
+
var GetStorefrontRecommendedDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontRecommended" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "excludeProductId" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_recommended" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "excludeProductId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "excludeProductId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
|
|
1266
|
+
var GetStorefrontWishlistDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontWishlist" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_wishlist" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "notes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_image" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }] };
|
|
1267
|
+
var CheckInStorefrontWishlistDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CheckInStorefrontWishlist" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "productId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "check_in_storefront_wishlist" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "productId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "productId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "in_wishlist" } }] } }] } }] };
|
|
1268
|
+
|
|
1269
|
+
// src/services/product.service.ts
|
|
1270
|
+
function mapProductType(raw) {
|
|
1271
|
+
switch (raw) {
|
|
1272
|
+
case "PHYSICAL":
|
|
1273
|
+
return "physical" /* PHYSICAL */;
|
|
1274
|
+
case "DIGITAL":
|
|
1275
|
+
return "digital" /* DIGITAL */;
|
|
1276
|
+
case "SERVICE":
|
|
1277
|
+
return "service" /* SERVICE */;
|
|
1278
|
+
case "BESPOKE":
|
|
1279
|
+
return "bespoke" /* BESPOKE */;
|
|
1280
|
+
default: {
|
|
1281
|
+
const _exhaustive = raw;
|
|
1282
|
+
throw new Error(`Unhandled GraphQL ProductType member: ${_exhaustive}`);
|
|
1536
1283
|
}
|
|
1537
1284
|
}
|
|
1538
|
-
|
|
1285
|
+
}
|
|
1286
|
+
function mapCustomFieldType(raw) {
|
|
1287
|
+
if (raw === "text" || raw === "choice") return raw;
|
|
1288
|
+
throw new Error(`Unrecognised custom field field_type from backend: "${raw}"`);
|
|
1289
|
+
}
|
|
1290
|
+
function mapProduct(raw) {
|
|
1291
|
+
return {
|
|
1292
|
+
...raw,
|
|
1293
|
+
product_type: mapProductType(raw.product_type),
|
|
1294
|
+
custom_fields: raw.custom_fields.map((f) => ({
|
|
1295
|
+
...f,
|
|
1296
|
+
unit: f.unit ?? void 0,
|
|
1297
|
+
field_type: mapCustomFieldType(f.field_type)
|
|
1298
|
+
})),
|
|
1299
|
+
description: raw.description ?? void 0,
|
|
1300
|
+
brand: raw.brand ?? void 0,
|
|
1301
|
+
is_physical: raw.is_physical ?? void 0,
|
|
1302
|
+
sale_price: raw.sale_price ?? void 0,
|
|
1303
|
+
sale_start: raw.sale_start ?? void 0,
|
|
1304
|
+
sale_end: raw.sale_end ?? void 0,
|
|
1305
|
+
source_channel_ref_id: raw.source_channel_ref_id ?? void 0,
|
|
1306
|
+
download_limit: raw.download_limit ?? void 0,
|
|
1307
|
+
download_expires_at: raw.download_expires_at ?? void 0,
|
|
1308
|
+
service_type: raw.service_type ?? void 0,
|
|
1309
|
+
service_duration_minutes: raw.service_duration_minutes ?? void 0,
|
|
1310
|
+
service_location_type: raw.service_location_type ?? void 0,
|
|
1311
|
+
service_coverage_radius_km: raw.service_coverage_radius_km ?? void 0,
|
|
1312
|
+
service_max_capacity_per_slot: raw.service_max_capacity_per_slot ?? void 0,
|
|
1313
|
+
service_recurring_interval: raw.service_recurring_interval ?? void 0,
|
|
1314
|
+
length_cm: raw.length_cm ?? void 0,
|
|
1315
|
+
width_cm: raw.width_cm ?? void 0,
|
|
1316
|
+
height_cm: raw.height_cm ?? void 0,
|
|
1317
|
+
average_rating: raw.average_rating ?? void 0,
|
|
1318
|
+
created_at: raw.created_at,
|
|
1319
|
+
updated_at: raw.updated_at,
|
|
1320
|
+
variants: raw.variants.map((v) => ({
|
|
1321
|
+
...v,
|
|
1322
|
+
sku: v.sku ?? void 0,
|
|
1323
|
+
attributes: v.attributes ? JSON.parse(v.attributes) : {},
|
|
1324
|
+
price: v.price ?? void 0,
|
|
1325
|
+
weight_kg: v.weight_kg ?? void 0,
|
|
1326
|
+
inventory: v.inventory ? {
|
|
1327
|
+
...v.inventory,
|
|
1328
|
+
variant_id: v.inventory.variant_id ?? void 0,
|
|
1329
|
+
updated_at: v.inventory.updated_at
|
|
1330
|
+
} : void 0,
|
|
1331
|
+
created_at: v.created_at,
|
|
1332
|
+
updated_at: v.updated_at
|
|
1333
|
+
})),
|
|
1334
|
+
collections: raw.collections.map((c) => ({
|
|
1335
|
+
...c,
|
|
1336
|
+
business_id: c.business_id ?? void 0,
|
|
1337
|
+
description: c.description ?? void 0,
|
|
1338
|
+
image_url: c.image_url ?? void 0,
|
|
1339
|
+
rules: c.rules ?? void 0,
|
|
1340
|
+
created_at: c.created_at,
|
|
1341
|
+
updated_at: c.updated_at
|
|
1342
|
+
}))
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
function mapProductConnection(connection) {
|
|
1346
|
+
return { ...connection, items: connection.items.map(mapProduct) };
|
|
1347
|
+
}
|
|
1539
1348
|
async function getStorefrontProducts(config, params) {
|
|
1540
1349
|
const client = createGraphQLClient(config);
|
|
1541
|
-
const
|
|
1350
|
+
const data = await client.request(GetStorefrontProductsDocument, {
|
|
1542
1351
|
page: params?.page || 1,
|
|
1543
1352
|
pageSize: params?.pageSize || 20,
|
|
1544
1353
|
collectionSlug: params?.collectionSlug,
|
|
1545
|
-
search: params?.search
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
return data.storefront_products;
|
|
1354
|
+
search: params?.search,
|
|
1355
|
+
productType: params?.productType
|
|
1356
|
+
});
|
|
1357
|
+
return mapProductConnection(data.storefront_products);
|
|
1549
1358
|
}
|
|
1550
1359
|
async function getStorefrontProductBySlug(config, slug) {
|
|
1551
1360
|
const client = createGraphQLClient(config);
|
|
1552
|
-
const data = await client.request(
|
|
1553
|
-
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
const variables = {
|
|
1558
|
-
page: params?.page || 1,
|
|
1559
|
-
pageSize: params?.pageSize || 4
|
|
1560
|
-
};
|
|
1561
|
-
const data = await client.request(GET_STOREFRONT_LATEST, variables);
|
|
1562
|
-
return data.storefront_latest;
|
|
1361
|
+
const data = await client.request(GetStorefrontProductBySlugDocument, { slug });
|
|
1362
|
+
if (!data.storefront_product_by_slug) {
|
|
1363
|
+
throw new Error(`Product not found: ${slug}`);
|
|
1364
|
+
}
|
|
1365
|
+
return mapProduct(data.storefront_product_by_slug);
|
|
1563
1366
|
}
|
|
1564
1367
|
async function getPopularProducts(config, params) {
|
|
1565
1368
|
const client = createGraphQLClient(config);
|
|
1566
|
-
const
|
|
1369
|
+
const data = await client.request(GetStorefrontPopularDocument, {
|
|
1567
1370
|
page: params?.page || 1,
|
|
1568
1371
|
pageSize: params?.pageSize || 4
|
|
1569
|
-
};
|
|
1570
|
-
|
|
1571
|
-
return data.storefront_popular;
|
|
1372
|
+
});
|
|
1373
|
+
return mapProductConnection(data.storefront_popular);
|
|
1572
1374
|
}
|
|
1573
1375
|
async function getFeaturedProducts(config, params) {
|
|
1574
1376
|
const client = createGraphQLClient(config);
|
|
1575
|
-
const
|
|
1377
|
+
const data = await client.request(GetStorefrontFeaturedDocument, {
|
|
1576
1378
|
page: params?.page || 1,
|
|
1577
1379
|
pageSize: params?.pageSize || 4
|
|
1578
|
-
};
|
|
1579
|
-
|
|
1580
|
-
return data.storefront_featured;
|
|
1380
|
+
});
|
|
1381
|
+
return mapProductConnection(data.storefront_featured);
|
|
1581
1382
|
}
|
|
1582
1383
|
async function getNewProducts(config, params) {
|
|
1583
1384
|
const client = createGraphQLClient(config);
|
|
1584
|
-
const
|
|
1385
|
+
const data = await client.request(GetStorefrontNewDocument, {
|
|
1585
1386
|
page: params?.page || 1,
|
|
1586
1387
|
pageSize: params?.pageSize || 4
|
|
1587
|
-
};
|
|
1588
|
-
|
|
1589
|
-
return data.storefront_new;
|
|
1388
|
+
});
|
|
1389
|
+
return mapProductConnection(data.storefront_new);
|
|
1590
1390
|
}
|
|
1591
1391
|
async function getOnSaleProducts(config, params) {
|
|
1592
1392
|
const client = createGraphQLClient(config);
|
|
1593
|
-
const
|
|
1393
|
+
const data = await client.request(GetStorefrontOnSaleDocument, {
|
|
1594
1394
|
page: params?.page || 1,
|
|
1595
1395
|
pageSize: params?.pageSize || 4
|
|
1596
|
-
};
|
|
1597
|
-
|
|
1598
|
-
return data.storefront_on_sale;
|
|
1599
|
-
}
|
|
1600
|
-
async function getLowStockProducts(config, params) {
|
|
1601
|
-
const client = createGraphQLClient(config);
|
|
1602
|
-
const variables = {
|
|
1603
|
-
page: params?.page || 1,
|
|
1604
|
-
pageSize: params?.pageSize || 4
|
|
1605
|
-
};
|
|
1606
|
-
const data = await client.request(GET_STOREFRONT_LOW_STOCK, variables);
|
|
1607
|
-
return data.storefront_low_stock;
|
|
1396
|
+
});
|
|
1397
|
+
return mapProductConnection(data.storefront_on_sale);
|
|
1608
1398
|
}
|
|
1609
1399
|
async function getRecommendedProducts(config, params) {
|
|
1610
1400
|
const client = createGraphQLClient(config);
|
|
1611
|
-
const
|
|
1401
|
+
const data = await client.request(GetStorefrontRecommendedDocument, {
|
|
1612
1402
|
page: params?.page || 1,
|
|
1613
1403
|
pageSize: params?.pageSize || 4,
|
|
1614
1404
|
excludeProductId: params?.excludeProductId
|
|
1615
|
-
};
|
|
1616
|
-
|
|
1617
|
-
return data.storefront_recommended;
|
|
1405
|
+
});
|
|
1406
|
+
return mapProductConnection(data.storefront_recommended);
|
|
1618
1407
|
}
|
|
1619
1408
|
|
|
1620
1409
|
// src/services/collection.service.ts
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
description
|
|
1631
|
-
image
|
|
1632
|
-
collection_type
|
|
1633
|
-
rules
|
|
1634
|
-
status
|
|
1635
|
-
sort_order
|
|
1636
|
-
created_at
|
|
1637
|
-
updated_at
|
|
1638
|
-
}
|
|
1639
|
-
total
|
|
1640
|
-
page
|
|
1641
|
-
page_size
|
|
1642
|
-
total_pages
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
`;
|
|
1646
|
-
var GET_STOREFRONT_COLLECTION_BY_SLUG = `
|
|
1647
|
-
query GetStorefrontCollectionBySlug($slug: String!) {
|
|
1648
|
-
storefront_collection_by_slug(slug: $slug) {
|
|
1649
|
-
id
|
|
1650
|
-
business_id
|
|
1651
|
-
name
|
|
1652
|
-
slug
|
|
1653
|
-
description
|
|
1654
|
-
image
|
|
1655
|
-
collection_type
|
|
1656
|
-
rules
|
|
1657
|
-
status
|
|
1658
|
-
sort_order
|
|
1659
|
-
created_at
|
|
1660
|
-
updated_at
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
|
-
`;
|
|
1664
|
-
function createGraphQLClient2(config) {
|
|
1665
|
-
const headers = {
|
|
1666
|
-
"Content-Type": "application/json",
|
|
1667
|
-
"Accept": "application/json",
|
|
1668
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1669
|
-
"X-Business-ID": config.businessId
|
|
1410
|
+
function mapCollection(raw) {
|
|
1411
|
+
return {
|
|
1412
|
+
...raw,
|
|
1413
|
+
business_id: raw.business_id ?? void 0,
|
|
1414
|
+
description: raw.description ?? void 0,
|
|
1415
|
+
image_url: raw.image_url ?? void 0,
|
|
1416
|
+
rules: raw.rules ?? void 0,
|
|
1417
|
+
created_at: raw.created_at,
|
|
1418
|
+
updated_at: raw.updated_at
|
|
1670
1419
|
};
|
|
1671
|
-
return new import_graphql_request2.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
1672
1420
|
}
|
|
1673
1421
|
async function getStorefrontCollections(config, params) {
|
|
1674
|
-
const client =
|
|
1675
|
-
const
|
|
1422
|
+
const client = createGraphQLClient(config);
|
|
1423
|
+
const data = await client.request(GetStorefrontCollectionsDocument, {
|
|
1676
1424
|
page: params?.page || 1,
|
|
1677
1425
|
pageSize: params?.pageSize || 20
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
return data.storefront_collections;
|
|
1426
|
+
});
|
|
1427
|
+
return { ...data.storefront_collections, items: data.storefront_collections.items.map(mapCollection) };
|
|
1681
1428
|
}
|
|
1682
1429
|
async function getStorefrontCollectionBySlug(config, slug) {
|
|
1683
|
-
const client =
|
|
1684
|
-
const data = await client.request(
|
|
1685
|
-
|
|
1430
|
+
const client = createGraphQLClient(config);
|
|
1431
|
+
const data = await client.request(GetStorefrontCollectionBySlugDocument, { slug });
|
|
1432
|
+
if (!data.storefront_collection_by_slug) {
|
|
1433
|
+
throw new Error(`Collection not found: ${slug}`);
|
|
1434
|
+
}
|
|
1435
|
+
return mapCollection(data.storefront_collection_by_slug);
|
|
1686
1436
|
}
|
|
1687
1437
|
|
|
1688
1438
|
// src/services/wishlist.service.ts
|
|
1689
|
-
var import_graphql_request3 = require("graphql-request");
|
|
1690
|
-
var GET_STOREFRONT_WISHLIST = `
|
|
1691
|
-
query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
|
|
1692
|
-
storefront_wishlist(page: $page, pageSize: $pageSize) {
|
|
1693
|
-
items {
|
|
1694
|
-
id
|
|
1695
|
-
product_id
|
|
1696
|
-
notes
|
|
1697
|
-
created_at
|
|
1698
|
-
product_name
|
|
1699
|
-
product_slug
|
|
1700
|
-
product_price
|
|
1701
|
-
currency
|
|
1702
|
-
product_image
|
|
1703
|
-
}
|
|
1704
|
-
total
|
|
1705
|
-
page
|
|
1706
|
-
page_size
|
|
1707
|
-
total_pages
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
`;
|
|
1711
|
-
var CHECK_IN_STOREFRONT_WISHLIST = `
|
|
1712
|
-
query CheckInStorefrontWishlist($productId: String!) {
|
|
1713
|
-
check_in_storefront_wishlist(productId: $productId) {
|
|
1714
|
-
in_wishlist
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
`;
|
|
1718
|
-
function createGraphQLClient3(config, accessToken) {
|
|
1719
|
-
const headers = {
|
|
1720
|
-
"Content-Type": "application/json",
|
|
1721
|
-
"Accept": "application/json",
|
|
1722
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1723
|
-
"X-Business-ID": config.businessId
|
|
1724
|
-
};
|
|
1725
|
-
if (accessToken) {
|
|
1726
|
-
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1727
|
-
}
|
|
1728
|
-
return new import_graphql_request3.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
1729
|
-
}
|
|
1730
1439
|
async function getWishlist(config, accessToken, params) {
|
|
1731
|
-
const client =
|
|
1732
|
-
const
|
|
1440
|
+
const client = createGraphQLClient(config, accessToken);
|
|
1441
|
+
const data = await client.request(GetStorefrontWishlistDocument, {
|
|
1733
1442
|
page: params?.page || 1,
|
|
1734
1443
|
pageSize: params?.pageSize || 20
|
|
1444
|
+
});
|
|
1445
|
+
return {
|
|
1446
|
+
...data.storefront_wishlist,
|
|
1447
|
+
items: data.storefront_wishlist.items.map((item) => ({
|
|
1448
|
+
...item,
|
|
1449
|
+
created_at: item.created_at,
|
|
1450
|
+
notes: item.notes ?? void 0,
|
|
1451
|
+
product_name: item.product_name ?? void 0,
|
|
1452
|
+
product_slug: item.product_slug ?? void 0,
|
|
1453
|
+
product_price: item.product_price ?? void 0,
|
|
1454
|
+
currency: item.currency ?? void 0,
|
|
1455
|
+
product_image: item.product_image ?? void 0
|
|
1456
|
+
}))
|
|
1735
1457
|
};
|
|
1736
|
-
const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
|
|
1737
|
-
return data.storefront_wishlist;
|
|
1738
1458
|
}
|
|
1739
1459
|
async function checkInWishlist(config, accessToken, productId) {
|
|
1740
|
-
const client =
|
|
1741
|
-
const data = await client.request(
|
|
1460
|
+
const client = createGraphQLClient(config, accessToken);
|
|
1461
|
+
const data = await client.request(CheckInStorefrontWishlistDocument, { productId });
|
|
1742
1462
|
return data.check_in_storefront_wishlist;
|
|
1743
1463
|
}
|
|
1744
1464
|
async function addToWishlist(config, accessToken, productId, notes) {
|
|
1745
|
-
|
|
1465
|
+
return apiRequest(`${config.backendUrls.store}/wishlist/`, {
|
|
1746
1466
|
method: "POST",
|
|
1747
|
-
headers: {
|
|
1748
|
-
"Content-Type": "application/json",
|
|
1749
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1750
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1751
|
-
"X-Business-ID": config.businessId
|
|
1752
|
-
},
|
|
1467
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1753
1468
|
body: JSON.stringify({
|
|
1754
1469
|
product_id: productId,
|
|
1755
1470
|
notes: notes || void 0
|
|
1756
|
-
})
|
|
1471
|
+
}),
|
|
1472
|
+
fallbackErrorMessage: "Failed to add to wishlist"
|
|
1757
1473
|
});
|
|
1758
|
-
if (!response.ok) throw new Error("Failed to add to wishlist");
|
|
1759
|
-
return response.json();
|
|
1760
1474
|
}
|
|
1761
1475
|
async function removeFromWishlist(config, accessToken, itemId) {
|
|
1762
|
-
|
|
1476
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/${itemId}`, {
|
|
1763
1477
|
method: "DELETE",
|
|
1764
|
-
headers:
|
|
1765
|
-
|
|
1766
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1767
|
-
"X-Business-ID": config.businessId
|
|
1768
|
-
}
|
|
1478
|
+
headers: authHeaders(config, accessToken),
|
|
1479
|
+
fallbackErrorMessage: "Failed to remove from wishlist"
|
|
1769
1480
|
});
|
|
1770
|
-
if (!response.ok) throw new Error("Failed to remove from wishlist");
|
|
1771
1481
|
}
|
|
1772
1482
|
async function removeProductFromWishlist(config, accessToken, productId) {
|
|
1773
|
-
|
|
1483
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/product/${productId}`, {
|
|
1774
1484
|
method: "DELETE",
|
|
1775
|
-
headers:
|
|
1776
|
-
|
|
1777
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1778
|
-
"X-Business-ID": config.businessId
|
|
1779
|
-
}
|
|
1485
|
+
headers: authHeaders(config, accessToken),
|
|
1486
|
+
fallbackErrorMessage: "Failed to remove product from wishlist"
|
|
1780
1487
|
});
|
|
1781
|
-
if (!response.ok) throw new Error("Failed to remove product from wishlist");
|
|
1782
1488
|
}
|
|
1783
1489
|
|
|
1784
1490
|
// src/services/payment.service.ts
|
|
1491
|
+
function isValidUUID(str) {
|
|
1492
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
1493
|
+
}
|
|
1494
|
+
async function getAvailablePaymentMethods(config, currency, countryCode) {
|
|
1495
|
+
const params = {};
|
|
1496
|
+
if (currency) params.currency = currency;
|
|
1497
|
+
if (countryCode) params.country_code = countryCode;
|
|
1498
|
+
const query = new URLSearchParams(params).toString();
|
|
1499
|
+
return apiRequest(`${config.backendUrls.payment}/payments/storefront/methods${query ? `?${query}` : ""}`, {
|
|
1500
|
+
headers: storefrontHeaders(config),
|
|
1501
|
+
fallbackErrorMessage: "Failed to fetch available payment methods"
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1785
1504
|
async function createDedicatedAccount(config, accessToken, request) {
|
|
1786
|
-
const
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1505
|
+
const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
|
|
1506
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
1507
|
+
if (accessToken) {
|
|
1508
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1509
|
+
}
|
|
1510
|
+
if (origin) {
|
|
1511
|
+
headers["Origin"] = origin;
|
|
1512
|
+
}
|
|
1513
|
+
return apiRequest(`${config.backendUrls.payment}/payments/storefront/dedicated-account`, {
|
|
1791
1514
|
method: "POST",
|
|
1792
|
-
headers
|
|
1793
|
-
"Content-Type": "application/json",
|
|
1794
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1795
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1796
|
-
"X-Business-ID": config.businessId
|
|
1797
|
-
},
|
|
1515
|
+
headers,
|
|
1798
1516
|
body: JSON.stringify({
|
|
1799
1517
|
order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
|
|
1800
1518
|
amount: request.amount,
|
|
1801
1519
|
customer_email: request.customer_email,
|
|
1802
1520
|
customer_name: request.customer_name,
|
|
1803
1521
|
currency: request.currency,
|
|
1522
|
+
gateway: request.gateway,
|
|
1804
1523
|
idempotency_key: request.idempotency_key
|
|
1805
|
-
})
|
|
1524
|
+
}),
|
|
1525
|
+
fallbackErrorMessage: "Failed to create dedicated account"
|
|
1806
1526
|
});
|
|
1807
|
-
if (!response.ok) throw new Error("Failed to create dedicated account");
|
|
1808
|
-
const data = await response.json();
|
|
1809
|
-
return data;
|
|
1810
1527
|
}
|
|
1811
1528
|
async function initiatePayment(config, accessToken, request) {
|
|
1812
|
-
const isValidUUID = (str) => {
|
|
1813
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1814
|
-
return uuidRegex.test(str);
|
|
1815
|
-
};
|
|
1816
1529
|
const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1530
|
+
const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
|
|
1531
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
1532
|
+
if (accessToken) {
|
|
1533
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1534
|
+
}
|
|
1535
|
+
if (origin) {
|
|
1536
|
+
headers["Origin"] = origin;
|
|
1537
|
+
}
|
|
1538
|
+
const data = await apiRequest(
|
|
1539
|
+
`${config.backendUrls.payment}/payments/storefront/initiate`,
|
|
1540
|
+
{
|
|
1541
|
+
method: "POST",
|
|
1542
|
+
headers,
|
|
1543
|
+
body: JSON.stringify({
|
|
1544
|
+
amount: request.amount,
|
|
1545
|
+
currency: request.currency,
|
|
1546
|
+
// Same real backend default as getAvailablePaymentMethods above
|
|
1547
|
+
// (huma's own `default:"NG"` on this field) — omit rather than
|
|
1548
|
+
// hardcode a client-side copy of it.
|
|
1549
|
+
country_code: request.country_code,
|
|
1550
|
+
gateway: request.gateway,
|
|
1833
1551
|
order_id: validOrderId,
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1552
|
+
quote_id: request.quote_id,
|
|
1553
|
+
metadata_json: {
|
|
1554
|
+
customer_email: request.customer_email,
|
|
1555
|
+
customer_name: request.customer_name ?? "",
|
|
1556
|
+
order_id: validOrderId,
|
|
1557
|
+
...request.metadata ?? {}
|
|
1558
|
+
},
|
|
1559
|
+
idempotency_key: request.idempotency_key
|
|
1560
|
+
}),
|
|
1561
|
+
fallbackErrorMessage: "Failed to initiate payment"
|
|
1562
|
+
}
|
|
1563
|
+
);
|
|
1841
1564
|
return {
|
|
1842
1565
|
id: data.id,
|
|
1843
1566
|
gateway_ref: data.gateway_ref,
|
|
@@ -1846,311 +1569,241 @@ async function initiatePayment(config, accessToken, request) {
|
|
|
1846
1569
|
checkout_url: data.metadata_json?.checkout_url ?? ""
|
|
1847
1570
|
};
|
|
1848
1571
|
}
|
|
1849
|
-
async function
|
|
1850
|
-
|
|
1572
|
+
async function verifyTransaction(config, reference) {
|
|
1573
|
+
return apiRequest(`${config.backendUrls.payment}/payments/verify/${reference}`, {
|
|
1851
1574
|
method: "POST",
|
|
1852
|
-
headers: {
|
|
1853
|
-
|
|
1854
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1855
|
-
"X-Business-ID": config.businessId
|
|
1856
|
-
},
|
|
1857
|
-
body: JSON.stringify({ amount })
|
|
1575
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1576
|
+
fallbackErrorMessage: "Failed to verify transaction"
|
|
1858
1577
|
});
|
|
1859
|
-
if (!response.ok) throw new Error("Failed to request quote");
|
|
1860
|
-
const data = await response.json();
|
|
1861
|
-
return data;
|
|
1862
1578
|
}
|
|
1863
|
-
async function
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
method: "POST",
|
|
1868
|
-
headers: { "Content-Type": "application/json" }
|
|
1869
|
-
});
|
|
1870
|
-
if (!response2.ok) throw new Error("Failed to verify transaction");
|
|
1871
|
-
return response2.json();
|
|
1872
|
-
}
|
|
1873
|
-
const config = configOrReference;
|
|
1874
|
-
const ref = reference || "";
|
|
1875
|
-
const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
|
|
1876
|
-
method: "POST",
|
|
1877
|
-
headers: {
|
|
1878
|
-
"Content-Type": "application/json",
|
|
1879
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1880
|
-
"X-Business-ID": config.businessId
|
|
1881
|
-
}
|
|
1579
|
+
async function getTransactionStatus(config, transactionId) {
|
|
1580
|
+
return apiRequest(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
|
|
1581
|
+
headers: storefrontHeaders(config),
|
|
1582
|
+
fallbackErrorMessage: "Failed to get transaction status"
|
|
1882
1583
|
});
|
|
1883
|
-
if (!response.ok) throw new Error("Failed to verify transaction");
|
|
1884
|
-
const data = await response.json();
|
|
1885
|
-
return data;
|
|
1886
1584
|
}
|
|
1887
|
-
async function
|
|
1888
|
-
|
|
1889
|
-
headers:
|
|
1890
|
-
|
|
1891
|
-
|
|
1585
|
+
async function getWalletBalance(config, accessToken) {
|
|
1586
|
+
return apiRequest(`${config.backendUrls.payment}/wallet/balance`, {
|
|
1587
|
+
headers: authHeaders(config, accessToken),
|
|
1588
|
+
fallbackErrorMessage: "Failed to fetch wallet balance"
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
async function getWalletLedger(config, accessToken, params) {
|
|
1592
|
+
const page = params?.page ?? 1;
|
|
1593
|
+
const pageSize = params?.page_size ?? 20;
|
|
1594
|
+
return apiRequest(
|
|
1595
|
+
`${config.backendUrls.payment}/wallet/ledger?page=${page}&page_size=${pageSize}`,
|
|
1596
|
+
{
|
|
1597
|
+
headers: authHeaders(config, accessToken),
|
|
1598
|
+
fallbackErrorMessage: "Failed to fetch wallet ledger"
|
|
1892
1599
|
}
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
async function claimWalletCredit(config, accessToken, claimToken) {
|
|
1603
|
+
return apiRequest(`${config.backendUrls.payment}/wallet/claim`, {
|
|
1604
|
+
method: "POST",
|
|
1605
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1606
|
+
body: JSON.stringify({ claim_token: claimToken }),
|
|
1607
|
+
fallbackErrorMessage: "Failed to claim wallet credit"
|
|
1893
1608
|
});
|
|
1894
|
-
if (!response.ok) throw new Error("Failed to get transaction status");
|
|
1895
|
-
const data = await response.json();
|
|
1896
|
-
return data;
|
|
1897
1609
|
}
|
|
1898
1610
|
var paymentService = {
|
|
1611
|
+
getAvailablePaymentMethods,
|
|
1899
1612
|
createDedicatedAccount,
|
|
1900
1613
|
initiatePayment,
|
|
1901
|
-
requestQuote,
|
|
1902
1614
|
verifyTransaction,
|
|
1903
|
-
getTransactionStatus
|
|
1615
|
+
getTransactionStatus,
|
|
1616
|
+
getWalletBalance,
|
|
1617
|
+
getWalletLedger,
|
|
1618
|
+
claimWalletCredit
|
|
1904
1619
|
};
|
|
1905
1620
|
|
|
1906
|
-
// src/services/
|
|
1907
|
-
async function
|
|
1908
|
-
|
|
1621
|
+
// src/services/logistics.service.ts
|
|
1622
|
+
async function getShippingRates(config, payload) {
|
|
1623
|
+
return apiRequest(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
1909
1624
|
method: "POST",
|
|
1910
|
-
headers: {
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1914
|
-
"X-Business-ID": config.businessId
|
|
1915
|
-
},
|
|
1916
|
-
body: JSON.stringify(payload)
|
|
1625
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1626
|
+
body: JSON.stringify(payload),
|
|
1627
|
+
fallbackErrorMessage: "Failed to get shipping rates"
|
|
1917
1628
|
});
|
|
1918
|
-
if (!response.ok) throw new Error("Failed to create consultation");
|
|
1919
|
-
return response.json();
|
|
1920
1629
|
}
|
|
1921
|
-
async function
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
}
|
|
1630
|
+
async function validateShippingAddress(config, payload) {
|
|
1631
|
+
return apiRequest(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
|
|
1632
|
+
method: "POST",
|
|
1633
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1634
|
+
body: JSON.stringify(payload),
|
|
1635
|
+
fallbackErrorMessage: "Failed to validate shipping address"
|
|
1928
1636
|
});
|
|
1929
|
-
if (!response.ok) throw new Error("Failed to get consultations");
|
|
1930
|
-
return response.json();
|
|
1931
1637
|
}
|
|
1932
|
-
async function
|
|
1933
|
-
const
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1638
|
+
async function fetchLocationList(config, path, coords, fallbackErrorMessage) {
|
|
1639
|
+
const params = new URLSearchParams();
|
|
1640
|
+
if (coords) {
|
|
1641
|
+
params.set("latitude", String(coords.latitude));
|
|
1642
|
+
params.set("longitude", String(coords.longitude));
|
|
1643
|
+
}
|
|
1644
|
+
const qs = params.toString();
|
|
1645
|
+
return apiRequest(`${config.backendUrls.store}/logistics/${path}${qs ? `?${qs}` : ""}`, {
|
|
1646
|
+
headers: storefrontHeaders(config),
|
|
1647
|
+
fallbackErrorMessage
|
|
1939
1648
|
});
|
|
1940
|
-
if (!response.ok) throw new Error("Failed to get consultation");
|
|
1941
|
-
return response.json();
|
|
1942
1649
|
}
|
|
1943
|
-
async function
|
|
1944
|
-
|
|
1945
|
-
method: "POST",
|
|
1946
|
-
headers: {
|
|
1947
|
-
"Content-Type": "application/json",
|
|
1948
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1949
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1950
|
-
"X-Business-ID": config.businessId
|
|
1951
|
-
},
|
|
1952
|
-
body: JSON.stringify(payload)
|
|
1953
|
-
});
|
|
1650
|
+
async function listPickupLocations(config, coords) {
|
|
1651
|
+
return fetchLocationList(config, "pickup-locations", coords, "Failed to list pickup locations");
|
|
1954
1652
|
}
|
|
1955
|
-
async function
|
|
1956
|
-
|
|
1957
|
-
method: "POST",
|
|
1958
|
-
headers: {
|
|
1959
|
-
"Content-Type": "application/json",
|
|
1960
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1961
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1962
|
-
"X-Business-ID": config.businessId
|
|
1963
|
-
},
|
|
1964
|
-
body: JSON.stringify(payload)
|
|
1965
|
-
});
|
|
1966
|
-
if (!response.ok) throw new Error("Failed to accept quote");
|
|
1967
|
-
return response.json();
|
|
1653
|
+
async function listBusinessLocations(config, coords) {
|
|
1654
|
+
return fetchLocationList(config, "locations", coords, "Failed to list business locations");
|
|
1968
1655
|
}
|
|
1969
|
-
async function
|
|
1970
|
-
|
|
1656
|
+
async function reverseGeocode(config, payload) {
|
|
1657
|
+
return apiRequest(`${config.backendUrls.store}/logistics/reverse-geocode`, {
|
|
1971
1658
|
method: "POST",
|
|
1972
|
-
headers: {
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1976
|
-
"X-Business-ID": config.businessId
|
|
1977
|
-
},
|
|
1978
|
-
body: JSON.stringify({ reason })
|
|
1659
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1660
|
+
body: JSON.stringify(payload),
|
|
1661
|
+
fallbackErrorMessage: "Failed to reverse geocode coordinates"
|
|
1979
1662
|
});
|
|
1980
|
-
if (!response.ok) throw new Error("Failed to reject quote");
|
|
1981
|
-
return response.json();
|
|
1982
1663
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
getConsultations,
|
|
1986
|
-
getConsultation,
|
|
1987
|
-
sendMessage,
|
|
1988
|
-
acceptQuote,
|
|
1989
|
-
rejectQuote
|
|
1990
|
-
};
|
|
1991
|
-
|
|
1992
|
-
// src/services/logistics.service.ts
|
|
1993
|
-
async function getShippingRates(config, payload) {
|
|
1994
|
-
const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
1664
|
+
async function decodePlusCode(config, payload) {
|
|
1665
|
+
return apiRequest(`${config.backendUrls.store}/logistics/plus-code/decode`, {
|
|
1995
1666
|
method: "POST",
|
|
1996
|
-
headers: {
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
"X-Business-ID": config.businessId
|
|
2000
|
-
},
|
|
2001
|
-
body: JSON.stringify(payload)
|
|
2002
|
-
});
|
|
2003
|
-
if (!response.ok) throw new Error("Failed to get shipping rates");
|
|
2004
|
-
return response.json();
|
|
2005
|
-
}
|
|
2006
|
-
async function getSellerShippingAddress(config) {
|
|
2007
|
-
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
|
|
2008
|
-
headers: {
|
|
2009
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2010
|
-
"X-Business-ID": config.businessId
|
|
2011
|
-
}
|
|
1667
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1668
|
+
body: JSON.stringify(payload),
|
|
1669
|
+
fallbackErrorMessage: "Failed to decode Plus Code"
|
|
2012
1670
|
});
|
|
2013
|
-
if (!response.ok) throw new Error("Failed to get seller shipping address");
|
|
2014
|
-
return response.json();
|
|
2015
1671
|
}
|
|
2016
|
-
async function
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
},
|
|
2024
|
-
body: JSON.stringify(payload)
|
|
1672
|
+
async function autocompleteAddress(config, q, country) {
|
|
1673
|
+
const params = new URLSearchParams();
|
|
1674
|
+
params.set("q", q);
|
|
1675
|
+
if (country) params.set("country", country);
|
|
1676
|
+
return apiRequest(`${config.backendUrls.store}/logistics/address/autocomplete?${params.toString()}`, {
|
|
1677
|
+
headers: storefrontHeaders(config),
|
|
1678
|
+
fallbackErrorMessage: "Failed to autocomplete address"
|
|
2025
1679
|
});
|
|
2026
|
-
if (!response.ok) throw new Error("Failed to validate shipping address");
|
|
2027
|
-
return response.json();
|
|
2028
1680
|
}
|
|
2029
1681
|
var logisticsService = {
|
|
2030
1682
|
getShippingRates,
|
|
2031
|
-
|
|
2032
|
-
|
|
1683
|
+
validateShippingAddress,
|
|
1684
|
+
listPickupLocations,
|
|
1685
|
+
listBusinessLocations,
|
|
1686
|
+
reverseGeocode,
|
|
1687
|
+
decodePlusCode,
|
|
1688
|
+
autocompleteAddress
|
|
2033
1689
|
};
|
|
2034
1690
|
|
|
2035
1691
|
// src/services/bespoke.service.ts
|
|
2036
1692
|
async function checkAvailability(config, product_id) {
|
|
2037
|
-
|
|
2038
|
-
headers:
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
1693
|
+
return apiRequest(`${config.backendUrls.store}/bespoke/capacity/availability/${product_id}`, {
|
|
1694
|
+
headers: storefrontHeaders(config),
|
|
1695
|
+
fallbackErrorMessage: "Failed to check bespoke availability"
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
async function approveBespokeDeliverable(config, accessToken, orderId) {
|
|
1699
|
+
return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/approve`, {
|
|
1700
|
+
method: "POST",
|
|
1701
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1702
|
+
body: JSON.stringify({}),
|
|
1703
|
+
fallbackErrorMessage: "Failed to approve deliverable"
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
async function requestBespokeRevision(config, accessToken, orderId, notes) {
|
|
1707
|
+
return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/request-revision`, {
|
|
1708
|
+
method: "POST",
|
|
1709
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1710
|
+
body: JSON.stringify({ notes }),
|
|
1711
|
+
fallbackErrorMessage: "Failed to request revision"
|
|
2042
1712
|
});
|
|
2043
|
-
if (!response.ok) throw new Error("Failed to check bespoke availability");
|
|
2044
|
-
return response.json();
|
|
2045
1713
|
}
|
|
2046
1714
|
var bespokeService = {
|
|
2047
|
-
checkAvailability
|
|
1715
|
+
checkAvailability,
|
|
1716
|
+
approveBespokeDeliverable,
|
|
1717
|
+
requestBespokeRevision
|
|
2048
1718
|
};
|
|
2049
1719
|
|
|
2050
1720
|
// src/services/service-booking.service.ts
|
|
2051
|
-
async function getAvailableSlots(config,
|
|
2052
|
-
const
|
|
2053
|
-
|
|
1721
|
+
async function getAvailableSlots(config, productId, date, params) {
|
|
1722
|
+
const query = new URLSearchParams({ date });
|
|
1723
|
+
if (params?.staffId) query.set("staff_id", params.staffId);
|
|
1724
|
+
if (params?.locationId) query.set("location_id", params.locationId);
|
|
1725
|
+
if (params?.customerLatitude !== void 0) query.set("customer_latitude", String(params.customerLatitude));
|
|
1726
|
+
if (params?.customerLongitude !== void 0) query.set("customer_longitude", String(params.customerLongitude));
|
|
1727
|
+
return apiRequest(
|
|
1728
|
+
`${config.backendUrls.store}/catalog/products/${productId}/available-slots?${query.toString()}`,
|
|
2054
1729
|
{
|
|
2055
|
-
headers:
|
|
2056
|
-
|
|
2057
|
-
"X-Business-ID": config.businessId
|
|
2058
|
-
}
|
|
1730
|
+
headers: storefrontHeaders(config),
|
|
1731
|
+
fallbackErrorMessage: "Failed to get available slots"
|
|
2059
1732
|
}
|
|
2060
1733
|
);
|
|
2061
|
-
if (!response.ok) throw new Error("Failed to get available slots");
|
|
2062
|
-
return response.json();
|
|
2063
1734
|
}
|
|
2064
1735
|
async function bookAppointment(config, accessToken, payload) {
|
|
2065
|
-
|
|
1736
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/schedule`, {
|
|
2066
1737
|
method: "POST",
|
|
2067
|
-
headers: {
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2071
|
-
"X-Business-ID": config.businessId
|
|
2072
|
-
},
|
|
2073
|
-
body: JSON.stringify(payload)
|
|
1738
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1739
|
+
body: JSON.stringify(payload),
|
|
1740
|
+
fallbackErrorMessage: "Failed to book appointment"
|
|
2074
1741
|
});
|
|
2075
|
-
if (!response.ok) throw new Error("Failed to book appointment");
|
|
2076
|
-
return response.json();
|
|
2077
1742
|
}
|
|
2078
|
-
async function getAppointments(config, accessToken) {
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
1743
|
+
async function getAppointments(config, accessToken, params) {
|
|
1744
|
+
const query = new URLSearchParams();
|
|
1745
|
+
if (params?.status) query.set("status", params.status);
|
|
1746
|
+
if (params?.page) query.set("page", String(params.page));
|
|
1747
|
+
if (params?.page_size) query.set("page_size", String(params.page_size));
|
|
1748
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/my?${query.toString()}`, {
|
|
1749
|
+
headers: authHeaders(config, accessToken),
|
|
1750
|
+
fallbackErrorMessage: "Failed to get appointments"
|
|
2085
1751
|
});
|
|
2086
|
-
if (!response.ok) throw new Error("Failed to get appointments");
|
|
2087
|
-
return response.json();
|
|
2088
1752
|
}
|
|
2089
1753
|
async function getAppointment(config, accessToken, id) {
|
|
2090
|
-
|
|
2091
|
-
headers:
|
|
2092
|
-
|
|
2093
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2094
|
-
"X-Business-ID": config.businessId
|
|
2095
|
-
}
|
|
1754
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}`, {
|
|
1755
|
+
headers: authHeaders(config, accessToken),
|
|
1756
|
+
fallbackErrorMessage: "Failed to get appointment"
|
|
2096
1757
|
});
|
|
2097
|
-
if (!response.ok) throw new Error("Failed to get appointment");
|
|
2098
|
-
return response.json();
|
|
2099
1758
|
}
|
|
2100
|
-
async function cancelAppointment(config, accessToken, id) {
|
|
2101
|
-
|
|
2102
|
-
method: "
|
|
2103
|
-
headers: {
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
"X-Business-ID": config.businessId
|
|
2107
|
-
}
|
|
1759
|
+
async function cancelAppointment(config, accessToken, id, payload) {
|
|
1760
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/cancel`, {
|
|
1761
|
+
method: "POST",
|
|
1762
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1763
|
+
body: JSON.stringify(payload ?? {}),
|
|
1764
|
+
fallbackErrorMessage: "Failed to cancel appointment"
|
|
2108
1765
|
});
|
|
2109
1766
|
}
|
|
2110
|
-
async function
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
}
|
|
1767
|
+
async function rescheduleAppointment(config, accessToken, id, payload) {
|
|
1768
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/reschedule`, {
|
|
1769
|
+
method: "POST",
|
|
1770
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1771
|
+
body: JSON.stringify(payload),
|
|
1772
|
+
fallbackErrorMessage: "Failed to reschedule appointment"
|
|
2117
1773
|
});
|
|
2118
|
-
if (!response.ok) throw new Error("Failed to get deliverables");
|
|
2119
|
-
return response.json();
|
|
2120
1774
|
}
|
|
2121
|
-
async function
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
{
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
return response.json();
|
|
1775
|
+
async function disputeAppointment(config, accessToken, id, payload) {
|
|
1776
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/dispute`, {
|
|
1777
|
+
method: "POST",
|
|
1778
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1779
|
+
body: JSON.stringify(payload),
|
|
1780
|
+
fallbackErrorMessage: "Failed to open dispute"
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
async function confirmAppointmentCompletion(config, accessToken, id, payload) {
|
|
1784
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/confirm`, {
|
|
1785
|
+
method: "POST",
|
|
1786
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1787
|
+
body: JSON.stringify(payload ?? {}),
|
|
1788
|
+
fallbackErrorMessage: "Failed to confirm completion"
|
|
1789
|
+
});
|
|
2137
1790
|
}
|
|
2138
|
-
async function
|
|
2139
|
-
|
|
2140
|
-
|
|
1791
|
+
async function getMilestones(config, accessToken, bookingId) {
|
|
1792
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${bookingId}/milestones`, {
|
|
1793
|
+
headers: authHeaders(config, accessToken),
|
|
1794
|
+
fallbackErrorMessage: "Failed to get milestones"
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
async function approveMilestone(config, accessToken, bookingId, milestoneId, payload) {
|
|
1798
|
+
return apiRequest(
|
|
1799
|
+
`${config.backendUrls.store}/service/bookings/${bookingId}/milestones/${milestoneId}/approve`,
|
|
2141
1800
|
{
|
|
2142
1801
|
method: "POST",
|
|
2143
|
-
headers: {
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2147
|
-
"X-Business-ID": config.businessId
|
|
2148
|
-
},
|
|
2149
|
-
body: JSON.stringify({ approved: false, feedback })
|
|
1802
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1803
|
+
body: JSON.stringify(payload ?? {}),
|
|
1804
|
+
fallbackErrorMessage: "Failed to approve milestone"
|
|
2150
1805
|
}
|
|
2151
1806
|
);
|
|
2152
|
-
if (!response.ok) throw new Error("Failed to request revision");
|
|
2153
|
-
return response.json();
|
|
2154
1807
|
}
|
|
2155
1808
|
var serviceBookingService = {
|
|
2156
1809
|
getAvailableSlots,
|
|
@@ -2158,41 +1811,111 @@ var serviceBookingService = {
|
|
|
2158
1811
|
getAppointments,
|
|
2159
1812
|
getAppointment,
|
|
2160
1813
|
cancelAppointment,
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
1814
|
+
rescheduleAppointment,
|
|
1815
|
+
disputeAppointment,
|
|
1816
|
+
confirmAppointmentCompletion,
|
|
1817
|
+
getMilestones,
|
|
1818
|
+
approveMilestone
|
|
2164
1819
|
};
|
|
2165
1820
|
|
|
2166
1821
|
// src/services/notifications.service.ts
|
|
1822
|
+
function bearerHeaders(accessToken) {
|
|
1823
|
+
return { Authorization: `Bearer ${accessToken}` };
|
|
1824
|
+
}
|
|
2167
1825
|
async function sendContactEmail(config, payload) {
|
|
2168
|
-
|
|
1826
|
+
return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-email`, {
|
|
2169
1827
|
method: "POST",
|
|
2170
|
-
headers: {
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
"X-Business-ID": config.businessId
|
|
2174
|
-
},
|
|
2175
|
-
body: JSON.stringify(payload)
|
|
1828
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1829
|
+
body: JSON.stringify(payload),
|
|
1830
|
+
fallbackErrorMessage: "Failed to send contact email"
|
|
2176
1831
|
});
|
|
2177
|
-
if (!response.ok) throw new Error("Failed to send contact email");
|
|
2178
|
-
return response.json();
|
|
2179
1832
|
}
|
|
2180
1833
|
async function sendContactConfirmation(config, payload) {
|
|
2181
|
-
|
|
1834
|
+
return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
|
|
2182
1835
|
method: "POST",
|
|
2183
|
-
headers: {
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
1836
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1837
|
+
body: JSON.stringify(payload),
|
|
1838
|
+
fallbackErrorMessage: "Failed to send contact confirmation"
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
async function getNotificationPreferences(config, accessToken) {
|
|
1842
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
|
|
1843
|
+
headers: bearerHeaders(accessToken),
|
|
1844
|
+
fallbackErrorMessage: "Failed to fetch notification preferences"
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
async function updateNotificationPreferences(config, accessToken, payload) {
|
|
1848
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
|
|
1849
|
+
method: "PATCH",
|
|
1850
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1851
|
+
body: JSON.stringify(payload),
|
|
1852
|
+
fallbackErrorMessage: "Failed to update notification preferences"
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
async function getVapidPublicKey(config) {
|
|
1856
|
+
return apiRequest(`${config.backendUrls.notifications}/push/vapid-public-key`, {
|
|
1857
|
+
fallbackErrorMessage: "Failed to fetch VAPID public key"
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
async function subscribeToPush(config, accessToken, params) {
|
|
1861
|
+
return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
|
|
1862
|
+
method: "POST",
|
|
1863
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1864
|
+
body: JSON.stringify(params),
|
|
1865
|
+
fallbackErrorMessage: "Failed to subscribe to push notifications"
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
async function unsubscribeFromPush(config, accessToken, endpoint) {
|
|
1869
|
+
return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
|
|
1870
|
+
method: "DELETE",
|
|
1871
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1872
|
+
body: JSON.stringify({ endpoint }),
|
|
1873
|
+
fallbackErrorMessage: "Failed to unsubscribe from push notifications"
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
async function getNotificationInbox(config, accessToken, params) {
|
|
1877
|
+
const query = new URLSearchParams();
|
|
1878
|
+
if (params?.page) query.set("page", String(params.page));
|
|
1879
|
+
if (params?.limit) query.set("limit", String(params.limit));
|
|
1880
|
+
if (params?.unread_only) query.set("unread_only", "true");
|
|
1881
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications?${query.toString()}`, {
|
|
1882
|
+
headers: bearerHeaders(accessToken),
|
|
1883
|
+
fallbackErrorMessage: "Failed to fetch notifications"
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
async function markNotificationRead(config, accessToken, notificationId) {
|
|
1887
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/read`, {
|
|
1888
|
+
method: "POST",
|
|
1889
|
+
headers: bearerHeaders(accessToken),
|
|
1890
|
+
fallbackErrorMessage: "Failed to mark notification as read"
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
async function markAllNotificationsRead(config, accessToken) {
|
|
1894
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/mark-all-read`, {
|
|
1895
|
+
method: "POST",
|
|
1896
|
+
headers: bearerHeaders(accessToken),
|
|
1897
|
+
fallbackErrorMessage: "Failed to mark all notifications as read"
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
async function trackNotificationClick(config, accessToken, notificationId) {
|
|
1901
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/click`, {
|
|
1902
|
+
method: "POST",
|
|
1903
|
+
headers: bearerHeaders(accessToken),
|
|
1904
|
+
fallbackErrorMessage: "Failed to track notification click"
|
|
2189
1905
|
});
|
|
2190
|
-
if (!response.ok) throw new Error("Failed to send contact confirmation");
|
|
2191
|
-
return response.json();
|
|
2192
1906
|
}
|
|
2193
1907
|
var notificationsService = {
|
|
2194
1908
|
sendContactEmail,
|
|
2195
|
-
sendContactConfirmation
|
|
1909
|
+
sendContactConfirmation,
|
|
1910
|
+
getNotificationPreferences,
|
|
1911
|
+
updateNotificationPreferences,
|
|
1912
|
+
getVapidPublicKey,
|
|
1913
|
+
subscribeToPush,
|
|
1914
|
+
unsubscribeFromPush,
|
|
1915
|
+
getNotificationInbox,
|
|
1916
|
+
markNotificationRead,
|
|
1917
|
+
markAllNotificationsRead,
|
|
1918
|
+
trackNotificationClick
|
|
2196
1919
|
};
|
|
2197
1920
|
|
|
2198
1921
|
// src/services/app.service.ts
|
|
@@ -2210,34 +1933,22 @@ async function googleTranslate(text, target, source = "en") {
|
|
|
2210
1933
|
|
|
2211
1934
|
// src/services/config.service.ts
|
|
2212
1935
|
async function getSupportedLanguages(config) {
|
|
2213
|
-
|
|
2214
|
-
headers:
|
|
2215
|
-
|
|
2216
|
-
"X-Business-ID": config.businessId
|
|
2217
|
-
}
|
|
1936
|
+
return apiRequest(`${config.backendUrls.payment}/config/supported-languages`, {
|
|
1937
|
+
headers: storefrontHeaders(config),
|
|
1938
|
+
fallbackErrorMessage: "Failed to get supported languages"
|
|
2218
1939
|
});
|
|
2219
|
-
if (!response.ok) throw new Error("Failed to get supported languages");
|
|
2220
|
-
return response.json();
|
|
2221
1940
|
}
|
|
2222
1941
|
async function getSupportedCurrencies(config) {
|
|
2223
|
-
|
|
2224
|
-
headers:
|
|
2225
|
-
|
|
2226
|
-
"X-Business-ID": config.businessId
|
|
2227
|
-
}
|
|
1942
|
+
return apiRequest(`${config.backendUrls.payment}/config/supported-currencies`, {
|
|
1943
|
+
headers: storefrontHeaders(config),
|
|
1944
|
+
fallbackErrorMessage: "Failed to get supported currencies"
|
|
2228
1945
|
});
|
|
2229
|
-
if (!response.ok) throw new Error("Failed to get supported currencies");
|
|
2230
|
-
return response.json();
|
|
2231
1946
|
}
|
|
2232
1947
|
async function getBusinessConfig(config) {
|
|
2233
|
-
|
|
2234
|
-
headers:
|
|
2235
|
-
|
|
2236
|
-
"X-Business-ID": config.businessId
|
|
2237
|
-
}
|
|
1948
|
+
return apiRequest(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
|
|
1949
|
+
headers: storefrontHeaders(config),
|
|
1950
|
+
fallbackErrorMessage: "Failed to get business config"
|
|
2238
1951
|
});
|
|
2239
|
-
if (!response.ok) throw new Error("Failed to get business config");
|
|
2240
|
-
return response.json();
|
|
2241
1952
|
}
|
|
2242
1953
|
var configService = {
|
|
2243
1954
|
getSupportedLanguages,
|
|
@@ -2246,105 +1957,245 @@ var configService = {
|
|
|
2246
1957
|
};
|
|
2247
1958
|
|
|
2248
1959
|
// src/services/cms.service.ts
|
|
2249
|
-
async function listCmsEntries(config, modelSlug, params) {
|
|
1960
|
+
async function listCmsEntries(config, businessUuid, modelSlug, params) {
|
|
2250
1961
|
const queryParams = new URLSearchParams();
|
|
2251
1962
|
queryParams.set("page", (params?.page || 1).toString());
|
|
2252
1963
|
queryParams.set("page_size", (params?.page_size || 50).toString());
|
|
2253
|
-
|
|
2254
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1964
|
+
return apiRequest(
|
|
1965
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries?${queryParams.toString()}`,
|
|
2255
1966
|
{
|
|
2256
|
-
headers:
|
|
2257
|
-
|
|
2258
|
-
"X-Business-ID": config.businessId
|
|
2259
|
-
}
|
|
1967
|
+
headers: storefrontHeaders(config),
|
|
1968
|
+
fallbackErrorMessage: "Failed to list CMS entries"
|
|
2260
1969
|
}
|
|
2261
1970
|
);
|
|
2262
|
-
if (!response.ok) throw new Error("Failed to list CMS entries");
|
|
2263
|
-
return response.json();
|
|
2264
1971
|
}
|
|
2265
|
-
async function getCmsEntry(config, modelSlug, entryId) {
|
|
2266
|
-
|
|
2267
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1972
|
+
async function getCmsEntry(config, businessUuid, modelSlug, entryId) {
|
|
1973
|
+
return apiRequest(
|
|
1974
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2268
1975
|
{
|
|
2269
|
-
headers:
|
|
2270
|
-
|
|
2271
|
-
"X-Business-ID": config.businessId
|
|
2272
|
-
}
|
|
1976
|
+
headers: storefrontHeaders(config),
|
|
1977
|
+
fallbackErrorMessage: "Failed to get CMS entry"
|
|
2273
1978
|
}
|
|
2274
1979
|
);
|
|
2275
|
-
if (!response.ok) throw new Error("Failed to get CMS entry");
|
|
2276
|
-
return response.json();
|
|
2277
1980
|
}
|
|
2278
|
-
async function createCmsEntry(config, accessToken, modelSlug, params) {
|
|
2279
|
-
|
|
2280
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1981
|
+
async function createCmsEntry(config, businessUuid, accessToken, modelSlug, params) {
|
|
1982
|
+
return apiRequest(
|
|
1983
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries`,
|
|
2281
1984
|
{
|
|
2282
1985
|
method: "POST",
|
|
2283
|
-
headers: {
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2287
|
-
"X-Business-ID": config.businessId
|
|
2288
|
-
},
|
|
2289
|
-
body: JSON.stringify(params)
|
|
1986
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1987
|
+
body: JSON.stringify(params),
|
|
1988
|
+
fallbackErrorMessage: "Failed to create CMS entry"
|
|
2290
1989
|
}
|
|
2291
1990
|
);
|
|
2292
|
-
if (!response.ok) throw new Error("Failed to create CMS entry");
|
|
2293
|
-
return response.json();
|
|
2294
1991
|
}
|
|
2295
|
-
async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
|
|
2296
|
-
|
|
2297
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1992
|
+
async function updateCmsEntry(config, businessUuid, accessToken, modelSlug, entryId, params) {
|
|
1993
|
+
return apiRequest(
|
|
1994
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2298
1995
|
{
|
|
2299
1996
|
method: "PUT",
|
|
2300
|
-
headers: {
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2304
|
-
"X-Business-ID": config.businessId
|
|
2305
|
-
},
|
|
2306
|
-
body: JSON.stringify(params)
|
|
1997
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1998
|
+
body: JSON.stringify(params),
|
|
1999
|
+
fallbackErrorMessage: "Failed to update CMS entry"
|
|
2307
2000
|
}
|
|
2308
2001
|
);
|
|
2309
|
-
if (!response.ok) throw new Error("Failed to update CMS entry");
|
|
2310
|
-
return response.json();
|
|
2311
2002
|
}
|
|
2312
|
-
async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
|
|
2313
|
-
|
|
2314
|
-
`${config.backendUrls.cms}/sdk/${
|
|
2003
|
+
async function deleteCmsEntry(config, businessUuid, accessToken, modelSlug, entryId) {
|
|
2004
|
+
await apiRequest(
|
|
2005
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2315
2006
|
{
|
|
2316
2007
|
method: "DELETE",
|
|
2317
|
-
headers:
|
|
2318
|
-
|
|
2319
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2320
|
-
"X-Business-ID": config.businessId
|
|
2321
|
-
}
|
|
2008
|
+
headers: authHeaders(config, accessToken),
|
|
2009
|
+
fallbackErrorMessage: "Failed to delete CMS entry"
|
|
2322
2010
|
}
|
|
2323
2011
|
);
|
|
2324
|
-
if (!response.ok) throw new Error("Failed to delete CMS entry");
|
|
2325
2012
|
}
|
|
2326
2013
|
|
|
2327
|
-
// src/
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
isDevelopment = development;
|
|
2014
|
+
// src/services/legal.service.ts
|
|
2015
|
+
async function getMerchantLegalDocument(config, businessUuid, documentType, fetchOptions) {
|
|
2016
|
+
if (!businessUuid || !config?.backendUrls?.cms) return null;
|
|
2017
|
+
try {
|
|
2018
|
+
const res = await fetch(
|
|
2019
|
+
`${config.backendUrls.cms}/cms/legal/storefront/${businessUuid}/${documentType}`,
|
|
2020
|
+
fetchOptions
|
|
2021
|
+
);
|
|
2022
|
+
if (!res.ok) return null;
|
|
2023
|
+
return await res.json();
|
|
2024
|
+
} catch {
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2341
2027
|
}
|
|
2342
|
-
var getCacheTier = (tier) => {
|
|
2343
|
-
if (isDevelopment) return CACHE_TIERS.none;
|
|
2344
|
-
return CACHE_TIERS[tier];
|
|
2345
|
-
};
|
|
2346
2028
|
|
|
2347
|
-
// src/
|
|
2029
|
+
// src/services/review.service.ts
|
|
2030
|
+
function fetchWithConfig(url, config, options = {}) {
|
|
2031
|
+
const headers = {
|
|
2032
|
+
...JSON_HEADERS,
|
|
2033
|
+
Accept: "application/json",
|
|
2034
|
+
...options.headers
|
|
2035
|
+
};
|
|
2036
|
+
if (config.storefrontApiKey) headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
2037
|
+
if (config.businessId) headers["X-Business-ID"] = config.businessId;
|
|
2038
|
+
if (config.authToken) headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
2039
|
+
return apiRequest(url, { ...options, headers, fallbackErrorMessage: options.fallbackErrorMessage ?? "Request failed" });
|
|
2040
|
+
}
|
|
2041
|
+
async function createReview(reviewData, config) {
|
|
2042
|
+
const url = `${config.backendUrls.crm}/reviews`;
|
|
2043
|
+
return fetchWithConfig(url, config, {
|
|
2044
|
+
method: "POST",
|
|
2045
|
+
body: JSON.stringify(reviewData),
|
|
2046
|
+
fallbackErrorMessage: "Failed to create review"
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
async function updateReview(reviewId, reviewData, config) {
|
|
2050
|
+
const url = `${config.backendUrls.crm}/reviews/${reviewId}`;
|
|
2051
|
+
return fetchWithConfig(url, config, {
|
|
2052
|
+
method: "PUT",
|
|
2053
|
+
body: JSON.stringify(reviewData),
|
|
2054
|
+
fallbackErrorMessage: "Failed to update review"
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
async function getProductReviews(productId, params = {}, config) {
|
|
2058
|
+
const queryParams = new URLSearchParams();
|
|
2059
|
+
if (params.page) queryParams.append("page", params.page.toString());
|
|
2060
|
+
if (params.page_size) queryParams.append("page_size", params.page_size.toString());
|
|
2061
|
+
if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
|
|
2062
|
+
const url = `${config.backendUrls.crm}/products/${productId}/reviews?${queryParams.toString()}`;
|
|
2063
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product reviews" });
|
|
2064
|
+
}
|
|
2065
|
+
async function createComment(commentData, config) {
|
|
2066
|
+
const url = `${config.backendUrls.crm}/comments`;
|
|
2067
|
+
return fetchWithConfig(url, config, {
|
|
2068
|
+
method: "POST",
|
|
2069
|
+
body: JSON.stringify(commentData),
|
|
2070
|
+
fallbackErrorMessage: "Failed to create comment"
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
async function updateComment(commentId, commentData, config) {
|
|
2074
|
+
const url = `${config.backendUrls.crm}/comments/${commentId}`;
|
|
2075
|
+
return fetchWithConfig(url, config, {
|
|
2076
|
+
method: "PUT",
|
|
2077
|
+
body: JSON.stringify(commentData),
|
|
2078
|
+
fallbackErrorMessage: "Failed to update comment"
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
async function getProductComments(productId, params = {}, config) {
|
|
2082
|
+
const queryParams = new URLSearchParams();
|
|
2083
|
+
if (params.page) queryParams.append("page", params.page.toString());
|
|
2084
|
+
if (params.page_size) queryParams.append("page_size", params.page_size.toString());
|
|
2085
|
+
if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
|
|
2086
|
+
const url = `${config.backendUrls.crm}/products/${productId}/comments?${queryParams.toString()}`;
|
|
2087
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product comments" });
|
|
2088
|
+
}
|
|
2089
|
+
async function getPendingReviews(config) {
|
|
2090
|
+
const url = `${config.backendUrls.crm}/admin/reviews/pending`;
|
|
2091
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending reviews" });
|
|
2092
|
+
}
|
|
2093
|
+
async function getPendingComments(config) {
|
|
2094
|
+
const url = `${config.backendUrls.crm}/admin/comments/pending`;
|
|
2095
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending comments" });
|
|
2096
|
+
}
|
|
2097
|
+
async function moderateReview(reviewId, action, config) {
|
|
2098
|
+
const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/moderate`;
|
|
2099
|
+
return fetchWithConfig(url, config, {
|
|
2100
|
+
method: "POST",
|
|
2101
|
+
body: JSON.stringify(action),
|
|
2102
|
+
fallbackErrorMessage: "Failed to moderate review"
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
async function moderateComment(commentId, action, config) {
|
|
2106
|
+
const url = `${config.backendUrls.crm}/admin/comments/${commentId}/moderate`;
|
|
2107
|
+
return fetchWithConfig(url, config, {
|
|
2108
|
+
method: "POST",
|
|
2109
|
+
body: JSON.stringify(action),
|
|
2110
|
+
fallbackErrorMessage: "Failed to moderate comment"
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
async function merchantReplyToReview(reviewId, replyData, config) {
|
|
2114
|
+
const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/reply`;
|
|
2115
|
+
return fetchWithConfig(url, config, {
|
|
2116
|
+
method: "POST",
|
|
2117
|
+
body: JSON.stringify(replyData),
|
|
2118
|
+
fallbackErrorMessage: "Failed to post merchant reply"
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// src/services/media.service.ts
|
|
2123
|
+
async function uploadMediaFile(params) {
|
|
2124
|
+
const presignedUrlEndpoint = params.presignedUrlEndpoint ?? "/api/auth/media/presigned-url";
|
|
2125
|
+
const confirmUploadEndpoint = params.confirmUploadEndpoint ?? "/api/auth/media/confirm-upload";
|
|
2126
|
+
const { presigned_url, storage_path } = await apiRequest(presignedUrlEndpoint, {
|
|
2127
|
+
method: "POST",
|
|
2128
|
+
headers: JSON_HEADERS,
|
|
2129
|
+
credentials: "include",
|
|
2130
|
+
body: JSON.stringify({
|
|
2131
|
+
filename: params.file.name,
|
|
2132
|
+
content_type: params.file.type,
|
|
2133
|
+
context: params.context,
|
|
2134
|
+
entity_id: params.entityId,
|
|
2135
|
+
affiliation: params.affiliation,
|
|
2136
|
+
owner_id: params.ownerId
|
|
2137
|
+
}),
|
|
2138
|
+
fallbackErrorMessage: "Could not start upload"
|
|
2139
|
+
});
|
|
2140
|
+
const putResponse = await fetch(presigned_url, {
|
|
2141
|
+
method: "PUT",
|
|
2142
|
+
headers: { "Content-Type": params.file.type },
|
|
2143
|
+
body: params.file
|
|
2144
|
+
});
|
|
2145
|
+
if (!putResponse.ok) {
|
|
2146
|
+
throw new Error(`Failed to upload ${params.file.name}`);
|
|
2147
|
+
}
|
|
2148
|
+
return apiRequest(confirmUploadEndpoint, {
|
|
2149
|
+
method: "POST",
|
|
2150
|
+
headers: JSON_HEADERS,
|
|
2151
|
+
credentials: "include",
|
|
2152
|
+
body: JSON.stringify({
|
|
2153
|
+
storage_path,
|
|
2154
|
+
entity_id: params.entityId,
|
|
2155
|
+
original_filename: params.file.name,
|
|
2156
|
+
content_type: params.file.type,
|
|
2157
|
+
size: params.file.size,
|
|
2158
|
+
context: params.context,
|
|
2159
|
+
affiliation: params.affiliation,
|
|
2160
|
+
owner_id: params.ownerId
|
|
2161
|
+
}),
|
|
2162
|
+
fallbackErrorMessage: `Could not confirm upload of ${params.file.name}`
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
async function uploadMediaFiles(files, params) {
|
|
2166
|
+
const assets = [];
|
|
2167
|
+
const errors = [];
|
|
2168
|
+
for (const file of files) {
|
|
2169
|
+
try {
|
|
2170
|
+
assets.push(await uploadMediaFile({ ...params, file }));
|
|
2171
|
+
} catch (err) {
|
|
2172
|
+
errors.push({ file: file.name, message: err instanceof Error ? err.message : "Upload failed" });
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return { assets, errors };
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
// src/utils/cache.ts
|
|
2179
|
+
var CACHE_TIERS = {
|
|
2180
|
+
none: { staleTime: 0, gcTime: 0 },
|
|
2181
|
+
infinity: { staleTime: Infinity, gcTime: 0 },
|
|
2182
|
+
low: { staleTime: 1e3 * 30, gcTime: 1e3 * 60 },
|
|
2183
|
+
// 30s / 1m
|
|
2184
|
+
medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
|
|
2185
|
+
// 5m / 10m
|
|
2186
|
+
high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
|
|
2187
|
+
// 30m / 1h
|
|
2188
|
+
};
|
|
2189
|
+
var isDevelopment = true;
|
|
2190
|
+
function setEnvironmentMode(development) {
|
|
2191
|
+
isDevelopment = development;
|
|
2192
|
+
}
|
|
2193
|
+
var getCacheTier = (tier) => {
|
|
2194
|
+
if (isDevelopment) return CACHE_TIERS.none;
|
|
2195
|
+
return CACHE_TIERS[tier];
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
// src/utils/logger.ts
|
|
2348
2199
|
var isDevelopment2 = true;
|
|
2349
2200
|
function setLoggerEnvironmentMode(development) {
|
|
2350
2201
|
isDevelopment2 = development;
|
|
@@ -2409,111 +2260,6 @@ var logger = {
|
|
|
2409
2260
|
})
|
|
2410
2261
|
};
|
|
2411
2262
|
|
|
2412
|
-
// src/utils/sanitize-url.ts
|
|
2413
|
-
var InvalidBaseURLError = class extends Error {
|
|
2414
|
-
constructor(message) {
|
|
2415
|
-
super(message);
|
|
2416
|
-
this.name = "InvalidBaseURLError";
|
|
2417
|
-
}
|
|
2418
|
-
};
|
|
2419
|
-
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
|
|
2420
|
-
function sanitizeBaseUrl(url, name = "URL") {
|
|
2421
|
-
if (url == null) {
|
|
2422
|
-
throw new InvalidBaseURLError(`${name} is not set`);
|
|
2423
|
-
}
|
|
2424
|
-
const cleaned0 = url.trim();
|
|
2425
|
-
if (!cleaned0) {
|
|
2426
|
-
throw new InvalidBaseURLError(`${name} is empty`);
|
|
2427
|
-
}
|
|
2428
|
-
const cleaned = cleaned0.replace(/\/+$/, "");
|
|
2429
|
-
let parsed;
|
|
2430
|
-
try {
|
|
2431
|
-
parsed = new URL(cleaned);
|
|
2432
|
-
} catch {
|
|
2433
|
-
throw new InvalidBaseURLError(
|
|
2434
|
-
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2435
|
-
);
|
|
2436
|
-
}
|
|
2437
|
-
if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
|
|
2438
|
-
throw new InvalidBaseURLError(
|
|
2439
|
-
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2440
|
-
);
|
|
2441
|
-
}
|
|
2442
|
-
if (!parsed.hostname) {
|
|
2443
|
-
throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
|
|
2444
|
-
}
|
|
2445
|
-
if (parsed.search || parsed.hash) {
|
|
2446
|
-
throw new InvalidBaseURLError(
|
|
2447
|
-
`${name} should not contain a query or fragment: ${url}`
|
|
2448
|
-
);
|
|
2449
|
-
}
|
|
2450
|
-
return cleaned;
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
// src/utils/customer.ts
|
|
2454
|
-
function buildFullName2(firstname, lastname) {
|
|
2455
|
-
const name = [firstname, lastname].filter(Boolean).join(" ").trim();
|
|
2456
|
-
return name || void 0;
|
|
2457
|
-
}
|
|
2458
|
-
function splitFullName2(fullName) {
|
|
2459
|
-
if (!fullName?.trim()) return { firstname: "", lastname: "" };
|
|
2460
|
-
const parts = fullName.trim().split(/\s+/);
|
|
2461
|
-
return {
|
|
2462
|
-
firstname: parts[0] ?? "",
|
|
2463
|
-
lastname: parts.slice(1).join(" ")
|
|
2464
|
-
};
|
|
2465
|
-
}
|
|
2466
|
-
function getCustomerDisplayName(user) {
|
|
2467
|
-
const fromParts = buildFullName2(user.firstname, user.lastname);
|
|
2468
|
-
return fromParts || user.full_name || user.email.split("@")[0];
|
|
2469
|
-
}
|
|
2470
|
-
function getStorefrontUrl(businessId, customDomain) {
|
|
2471
|
-
if (customDomain && customDomain.trim()) {
|
|
2472
|
-
const cleanDomain = customDomain.trim().replace(/^https?:\/\//, "");
|
|
2473
|
-
return `https://${cleanDomain}`;
|
|
2474
|
-
}
|
|
2475
|
-
const cleanBid = (businessId || "store").toLowerCase().trim();
|
|
2476
|
-
return `https://${cleanBid}.kasuvia.com`;
|
|
2477
|
-
}
|
|
2478
|
-
|
|
2479
|
-
// src/utils/checkout.ts
|
|
2480
|
-
function buildDeliveryAddress(customer, location) {
|
|
2481
|
-
return {
|
|
2482
|
-
first_name: customer.first_name,
|
|
2483
|
-
last_name: customer.last_name,
|
|
2484
|
-
phone: customer.phone,
|
|
2485
|
-
...location
|
|
2486
|
-
};
|
|
2487
|
-
}
|
|
2488
|
-
function getCheckoutCustomerName(customer) {
|
|
2489
|
-
return buildFullName2(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
|
|
2490
|
-
}
|
|
2491
|
-
function enrichCompletedOrder(order, options) {
|
|
2492
|
-
const customerName = getCheckoutCustomerName(options.customer);
|
|
2493
|
-
return {
|
|
2494
|
-
...order,
|
|
2495
|
-
customerName: order.customerName || customerName,
|
|
2496
|
-
customerEmail: order.customerEmail || options.customer.email,
|
|
2497
|
-
shippingAddress: order.shippingAddress ?? (options.productType === "physical" && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
|
|
2498
|
-
bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
|
|
2499
|
-
};
|
|
2500
|
-
}
|
|
2501
|
-
|
|
2502
|
-
// src/utils/error-handler.ts
|
|
2503
|
-
function getErrorMessage(error, fallback = "Something went wrong") {
|
|
2504
|
-
if (error instanceof Error) {
|
|
2505
|
-
return error.message;
|
|
2506
|
-
}
|
|
2507
|
-
if (error instanceof Response) {
|
|
2508
|
-
return `HTTP ${error.status}: ${error.statusText}`;
|
|
2509
|
-
}
|
|
2510
|
-
if (typeof error === "object" && error !== null) {
|
|
2511
|
-
const err = error;
|
|
2512
|
-
return err.detail || err.message || fallback;
|
|
2513
|
-
}
|
|
2514
|
-
return fallback;
|
|
2515
|
-
}
|
|
2516
|
-
|
|
2517
2263
|
// src/utils/storage.ts
|
|
2518
2264
|
function getPrefixedKey(businessId, key) {
|
|
2519
2265
|
const cleanKey = key.startsWith("kasuvia_") ? key.substring(5) : key;
|
|
@@ -2600,6 +2346,454 @@ var localStore = {
|
|
|
2600
2346
|
}
|
|
2601
2347
|
};
|
|
2602
2348
|
|
|
2349
|
+
// src/utils/sanitize-url.ts
|
|
2350
|
+
var InvalidBaseURLError = class extends Error {
|
|
2351
|
+
constructor(message) {
|
|
2352
|
+
super(message);
|
|
2353
|
+
this.name = "InvalidBaseURLError";
|
|
2354
|
+
}
|
|
2355
|
+
};
|
|
2356
|
+
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
|
|
2357
|
+
function sanitizeBaseUrl(url, name = "URL") {
|
|
2358
|
+
if (url == null) {
|
|
2359
|
+
throw new InvalidBaseURLError(`${name} is not set`);
|
|
2360
|
+
}
|
|
2361
|
+
const cleaned0 = url.trim();
|
|
2362
|
+
if (!cleaned0) {
|
|
2363
|
+
throw new InvalidBaseURLError(`${name} is empty`);
|
|
2364
|
+
}
|
|
2365
|
+
const cleaned = cleaned0.replace(/\/+$/, "");
|
|
2366
|
+
let parsed;
|
|
2367
|
+
try {
|
|
2368
|
+
parsed = new URL(cleaned);
|
|
2369
|
+
} catch {
|
|
2370
|
+
throw new InvalidBaseURLError(
|
|
2371
|
+
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
|
|
2375
|
+
throw new InvalidBaseURLError(
|
|
2376
|
+
`${name} must start with http://, https://, ws://, or wss://, got: ${url}`
|
|
2377
|
+
);
|
|
2378
|
+
}
|
|
2379
|
+
if (!parsed.hostname) {
|
|
2380
|
+
throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
|
|
2381
|
+
}
|
|
2382
|
+
if (parsed.search || parsed.hash) {
|
|
2383
|
+
throw new InvalidBaseURLError(
|
|
2384
|
+
`${name} should not contain a query or fragment: ${url}`
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
return cleaned;
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
// src/utils/checkout.ts
|
|
2391
|
+
function buildDeliveryAddress(customer, location) {
|
|
2392
|
+
if (!customer.first_name || !customer.last_name || !customer.phone) {
|
|
2393
|
+
throw new Error("Customer first_name, last_name, and phone are required for delivery address");
|
|
2394
|
+
}
|
|
2395
|
+
if (!location.street || !location.city || !location.state || !location.country) {
|
|
2396
|
+
throw new Error("Location street, city, state, and country are required for delivery address");
|
|
2397
|
+
}
|
|
2398
|
+
return {
|
|
2399
|
+
first_name: customer.first_name,
|
|
2400
|
+
last_name: customer.last_name,
|
|
2401
|
+
phone: customer.phone,
|
|
2402
|
+
street: location.street,
|
|
2403
|
+
city: location.city,
|
|
2404
|
+
state: location.state,
|
|
2405
|
+
lga: location.lga,
|
|
2406
|
+
country: location.country,
|
|
2407
|
+
postal: location.postal
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
function getCheckoutCustomerName(customer) {
|
|
2411
|
+
return buildFullName(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
|
|
2412
|
+
}
|
|
2413
|
+
function enrichCompletedOrder(order, options) {
|
|
2414
|
+
const customerName = getCheckoutCustomerName(options.customer);
|
|
2415
|
+
return {
|
|
2416
|
+
...order,
|
|
2417
|
+
customer_name: order.customer_name || customerName,
|
|
2418
|
+
customer_email: order.customer_email || options.customer.email,
|
|
2419
|
+
customerName: order.customerName || customerName,
|
|
2420
|
+
customerEmail: order.customerEmail || options.customer.email,
|
|
2421
|
+
shippingAddress: order.shippingAddress ?? (options.productType === "physical" /* PHYSICAL */ && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
|
|
2422
|
+
bespoke_brief: order.bespoke_brief ?? options.bespokeBrief,
|
|
2423
|
+
bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// src/utils/error-handler.ts
|
|
2428
|
+
function getErrorMessage(error, fallback = "Something went wrong") {
|
|
2429
|
+
if (error instanceof Error) {
|
|
2430
|
+
return error.message;
|
|
2431
|
+
}
|
|
2432
|
+
if (error instanceof Response) {
|
|
2433
|
+
return `HTTP ${error.status}: ${error.statusText}`;
|
|
2434
|
+
}
|
|
2435
|
+
if (typeof error === "object" && error !== null) {
|
|
2436
|
+
const err = error;
|
|
2437
|
+
return err.detail || err.message || fallback;
|
|
2438
|
+
}
|
|
2439
|
+
return fallback;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
// src/utils/format.ts
|
|
2443
|
+
var COMPACT_THRESHOLDS = [
|
|
2444
|
+
{ value: 1e12, suffixUpper: "T", suffixLower: "t", full: "Trillion" },
|
|
2445
|
+
{ value: 1e9, suffixUpper: "B", suffixLower: "b", full: "Billion" },
|
|
2446
|
+
{ value: 1e6, suffixUpper: "M", suffixLower: "m", full: "Million" },
|
|
2447
|
+
{ value: 1e3, suffixUpper: "K", suffixLower: "k", full: "Thousand" }
|
|
2448
|
+
];
|
|
2449
|
+
var BYTE_THRESHOLDS = [
|
|
2450
|
+
{ value: 1024 ** 5, label: "PB" },
|
|
2451
|
+
{ value: 1024 ** 4, label: "TB" },
|
|
2452
|
+
{ value: 1024 ** 3, label: "GB" },
|
|
2453
|
+
{ value: 1024 ** 2, label: "MB" },
|
|
2454
|
+
{ value: 1024 ** 1, label: "KB" }
|
|
2455
|
+
];
|
|
2456
|
+
function trimDecimals(value, decimals) {
|
|
2457
|
+
if (decimals !== void 0) return value.toFixed(decimals);
|
|
2458
|
+
const fixed = value.toFixed(10);
|
|
2459
|
+
return parseFloat(fixed).toString();
|
|
2460
|
+
}
|
|
2461
|
+
function autoDecimals(value, defaultDecimals, decimals) {
|
|
2462
|
+
return (decimals !== void 0 ? value.toFixed(decimals) : value.toFixed(defaultDecimals)).replace(/\.?0+$/, "");
|
|
2463
|
+
}
|
|
2464
|
+
function applySign(str, num, showSign) {
|
|
2465
|
+
if (showSign && num > 0) return `+${str}`;
|
|
2466
|
+
return str;
|
|
2467
|
+
}
|
|
2468
|
+
function toOrdinal(n) {
|
|
2469
|
+
const abs = Math.abs(Math.round(n));
|
|
2470
|
+
const mod100 = abs % 100;
|
|
2471
|
+
const mod10 = abs % 10;
|
|
2472
|
+
if (mod100 >= 11 && mod100 <= 13) return `${abs}th`;
|
|
2473
|
+
if (mod10 === 1) return `${abs}st`;
|
|
2474
|
+
if (mod10 === 2) return `${abs}nd`;
|
|
2475
|
+
if (mod10 === 3) return `${abs}rd`;
|
|
2476
|
+
return `${abs}th`;
|
|
2477
|
+
}
|
|
2478
|
+
function toRoman(n) {
|
|
2479
|
+
if (n <= 0 || n > 3999 || !Number.isInteger(n)) {
|
|
2480
|
+
throw new RangeError("Roman numerals only support integers between 1 and 3999.");
|
|
2481
|
+
}
|
|
2482
|
+
const vals = [1e3, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
|
|
2483
|
+
const syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
|
|
2484
|
+
let result = "";
|
|
2485
|
+
let remaining = n;
|
|
2486
|
+
for (let i = 0; i < vals.length; i++) {
|
|
2487
|
+
while (remaining >= vals[i]) {
|
|
2488
|
+
result += syms[i];
|
|
2489
|
+
remaining -= vals[i];
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return result;
|
|
2493
|
+
}
|
|
2494
|
+
function formatCompact(n, suffixKey, lowerFull, decimals) {
|
|
2495
|
+
const abs = Math.abs(n);
|
|
2496
|
+
for (const tier of COMPACT_THRESHOLDS) {
|
|
2497
|
+
if (abs >= tier.value) {
|
|
2498
|
+
const divided = n / tier.value;
|
|
2499
|
+
const suffix = suffixKey === "full" ? lowerFull ? tier.full.toLowerCase() : tier.full : tier[suffixKey];
|
|
2500
|
+
const spacer = suffixKey === "full" ? " " : "";
|
|
2501
|
+
return `${autoDecimals(divided, 2, decimals)}${spacer}${suffix}`;
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
return trimDecimals(n, decimals ?? 0);
|
|
2505
|
+
}
|
|
2506
|
+
function formatDecimal(n, separator, decimalChar = ".", decimals) {
|
|
2507
|
+
const fixed = decimals !== void 0 ? Math.abs(n).toFixed(decimals) : Math.abs(n).toFixed(0);
|
|
2508
|
+
const [intPart, decPart] = fixed.split(".");
|
|
2509
|
+
const grouped = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
|
|
2510
|
+
const sign = n < 0 ? "-" : "";
|
|
2511
|
+
return decPart !== void 0 ? `${sign}${grouped}${decimalChar}${decPart}` : `${sign}${grouped}`;
|
|
2512
|
+
}
|
|
2513
|
+
function formatBytes(n, decimals = 2) {
|
|
2514
|
+
if (n === 0) return "0 B";
|
|
2515
|
+
const abs = Math.abs(n);
|
|
2516
|
+
for (const tier of BYTE_THRESHOLDS) {
|
|
2517
|
+
if (abs >= tier.value) {
|
|
2518
|
+
return `${(n / tier.value).toFixed(decimals)} ${tier.label}`;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
return `${n.toFixed(0)} B`;
|
|
2522
|
+
}
|
|
2523
|
+
function formatNumber(value, options = {}) {
|
|
2524
|
+
const {
|
|
2525
|
+
style = "compact",
|
|
2526
|
+
decimals,
|
|
2527
|
+
currencySymbol = "$",
|
|
2528
|
+
locale = "en-US",
|
|
2529
|
+
showSign
|
|
2530
|
+
} = options;
|
|
2531
|
+
if (!isFinite(value)) return String(value);
|
|
2532
|
+
let result;
|
|
2533
|
+
switch (style) {
|
|
2534
|
+
case "compact":
|
|
2535
|
+
result = formatCompact(value, "suffixUpper", false, decimals);
|
|
2536
|
+
break;
|
|
2537
|
+
case "compact-lower":
|
|
2538
|
+
result = formatCompact(value, "suffixLower", false, decimals);
|
|
2539
|
+
break;
|
|
2540
|
+
case "compact-full":
|
|
2541
|
+
result = formatCompact(value, "full", false, decimals);
|
|
2542
|
+
break;
|
|
2543
|
+
case "compact-full-lower":
|
|
2544
|
+
result = formatCompact(value, "full", true, decimals);
|
|
2545
|
+
break;
|
|
2546
|
+
case "currency": {
|
|
2547
|
+
const d = decimals ?? 2;
|
|
2548
|
+
const formatted = formatDecimal(value, ",", ".", d);
|
|
2549
|
+
result = `${currencySymbol}${formatted}`;
|
|
2550
|
+
break;
|
|
2551
|
+
}
|
|
2552
|
+
case "currency-compact": {
|
|
2553
|
+
const compact2 = formatCompact(Math.abs(value), "suffixUpper", false, decimals);
|
|
2554
|
+
const sign = value < 0 ? "-" : "";
|
|
2555
|
+
result = `${sign}${currencySymbol}${compact2}`;
|
|
2556
|
+
break;
|
|
2557
|
+
}
|
|
2558
|
+
case "decimal":
|
|
2559
|
+
result = formatDecimal(value, ",", ".", decimals);
|
|
2560
|
+
break;
|
|
2561
|
+
case "decimal-dot":
|
|
2562
|
+
result = formatDecimal(value, ".", ",", decimals);
|
|
2563
|
+
break;
|
|
2564
|
+
case "decimal-space":
|
|
2565
|
+
result = formatDecimal(value, "\xA0", ".", decimals);
|
|
2566
|
+
break;
|
|
2567
|
+
case "plain":
|
|
2568
|
+
result = decimals !== void 0 ? value.toFixed(decimals) : String(value);
|
|
2569
|
+
break;
|
|
2570
|
+
case "scientific": {
|
|
2571
|
+
const d = decimals ?? 2;
|
|
2572
|
+
result = value.toExponential(d);
|
|
2573
|
+
break;
|
|
2574
|
+
}
|
|
2575
|
+
case "ordinal":
|
|
2576
|
+
return toOrdinal(value);
|
|
2577
|
+
// sign not applicable
|
|
2578
|
+
case "percent": {
|
|
2579
|
+
const d = decimals ?? 1;
|
|
2580
|
+
result = `${(value * 100).toFixed(d).replace(/\.?0+$/, "")}%`;
|
|
2581
|
+
break;
|
|
2582
|
+
}
|
|
2583
|
+
case "bytes":
|
|
2584
|
+
result = formatBytes(value, decimals);
|
|
2585
|
+
break;
|
|
2586
|
+
case "roman":
|
|
2587
|
+
return toRoman(Math.round(value));
|
|
2588
|
+
// sign not applicable
|
|
2589
|
+
default:
|
|
2590
|
+
result = String(value);
|
|
2591
|
+
}
|
|
2592
|
+
return applySign(result, value, showSign);
|
|
2593
|
+
}
|
|
2594
|
+
var compact = (n, decimals) => formatNumber(n, { style: "compact", decimals });
|
|
2595
|
+
var compactLower = (n, decimals) => formatNumber(n, { style: "compact-lower", decimals });
|
|
2596
|
+
var compactFull = (n, decimals) => formatNumber(n, { style: "compact-full", decimals });
|
|
2597
|
+
var currencyFormat = (n, symbol = "$", decimals = 2) => formatNumber(n, { style: "currency", currencySymbol: symbol, decimals });
|
|
2598
|
+
var currencyCompact = (n, symbol = "$") => formatNumber(n, { style: "currency-compact", currencySymbol: symbol });
|
|
2599
|
+
var decimal = (n, decimals) => formatNumber(n, { style: "decimal", decimals });
|
|
2600
|
+
var percent = (n, decimals) => formatNumber(n, { style: "percent", decimals });
|
|
2601
|
+
var bytes = (n, decimals) => formatNumber(n, { style: "bytes", decimals });
|
|
2602
|
+
var roman = (n) => formatNumber(n, { style: "roman" });
|
|
2603
|
+
var ordinal = (n) => formatNumber(n, { style: "ordinal" });
|
|
2604
|
+
function formatTimeString(time) {
|
|
2605
|
+
const [hoursStr, minutesStr] = time.split(":");
|
|
2606
|
+
const hours = parseInt(hoursStr, 10);
|
|
2607
|
+
if (isNaN(hours) || minutesStr === void 0) return time;
|
|
2608
|
+
const period = hours >= 12 ? "PM" : "AM";
|
|
2609
|
+
const displayHours = hours % 12 || 12;
|
|
2610
|
+
return `${displayHours}:${minutesStr} ${period}`;
|
|
2611
|
+
}
|
|
2612
|
+
function formatPrice(amount, currency, locale = "en-US") {
|
|
2613
|
+
if (amount == null || isNaN(amount)) return "";
|
|
2614
|
+
if (!currency) return `N/A ${amount.toLocaleString()}`;
|
|
2615
|
+
const code = currency.toUpperCase();
|
|
2616
|
+
try {
|
|
2617
|
+
return new Intl.NumberFormat(locale, {
|
|
2618
|
+
style: "currency",
|
|
2619
|
+
currency: code,
|
|
2620
|
+
minimumFractionDigits: 0,
|
|
2621
|
+
maximumFractionDigits: 2
|
|
2622
|
+
}).format(amount);
|
|
2623
|
+
} catch {
|
|
2624
|
+
return `${code} ${amount.toLocaleString()}`;
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
function getCurrencySymbol(currency, locale = "en-US") {
|
|
2628
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
2629
|
+
style: "currency",
|
|
2630
|
+
currency
|
|
2631
|
+
});
|
|
2632
|
+
const parts = formatter.formatToParts(0);
|
|
2633
|
+
const symbolPart = parts.find((part) => part.type === "currency");
|
|
2634
|
+
return symbolPart?.value || currency;
|
|
2635
|
+
}
|
|
2636
|
+
function formatCompactPrice(amount, currency, locale = "en-US") {
|
|
2637
|
+
if (!currency) return `N/A ${formatNumber(amount, { style: "compact", decimals: 0 })}`;
|
|
2638
|
+
const symbol = getCurrencySymbol(currency, locale);
|
|
2639
|
+
const compactStr = formatNumber(amount, { style: "compact", decimals: 0 });
|
|
2640
|
+
return `${symbol}${compactStr}`;
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// src/utils/geolocation.ts
|
|
2644
|
+
async function handlePinDrop(coords, setAddress, setIsReverseGeocoding, config) {
|
|
2645
|
+
setAddress((prev) => ({
|
|
2646
|
+
...prev,
|
|
2647
|
+
latitude: coords.latitude,
|
|
2648
|
+
longitude: coords.longitude,
|
|
2649
|
+
coordinate_source: "pin_drop"
|
|
2650
|
+
}));
|
|
2651
|
+
if (setIsReverseGeocoding) {
|
|
2652
|
+
setIsReverseGeocoding(true);
|
|
2653
|
+
try {
|
|
2654
|
+
if (config) {
|
|
2655
|
+
const data = await reverseGeocode(config, {
|
|
2656
|
+
latitude: coords.latitude,
|
|
2657
|
+
longitude: coords.longitude
|
|
2658
|
+
});
|
|
2659
|
+
setAddress((prev) => ({
|
|
2660
|
+
...prev,
|
|
2661
|
+
city: data.city || prev.city,
|
|
2662
|
+
state: data.state || prev.state,
|
|
2663
|
+
country: data.country_code || prev.country
|
|
2664
|
+
}));
|
|
2665
|
+
} else {
|
|
2666
|
+
logger.warn("[GeolocationHelper] SdkConfig is required to perform reverse geocoding.");
|
|
2667
|
+
}
|
|
2668
|
+
} catch (error) {
|
|
2669
|
+
logger.error("[GeolocationHelper] Reverse geocoding failed:", error);
|
|
2670
|
+
} finally {
|
|
2671
|
+
setIsReverseGeocoding(false);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
async function handlePlusCodeChange(plusCode, setAddress, config) {
|
|
2676
|
+
setAddress((prev) => ({
|
|
2677
|
+
...prev,
|
|
2678
|
+
plus_code: plusCode
|
|
2679
|
+
}));
|
|
2680
|
+
if (plusCode) {
|
|
2681
|
+
setAddress((prev) => ({
|
|
2682
|
+
...prev,
|
|
2683
|
+
plus_code: plusCode,
|
|
2684
|
+
coordinate_source: "plus_code"
|
|
2685
|
+
}));
|
|
2686
|
+
try {
|
|
2687
|
+
if (config) {
|
|
2688
|
+
const data = await decodePlusCode(config, { plus_code: plusCode });
|
|
2689
|
+
setAddress((prev) => ({
|
|
2690
|
+
...prev,
|
|
2691
|
+
latitude: data.latitude,
|
|
2692
|
+
longitude: data.longitude
|
|
2693
|
+
}));
|
|
2694
|
+
} else {
|
|
2695
|
+
logger.warn("[GeolocationHelper] SdkConfig is required to decode Plus Code.");
|
|
2696
|
+
}
|
|
2697
|
+
} catch (error) {
|
|
2698
|
+
logger.error("[GeolocationHelper] Plus Code decoding failed:", error);
|
|
2699
|
+
}
|
|
2700
|
+
} else {
|
|
2701
|
+
setAddress((prev) => ({
|
|
2702
|
+
...prev,
|
|
2703
|
+
plus_code: "",
|
|
2704
|
+
coordinate_source: void 0
|
|
2705
|
+
}));
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
function applyAddressSuggestion(suggestion, setAddress) {
|
|
2709
|
+
setAddress((prev) => ({
|
|
2710
|
+
...prev,
|
|
2711
|
+
street: suggestion.line1 || prev.street,
|
|
2712
|
+
city: suggestion.city || prev.city,
|
|
2713
|
+
state: suggestion.state || prev.state,
|
|
2714
|
+
postal: suggestion.postal_code || prev.postal,
|
|
2715
|
+
country: suggestion.country || prev.country,
|
|
2716
|
+
latitude: suggestion.latitude ?? prev.latitude,
|
|
2717
|
+
longitude: suggestion.longitude ?? prev.longitude,
|
|
2718
|
+
coordinate_source: suggestion.latitude != null && suggestion.longitude != null ? "manual" : prev.coordinate_source
|
|
2719
|
+
}));
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
// src/utils/status-colors.ts
|
|
2723
|
+
var appointmentStatusColors = {
|
|
2724
|
+
scheduled: "bg-yellow-100 text-yellow-800 hover:bg-yellow-200",
|
|
2725
|
+
confirmed: "bg-green-100 text-green-800 hover:bg-green-200",
|
|
2726
|
+
in_progress: "bg-blue-100 text-blue-800 hover:bg-blue-200",
|
|
2727
|
+
completed: "bg-gray-100 text-gray-800 hover:bg-gray-200",
|
|
2728
|
+
voided: "bg-red-100 text-red-800 hover:bg-red-200",
|
|
2729
|
+
no_show: "bg-red-100 text-red-800 hover:bg-red-200"
|
|
2730
|
+
};
|
|
2731
|
+
var milestoneStatusColors = {
|
|
2732
|
+
pending: "bg-gray-100 text-gray-800",
|
|
2733
|
+
funded: "bg-blue-100 text-blue-800",
|
|
2734
|
+
submitted: "bg-yellow-100 text-yellow-800",
|
|
2735
|
+
approved: "bg-green-100 text-green-800",
|
|
2736
|
+
released: "bg-green-100 text-green-800",
|
|
2737
|
+
disputed: "bg-red-100 text-red-800",
|
|
2738
|
+
refunded: "bg-gray-100 text-gray-800"
|
|
2739
|
+
};
|
|
2740
|
+
var orderStatusColors = {
|
|
2741
|
+
pending: "bg-gray-100 text-gray-800",
|
|
2742
|
+
confirmed: "bg-blue-100 text-blue-800",
|
|
2743
|
+
processing: "bg-yellow-100 text-yellow-800",
|
|
2744
|
+
packed: "bg-yellow-100 text-yellow-800",
|
|
2745
|
+
picked_up: "bg-blue-100 text-blue-800",
|
|
2746
|
+
ready_for_pickup: "bg-blue-100 text-blue-800",
|
|
2747
|
+
picked_up_by_customer: "bg-green-100 text-green-800",
|
|
2748
|
+
in_transit: "bg-blue-100 text-blue-800",
|
|
2749
|
+
shipped: "bg-blue-100 text-blue-800",
|
|
2750
|
+
delivered: "bg-green-100 text-green-800",
|
|
2751
|
+
voided: "bg-red-100 text-red-800",
|
|
2752
|
+
refunded: "bg-gray-100 text-gray-800",
|
|
2753
|
+
failed: "bg-red-100 text-red-800"
|
|
2754
|
+
};
|
|
2755
|
+
var orderStatusLabels = {
|
|
2756
|
+
pending: "Order Placed",
|
|
2757
|
+
confirmed: "Confirmed",
|
|
2758
|
+
processing: "Preparing",
|
|
2759
|
+
packed: "Packed",
|
|
2760
|
+
picked_up: "Picked Up",
|
|
2761
|
+
ready_for_pickup: "Ready for Pickup",
|
|
2762
|
+
picked_up_by_customer: "Collected",
|
|
2763
|
+
in_transit: "In Transit",
|
|
2764
|
+
shipped: "On the Way",
|
|
2765
|
+
delivered: "Delivered",
|
|
2766
|
+
voided: "Voided",
|
|
2767
|
+
refunded: "Refunded",
|
|
2768
|
+
failed: "Failed"
|
|
2769
|
+
};
|
|
2770
|
+
|
|
2771
|
+
// src/utils/youtube.ts
|
|
2772
|
+
function getYouTubeID(url) {
|
|
2773
|
+
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
2774
|
+
const match = url.match(regExp);
|
|
2775
|
+
return match && match[2].length === 11 ? match[2] : null;
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
// src/utils/cookieConsent.ts
|
|
2779
|
+
var STORAGE_KEY = "kasuvia_cookie_consent";
|
|
2780
|
+
var COOKIE_CONSENT_CHANGED_EVENT = "kasuvia:cookie-consent-changed";
|
|
2781
|
+
function getCookieConsent() {
|
|
2782
|
+
try {
|
|
2783
|
+
const value = window.localStorage.getItem(STORAGE_KEY);
|
|
2784
|
+
return value === "accepted" || value === "rejected" ? value : null;
|
|
2785
|
+
} catch {
|
|
2786
|
+
return null;
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
function setCookieConsent(value) {
|
|
2790
|
+
try {
|
|
2791
|
+
window.localStorage.setItem(STORAGE_KEY, value);
|
|
2792
|
+
window.dispatchEvent(new Event(COOKIE_CONSENT_CHANGED_EVENT));
|
|
2793
|
+
} catch {
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2603
2797
|
// src/utils/validators.ts
|
|
2604
2798
|
function validateEmail(email) {
|
|
2605
2799
|
if (!email || email.trim() === "") {
|
|
@@ -2670,70 +2864,143 @@ function validateMessage(message) {
|
|
|
2670
2864
|
}
|
|
2671
2865
|
return null;
|
|
2672
2866
|
}
|
|
2867
|
+
function isValidCountryCode(code) {
|
|
2868
|
+
if (!code) return false;
|
|
2869
|
+
return /^[A-Z]{2}$/.test(code) && code.length === 2;
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
// src/utils/guest-session.ts
|
|
2873
|
+
var GUEST_SESSION_KEY = "guest_session_id";
|
|
2874
|
+
function getOrCreateGuestSessionId(businessId) {
|
|
2875
|
+
if (typeof window === "undefined") return null;
|
|
2876
|
+
try {
|
|
2877
|
+
const existing = localStore.get(businessId, GUEST_SESSION_KEY);
|
|
2878
|
+
if (existing) return existing;
|
|
2879
|
+
const generated = crypto.randomUUID();
|
|
2880
|
+
localStore.set(businessId, GUEST_SESSION_KEY, generated);
|
|
2881
|
+
return generated;
|
|
2882
|
+
} catch {
|
|
2883
|
+
return null;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
function clearGuestSessionId(businessId) {
|
|
2887
|
+
if (typeof window === "undefined") return;
|
|
2888
|
+
try {
|
|
2889
|
+
localStore.remove(businessId, GUEST_SESSION_KEY);
|
|
2890
|
+
} catch {
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2673
2893
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2674
2894
|
0 && (module.exports = {
|
|
2895
|
+
ApiError,
|
|
2896
|
+
COOKIE_CONSENT_CHANGED_EVENT,
|
|
2675
2897
|
InvalidBaseURLError,
|
|
2898
|
+
JSON_HEADERS,
|
|
2899
|
+
ModerationStatus,
|
|
2676
2900
|
PAYMENT_URLS,
|
|
2901
|
+
PaymentGatewayEnum,
|
|
2902
|
+
PaymentMethodTypeEnum,
|
|
2903
|
+
ProductTypeEnum,
|
|
2677
2904
|
STORAGE_KEYS,
|
|
2678
2905
|
ServiceLocationTypeEnum,
|
|
2679
2906
|
ServiceRecurringIntervalEnum,
|
|
2680
2907
|
ServiceTypeEnum,
|
|
2681
|
-
acceptQuote,
|
|
2682
2908
|
addToCart,
|
|
2683
2909
|
addToGuestCart,
|
|
2684
2910
|
addToWishlist,
|
|
2685
|
-
|
|
2911
|
+
apiRequest,
|
|
2912
|
+
applyAddressSuggestion,
|
|
2913
|
+
appointmentStatusColors,
|
|
2914
|
+
approveBespokeDeliverable,
|
|
2915
|
+
approveMilestone,
|
|
2916
|
+
authHeaders,
|
|
2917
|
+
autocompleteAddress,
|
|
2686
2918
|
bespokeService,
|
|
2687
2919
|
bookAppointment,
|
|
2688
2920
|
buildDeliveryAddress,
|
|
2689
2921
|
buildFullName,
|
|
2922
|
+
bytes,
|
|
2690
2923
|
cancelAppointment,
|
|
2691
2924
|
cancelOrder,
|
|
2925
|
+
changePassword,
|
|
2692
2926
|
checkAvailability,
|
|
2693
2927
|
checkInWishlist,
|
|
2928
|
+
claimWalletCredit,
|
|
2694
2929
|
clearCart,
|
|
2695
2930
|
clearGuestCart,
|
|
2931
|
+
clearGuestSessionId,
|
|
2696
2932
|
clearTokens,
|
|
2933
|
+
compact,
|
|
2934
|
+
compactFull,
|
|
2935
|
+
compactLower,
|
|
2697
2936
|
configService,
|
|
2698
|
-
|
|
2937
|
+
confirmAppointmentCompletion,
|
|
2938
|
+
confirmMediaUpload,
|
|
2939
|
+
createBespokeOrder,
|
|
2699
2940
|
createCmsEntry,
|
|
2941
|
+
createComment,
|
|
2700
2942
|
createConsultation,
|
|
2943
|
+
createCustomerAddress,
|
|
2701
2944
|
createDedicatedAccount,
|
|
2945
|
+
createFeedback,
|
|
2946
|
+
createGraphQLClient,
|
|
2702
2947
|
createOrder,
|
|
2948
|
+
createReview,
|
|
2949
|
+
createServiceBookingOrder,
|
|
2950
|
+
currencyCompact,
|
|
2951
|
+
currencyFormat,
|
|
2952
|
+
deactivateCustomerAccount,
|
|
2953
|
+
decimal,
|
|
2954
|
+
decodePlusCode,
|
|
2703
2955
|
deleteCmsEntry,
|
|
2956
|
+
deleteCustomerAddress,
|
|
2957
|
+
disputeAppointment,
|
|
2704
2958
|
enrichCompletedOrder,
|
|
2959
|
+
extractApiErrorMessage,
|
|
2705
2960
|
findOrder,
|
|
2706
|
-
|
|
2961
|
+
forgotPasswordCustomer,
|
|
2962
|
+
formatCompactPrice,
|
|
2963
|
+
formatNumber,
|
|
2964
|
+
formatPrice,
|
|
2965
|
+
formatTimeString,
|
|
2707
2966
|
getAppointment,
|
|
2708
2967
|
getAppointments,
|
|
2709
2968
|
getAuthUser,
|
|
2969
|
+
getAvailablePaymentMethods,
|
|
2710
2970
|
getAvailableSlots,
|
|
2711
2971
|
getBusinessConfig,
|
|
2712
2972
|
getCacheTier,
|
|
2713
2973
|
getCart,
|
|
2714
2974
|
getCheckoutCustomerName,
|
|
2715
2975
|
getCmsEntry,
|
|
2716
|
-
|
|
2717
|
-
|
|
2976
|
+
getCookieConsent,
|
|
2977
|
+
getCurrencySymbol,
|
|
2978
|
+
getCustomerAddresses,
|
|
2718
2979
|
getCustomerDisplayName,
|
|
2719
|
-
getDeliverables,
|
|
2720
2980
|
getErrorMessage,
|
|
2721
2981
|
getFeaturedProducts,
|
|
2722
2982
|
getGuestCart,
|
|
2723
|
-
getGuestCartCount,
|
|
2724
2983
|
getGuestCartProductType,
|
|
2725
|
-
getGuestCartSubtotal,
|
|
2726
|
-
getLatestProducts,
|
|
2727
|
-
getLowStockProducts,
|
|
2728
2984
|
getMe,
|
|
2985
|
+
getMerchantLegalDocument,
|
|
2986
|
+
getMilestones,
|
|
2987
|
+
getMyFeedback,
|
|
2729
2988
|
getNewProducts,
|
|
2989
|
+
getNotificationInbox,
|
|
2990
|
+
getNotificationPreferences,
|
|
2730
2991
|
getOnSaleProducts,
|
|
2992
|
+
getOrCreateGuestSessionId,
|
|
2731
2993
|
getOrders,
|
|
2994
|
+
getPendingComments,
|
|
2995
|
+
getPendingReviews,
|
|
2732
2996
|
getPopularProducts,
|
|
2997
|
+
getPresignedUploadUrl,
|
|
2998
|
+
getProductComments,
|
|
2999
|
+
getProductReviews,
|
|
2733
3000
|
getRecommendedProducts,
|
|
2734
|
-
getSellerShippingAddress,
|
|
2735
3001
|
getShippingRates,
|
|
2736
3002
|
getStoredTokens,
|
|
3003
|
+
getStorefrontBusinessInfo,
|
|
2737
3004
|
getStorefrontCollectionBySlug,
|
|
2738
3005
|
getStorefrontCollections,
|
|
2739
3006
|
getStorefrontProductBySlug,
|
|
@@ -2742,52 +3009,94 @@ function validateMessage(message) {
|
|
|
2742
3009
|
getSupportedCurrencies,
|
|
2743
3010
|
getSupportedLanguages,
|
|
2744
3011
|
getTransactionStatus,
|
|
3012
|
+
getVapidPublicKey,
|
|
3013
|
+
getWalletBalance,
|
|
3014
|
+
getWalletLedger,
|
|
2745
3015
|
getWishlist,
|
|
3016
|
+
getYouTubeID,
|
|
2746
3017
|
googleTranslate,
|
|
3018
|
+
handlePinDrop,
|
|
3019
|
+
handlePlusCodeChange,
|
|
3020
|
+
hasRefreshHandler,
|
|
2747
3021
|
initiatePayment,
|
|
3022
|
+
isValidCountryCode,
|
|
3023
|
+
listBusinessLocations,
|
|
2748
3024
|
listCmsEntries,
|
|
3025
|
+
listPickupLocations,
|
|
2749
3026
|
localStore,
|
|
2750
3027
|
logger,
|
|
2751
3028
|
loginCustomer,
|
|
2752
3029
|
logisticsService,
|
|
2753
3030
|
logout,
|
|
2754
3031
|
mapAuthUserToCustomer,
|
|
3032
|
+
markAllNotificationsRead,
|
|
3033
|
+
markNotificationRead,
|
|
3034
|
+
merchantReplyToReview,
|
|
2755
3035
|
mergeGuestCart,
|
|
2756
3036
|
mergeGuestCartIfPresent,
|
|
3037
|
+
milestoneStatusColors,
|
|
3038
|
+
moderateComment,
|
|
3039
|
+
moderateReview,
|
|
2757
3040
|
notificationsService,
|
|
3041
|
+
orderStatusColors,
|
|
3042
|
+
orderStatusLabels,
|
|
3043
|
+
ordinal,
|
|
2758
3044
|
paymentService,
|
|
3045
|
+
percent,
|
|
3046
|
+
refreshAccessToken,
|
|
2759
3047
|
refreshToken,
|
|
2760
3048
|
registerCustomer,
|
|
2761
|
-
|
|
3049
|
+
registerRefreshHandler,
|
|
2762
3050
|
removeFromCart,
|
|
2763
3051
|
removeFromGuestCart,
|
|
2764
3052
|
removeFromWishlist,
|
|
2765
3053
|
removeProductFromWishlist,
|
|
2766
|
-
|
|
2767
|
-
|
|
3054
|
+
requestBespokeRevision,
|
|
3055
|
+
requestCustomerOtp,
|
|
3056
|
+
requestCustomerReactivation,
|
|
3057
|
+
rescheduleAppointment,
|
|
3058
|
+
resetPasswordCustomer,
|
|
3059
|
+
resolveDigitalDownload,
|
|
3060
|
+
resolveDigitalDownloadFile,
|
|
3061
|
+
resolveGraphQLEndpoint,
|
|
3062
|
+
reverseGeocode,
|
|
3063
|
+
roman,
|
|
2768
3064
|
sanitizeBaseUrl,
|
|
2769
3065
|
sendContactConfirmation,
|
|
2770
3066
|
sendContactEmail,
|
|
2771
|
-
sendMessage,
|
|
2772
3067
|
serviceBookingService,
|
|
2773
3068
|
sessionStore,
|
|
3069
|
+
setCookieConsent,
|
|
2774
3070
|
setEnvironmentMode,
|
|
2775
3071
|
setLoggerEnvironmentMode,
|
|
2776
3072
|
silentRefresh,
|
|
2777
3073
|
splitFullName,
|
|
2778
3074
|
storeTokens,
|
|
3075
|
+
storefrontHeaders,
|
|
3076
|
+
subscribeToPush,
|
|
3077
|
+
trackNotificationClick,
|
|
2779
3078
|
trackOrder,
|
|
3079
|
+
unsubscribeFromPush,
|
|
2780
3080
|
updateCartItem,
|
|
2781
3081
|
updateCmsEntry,
|
|
3082
|
+
updateComment,
|
|
3083
|
+
updateCustomerAddress,
|
|
2782
3084
|
updateGuestCartItemQuantity,
|
|
3085
|
+
updateNotificationPreferences,
|
|
2783
3086
|
updateProfile,
|
|
3087
|
+
updateReview,
|
|
3088
|
+
uploadMediaFile,
|
|
3089
|
+
uploadMediaFiles,
|
|
2784
3090
|
validateConfirmPassword,
|
|
2785
3091
|
validateEmail,
|
|
2786
3092
|
validateMessage,
|
|
2787
3093
|
validateName,
|
|
2788
3094
|
validatePassword,
|
|
3095
|
+
validatePromoCode,
|
|
2789
3096
|
validateRequired,
|
|
2790
3097
|
validateShippingAddress,
|
|
3098
|
+
verifyCustomerOtp,
|
|
3099
|
+
verifyCustomerReactivation,
|
|
2791
3100
|
verifySocialToken,
|
|
2792
3101
|
verifyTransaction
|
|
2793
3102
|
});
|