@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/services/index.js
CHANGED
|
@@ -20,55 +20,74 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/services/index.ts
|
|
21
21
|
var services_exports = {};
|
|
22
22
|
__export(services_exports, {
|
|
23
|
-
acceptQuote: () => acceptQuote,
|
|
24
23
|
addToCart: () => addToCart,
|
|
25
24
|
addToGuestCart: () => addToGuestCart,
|
|
26
25
|
addToWishlist: () => addToWishlist,
|
|
27
|
-
|
|
26
|
+
approveBespokeDeliverable: () => approveBespokeDeliverable,
|
|
27
|
+
approveMilestone: () => approveMilestone,
|
|
28
|
+
autocompleteAddress: () => autocompleteAddress,
|
|
28
29
|
bespokeService: () => bespokeService,
|
|
29
30
|
bookAppointment: () => bookAppointment,
|
|
30
31
|
cancelAppointment: () => cancelAppointment,
|
|
31
32
|
cancelOrder: () => cancelOrder,
|
|
33
|
+
changePassword: () => changePassword,
|
|
32
34
|
checkAvailability: () => checkAvailability,
|
|
33
35
|
checkInWishlist: () => checkInWishlist,
|
|
36
|
+
claimWalletCredit: () => claimWalletCredit,
|
|
34
37
|
clearCart: () => clearCart,
|
|
35
38
|
clearGuestCart: () => clearGuestCart,
|
|
36
39
|
clearTokens: () => clearTokens,
|
|
37
40
|
configService: () => configService,
|
|
38
|
-
|
|
41
|
+
confirmAppointmentCompletion: () => confirmAppointmentCompletion,
|
|
42
|
+
confirmMediaUpload: () => confirmMediaUpload,
|
|
43
|
+
createBespokeOrder: () => createBespokeOrder,
|
|
39
44
|
createCmsEntry: () => createCmsEntry,
|
|
45
|
+
createComment: () => createComment,
|
|
40
46
|
createConsultation: () => createConsultation,
|
|
47
|
+
createCustomerAddress: () => createCustomerAddress,
|
|
41
48
|
createDedicatedAccount: () => createDedicatedAccount,
|
|
49
|
+
createFeedback: () => createFeedback,
|
|
42
50
|
createOrder: () => createOrder,
|
|
51
|
+
createReview: () => createReview,
|
|
52
|
+
createServiceBookingOrder: () => createServiceBookingOrder,
|
|
53
|
+
deactivateCustomerAccount: () => deactivateCustomerAccount,
|
|
54
|
+
decodePlusCode: () => decodePlusCode,
|
|
43
55
|
deleteCmsEntry: () => deleteCmsEntry,
|
|
56
|
+
deleteCustomerAddress: () => deleteCustomerAddress,
|
|
57
|
+
disputeAppointment: () => disputeAppointment,
|
|
44
58
|
findOrder: () => findOrder,
|
|
45
|
-
|
|
59
|
+
forgotPasswordCustomer: () => forgotPasswordCustomer,
|
|
46
60
|
getAppointment: () => getAppointment,
|
|
47
61
|
getAppointments: () => getAppointments,
|
|
48
62
|
getAuthUser: () => getAuthUser,
|
|
63
|
+
getAvailablePaymentMethods: () => getAvailablePaymentMethods,
|
|
49
64
|
getAvailableSlots: () => getAvailableSlots,
|
|
50
65
|
getBusinessConfig: () => getBusinessConfig,
|
|
51
66
|
getCart: () => getCart,
|
|
52
67
|
getCmsEntry: () => getCmsEntry,
|
|
53
|
-
|
|
54
|
-
getConsultations: () => getConsultations,
|
|
55
|
-
getDeliverables: () => getDeliverables,
|
|
68
|
+
getCustomerAddresses: () => getCustomerAddresses,
|
|
56
69
|
getFeaturedProducts: () => getFeaturedProducts,
|
|
57
70
|
getGuestCart: () => getGuestCart,
|
|
58
|
-
getGuestCartCount: () => getGuestCartCount,
|
|
59
71
|
getGuestCartProductType: () => getGuestCartProductType,
|
|
60
|
-
getGuestCartSubtotal: () => getGuestCartSubtotal,
|
|
61
|
-
getLatestProducts: () => getLatestProducts,
|
|
62
|
-
getLowStockProducts: () => getLowStockProducts,
|
|
63
72
|
getMe: () => getMe,
|
|
73
|
+
getMerchantLegalDocument: () => getMerchantLegalDocument,
|
|
74
|
+
getMilestones: () => getMilestones,
|
|
75
|
+
getMyFeedback: () => getMyFeedback,
|
|
64
76
|
getNewProducts: () => getNewProducts,
|
|
77
|
+
getNotificationInbox: () => getNotificationInbox,
|
|
78
|
+
getNotificationPreferences: () => getNotificationPreferences,
|
|
65
79
|
getOnSaleProducts: () => getOnSaleProducts,
|
|
66
80
|
getOrders: () => getOrders,
|
|
81
|
+
getPendingComments: () => getPendingComments,
|
|
82
|
+
getPendingReviews: () => getPendingReviews,
|
|
67
83
|
getPopularProducts: () => getPopularProducts,
|
|
84
|
+
getPresignedUploadUrl: () => getPresignedUploadUrl,
|
|
85
|
+
getProductComments: () => getProductComments,
|
|
86
|
+
getProductReviews: () => getProductReviews,
|
|
68
87
|
getRecommendedProducts: () => getRecommendedProducts,
|
|
69
|
-
getSellerShippingAddress: () => getSellerShippingAddress,
|
|
70
88
|
getShippingRates: () => getShippingRates,
|
|
71
89
|
getStoredTokens: () => getStoredTokens,
|
|
90
|
+
getStorefrontBusinessInfo: () => getStorefrontBusinessInfo,
|
|
72
91
|
getStorefrontCollectionBySlug: () => getStorefrontCollectionBySlug,
|
|
73
92
|
getStorefrontCollections: () => getStorefrontCollections,
|
|
74
93
|
getStorefrontProductBySlug: () => getStorefrontProductBySlug,
|
|
@@ -76,44 +95,167 @@ __export(services_exports, {
|
|
|
76
95
|
getSupportedCurrencies: () => getSupportedCurrencies,
|
|
77
96
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
78
97
|
getTransactionStatus: () => getTransactionStatus,
|
|
98
|
+
getVapidPublicKey: () => getVapidPublicKey,
|
|
99
|
+
getWalletBalance: () => getWalletBalance,
|
|
100
|
+
getWalletLedger: () => getWalletLedger,
|
|
79
101
|
getWishlist: () => getWishlist,
|
|
80
102
|
googleTranslate: () => googleTranslate,
|
|
81
103
|
initiatePayment: () => initiatePayment,
|
|
104
|
+
listBusinessLocations: () => listBusinessLocations,
|
|
82
105
|
listCmsEntries: () => listCmsEntries,
|
|
106
|
+
listPickupLocations: () => listPickupLocations,
|
|
83
107
|
loginCustomer: () => loginCustomer,
|
|
84
108
|
logisticsService: () => logisticsService,
|
|
85
109
|
logout: () => logout,
|
|
86
110
|
mapAuthUserToCustomer: () => mapAuthUserToCustomer,
|
|
111
|
+
markAllNotificationsRead: () => markAllNotificationsRead,
|
|
112
|
+
markNotificationRead: () => markNotificationRead,
|
|
113
|
+
merchantReplyToReview: () => merchantReplyToReview,
|
|
87
114
|
mergeGuestCart: () => mergeGuestCart,
|
|
88
115
|
mergeGuestCartIfPresent: () => mergeGuestCartIfPresent,
|
|
116
|
+
moderateComment: () => moderateComment,
|
|
117
|
+
moderateReview: () => moderateReview,
|
|
89
118
|
notificationsService: () => notificationsService,
|
|
90
119
|
paymentService: () => paymentService,
|
|
91
120
|
refreshToken: () => refreshToken,
|
|
92
121
|
registerCustomer: () => registerCustomer,
|
|
93
|
-
rejectQuote: () => rejectQuote,
|
|
94
122
|
removeFromCart: () => removeFromCart,
|
|
95
123
|
removeFromGuestCart: () => removeFromGuestCart,
|
|
96
124
|
removeFromWishlist: () => removeFromWishlist,
|
|
97
125
|
removeProductFromWishlist: () => removeProductFromWishlist,
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
requestBespokeRevision: () => requestBespokeRevision,
|
|
127
|
+
requestCustomerOtp: () => requestCustomerOtp,
|
|
128
|
+
requestCustomerReactivation: () => requestCustomerReactivation,
|
|
129
|
+
rescheduleAppointment: () => rescheduleAppointment,
|
|
130
|
+
resetPasswordCustomer: () => resetPasswordCustomer,
|
|
131
|
+
resolveDigitalDownload: () => resolveDigitalDownload,
|
|
132
|
+
resolveDigitalDownloadFile: () => resolveDigitalDownloadFile,
|
|
133
|
+
reverseGeocode: () => reverseGeocode,
|
|
100
134
|
sendContactConfirmation: () => sendContactConfirmation,
|
|
101
135
|
sendContactEmail: () => sendContactEmail,
|
|
102
|
-
sendMessage: () => sendMessage,
|
|
103
136
|
serviceBookingService: () => serviceBookingService,
|
|
104
137
|
silentRefresh: () => silentRefresh,
|
|
105
138
|
storeTokens: () => storeTokens,
|
|
139
|
+
subscribeToPush: () => subscribeToPush,
|
|
140
|
+
trackNotificationClick: () => trackNotificationClick,
|
|
106
141
|
trackOrder: () => trackOrder,
|
|
142
|
+
unsubscribeFromPush: () => unsubscribeFromPush,
|
|
107
143
|
updateCartItem: () => updateCartItem,
|
|
108
144
|
updateCmsEntry: () => updateCmsEntry,
|
|
145
|
+
updateComment: () => updateComment,
|
|
146
|
+
updateCustomerAddress: () => updateCustomerAddress,
|
|
109
147
|
updateGuestCartItemQuantity: () => updateGuestCartItemQuantity,
|
|
148
|
+
updateNotificationPreferences: () => updateNotificationPreferences,
|
|
110
149
|
updateProfile: () => updateProfile,
|
|
150
|
+
updateReview: () => updateReview,
|
|
151
|
+
uploadMediaFile: () => uploadMediaFile,
|
|
152
|
+
uploadMediaFiles: () => uploadMediaFiles,
|
|
153
|
+
validatePromoCode: () => validatePromoCode,
|
|
111
154
|
validateShippingAddress: () => validateShippingAddress,
|
|
155
|
+
verifyCustomerOtp: () => verifyCustomerOtp,
|
|
156
|
+
verifyCustomerReactivation: () => verifyCustomerReactivation,
|
|
112
157
|
verifySocialToken: () => verifySocialToken,
|
|
113
158
|
verifyTransaction: () => verifyTransaction
|
|
114
159
|
});
|
|
115
160
|
module.exports = __toCommonJS(services_exports);
|
|
116
161
|
|
|
162
|
+
// src/utils/token-refresh.ts
|
|
163
|
+
var GLOBAL_KEY = "__kasuviaSdkTokenRefreshRegistry__";
|
|
164
|
+
function getRegistry() {
|
|
165
|
+
const g = globalThis;
|
|
166
|
+
if (!g[GLOBAL_KEY]) {
|
|
167
|
+
g[GLOBAL_KEY] = { handler: null, inFlight: null };
|
|
168
|
+
}
|
|
169
|
+
return g[GLOBAL_KEY];
|
|
170
|
+
}
|
|
171
|
+
async function refreshAccessToken() {
|
|
172
|
+
const registry = getRegistry();
|
|
173
|
+
if (!registry.handler) return null;
|
|
174
|
+
if (registry.inFlight) return registry.inFlight;
|
|
175
|
+
registry.inFlight = registry.handler().finally(() => {
|
|
176
|
+
registry.inFlight = null;
|
|
177
|
+
});
|
|
178
|
+
return registry.inFlight;
|
|
179
|
+
}
|
|
180
|
+
function hasRefreshHandler() {
|
|
181
|
+
return getRegistry().handler !== null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/utils/http-client.ts
|
|
185
|
+
var ApiError = class extends Error {
|
|
186
|
+
constructor(message, status, body) {
|
|
187
|
+
super(message);
|
|
188
|
+
this.name = "ApiError";
|
|
189
|
+
this.status = status;
|
|
190
|
+
this.body = body;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
function extractApiErrorMessage(body, fallback) {
|
|
194
|
+
if (typeof body !== "object" || body === null) return fallback;
|
|
195
|
+
const record = body;
|
|
196
|
+
if (typeof record.detail === "string") return record.detail;
|
|
197
|
+
if (Array.isArray(record.detail) && record.detail.length > 0) {
|
|
198
|
+
const first = record.detail[0];
|
|
199
|
+
if (first && typeof first.msg === "string") {
|
|
200
|
+
const loc = first.loc;
|
|
201
|
+
const field = Array.isArray(loc) ? loc[loc.length - 1] : void 0;
|
|
202
|
+
return typeof field === "string" || typeof field === "number" ? `${field}: ${first.msg}` : first.msg;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const firstStringOrArrayItem = (value) => {
|
|
206
|
+
if (typeof value === "string") return value;
|
|
207
|
+
if (Array.isArray(value) && typeof value[0] === "string") return value[0];
|
|
208
|
+
return void 0;
|
|
209
|
+
};
|
|
210
|
+
const nonFieldMessage = firstStringOrArrayItem(record.non_field_errors);
|
|
211
|
+
if (nonFieldMessage) return nonFieldMessage;
|
|
212
|
+
for (const [key, value] of Object.entries(record)) {
|
|
213
|
+
if (key === "detail" || key === "non_field_errors") continue;
|
|
214
|
+
const message = firstStringOrArrayItem(value);
|
|
215
|
+
if (message) return message;
|
|
216
|
+
}
|
|
217
|
+
return fallback;
|
|
218
|
+
}
|
|
219
|
+
function storefrontHeaders(config) {
|
|
220
|
+
return {
|
|
221
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
222
|
+
"X-Business-ID": config.businessId
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function authHeaders(config, accessToken) {
|
|
226
|
+
return {
|
|
227
|
+
...storefrontHeaders(config),
|
|
228
|
+
Authorization: `Bearer ${accessToken}`
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
232
|
+
async function apiRequest(url, options = {}) {
|
|
233
|
+
const { fallbackErrorMessage = "Request failed", ...init } = options;
|
|
234
|
+
const headers = new Headers(init.headers);
|
|
235
|
+
const hadBearerToken = headers.get("Authorization")?.startsWith("Bearer ") ?? false;
|
|
236
|
+
const response = await fetch(url, { ...init, headers });
|
|
237
|
+
if (response.status === 401 && hadBearerToken && hasRefreshHandler()) {
|
|
238
|
+
const freshToken = await refreshAccessToken();
|
|
239
|
+
if (freshToken) {
|
|
240
|
+
const retryHeaders = new Headers(headers);
|
|
241
|
+
retryHeaders.set("Authorization", `Bearer ${freshToken}`);
|
|
242
|
+
const retryResponse = await fetch(url, { ...init, headers: retryHeaders });
|
|
243
|
+
if (retryResponse.ok) {
|
|
244
|
+
const retryText = await retryResponse.text();
|
|
245
|
+
return retryText ? JSON.parse(retryText) : void 0;
|
|
246
|
+
}
|
|
247
|
+
const retryBody = await retryResponse.json().catch(() => ({}));
|
|
248
|
+
throw new ApiError(extractApiErrorMessage(retryBody, fallbackErrorMessage), retryResponse.status, retryBody);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (!response.ok) {
|
|
252
|
+
const body = await response.json().catch(() => ({}));
|
|
253
|
+
throw new ApiError(extractApiErrorMessage(body, fallbackErrorMessage), response.status, body);
|
|
254
|
+
}
|
|
255
|
+
const text = await response.text();
|
|
256
|
+
return text ? JSON.parse(text) : void 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
117
259
|
// src/services/cart.service.ts
|
|
118
260
|
function parseItems(items) {
|
|
119
261
|
return items.map((item) => ({
|
|
@@ -121,218 +263,148 @@ function parseItems(items) {
|
|
|
121
263
|
variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
|
|
122
264
|
}));
|
|
123
265
|
}
|
|
266
|
+
function guestHeaders(config, guestSessionId, extra) {
|
|
267
|
+
return { ...extra, ...storefrontHeaders(config), "X-Guest-Session": guestSessionId };
|
|
268
|
+
}
|
|
124
269
|
async function getGuestCart(config, guestSessionId) {
|
|
125
|
-
if (!guestSessionId)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
"X-Guest-Session": guestSessionId
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
if (!response.ok) return [];
|
|
135
|
-
const data = await response.json();
|
|
136
|
-
return parseItems(data.items || []);
|
|
137
|
-
} catch {
|
|
138
|
-
return [];
|
|
139
|
-
}
|
|
270
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to fetch guest cart");
|
|
271
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
272
|
+
headers: guestHeaders(config, guestSessionId),
|
|
273
|
+
fallbackErrorMessage: "Failed to fetch guest cart"
|
|
274
|
+
});
|
|
275
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
140
276
|
}
|
|
141
277
|
async function addToGuestCart(config, guestSessionId, item) {
|
|
142
|
-
if (!guestSessionId)
|
|
278
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to add to guest cart");
|
|
143
279
|
const payload = {
|
|
144
280
|
product_id: item.product_id,
|
|
145
|
-
|
|
146
|
-
product_name: item.product_name,
|
|
147
|
-
image: item.image,
|
|
148
|
-
variant_id: item.variant_id,
|
|
149
|
-
variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes),
|
|
150
|
-
unit_price: item.unit_price,
|
|
281
|
+
variant_id: item.variant_id ?? void 0,
|
|
151
282
|
quantity: item.quantity,
|
|
152
|
-
custom_measurements: item.custom_measurements
|
|
153
|
-
is_bespoke: item.is_bespoke
|
|
283
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
154
284
|
};
|
|
155
|
-
const
|
|
285
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
156
286
|
method: "POST",
|
|
157
|
-
headers:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
body: JSON.stringify(payload)
|
|
164
|
-
});
|
|
165
|
-
if (!response.ok) return [];
|
|
166
|
-
const data = await response.json();
|
|
167
|
-
return parseItems(data.items || []);
|
|
287
|
+
headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
|
|
288
|
+
body: JSON.stringify(payload),
|
|
289
|
+
fallbackErrorMessage: "Failed to add to guest cart"
|
|
290
|
+
});
|
|
291
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
168
292
|
}
|
|
169
293
|
async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
|
|
170
|
-
if (!guestSessionId)
|
|
171
|
-
const
|
|
294
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to update guest cart item");
|
|
295
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
172
296
|
method: "PATCH",
|
|
173
|
-
headers:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
},
|
|
179
|
-
body: JSON.stringify({ quantity })
|
|
180
|
-
});
|
|
181
|
-
if (!response.ok) return [];
|
|
182
|
-
const data = await response.json();
|
|
183
|
-
return parseItems(data.items || []);
|
|
297
|
+
headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
|
|
298
|
+
body: JSON.stringify({ quantity }),
|
|
299
|
+
fallbackErrorMessage: "Failed to update guest cart item"
|
|
300
|
+
});
|
|
301
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
184
302
|
}
|
|
185
303
|
async function removeFromGuestCart(config, guestSessionId, itemId) {
|
|
186
|
-
if (!guestSessionId)
|
|
187
|
-
await
|
|
304
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to remove from guest cart");
|
|
305
|
+
await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
188
306
|
method: "DELETE",
|
|
189
|
-
headers:
|
|
190
|
-
|
|
191
|
-
"X-Business-ID": config.businessId,
|
|
192
|
-
"X-Guest-Session": guestSessionId
|
|
193
|
-
}
|
|
307
|
+
headers: guestHeaders(config, guestSessionId),
|
|
308
|
+
fallbackErrorMessage: "Failed to remove item from guest cart"
|
|
194
309
|
});
|
|
195
|
-
return getGuestCart(config, guestSessionId);
|
|
196
310
|
}
|
|
197
311
|
async function clearGuestCart(config, guestSessionId) {
|
|
198
|
-
if (!guestSessionId)
|
|
199
|
-
await
|
|
312
|
+
if (!guestSessionId) throw new Error("Guest session ID is required to clear guest cart");
|
|
313
|
+
await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
|
|
200
314
|
method: "DELETE",
|
|
201
|
-
headers:
|
|
202
|
-
|
|
203
|
-
"X-Business-ID": config.businessId,
|
|
204
|
-
"X-Guest-Session": guestSessionId
|
|
205
|
-
}
|
|
315
|
+
headers: guestHeaders(config, guestSessionId),
|
|
316
|
+
fallbackErrorMessage: "Failed to clear guest cart"
|
|
206
317
|
});
|
|
207
318
|
}
|
|
208
319
|
async function getCart(config, accessToken) {
|
|
209
320
|
if (!accessToken) {
|
|
210
|
-
|
|
321
|
+
throw new Error("Access token is required to fetch authenticated cart");
|
|
211
322
|
}
|
|
212
|
-
const
|
|
213
|
-
headers:
|
|
214
|
-
|
|
215
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
216
|
-
"X-Business-ID": config.businessId
|
|
217
|
-
}
|
|
323
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
324
|
+
headers: authHeaders(config, accessToken),
|
|
325
|
+
fallbackErrorMessage: "Failed to fetch cart"
|
|
218
326
|
});
|
|
219
|
-
|
|
220
|
-
const data = await response.json();
|
|
221
|
-
const parsedItems = parseItems(data.items || []);
|
|
222
|
-
return { ...data, items: parsedItems };
|
|
327
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
223
328
|
}
|
|
224
329
|
async function addToCart(config, accessToken, item) {
|
|
225
|
-
const
|
|
330
|
+
const payload = {
|
|
331
|
+
product_id: item.product_id,
|
|
332
|
+
variant_id: item.variant_id ?? void 0,
|
|
333
|
+
quantity: item.quantity,
|
|
334
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
335
|
+
};
|
|
336
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
|
|
226
337
|
method: "POST",
|
|
227
|
-
headers: {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
},
|
|
233
|
-
body: JSON.stringify(item)
|
|
234
|
-
});
|
|
235
|
-
if (!response.ok) throw new Error("Failed to add to cart");
|
|
236
|
-
const data = await response.json();
|
|
237
|
-
const parsedItems = parseItems(data.items || []);
|
|
238
|
-
return { ...data, items: parsedItems };
|
|
338
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
339
|
+
body: JSON.stringify(payload),
|
|
340
|
+
fallbackErrorMessage: "Failed to add to cart"
|
|
341
|
+
});
|
|
342
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
239
343
|
}
|
|
240
344
|
async function updateCartItem(config, accessToken, itemId, quantity) {
|
|
241
|
-
const
|
|
345
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
242
346
|
method: "PATCH",
|
|
243
|
-
headers: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
},
|
|
249
|
-
body: JSON.stringify({ quantity })
|
|
250
|
-
});
|
|
251
|
-
if (!response.ok) throw new Error("Failed to update cart item");
|
|
252
|
-
const data = await response.json();
|
|
253
|
-
const parsedItems = parseItems(data.items || []);
|
|
254
|
-
return { ...data, items: parsedItems };
|
|
347
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
348
|
+
body: JSON.stringify({ quantity }),
|
|
349
|
+
fallbackErrorMessage: "Failed to update cart item"
|
|
350
|
+
});
|
|
351
|
+
return { ...data, items: parseItems(data.items || []) };
|
|
255
352
|
}
|
|
256
353
|
async function removeFromCart(config, accessToken, itemId) {
|
|
257
|
-
await
|
|
354
|
+
await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
|
|
258
355
|
method: "DELETE",
|
|
259
|
-
headers:
|
|
260
|
-
|
|
261
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
262
|
-
"X-Business-ID": config.businessId
|
|
263
|
-
}
|
|
356
|
+
headers: authHeaders(config, accessToken),
|
|
357
|
+
fallbackErrorMessage: "Failed to remove cart item"
|
|
264
358
|
});
|
|
265
|
-
return getCart(config, accessToken);
|
|
266
359
|
}
|
|
267
360
|
async function clearCart(config, accessToken) {
|
|
268
|
-
await
|
|
361
|
+
await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
|
|
269
362
|
method: "DELETE",
|
|
270
|
-
headers:
|
|
271
|
-
|
|
272
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
273
|
-
"X-Business-ID": config.businessId
|
|
274
|
-
}
|
|
363
|
+
headers: authHeaders(config, accessToken),
|
|
364
|
+
fallbackErrorMessage: "Failed to clear cart"
|
|
275
365
|
});
|
|
276
366
|
}
|
|
277
|
-
async function mergeGuestCart(config, accessToken, guestSessionId) {
|
|
278
|
-
const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
|
|
279
|
-
if (guestItems.length === 0) {
|
|
280
|
-
return getCart(config, accessToken);
|
|
281
|
-
}
|
|
367
|
+
async function mergeGuestCart(config, accessToken, guestSessionId, guestItems) {
|
|
282
368
|
const payloadItems = guestItems.map((item) => ({
|
|
283
369
|
product_id: item.product_id,
|
|
284
|
-
|
|
285
|
-
product_name: item.product_name,
|
|
286
|
-
image: item.image,
|
|
287
|
-
variant_id: item.variant_id,
|
|
288
|
-
variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
|
|
289
|
-
unit_price: item.unit_price,
|
|
370
|
+
variant_id: item.variant_id ?? void 0,
|
|
290
371
|
quantity: item.quantity,
|
|
291
|
-
custom_measurements:
|
|
292
|
-
is_bespoke: item.is_bespoke
|
|
372
|
+
custom_measurements: item.custom_measurements ?? void 0
|
|
293
373
|
}));
|
|
294
|
-
const headers = {
|
|
295
|
-
"Content-Type": "application/json",
|
|
296
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
297
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
298
|
-
"X-Business-ID": config.businessId
|
|
299
|
-
};
|
|
374
|
+
const headers = { ...JSON_HEADERS, ...authHeaders(config, accessToken) };
|
|
300
375
|
if (guestSessionId) {
|
|
301
376
|
headers["X-Guest-Session"] = guestSessionId;
|
|
302
377
|
}
|
|
303
|
-
const
|
|
378
|
+
const data = await apiRequest(`${config.backendUrls.cart}/cart/merge`, {
|
|
304
379
|
method: "POST",
|
|
305
380
|
headers,
|
|
306
|
-
body: JSON.stringify({ items: payloadItems })
|
|
381
|
+
body: JSON.stringify({ items: payloadItems }),
|
|
382
|
+
fallbackErrorMessage: "Failed to merge guest cart"
|
|
307
383
|
});
|
|
308
|
-
if (!response.ok) throw new Error("Failed to merge guest cart");
|
|
309
|
-
const data = await response.json();
|
|
310
384
|
return { ...data, items: parseItems(data.items || []) };
|
|
311
385
|
}
|
|
312
386
|
async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
await mergeGuestCart(config, accessToken, guestSessionId);
|
|
317
|
-
} catch (error) {
|
|
318
|
-
console.warn("[Cart] Failed to merge guest cart:", error);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
function getGuestCartCount() {
|
|
322
|
-
return 0;
|
|
387
|
+
const guestCart = await getGuestCart(config, guestSessionId);
|
|
388
|
+
if (!guestCart.items.length) return;
|
|
389
|
+
await mergeGuestCart(config, accessToken, guestSessionId, guestCart.items);
|
|
323
390
|
}
|
|
324
|
-
function
|
|
325
|
-
return
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return
|
|
391
|
+
function getGuestCartProductType(items) {
|
|
392
|
+
if (!items || !items.length) return null;
|
|
393
|
+
const types = new Set(items.map((i) => i.product_type).filter(Boolean));
|
|
394
|
+
if (types.size === 0) return null;
|
|
395
|
+
if (types.size === 1) return [...types][0] ?? null;
|
|
396
|
+
return "physical" /* PHYSICAL */;
|
|
329
397
|
}
|
|
330
398
|
|
|
331
399
|
// src/services/order.service.ts
|
|
400
|
+
function extractShippingAddress(raw) {
|
|
401
|
+
const val = raw.physical_fulfillment?.shipping_address;
|
|
402
|
+
return typeof val === "object" && val !== null ? val : null;
|
|
403
|
+
}
|
|
332
404
|
function deriveCustomerName(raw) {
|
|
333
405
|
if (raw.customer_name) return raw.customer_name;
|
|
334
406
|
if (raw.guest_name) return raw.guest_name;
|
|
335
|
-
const addr =
|
|
407
|
+
const addr = extractShippingAddress(raw);
|
|
336
408
|
if (addr) {
|
|
337
409
|
const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
|
|
338
410
|
if (full) return full;
|
|
@@ -344,25 +416,123 @@ function deriveCustomerName(raw) {
|
|
|
344
416
|
function normaliseStorefrontOrder(raw) {
|
|
345
417
|
const items = (raw.items ?? []).map((item) => ({
|
|
346
418
|
id: item.id,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
419
|
+
order_id: item.order_id,
|
|
420
|
+
product_id: item.product_id ?? void 0,
|
|
421
|
+
variant_id: item.variant_id ?? void 0,
|
|
422
|
+
product_name: item.product_name ?? "",
|
|
423
|
+
quantity: item.quantity,
|
|
424
|
+
unit_price: item.unit_price,
|
|
425
|
+
variant_details: item.variant_details,
|
|
426
|
+
custom_measurements: item.custom_measurements,
|
|
427
|
+
image_url: item.image_url ?? void 0
|
|
351
428
|
}));
|
|
352
|
-
const addr =
|
|
429
|
+
const addr = extractShippingAddress(raw);
|
|
430
|
+
const customerName = deriveCustomerName(raw);
|
|
431
|
+
const customerEmail = raw.guest_email ?? raw.customer_email ?? "";
|
|
432
|
+
const physical = raw.physical_fulfillment;
|
|
433
|
+
if (!raw.currency) {
|
|
434
|
+
throw new Error(`Order ${raw.id} response is missing a currency field.`);
|
|
435
|
+
}
|
|
436
|
+
if (!raw.created_at) {
|
|
437
|
+
throw new Error(`Order ${raw.id} response is missing a created_at field.`);
|
|
438
|
+
}
|
|
439
|
+
if (!raw.updated_at) {
|
|
440
|
+
throw new Error(`Order ${raw.id} response is missing an updated_at field.`);
|
|
441
|
+
}
|
|
442
|
+
if (!raw.business_id) {
|
|
443
|
+
throw new Error(`Order ${raw.id} response is missing a business_id field.`);
|
|
444
|
+
}
|
|
353
445
|
return {
|
|
354
446
|
id: raw.id,
|
|
355
|
-
display_id: raw.display_id,
|
|
447
|
+
display_id: raw.display_id || raw.id,
|
|
448
|
+
business_id: raw.business_id,
|
|
449
|
+
customer_id: raw.customer_id ?? void 0,
|
|
356
450
|
items,
|
|
357
|
-
total: raw.total_amount ?? raw.total ?? 0,
|
|
358
451
|
status: raw.status,
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
452
|
+
payment_status: raw.payment_status || "pending",
|
|
453
|
+
product_type: raw.product_type ?? void 0,
|
|
454
|
+
// Canonical backend fields
|
|
455
|
+
total_amount: raw.total_amount,
|
|
456
|
+
currency: raw.currency,
|
|
457
|
+
subtotal_amount: raw.subtotal_amount ?? void 0,
|
|
458
|
+
shipping_amount: raw.shipping_amount ?? void 0,
|
|
459
|
+
discount_amount: raw.discount_amount ?? void 0,
|
|
460
|
+
tax_amount: raw.tax_amount ?? void 0,
|
|
461
|
+
customer_name: customerName,
|
|
462
|
+
customer_email: customerEmail,
|
|
463
|
+
// REAL BUG FIXED (2026-09-23) via the REST codegen initiative: every
|
|
464
|
+
// field below this point used to read a flat `raw.<field>` that does
|
|
465
|
+
// NOT exist anywhere on the real OrderResponse - confirmed by reading
|
|
466
|
+
// the actual Pydantic classes, not just the generated types. They
|
|
467
|
+
// genuinely live nested under `physical_fulfillment` (shipping/
|
|
468
|
+
// tracking/carrier/pickup/surcharge/weight) or `digital_fulfillment`
|
|
469
|
+
// (buyer_country) - "One nested block per product type, instead of
|
|
470
|
+
// ~35 flat fields on OrderBase" per that schema file's own Order
|
|
471
|
+
// Schema Refactor comment. Every one of these was silently `undefined`
|
|
472
|
+
// on every real order: a customer's tracking number, carrier, delivery
|
|
473
|
+
// status, and shipping address never actually rendered anywhere on the
|
|
474
|
+
// storefront's order tracking page.
|
|
475
|
+
tracking_number: physical?.tracking_number ?? void 0,
|
|
476
|
+
delivery_status: physical?.delivery_status ?? void 0,
|
|
477
|
+
carrier_name: physical?.carrier_name ?? void 0,
|
|
478
|
+
carrier_slug: physical?.carrier_slug ?? void 0,
|
|
479
|
+
terminal_rate_id: physical?.terminal_rate_id ?? void 0,
|
|
480
|
+
guest_token: raw.guest_token ?? void 0,
|
|
481
|
+
guest_email: raw.guest_email ?? void 0,
|
|
482
|
+
guest_phone: raw.guest_phone ?? void 0,
|
|
483
|
+
guest_name: raw.guest_name ?? void 0,
|
|
484
|
+
buyer_country: raw.digital_fulfillment?.buyer_country ?? void 0,
|
|
485
|
+
created_at: raw.created_at,
|
|
486
|
+
updated_at: raw.updated_at,
|
|
487
|
+
// Weight discrepancy & surcharge fields (Task 2) — physical_fulfillment
|
|
488
|
+
shipping_surcharge_amount: physical?.shipping_surcharge_amount ?? void 0,
|
|
489
|
+
shipping_surcharge_reason: physical?.shipping_surcharge_reason ?? void 0,
|
|
490
|
+
shipping_surcharge_description: physical?.shipping_surcharge_description ?? void 0,
|
|
491
|
+
shipping_surcharge_applied_at: physical?.shipping_surcharge_applied_at ?? void 0,
|
|
492
|
+
declared_weight_kg: physical?.declared_weight_kg ?? void 0,
|
|
493
|
+
actual_weight_kg: physical?.actual_weight_kg ?? void 0,
|
|
494
|
+
// Self-pickup verification fields (Task 3) — physical_fulfillment
|
|
495
|
+
pickup_verification_code: physical?.pickup_verification_code ?? void 0,
|
|
496
|
+
pickup_verification_code_generated_at: physical?.pickup_verification_code_generated_at ?? void 0,
|
|
497
|
+
pickup_verification_code_used_at: physical?.pickup_verification_code_used_at ?? void 0,
|
|
498
|
+
pickup_verification_failed_attempts: physical?.pickup_verification_failed_attempts,
|
|
499
|
+
pickup_verification_locked_until: physical?.pickup_verification_locked_until ?? void 0,
|
|
500
|
+
pickup_qr_payload: physical?.pickup_qr_payload ?? void 0,
|
|
501
|
+
// Bespoke fields — real backend nests these under `bespoke_fulfillment`.
|
|
502
|
+
bespoke_brief: raw.bespoke_fulfillment?.brief ?? void 0,
|
|
503
|
+
bespoke_reference_images: raw.bespoke_fulfillment?.reference_images ?? void 0,
|
|
504
|
+
bespoke_measurements: raw.bespoke_fulfillment?.measurements ?? void 0,
|
|
505
|
+
bespoke_preferred_timeline: raw.bespoke_fulfillment?.preferred_timeline ?? void 0,
|
|
506
|
+
bespoke_special_instructions: raw.bespoke_fulfillment?.special_instructions ?? void 0,
|
|
507
|
+
bespoke_deposit_ratio: raw.bespoke_fulfillment?.deposit_ratio ?? void 0,
|
|
508
|
+
bespoke_deposit_amount: raw.bespoke_fulfillment?.deposit_amount ?? void 0,
|
|
509
|
+
bespoke_balance_amount: raw.bespoke_fulfillment?.balance_amount ?? void 0,
|
|
510
|
+
bespoke_status: raw.bespoke_fulfillment?.status ?? void 0,
|
|
511
|
+
bespoke_deliverable_submitted_at: raw.bespoke_fulfillment?.deliverable_submitted_at ?? void 0,
|
|
512
|
+
bespoke_deliverable_url: raw.bespoke_fulfillment?.deliverable_url ?? void 0,
|
|
513
|
+
bespoke_deliverable_notes: raw.bespoke_fulfillment?.deliverable_notes ?? void 0,
|
|
514
|
+
bespoke_buyer_approved_at: raw.bespoke_fulfillment?.buyer_approved_at ?? void 0,
|
|
515
|
+
bespoke_revision_count: raw.bespoke_fulfillment?.revision_count ?? 0,
|
|
516
|
+
bespoke_revision_notes: raw.bespoke_fulfillment?.revision_notes ?? void 0,
|
|
517
|
+
// SDK camelCase convenience aliases
|
|
518
|
+
total: raw.total_amount ?? void 0,
|
|
519
|
+
shippingAmount: raw.shipping_amount ?? void 0,
|
|
520
|
+
discountAmount: raw.discount_amount ?? void 0,
|
|
521
|
+
customerEmail,
|
|
522
|
+
customerName,
|
|
523
|
+
createdAt: new Date(raw.created_at).getTime(),
|
|
524
|
+
updatedAt: new Date(raw.updated_at).getTime(),
|
|
525
|
+
// REAL BUG FIXED (2026-09-23), found alongside the nesting bug above:
|
|
526
|
+
// `deliveryMethod` reads physical_fulfillment.shipping_method now
|
|
527
|
+
// (was reading a flat `delivery_method` field that never existed at
|
|
528
|
+
// all, anywhere - not even nested). The real value is "carrier" or
|
|
529
|
+
// "self_pickup" (PhysicalFulfillmentCreate.shipping_method's own
|
|
530
|
+
// docstring) - see the matching fix in kasuvia-storefront's
|
|
531
|
+
// OrderDeliveryInfo.tsx, which used to compare against the wrong
|
|
532
|
+
// string "pickup".
|
|
533
|
+
deliveryMethod: physical?.shipping_method ?? void 0,
|
|
534
|
+
trackingNumber: physical?.tracking_number ?? void 0,
|
|
535
|
+
deliveryAddress: addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
|
|
366
536
|
shippingAddress: addr ? {
|
|
367
537
|
first_name: addr.first_name ?? "",
|
|
368
538
|
last_name: addr.last_name ?? "",
|
|
@@ -370,62 +540,85 @@ function normaliseStorefrontOrder(raw) {
|
|
|
370
540
|
street: addr.street ?? "",
|
|
371
541
|
city: addr.city ?? "",
|
|
372
542
|
state: addr.state ?? "",
|
|
373
|
-
lga: addr.lga
|
|
543
|
+
lga: addr.lga,
|
|
374
544
|
country: addr.country ?? "",
|
|
375
|
-
postal: addr.postal
|
|
545
|
+
postal: addr.postal
|
|
376
546
|
} : void 0,
|
|
377
|
-
|
|
547
|
+
// REAL GAP (2026-09-23), NOT fixed here: confirmed cancellation_reason
|
|
548
|
+
// does not exist anywhere in OrderResponse or any of its fulfillment
|
|
549
|
+
// sub-schemas (kasuvia-store-management's app/schemas/order.py) - the
|
|
550
|
+
// cancel-order endpoint accepts a `reason` in its request body but the
|
|
551
|
+
// backend never persists/returns it back on the order. Permanently
|
|
552
|
+
// undefined until the backend adds real storage for it; kept as a
|
|
553
|
+
// field on the public Order type rather than silently removed, since
|
|
554
|
+
// deleting a public SDK field is a breaking change this fix's scope
|
|
555
|
+
// doesn't cover.
|
|
556
|
+
cancellationReason: void 0,
|
|
378
557
|
hasBespoke: raw.product_type === "bespoke",
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
558
|
+
// REAL GAP (2026-09-23), NOT fixed here: same as cancellationReason -
|
|
559
|
+
// confirmed no `bespoke_stage` field exists anywhere; the real,
|
|
560
|
+
// equivalent concept is bespoke_fulfillment.status (already exposed
|
|
561
|
+
// above as `bespoke_status`). Reads that here rather than staying
|
|
562
|
+
// permanently undefined, since it's genuinely the same real data the
|
|
563
|
+
// consuming components (BespokeProgress) want to key off of.
|
|
564
|
+
bespokeStage: raw.bespoke_fulfillment?.status ?? void 0,
|
|
565
|
+
bespokeBrief: raw.bespoke_fulfillment?.brief ?? void 0,
|
|
566
|
+
deliveryStatus: physical?.delivery_status ?? void 0,
|
|
567
|
+
carrierName: physical?.carrier_name ?? void 0,
|
|
568
|
+
terminalShipmentId: physical?.terminal_shipment_id ?? void 0,
|
|
569
|
+
guestToken: raw.guest_token ?? void 0,
|
|
570
|
+
guestEmail: raw.guest_email ?? void 0,
|
|
571
|
+
guestPhone: raw.guest_phone ?? void 0,
|
|
572
|
+
guestName: raw.guest_name ?? void 0
|
|
388
573
|
};
|
|
389
574
|
}
|
|
390
|
-
async function createOrder(config, accessToken, payload) {
|
|
391
|
-
const
|
|
575
|
+
async function createOrder(config, accessToken, payload, guestSessionId) {
|
|
576
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
577
|
+
if (accessToken) {
|
|
578
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
579
|
+
} else if (guestSessionId) {
|
|
580
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
581
|
+
}
|
|
582
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront`, {
|
|
392
583
|
method: "POST",
|
|
393
|
-
headers
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
"X-Business-ID": config.businessId
|
|
398
|
-
},
|
|
399
|
-
body: JSON.stringify(payload)
|
|
400
|
-
});
|
|
401
|
-
if (!response.ok) throw new Error("Failed to create order");
|
|
402
|
-
const data = await response.json();
|
|
584
|
+
headers,
|
|
585
|
+
body: JSON.stringify(payload),
|
|
586
|
+
fallbackErrorMessage: "Failed to create order"
|
|
587
|
+
});
|
|
403
588
|
return normaliseStorefrontOrder(data);
|
|
404
589
|
}
|
|
405
|
-
async function
|
|
406
|
-
const
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
"X-Business-ID": config.businessId
|
|
414
|
-
}
|
|
590
|
+
async function createBespokeOrder(config, accessToken, payload) {
|
|
591
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
592
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
593
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/bespoke`, {
|
|
594
|
+
method: "POST",
|
|
595
|
+
headers,
|
|
596
|
+
body: JSON.stringify(payload),
|
|
597
|
+
fallbackErrorMessage: "Failed to create bespoke order"
|
|
415
598
|
});
|
|
416
|
-
if (!response.ok) throw new Error("Failed to find order");
|
|
417
|
-
const data = await response.json();
|
|
418
599
|
return normaliseStorefrontOrder(data);
|
|
419
600
|
}
|
|
420
|
-
async function
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
601
|
+
async function createServiceBookingOrder(config, accessToken, payload) {
|
|
602
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
603
|
+
if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
|
|
604
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/service`, {
|
|
605
|
+
method: "POST",
|
|
606
|
+
headers,
|
|
607
|
+
body: JSON.stringify(payload),
|
|
608
|
+
fallbackErrorMessage: "Failed to create service booking order"
|
|
609
|
+
});
|
|
610
|
+
return normaliseStorefrontOrder(data);
|
|
611
|
+
}
|
|
612
|
+
async function findOrder(config, params) {
|
|
613
|
+
if (!params.email || !params.order_id) {
|
|
614
|
+
throw new Error("Both email and order_id are required to find an order.");
|
|
615
|
+
}
|
|
616
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/track`, {
|
|
617
|
+
method: "POST",
|
|
618
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
619
|
+
body: JSON.stringify({ order_id: params.order_id, email: params.email }),
|
|
620
|
+
fallbackErrorMessage: "Failed to find order"
|
|
426
621
|
});
|
|
427
|
-
if (!response.ok) throw new Error("Failed to find order by token");
|
|
428
|
-
const data = await response.json();
|
|
429
622
|
return normaliseStorefrontOrder(data);
|
|
430
623
|
}
|
|
431
624
|
async function getOrders(config, accessToken, params) {
|
|
@@ -433,45 +626,110 @@ async function getOrders(config, accessToken, params) {
|
|
|
433
626
|
if (params?.email) queryParams.set("email", params.email);
|
|
434
627
|
if (params?.page) queryParams.set("page", params.page.toString());
|
|
435
628
|
if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
|
|
436
|
-
const
|
|
437
|
-
headers:
|
|
438
|
-
|
|
439
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
440
|
-
"X-Business-ID": config.businessId
|
|
441
|
-
}
|
|
629
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
|
|
630
|
+
headers: authHeaders(config, accessToken),
|
|
631
|
+
fallbackErrorMessage: "Failed to get orders"
|
|
442
632
|
});
|
|
443
|
-
if (!response.ok) throw new Error("Failed to get orders");
|
|
444
|
-
const data = await response.json();
|
|
445
633
|
const items = Array.isArray(data) ? data : data.items ?? [];
|
|
446
634
|
return items.map(normaliseStorefrontOrder);
|
|
447
635
|
}
|
|
448
636
|
async function cancelOrder(config, accessToken, orderId, reason) {
|
|
449
|
-
const
|
|
637
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
|
|
450
638
|
method: "POST",
|
|
451
|
-
headers: {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
"X-Business-ID": config.businessId
|
|
456
|
-
},
|
|
457
|
-
body: JSON.stringify({ reason })
|
|
458
|
-
});
|
|
459
|
-
if (!response.ok) throw new Error("Failed to cancel order");
|
|
460
|
-
const data = await response.json();
|
|
639
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
640
|
+
body: JSON.stringify({ reason }),
|
|
641
|
+
fallbackErrorMessage: "Failed to cancel order"
|
|
642
|
+
});
|
|
461
643
|
return normaliseStorefrontOrder(data);
|
|
462
644
|
}
|
|
463
|
-
async function trackOrder(config, orderId,
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
468
|
-
"X-Business-ID": config.businessId
|
|
469
|
-
}
|
|
645
|
+
async function trackOrder(config, orderId, accessToken) {
|
|
646
|
+
const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}`, {
|
|
647
|
+
headers: authHeaders(config, accessToken),
|
|
648
|
+
fallbackErrorMessage: "Failed to track order"
|
|
470
649
|
});
|
|
471
|
-
if (!response.ok) throw new Error("Failed to track order");
|
|
472
|
-
const data = await response.json();
|
|
473
650
|
return normaliseStorefrontOrder(data);
|
|
474
651
|
}
|
|
652
|
+
async function validatePromoCode(config, code, cartTotal) {
|
|
653
|
+
try {
|
|
654
|
+
return await apiRequest(`${config.backendUrls.store}/sales/discounts/validate`, {
|
|
655
|
+
method: "POST",
|
|
656
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
657
|
+
body: JSON.stringify({ code, cart_total: cartTotal }),
|
|
658
|
+
fallbackErrorMessage: "Invalid promo code"
|
|
659
|
+
});
|
|
660
|
+
} catch (err) {
|
|
661
|
+
const message = err instanceof ApiError ? err.message : "Invalid promo code";
|
|
662
|
+
return { valid: false, discount_amount: 0, discount_type: "fixed", message };
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
async function resolveRedirectOrJson(url, fallbackErrorMessage) {
|
|
666
|
+
const response = await fetch(url, { redirect: "manual" });
|
|
667
|
+
if (response.status >= 300 && response.status < 400) {
|
|
668
|
+
const location = response.headers.get("location");
|
|
669
|
+
if (!location) {
|
|
670
|
+
throw new Error(`${fallbackErrorMessage}: server redirected with no destination URL.`);
|
|
671
|
+
}
|
|
672
|
+
return { type: "redirect", url: location };
|
|
673
|
+
}
|
|
674
|
+
const body = await response.json().catch(() => ({}));
|
|
675
|
+
if (!response.ok) {
|
|
676
|
+
throw new ApiError(extractDigitalDownloadError(body, fallbackErrorMessage), response.status, body);
|
|
677
|
+
}
|
|
678
|
+
return { type: "json", data: body };
|
|
679
|
+
}
|
|
680
|
+
function extractDigitalDownloadError(body, fallback) {
|
|
681
|
+
if (typeof body === "object" && body !== null && "detail" in body && typeof body.detail === "string") {
|
|
682
|
+
return body.detail;
|
|
683
|
+
}
|
|
684
|
+
return fallback;
|
|
685
|
+
}
|
|
686
|
+
async function resolveDigitalDownload(config, orderId, token) {
|
|
687
|
+
const result = await resolveRedirectOrJson(
|
|
688
|
+
`${config.backendUrls.store}/orders/${orderId}/download/${token}`,
|
|
689
|
+
"Failed to resolve digital download link"
|
|
690
|
+
);
|
|
691
|
+
if (result.type === "redirect") return result;
|
|
692
|
+
return { type: "listing", ...result.data };
|
|
693
|
+
}
|
|
694
|
+
async function resolveDigitalDownloadFile(config, orderId, token, fileId) {
|
|
695
|
+
const result = await resolveRedirectOrJson(
|
|
696
|
+
`${config.backendUrls.store}/orders/${orderId}/download/${token}/${fileId}`,
|
|
697
|
+
"Failed to resolve this file's download link"
|
|
698
|
+
);
|
|
699
|
+
if (result.type !== "redirect") {
|
|
700
|
+
throw new Error("Failed to resolve this file's download link: server did not return a redirect.");
|
|
701
|
+
}
|
|
702
|
+
return result.url;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/services/consultation.service.ts
|
|
706
|
+
async function createConsultation(config, accessToken, params) {
|
|
707
|
+
return apiRequest(`${config.backendUrls.crm}/consultations/`, {
|
|
708
|
+
method: "POST",
|
|
709
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
710
|
+
body: JSON.stringify(params),
|
|
711
|
+
fallbackErrorMessage: "Failed to submit your request"
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// src/services/feedback.service.ts
|
|
716
|
+
async function createFeedback(config, accessToken, params) {
|
|
717
|
+
return apiRequest(`${config.backendUrls.crm}/feedback/`, {
|
|
718
|
+
method: "POST",
|
|
719
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
720
|
+
body: JSON.stringify(params),
|
|
721
|
+
fallbackErrorMessage: "Failed to submit your message"
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
async function getMyFeedback(config, accessToken, params) {
|
|
725
|
+
const query = new URLSearchParams();
|
|
726
|
+
if (params?.page) query.set("page", String(params.page));
|
|
727
|
+
if (params?.page_size) query.set("page_size", String(params.page_size));
|
|
728
|
+
return apiRequest(`${config.backendUrls.crm}/feedback/my?${query.toString()}`, {
|
|
729
|
+
headers: authHeaders(config, accessToken),
|
|
730
|
+
fallbackErrorMessage: "Failed to load your requests"
|
|
731
|
+
});
|
|
732
|
+
}
|
|
475
733
|
|
|
476
734
|
// src/constants.ts
|
|
477
735
|
var STORAGE_KEYS = {
|
|
@@ -482,88 +740,145 @@ var STORAGE_KEYS = {
|
|
|
482
740
|
STOREFRONT_STATE: "storefront_state_v3"
|
|
483
741
|
};
|
|
484
742
|
|
|
743
|
+
// src/utils/customer.ts
|
|
744
|
+
function buildFullName(firstname, lastname) {
|
|
745
|
+
const name = [firstname, lastname].filter(Boolean).join(" ").trim();
|
|
746
|
+
return name || void 0;
|
|
747
|
+
}
|
|
748
|
+
function splitFullName(fullName) {
|
|
749
|
+
if (!fullName?.trim()) return { firstname: "", lastname: "" };
|
|
750
|
+
const parts = fullName.trim().split(/\s+/);
|
|
751
|
+
return {
|
|
752
|
+
firstname: parts[0] ?? "",
|
|
753
|
+
lastname: parts.slice(1).join(" ")
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
|
|
485
757
|
// src/services/auth.service.ts
|
|
486
|
-
async function loginCustomer(config, payload) {
|
|
487
|
-
const
|
|
758
|
+
async function loginCustomer(config, payload, guestSessionId) {
|
|
759
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
760
|
+
if (guestSessionId) {
|
|
761
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
762
|
+
}
|
|
763
|
+
return apiRequest(`${config.backendUrls.auth}/auth/login/customer/`, {
|
|
488
764
|
method: "POST",
|
|
489
|
-
headers
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
"X-Business-ID": config.businessId
|
|
493
|
-
},
|
|
494
|
-
body: JSON.stringify({
|
|
495
|
-
...payload,
|
|
496
|
-
tenant_id: config.businessId
|
|
497
|
-
})
|
|
765
|
+
headers,
|
|
766
|
+
body: JSON.stringify(payload),
|
|
767
|
+
fallbackErrorMessage: "Login failed"
|
|
498
768
|
});
|
|
499
|
-
if (!response.ok) {
|
|
500
|
-
throw new Error("Login failed");
|
|
501
|
-
}
|
|
502
|
-
const data = await response.json();
|
|
503
|
-
return data;
|
|
504
769
|
}
|
|
505
|
-
async function registerCustomer(config, payload) {
|
|
506
|
-
const
|
|
770
|
+
async function registerCustomer(config, payload, guestSessionId) {
|
|
771
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
772
|
+
if (guestSessionId) {
|
|
773
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
774
|
+
}
|
|
775
|
+
return apiRequest(`${config.backendUrls.auth}/auth/register/customer/`, {
|
|
507
776
|
method: "POST",
|
|
508
|
-
headers
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
"X-Business-ID": config.businessId
|
|
512
|
-
},
|
|
513
|
-
body: JSON.stringify({
|
|
514
|
-
...payload,
|
|
515
|
-
tenant_id: config.businessId
|
|
516
|
-
})
|
|
777
|
+
headers,
|
|
778
|
+
body: JSON.stringify(payload),
|
|
779
|
+
fallbackErrorMessage: "Registration failed"
|
|
517
780
|
});
|
|
518
|
-
if (!response.ok) {
|
|
519
|
-
throw new Error("Registration failed");
|
|
520
|
-
}
|
|
521
|
-
const data = await response.json();
|
|
522
|
-
return data;
|
|
523
781
|
}
|
|
524
782
|
async function refreshToken(config, refresh) {
|
|
525
|
-
|
|
783
|
+
return apiRequest(`${config.backendUrls.auth}/auth/token/refresh/`, {
|
|
526
784
|
method: "POST",
|
|
527
|
-
headers:
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
body: JSON.stringify({ refresh })
|
|
785
|
+
headers: JSON_HEADERS,
|
|
786
|
+
body: JSON.stringify({ refresh }),
|
|
787
|
+
fallbackErrorMessage: "Token refresh failed"
|
|
531
788
|
});
|
|
532
|
-
if (!response.ok) {
|
|
533
|
-
throw new Error("Token refresh failed");
|
|
534
|
-
}
|
|
535
|
-
const data = await response.json();
|
|
536
|
-
return data;
|
|
537
789
|
}
|
|
538
790
|
async function logout(config, refresh) {
|
|
539
791
|
const payload = refresh ? { refresh } : {};
|
|
540
792
|
try {
|
|
541
|
-
await
|
|
793
|
+
await apiRequest(`${config.backendUrls.auth}/auth/logout/`, {
|
|
542
794
|
method: "POST",
|
|
543
|
-
headers:
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
body: JSON.stringify(payload)
|
|
795
|
+
headers: JSON_HEADERS,
|
|
796
|
+
body: JSON.stringify(payload),
|
|
797
|
+
fallbackErrorMessage: "Server-side logout failed"
|
|
547
798
|
});
|
|
548
|
-
} catch {
|
|
799
|
+
} catch (err) {
|
|
800
|
+
if (err instanceof ApiError) {
|
|
801
|
+
console.error(`[auth.service] Server-side logout failed with status ${err.status}; local session will still be cleared.`);
|
|
802
|
+
} else {
|
|
803
|
+
console.error("[auth.service] Server-side logout request failed; local session will still be cleared.", err);
|
|
804
|
+
}
|
|
549
805
|
}
|
|
550
806
|
}
|
|
551
807
|
async function verifySocialToken(config, provider, token) {
|
|
552
|
-
|
|
808
|
+
return apiRequest(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
|
|
553
809
|
method: "POST",
|
|
554
|
-
headers: {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
body: JSON.stringify({
|
|
558
|
-
id_token: token,
|
|
559
|
-
storefront_key: config.storefrontApiKey
|
|
560
|
-
})
|
|
810
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
811
|
+
body: JSON.stringify({ id_token: token }),
|
|
812
|
+
fallbackErrorMessage: "Social token verification failed"
|
|
561
813
|
});
|
|
562
|
-
|
|
563
|
-
|
|
814
|
+
}
|
|
815
|
+
async function requestCustomerOtp(config, payload) {
|
|
816
|
+
await apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/request/`, {
|
|
817
|
+
method: "POST",
|
|
818
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
819
|
+
body: JSON.stringify(payload),
|
|
820
|
+
fallbackErrorMessage: "Failed to send login code"
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
async function verifyCustomerOtp(config, payload, guestSessionId) {
|
|
824
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
825
|
+
if (guestSessionId) {
|
|
826
|
+
headers["X-Guest-Session"] = guestSessionId;
|
|
564
827
|
}
|
|
565
|
-
|
|
566
|
-
|
|
828
|
+
return apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/verify/`, {
|
|
829
|
+
method: "POST",
|
|
830
|
+
headers,
|
|
831
|
+
body: JSON.stringify(payload),
|
|
832
|
+
fallbackErrorMessage: "Invalid or expired code"
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
async function forgotPasswordCustomer(config, payload) {
|
|
836
|
+
return apiRequest(`${config.backendUrls.auth}/auth/forgot-password/customer/`, {
|
|
837
|
+
method: "POST",
|
|
838
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
839
|
+
body: JSON.stringify(payload),
|
|
840
|
+
fallbackErrorMessage: "Failed to request password reset"
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
async function resetPasswordCustomer(config, payload) {
|
|
844
|
+
return apiRequest(`${config.backendUrls.auth}/auth/reset-password/customer/`, {
|
|
845
|
+
method: "POST",
|
|
846
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
847
|
+
body: JSON.stringify(payload),
|
|
848
|
+
fallbackErrorMessage: "Invalid or expired reset code"
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
async function deactivateCustomerAccount(config, accessToken, payload) {
|
|
852
|
+
try {
|
|
853
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/customer/deactivate/`, {
|
|
854
|
+
method: "POST",
|
|
855
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
856
|
+
body: JSON.stringify(payload || {}),
|
|
857
|
+
fallbackErrorMessage: "Failed to deactivate account"
|
|
858
|
+
});
|
|
859
|
+
return { status: "success", detail: data.detail };
|
|
860
|
+
} catch (err) {
|
|
861
|
+
if (err instanceof ApiError && err.status === 409) {
|
|
862
|
+
return { status: "confirmation_required", data: err.body };
|
|
863
|
+
}
|
|
864
|
+
throw err;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
async function requestCustomerReactivation(config, payload) {
|
|
868
|
+
return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/`, {
|
|
869
|
+
method: "POST",
|
|
870
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
871
|
+
body: JSON.stringify(payload),
|
|
872
|
+
fallbackErrorMessage: "Failed to request reactivation"
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
async function verifyCustomerReactivation(config, payload) {
|
|
876
|
+
return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/verify/`, {
|
|
877
|
+
method: "POST",
|
|
878
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
879
|
+
body: JSON.stringify(payload),
|
|
880
|
+
fallbackErrorMessage: "Invalid or expired reactivation code"
|
|
881
|
+
});
|
|
567
882
|
}
|
|
568
883
|
function parseJwtPayload(token) {
|
|
569
884
|
try {
|
|
@@ -618,70 +933,94 @@ function buildCustomerFromClaims(claims) {
|
|
|
618
933
|
}
|
|
619
934
|
async function getMe(config, accessToken) {
|
|
620
935
|
if (!config || !accessToken) {
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
936
|
+
const data2 = await apiRequest("/api/auth/me", {
|
|
937
|
+
credentials: "include",
|
|
938
|
+
fallbackErrorMessage: "Failed to fetch profile"
|
|
939
|
+
});
|
|
940
|
+
return mapAuthUserToCustomer(data2.user);
|
|
625
941
|
}
|
|
626
|
-
const
|
|
627
|
-
headers:
|
|
628
|
-
|
|
629
|
-
}
|
|
942
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
943
|
+
headers: authHeaders(config, accessToken),
|
|
944
|
+
fallbackErrorMessage: "Failed to fetch profile"
|
|
630
945
|
});
|
|
631
|
-
if (!response.ok) {
|
|
632
|
-
throw new Error("Failed to fetch profile");
|
|
633
|
-
}
|
|
634
|
-
const data = await response.json();
|
|
635
946
|
return mapAuthUserToCustomer(data);
|
|
636
947
|
}
|
|
637
948
|
async function getAuthUser(config, accessToken) {
|
|
638
949
|
if (!config || !accessToken) {
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
950
|
+
const data = await apiRequest("/api/auth/me", {
|
|
951
|
+
credentials: "include",
|
|
952
|
+
fallbackErrorMessage: "Failed to fetch auth user"
|
|
953
|
+
});
|
|
954
|
+
return data.user;
|
|
643
955
|
}
|
|
644
|
-
|
|
645
|
-
headers:
|
|
646
|
-
|
|
647
|
-
}
|
|
956
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
957
|
+
headers: authHeaders(config, accessToken),
|
|
958
|
+
fallbackErrorMessage: "Failed to fetch auth user"
|
|
648
959
|
});
|
|
649
|
-
if (!response.ok) {
|
|
650
|
-
throw new Error("Failed to fetch auth user");
|
|
651
|
-
}
|
|
652
|
-
const data = await response.json();
|
|
653
|
-
return data;
|
|
654
960
|
}
|
|
655
961
|
async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
|
|
656
962
|
const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
|
|
657
963
|
if (!isArg1Config) {
|
|
658
964
|
const payload2 = configOrPayload;
|
|
659
|
-
|
|
965
|
+
return apiRequest("/api/auth/profile", {
|
|
660
966
|
method: "PUT",
|
|
661
|
-
headers:
|
|
967
|
+
headers: JSON_HEADERS,
|
|
662
968
|
credentials: "include",
|
|
663
|
-
body: JSON.stringify(payload2)
|
|
969
|
+
body: JSON.stringify(payload2),
|
|
970
|
+
fallbackErrorMessage: "Failed to update profile"
|
|
664
971
|
});
|
|
665
|
-
if (!response2.ok) throw new Error("Failed to update profile");
|
|
666
|
-
return response2.json();
|
|
667
972
|
}
|
|
668
973
|
const config = configOrPayload;
|
|
669
974
|
const accessToken = accessTokenOrPayload;
|
|
670
975
|
const payload = payloadParam;
|
|
671
|
-
const
|
|
976
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
|
|
672
977
|
method: "PUT",
|
|
673
|
-
headers: {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
},
|
|
677
|
-
body: JSON.stringify(payload)
|
|
978
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
979
|
+
body: JSON.stringify(payload),
|
|
980
|
+
fallbackErrorMessage: "Failed to update profile"
|
|
678
981
|
});
|
|
679
|
-
if (!response.ok) {
|
|
680
|
-
throw new Error("Failed to update profile");
|
|
681
|
-
}
|
|
682
|
-
const data = await response.json();
|
|
683
982
|
return mapAuthUserToCustomer(data);
|
|
684
983
|
}
|
|
984
|
+
async function changePassword(config, accessToken, payload) {
|
|
985
|
+
return apiRequest(`${config.backendUrls.auth}/auth/change-password/`, {
|
|
986
|
+
method: "POST",
|
|
987
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
988
|
+
body: JSON.stringify(payload),
|
|
989
|
+
fallbackErrorMessage: "Failed to change password"
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
async function getStorefrontBusinessInfo(config) {
|
|
993
|
+
return apiRequest(`${config.backendUrls.auth}/auth/storefront/business-info/`, {
|
|
994
|
+
headers: storefrontHeaders(config),
|
|
995
|
+
fallbackErrorMessage: "Failed to fetch business info"
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
async function getPresignedUploadUrl(config, accessToken, params) {
|
|
999
|
+
const query = new URLSearchParams(
|
|
1000
|
+
Object.entries(params).filter(([, v]) => v !== void 0)
|
|
1001
|
+
);
|
|
1002
|
+
return apiRequest(
|
|
1003
|
+
`${config.backendUrls.auth}/auth/media/presigned-url/?${query.toString()}`,
|
|
1004
|
+
{
|
|
1005
|
+
method: "POST",
|
|
1006
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
1007
|
+
fallbackErrorMessage: "Failed to get presigned upload URL"
|
|
1008
|
+
}
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
async function confirmMediaUpload(config, accessToken, params) {
|
|
1012
|
+
const query = new URLSearchParams(
|
|
1013
|
+
Object.entries(params).filter(([, v]) => v !== void 0)
|
|
1014
|
+
);
|
|
1015
|
+
return apiRequest(
|
|
1016
|
+
`${config.backendUrls.auth}/auth/media/confirm-upload/?${query.toString()}`,
|
|
1017
|
+
{
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
1020
|
+
fallbackErrorMessage: "Failed to confirm upload"
|
|
1021
|
+
}
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
685
1024
|
async function silentRefresh(config, refresh) {
|
|
686
1025
|
try {
|
|
687
1026
|
const data = await refreshToken(config, refresh);
|
|
@@ -692,25 +1031,11 @@ async function silentRefresh(config, refresh) {
|
|
|
692
1031
|
const user = buildCustomerFromClaims(claims);
|
|
693
1032
|
const provider = user.provider;
|
|
694
1033
|
return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
|
|
695
|
-
} catch {
|
|
1034
|
+
} catch (err) {
|
|
1035
|
+
console.error("[auth.service] Silent token refresh failed:", err);
|
|
696
1036
|
return null;
|
|
697
1037
|
}
|
|
698
1038
|
}
|
|
699
|
-
function buildFullName(firstname, lastname) {
|
|
700
|
-
if (firstname && lastname) return `${firstname} ${lastname}`;
|
|
701
|
-
return firstname || lastname || "";
|
|
702
|
-
}
|
|
703
|
-
function splitFullName(fullName) {
|
|
704
|
-
if (!fullName) return { firstname: "", lastname: "" };
|
|
705
|
-
const parts = fullName.trim().split(/\s+/);
|
|
706
|
-
if (parts.length === 1) {
|
|
707
|
-
return { firstname: parts[0], lastname: "" };
|
|
708
|
-
}
|
|
709
|
-
return {
|
|
710
|
-
firstname: parts[0],
|
|
711
|
-
lastname: parts.slice(1).join(" ")
|
|
712
|
-
};
|
|
713
|
-
}
|
|
714
1039
|
function storeTokens(accessToken, refreshToken2) {
|
|
715
1040
|
if (typeof window !== "undefined") {
|
|
716
1041
|
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
|
|
@@ -732,1061 +1057,369 @@ function getStoredTokens() {
|
|
|
732
1057
|
refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
|
|
733
1058
|
};
|
|
734
1059
|
}
|
|
1060
|
+
async function getCustomerAddresses(config, accessToken) {
|
|
1061
|
+
const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
|
|
1062
|
+
headers: authHeaders(config, accessToken),
|
|
1063
|
+
fallbackErrorMessage: "Failed to fetch saved addresses"
|
|
1064
|
+
});
|
|
1065
|
+
return data.results;
|
|
1066
|
+
}
|
|
1067
|
+
async function createCustomerAddress(config, accessToken, payload) {
|
|
1068
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
|
|
1069
|
+
method: "POST",
|
|
1070
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1071
|
+
body: JSON.stringify(payload),
|
|
1072
|
+
fallbackErrorMessage: "Failed to save address"
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
async function updateCustomerAddress(config, accessToken, addressId, payload) {
|
|
1076
|
+
return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
|
|
1077
|
+
method: "PATCH",
|
|
1078
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1079
|
+
body: JSON.stringify(payload),
|
|
1080
|
+
fallbackErrorMessage: "Failed to update address"
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
async function deleteCustomerAddress(config, accessToken, addressId) {
|
|
1084
|
+
await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
|
|
1085
|
+
method: "DELETE",
|
|
1086
|
+
headers: authHeaders(config, accessToken),
|
|
1087
|
+
fallbackErrorMessage: "Failed to delete address"
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
735
1090
|
|
|
736
|
-
// src/
|
|
1091
|
+
// src/utils/graphql-url.ts
|
|
737
1092
|
var import_graphql_request = require("graphql-request");
|
|
738
|
-
function
|
|
1093
|
+
function resolveGraphQLEndpoint(url) {
|
|
1094
|
+
if (typeof window === "undefined") return url;
|
|
1095
|
+
try {
|
|
1096
|
+
new URL(url);
|
|
1097
|
+
return url;
|
|
1098
|
+
} catch {
|
|
1099
|
+
return `${window.location.origin}${url}`;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
function createGraphQLClient(config, accessToken) {
|
|
739
1103
|
const headers = {
|
|
740
1104
|
"Content-Type": "application/json",
|
|
741
1105
|
"Accept": "application/json",
|
|
742
1106
|
"X-Storefront-Key": config.storefrontApiKey,
|
|
743
1107
|
"X-Business-ID": config.businessId
|
|
744
1108
|
};
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
var GET_STOREFRONT_PRODUCTS = `
|
|
748
|
-
query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
|
|
749
|
-
storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
|
|
750
|
-
items {
|
|
751
|
-
id
|
|
752
|
-
business_id
|
|
753
|
-
name
|
|
754
|
-
slug
|
|
755
|
-
description
|
|
756
|
-
brand
|
|
757
|
-
product_type
|
|
758
|
-
requires_shipping
|
|
759
|
-
is_consumable
|
|
760
|
-
is_bespoke
|
|
761
|
-
base_price
|
|
762
|
-
currency
|
|
763
|
-
images
|
|
764
|
-
tags
|
|
765
|
-
custom_fields { label unit required }
|
|
766
|
-
is_published
|
|
767
|
-
is_featured
|
|
768
|
-
is_popular
|
|
769
|
-
is_new
|
|
770
|
-
is_temporary
|
|
771
|
-
digital_file_key
|
|
772
|
-
download_limit
|
|
773
|
-
download_expires_at
|
|
774
|
-
weight_kg
|
|
775
|
-
length_cm
|
|
776
|
-
width_cm
|
|
777
|
-
height_cm
|
|
778
|
-
created_at
|
|
779
|
-
updated_at
|
|
780
|
-
variants {
|
|
781
|
-
id
|
|
782
|
-
product_id
|
|
783
|
-
sku
|
|
784
|
-
attributes
|
|
785
|
-
price
|
|
786
|
-
images
|
|
787
|
-
weight_kg
|
|
788
|
-
is_active
|
|
789
|
-
inventory {
|
|
790
|
-
id
|
|
791
|
-
product_id
|
|
792
|
-
variant_id
|
|
793
|
-
quantity
|
|
794
|
-
reserved
|
|
795
|
-
reorder_point
|
|
796
|
-
reorder_quantity
|
|
797
|
-
track_quantity
|
|
798
|
-
allow_backorder
|
|
799
|
-
available
|
|
800
|
-
is_in_stock
|
|
801
|
-
is_low_stock
|
|
802
|
-
updated_at
|
|
803
|
-
}
|
|
804
|
-
created_at
|
|
805
|
-
updated_at
|
|
806
|
-
}
|
|
807
|
-
collections {
|
|
808
|
-
id
|
|
809
|
-
business_id
|
|
810
|
-
name
|
|
811
|
-
slug
|
|
812
|
-
description
|
|
813
|
-
image
|
|
814
|
-
collection_type
|
|
815
|
-
rules
|
|
816
|
-
status
|
|
817
|
-
sort_order
|
|
818
|
-
created_at
|
|
819
|
-
updated_at
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
total
|
|
823
|
-
page
|
|
824
|
-
page_size
|
|
825
|
-
total_pages
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
`;
|
|
829
|
-
var GET_STOREFRONT_PRODUCT_BY_SLUG = `
|
|
830
|
-
query GetStorefrontProductBySlug($slug: String!) {
|
|
831
|
-
storefront_product_by_slug(slug: $slug) {
|
|
832
|
-
id
|
|
833
|
-
business_id
|
|
834
|
-
name
|
|
835
|
-
slug
|
|
836
|
-
description
|
|
837
|
-
brand
|
|
838
|
-
product_type
|
|
839
|
-
requires_shipping
|
|
840
|
-
is_consumable
|
|
841
|
-
is_bespoke
|
|
842
|
-
base_price
|
|
843
|
-
currency
|
|
844
|
-
images
|
|
845
|
-
tags
|
|
846
|
-
custom_fields { label unit required }
|
|
847
|
-
is_published
|
|
848
|
-
is_featured
|
|
849
|
-
is_popular
|
|
850
|
-
is_new
|
|
851
|
-
is_temporary
|
|
852
|
-
digital_file_key
|
|
853
|
-
download_limit
|
|
854
|
-
download_expires_at
|
|
855
|
-
weight_kg
|
|
856
|
-
length_cm
|
|
857
|
-
width_cm
|
|
858
|
-
height_cm
|
|
859
|
-
created_at
|
|
860
|
-
updated_at
|
|
861
|
-
variants {
|
|
862
|
-
id
|
|
863
|
-
product_id
|
|
864
|
-
sku
|
|
865
|
-
attributes
|
|
866
|
-
price
|
|
867
|
-
images
|
|
868
|
-
weight_kg
|
|
869
|
-
is_active
|
|
870
|
-
inventory {
|
|
871
|
-
id
|
|
872
|
-
product_id
|
|
873
|
-
variant_id
|
|
874
|
-
quantity
|
|
875
|
-
reserved
|
|
876
|
-
reorder_point
|
|
877
|
-
reorder_quantity
|
|
878
|
-
track_quantity
|
|
879
|
-
allow_backorder
|
|
880
|
-
available
|
|
881
|
-
is_in_stock
|
|
882
|
-
is_low_stock
|
|
883
|
-
updated_at
|
|
884
|
-
}
|
|
885
|
-
created_at
|
|
886
|
-
updated_at
|
|
887
|
-
}
|
|
888
|
-
collections {
|
|
889
|
-
id
|
|
890
|
-
business_id
|
|
891
|
-
name
|
|
892
|
-
slug
|
|
893
|
-
description
|
|
894
|
-
image
|
|
895
|
-
collection_type
|
|
896
|
-
rules
|
|
897
|
-
status
|
|
898
|
-
sort_order
|
|
899
|
-
created_at
|
|
900
|
-
updated_at
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
`;
|
|
905
|
-
var GET_STOREFRONT_LATEST = `
|
|
906
|
-
query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
|
|
907
|
-
storefront_latest(page: $page, pageSize: $pageSize) {
|
|
908
|
-
items {
|
|
909
|
-
id
|
|
910
|
-
business_id
|
|
911
|
-
name
|
|
912
|
-
slug
|
|
913
|
-
description
|
|
914
|
-
brand
|
|
915
|
-
product_type
|
|
916
|
-
requires_shipping
|
|
917
|
-
is_consumable
|
|
918
|
-
is_bespoke
|
|
919
|
-
base_price
|
|
920
|
-
currency
|
|
921
|
-
images
|
|
922
|
-
tags
|
|
923
|
-
custom_fields { label unit required }
|
|
924
|
-
is_published
|
|
925
|
-
is_featured
|
|
926
|
-
is_popular
|
|
927
|
-
is_new
|
|
928
|
-
is_temporary
|
|
929
|
-
digital_file_key
|
|
930
|
-
download_limit
|
|
931
|
-
download_expires_at
|
|
932
|
-
weight_kg
|
|
933
|
-
length_cm
|
|
934
|
-
width_cm
|
|
935
|
-
height_cm
|
|
936
|
-
created_at
|
|
937
|
-
updated_at
|
|
938
|
-
variants {
|
|
939
|
-
id
|
|
940
|
-
product_id
|
|
941
|
-
sku
|
|
942
|
-
attributes
|
|
943
|
-
price
|
|
944
|
-
images
|
|
945
|
-
weight_kg
|
|
946
|
-
is_active
|
|
947
|
-
inventory {
|
|
948
|
-
id
|
|
949
|
-
product_id
|
|
950
|
-
variant_id
|
|
951
|
-
quantity
|
|
952
|
-
reserved
|
|
953
|
-
reorder_point
|
|
954
|
-
reorder_quantity
|
|
955
|
-
track_quantity
|
|
956
|
-
allow_backorder
|
|
957
|
-
available
|
|
958
|
-
is_in_stock
|
|
959
|
-
is_low_stock
|
|
960
|
-
updated_at
|
|
961
|
-
}
|
|
962
|
-
created_at
|
|
963
|
-
updated_at
|
|
964
|
-
}
|
|
965
|
-
collections {
|
|
966
|
-
id
|
|
967
|
-
business_id
|
|
968
|
-
name
|
|
969
|
-
slug
|
|
970
|
-
description
|
|
971
|
-
image
|
|
972
|
-
collection_type
|
|
973
|
-
rules
|
|
974
|
-
status
|
|
975
|
-
sort_order
|
|
976
|
-
created_at
|
|
977
|
-
updated_at
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
total
|
|
981
|
-
page
|
|
982
|
-
page_size
|
|
983
|
-
total_pages
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
`;
|
|
987
|
-
var GET_STOREFRONT_POPULAR = `
|
|
988
|
-
query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
|
|
989
|
-
storefront_popular(page: $page, pageSize: $pageSize) {
|
|
990
|
-
items {
|
|
991
|
-
id
|
|
992
|
-
business_id
|
|
993
|
-
name
|
|
994
|
-
slug
|
|
995
|
-
description
|
|
996
|
-
brand
|
|
997
|
-
product_type
|
|
998
|
-
requires_shipping
|
|
999
|
-
is_consumable
|
|
1000
|
-
is_bespoke
|
|
1001
|
-
base_price
|
|
1002
|
-
currency
|
|
1003
|
-
images
|
|
1004
|
-
tags
|
|
1005
|
-
custom_fields { label unit required }
|
|
1006
|
-
is_published
|
|
1007
|
-
is_featured
|
|
1008
|
-
is_popular
|
|
1009
|
-
is_new
|
|
1010
|
-
is_temporary
|
|
1011
|
-
digital_file_key
|
|
1012
|
-
download_limit
|
|
1013
|
-
download_expires_at
|
|
1014
|
-
weight_kg
|
|
1015
|
-
length_cm
|
|
1016
|
-
width_cm
|
|
1017
|
-
height_cm
|
|
1018
|
-
created_at
|
|
1019
|
-
updated_at
|
|
1020
|
-
variants {
|
|
1021
|
-
id
|
|
1022
|
-
product_id
|
|
1023
|
-
sku
|
|
1024
|
-
attributes
|
|
1025
|
-
price
|
|
1026
|
-
images
|
|
1027
|
-
weight_kg
|
|
1028
|
-
is_active
|
|
1029
|
-
inventory {
|
|
1030
|
-
id
|
|
1031
|
-
product_id
|
|
1032
|
-
variant_id
|
|
1033
|
-
quantity
|
|
1034
|
-
reserved
|
|
1035
|
-
reorder_point
|
|
1036
|
-
reorder_quantity
|
|
1037
|
-
track_quantity
|
|
1038
|
-
allow_backorder
|
|
1039
|
-
available
|
|
1040
|
-
is_in_stock
|
|
1041
|
-
is_low_stock
|
|
1042
|
-
updated_at
|
|
1043
|
-
}
|
|
1044
|
-
created_at
|
|
1045
|
-
updated_at
|
|
1046
|
-
}
|
|
1047
|
-
collections {
|
|
1048
|
-
id
|
|
1049
|
-
business_id
|
|
1050
|
-
name
|
|
1051
|
-
slug
|
|
1052
|
-
description
|
|
1053
|
-
image
|
|
1054
|
-
collection_type
|
|
1055
|
-
rules
|
|
1056
|
-
status
|
|
1057
|
-
sort_order
|
|
1058
|
-
created_at
|
|
1059
|
-
updated_at
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
total
|
|
1063
|
-
page
|
|
1064
|
-
page_size
|
|
1065
|
-
total_pages
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
`;
|
|
1069
|
-
var GET_STOREFRONT_FEATURED = `
|
|
1070
|
-
query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
|
|
1071
|
-
storefront_featured(page: $page, pageSize: $pageSize) {
|
|
1072
|
-
items {
|
|
1073
|
-
id
|
|
1074
|
-
business_id
|
|
1075
|
-
name
|
|
1076
|
-
slug
|
|
1077
|
-
description
|
|
1078
|
-
brand
|
|
1079
|
-
product_type
|
|
1080
|
-
requires_shipping
|
|
1081
|
-
is_consumable
|
|
1082
|
-
is_bespoke
|
|
1083
|
-
base_price
|
|
1084
|
-
currency
|
|
1085
|
-
images
|
|
1086
|
-
tags
|
|
1087
|
-
custom_fields { label unit required }
|
|
1088
|
-
is_published
|
|
1089
|
-
is_featured
|
|
1090
|
-
is_popular
|
|
1091
|
-
is_new
|
|
1092
|
-
is_temporary
|
|
1093
|
-
digital_file_key
|
|
1094
|
-
download_limit
|
|
1095
|
-
download_expires_at
|
|
1096
|
-
weight_kg
|
|
1097
|
-
length_cm
|
|
1098
|
-
width_cm
|
|
1099
|
-
height_cm
|
|
1100
|
-
created_at
|
|
1101
|
-
updated_at
|
|
1102
|
-
variants {
|
|
1103
|
-
id
|
|
1104
|
-
product_id
|
|
1105
|
-
sku
|
|
1106
|
-
attributes
|
|
1107
|
-
price
|
|
1108
|
-
images
|
|
1109
|
-
weight_kg
|
|
1110
|
-
is_active
|
|
1111
|
-
inventory {
|
|
1112
|
-
id
|
|
1113
|
-
product_id
|
|
1114
|
-
variant_id
|
|
1115
|
-
quantity
|
|
1116
|
-
reserved
|
|
1117
|
-
reorder_point
|
|
1118
|
-
reorder_quantity
|
|
1119
|
-
track_quantity
|
|
1120
|
-
allow_backorder
|
|
1121
|
-
available
|
|
1122
|
-
is_in_stock
|
|
1123
|
-
is_low_stock
|
|
1124
|
-
updated_at
|
|
1125
|
-
}
|
|
1126
|
-
created_at
|
|
1127
|
-
updated_at
|
|
1128
|
-
}
|
|
1129
|
-
collections {
|
|
1130
|
-
id
|
|
1131
|
-
business_id
|
|
1132
|
-
name
|
|
1133
|
-
slug
|
|
1134
|
-
description
|
|
1135
|
-
image
|
|
1136
|
-
collection_type
|
|
1137
|
-
rules
|
|
1138
|
-
status
|
|
1139
|
-
sort_order
|
|
1140
|
-
created_at
|
|
1141
|
-
updated_at
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
total
|
|
1145
|
-
page
|
|
1146
|
-
page_size
|
|
1147
|
-
total_pages
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
`;
|
|
1151
|
-
var GET_STOREFRONT_NEW = `
|
|
1152
|
-
query GetStorefrontNew($page: Int!, $pageSize: Int!) {
|
|
1153
|
-
storefront_new(page: $page, pageSize: $pageSize) {
|
|
1154
|
-
items {
|
|
1155
|
-
id
|
|
1156
|
-
business_id
|
|
1157
|
-
name
|
|
1158
|
-
slug
|
|
1159
|
-
description
|
|
1160
|
-
brand
|
|
1161
|
-
product_type
|
|
1162
|
-
requires_shipping
|
|
1163
|
-
is_consumable
|
|
1164
|
-
is_bespoke
|
|
1165
|
-
base_price
|
|
1166
|
-
currency
|
|
1167
|
-
sale_price
|
|
1168
|
-
sale_start
|
|
1169
|
-
sale_end
|
|
1170
|
-
images
|
|
1171
|
-
tags
|
|
1172
|
-
custom_fields { label unit required }
|
|
1173
|
-
is_published
|
|
1174
|
-
is_featured
|
|
1175
|
-
is_popular
|
|
1176
|
-
is_new
|
|
1177
|
-
is_temporary
|
|
1178
|
-
digital_file_key
|
|
1179
|
-
download_limit
|
|
1180
|
-
download_expires_at
|
|
1181
|
-
weight_kg
|
|
1182
|
-
length_cm
|
|
1183
|
-
width_cm
|
|
1184
|
-
height_cm
|
|
1185
|
-
created_at
|
|
1186
|
-
updated_at
|
|
1187
|
-
variants {
|
|
1188
|
-
id
|
|
1189
|
-
product_id
|
|
1190
|
-
sku
|
|
1191
|
-
attributes
|
|
1192
|
-
price
|
|
1193
|
-
images
|
|
1194
|
-
weight_kg
|
|
1195
|
-
is_active
|
|
1196
|
-
inventory {
|
|
1197
|
-
id
|
|
1198
|
-
product_id
|
|
1199
|
-
variant_id
|
|
1200
|
-
quantity
|
|
1201
|
-
reserved
|
|
1202
|
-
reorder_point
|
|
1203
|
-
reorder_quantity
|
|
1204
|
-
track_quantity
|
|
1205
|
-
allow_backorder
|
|
1206
|
-
available
|
|
1207
|
-
is_in_stock
|
|
1208
|
-
is_low_stock
|
|
1209
|
-
updated_at
|
|
1210
|
-
}
|
|
1211
|
-
created_at
|
|
1212
|
-
updated_at
|
|
1213
|
-
}
|
|
1214
|
-
collections {
|
|
1215
|
-
id
|
|
1216
|
-
business_id
|
|
1217
|
-
name
|
|
1218
|
-
slug
|
|
1219
|
-
description
|
|
1220
|
-
image
|
|
1221
|
-
collection_type
|
|
1222
|
-
rules
|
|
1223
|
-
status
|
|
1224
|
-
sort_order
|
|
1225
|
-
created_at
|
|
1226
|
-
updated_at
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
total
|
|
1230
|
-
page
|
|
1231
|
-
page_size
|
|
1232
|
-
total_pages
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
`;
|
|
1236
|
-
var GET_STOREFRONT_ON_SALE = `
|
|
1237
|
-
query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
|
|
1238
|
-
storefront_on_sale(page: $page, pageSize: $pageSize) {
|
|
1239
|
-
items {
|
|
1240
|
-
id
|
|
1241
|
-
business_id
|
|
1242
|
-
name
|
|
1243
|
-
slug
|
|
1244
|
-
description
|
|
1245
|
-
brand
|
|
1246
|
-
product_type
|
|
1247
|
-
requires_shipping
|
|
1248
|
-
is_consumable
|
|
1249
|
-
is_bespoke
|
|
1250
|
-
base_price
|
|
1251
|
-
currency
|
|
1252
|
-
sale_price
|
|
1253
|
-
sale_start
|
|
1254
|
-
sale_end
|
|
1255
|
-
images
|
|
1256
|
-
tags
|
|
1257
|
-
custom_fields { label unit required }
|
|
1258
|
-
is_published
|
|
1259
|
-
is_featured
|
|
1260
|
-
is_popular
|
|
1261
|
-
is_new
|
|
1262
|
-
is_temporary
|
|
1263
|
-
digital_file_key
|
|
1264
|
-
download_limit
|
|
1265
|
-
download_expires_at
|
|
1266
|
-
weight_kg
|
|
1267
|
-
length_cm
|
|
1268
|
-
width_cm
|
|
1269
|
-
height_cm
|
|
1270
|
-
created_at
|
|
1271
|
-
updated_at
|
|
1272
|
-
variants {
|
|
1273
|
-
id
|
|
1274
|
-
product_id
|
|
1275
|
-
sku
|
|
1276
|
-
attributes
|
|
1277
|
-
price
|
|
1278
|
-
images
|
|
1279
|
-
weight_kg
|
|
1280
|
-
is_active
|
|
1281
|
-
inventory {
|
|
1282
|
-
id
|
|
1283
|
-
product_id
|
|
1284
|
-
variant_id
|
|
1285
|
-
quantity
|
|
1286
|
-
reserved
|
|
1287
|
-
reorder_point
|
|
1288
|
-
reorder_quantity
|
|
1289
|
-
track_quantity
|
|
1290
|
-
allow_backorder
|
|
1291
|
-
available
|
|
1292
|
-
is_in_stock
|
|
1293
|
-
is_low_stock
|
|
1294
|
-
updated_at
|
|
1295
|
-
}
|
|
1296
|
-
created_at
|
|
1297
|
-
updated_at
|
|
1298
|
-
}
|
|
1299
|
-
collections {
|
|
1300
|
-
id
|
|
1301
|
-
business_id
|
|
1302
|
-
name
|
|
1303
|
-
slug
|
|
1304
|
-
description
|
|
1305
|
-
image
|
|
1306
|
-
collection_type
|
|
1307
|
-
rules
|
|
1308
|
-
status
|
|
1309
|
-
sort_order
|
|
1310
|
-
created_at
|
|
1311
|
-
updated_at
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
total
|
|
1315
|
-
page
|
|
1316
|
-
page_size
|
|
1317
|
-
total_pages
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
`;
|
|
1321
|
-
var GET_STOREFRONT_LOW_STOCK = `
|
|
1322
|
-
query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
|
|
1323
|
-
storefront_low_stock(page: $page, pageSize: $pageSize) {
|
|
1324
|
-
items {
|
|
1325
|
-
id
|
|
1326
|
-
business_id
|
|
1327
|
-
name
|
|
1328
|
-
slug
|
|
1329
|
-
description
|
|
1330
|
-
brand
|
|
1331
|
-
product_type
|
|
1332
|
-
requires_shipping
|
|
1333
|
-
is_consumable
|
|
1334
|
-
is_bespoke
|
|
1335
|
-
base_price
|
|
1336
|
-
currency
|
|
1337
|
-
sale_price
|
|
1338
|
-
sale_start
|
|
1339
|
-
sale_end
|
|
1340
|
-
images
|
|
1341
|
-
tags
|
|
1342
|
-
custom_fields { label unit required }
|
|
1343
|
-
is_published
|
|
1344
|
-
is_featured
|
|
1345
|
-
is_popular
|
|
1346
|
-
is_new
|
|
1347
|
-
is_temporary
|
|
1348
|
-
digital_file_key
|
|
1349
|
-
download_limit
|
|
1350
|
-
download_expires_at
|
|
1351
|
-
weight_kg
|
|
1352
|
-
length_cm
|
|
1353
|
-
width_cm
|
|
1354
|
-
height_cm
|
|
1355
|
-
created_at
|
|
1356
|
-
updated_at
|
|
1357
|
-
variants {
|
|
1358
|
-
id
|
|
1359
|
-
product_id
|
|
1360
|
-
sku
|
|
1361
|
-
attributes
|
|
1362
|
-
price
|
|
1363
|
-
images
|
|
1364
|
-
weight_kg
|
|
1365
|
-
is_active
|
|
1366
|
-
inventory {
|
|
1367
|
-
id
|
|
1368
|
-
product_id
|
|
1369
|
-
variant_id
|
|
1370
|
-
quantity
|
|
1371
|
-
reserved
|
|
1372
|
-
reorder_point
|
|
1373
|
-
reorder_quantity
|
|
1374
|
-
track_quantity
|
|
1375
|
-
allow_backorder
|
|
1376
|
-
available
|
|
1377
|
-
is_in_stock
|
|
1378
|
-
is_low_stock
|
|
1379
|
-
updated_at
|
|
1380
|
-
}
|
|
1381
|
-
created_at
|
|
1382
|
-
updated_at
|
|
1383
|
-
}
|
|
1384
|
-
collections {
|
|
1385
|
-
id
|
|
1386
|
-
business_id
|
|
1387
|
-
name
|
|
1388
|
-
slug
|
|
1389
|
-
description
|
|
1390
|
-
image
|
|
1391
|
-
collection_type
|
|
1392
|
-
rules
|
|
1393
|
-
status
|
|
1394
|
-
sort_order
|
|
1395
|
-
created_at
|
|
1396
|
-
updated_at
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
total
|
|
1400
|
-
page
|
|
1401
|
-
page_size
|
|
1402
|
-
total_pages
|
|
1403
|
-
}
|
|
1109
|
+
if (accessToken) {
|
|
1110
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1404
1111
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
business_id
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
width_cm
|
|
1436
|
-
height_cm
|
|
1437
|
-
created_at
|
|
1438
|
-
updated_at
|
|
1439
|
-
variants {
|
|
1440
|
-
id
|
|
1441
|
-
product_id
|
|
1442
|
-
sku
|
|
1443
|
-
attributes
|
|
1444
|
-
price
|
|
1445
|
-
images
|
|
1446
|
-
weight_kg
|
|
1447
|
-
is_active
|
|
1448
|
-
inventory {
|
|
1449
|
-
id
|
|
1450
|
-
product_id
|
|
1451
|
-
variant_id
|
|
1452
|
-
quantity
|
|
1453
|
-
reserved
|
|
1454
|
-
reorder_point
|
|
1455
|
-
reorder_quantity
|
|
1456
|
-
track_quantity
|
|
1457
|
-
allow_backorder
|
|
1458
|
-
available
|
|
1459
|
-
is_in_stock
|
|
1460
|
-
is_low_stock
|
|
1461
|
-
updated_at
|
|
1462
|
-
}
|
|
1463
|
-
created_at
|
|
1464
|
-
updated_at
|
|
1465
|
-
}
|
|
1466
|
-
collections {
|
|
1467
|
-
id
|
|
1468
|
-
business_id
|
|
1469
|
-
name
|
|
1470
|
-
slug
|
|
1471
|
-
description
|
|
1472
|
-
image
|
|
1473
|
-
collection_type
|
|
1474
|
-
rules
|
|
1475
|
-
status
|
|
1476
|
-
sort_order
|
|
1477
|
-
created_at
|
|
1478
|
-
updated_at
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
total
|
|
1482
|
-
page
|
|
1483
|
-
page_size
|
|
1484
|
-
total_pages
|
|
1112
|
+
return new import_graphql_request.GraphQLClient(resolveGraphQLEndpoint(`${config.backendUrls.store}/graphql`), { headers });
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// src/generated/graphql.ts
|
|
1116
|
+
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" } }] } }] };
|
|
1117
|
+
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" } }] } }] };
|
|
1118
|
+
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" } }] } }] } }] };
|
|
1119
|
+
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" } }] } }] } }] };
|
|
1120
|
+
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" } }] } }] } }] };
|
|
1121
|
+
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" } }] } }] } }] };
|
|
1122
|
+
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" } }] } }] } }] };
|
|
1123
|
+
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" } }] } }] } }] };
|
|
1124
|
+
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" } }] } }] } }] };
|
|
1125
|
+
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" } }] } }] } }] };
|
|
1126
|
+
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" } }] } }] } }] };
|
|
1127
|
+
|
|
1128
|
+
// src/services/product.service.ts
|
|
1129
|
+
function mapProductType(raw) {
|
|
1130
|
+
switch (raw) {
|
|
1131
|
+
case "PHYSICAL":
|
|
1132
|
+
return "physical" /* PHYSICAL */;
|
|
1133
|
+
case "DIGITAL":
|
|
1134
|
+
return "digital" /* DIGITAL */;
|
|
1135
|
+
case "SERVICE":
|
|
1136
|
+
return "service" /* SERVICE */;
|
|
1137
|
+
case "BESPOKE":
|
|
1138
|
+
return "bespoke" /* BESPOKE */;
|
|
1139
|
+
default: {
|
|
1140
|
+
const _exhaustive = raw;
|
|
1141
|
+
throw new Error(`Unhandled GraphQL ProductType member: ${_exhaustive}`);
|
|
1485
1142
|
}
|
|
1486
1143
|
}
|
|
1487
|
-
|
|
1144
|
+
}
|
|
1145
|
+
function mapCustomFieldType(raw) {
|
|
1146
|
+
if (raw === "text" || raw === "choice") return raw;
|
|
1147
|
+
throw new Error(`Unrecognised custom field field_type from backend: "${raw}"`);
|
|
1148
|
+
}
|
|
1149
|
+
function mapProduct(raw) {
|
|
1150
|
+
return {
|
|
1151
|
+
...raw,
|
|
1152
|
+
product_type: mapProductType(raw.product_type),
|
|
1153
|
+
custom_fields: raw.custom_fields.map((f) => ({
|
|
1154
|
+
...f,
|
|
1155
|
+
unit: f.unit ?? void 0,
|
|
1156
|
+
field_type: mapCustomFieldType(f.field_type)
|
|
1157
|
+
})),
|
|
1158
|
+
description: raw.description ?? void 0,
|
|
1159
|
+
brand: raw.brand ?? void 0,
|
|
1160
|
+
is_physical: raw.is_physical ?? void 0,
|
|
1161
|
+
sale_price: raw.sale_price ?? void 0,
|
|
1162
|
+
sale_start: raw.sale_start ?? void 0,
|
|
1163
|
+
sale_end: raw.sale_end ?? void 0,
|
|
1164
|
+
source_channel_ref_id: raw.source_channel_ref_id ?? void 0,
|
|
1165
|
+
download_limit: raw.download_limit ?? void 0,
|
|
1166
|
+
download_expires_at: raw.download_expires_at ?? void 0,
|
|
1167
|
+
service_type: raw.service_type ?? void 0,
|
|
1168
|
+
service_duration_minutes: raw.service_duration_minutes ?? void 0,
|
|
1169
|
+
service_location_type: raw.service_location_type ?? void 0,
|
|
1170
|
+
service_coverage_radius_km: raw.service_coverage_radius_km ?? void 0,
|
|
1171
|
+
service_max_capacity_per_slot: raw.service_max_capacity_per_slot ?? void 0,
|
|
1172
|
+
service_recurring_interval: raw.service_recurring_interval ?? void 0,
|
|
1173
|
+
length_cm: raw.length_cm ?? void 0,
|
|
1174
|
+
width_cm: raw.width_cm ?? void 0,
|
|
1175
|
+
height_cm: raw.height_cm ?? void 0,
|
|
1176
|
+
average_rating: raw.average_rating ?? void 0,
|
|
1177
|
+
created_at: raw.created_at,
|
|
1178
|
+
updated_at: raw.updated_at,
|
|
1179
|
+
variants: raw.variants.map((v) => ({
|
|
1180
|
+
...v,
|
|
1181
|
+
sku: v.sku ?? void 0,
|
|
1182
|
+
attributes: v.attributes ? JSON.parse(v.attributes) : {},
|
|
1183
|
+
price: v.price ?? void 0,
|
|
1184
|
+
weight_kg: v.weight_kg ?? void 0,
|
|
1185
|
+
inventory: v.inventory ? {
|
|
1186
|
+
...v.inventory,
|
|
1187
|
+
variant_id: v.inventory.variant_id ?? void 0,
|
|
1188
|
+
updated_at: v.inventory.updated_at
|
|
1189
|
+
} : void 0,
|
|
1190
|
+
created_at: v.created_at,
|
|
1191
|
+
updated_at: v.updated_at
|
|
1192
|
+
})),
|
|
1193
|
+
collections: raw.collections.map((c) => ({
|
|
1194
|
+
...c,
|
|
1195
|
+
business_id: c.business_id ?? void 0,
|
|
1196
|
+
description: c.description ?? void 0,
|
|
1197
|
+
image_url: c.image_url ?? void 0,
|
|
1198
|
+
rules: c.rules ?? void 0,
|
|
1199
|
+
created_at: c.created_at,
|
|
1200
|
+
updated_at: c.updated_at
|
|
1201
|
+
}))
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
function mapProductConnection(connection) {
|
|
1205
|
+
return { ...connection, items: connection.items.map(mapProduct) };
|
|
1206
|
+
}
|
|
1488
1207
|
async function getStorefrontProducts(config, params) {
|
|
1489
1208
|
const client = createGraphQLClient(config);
|
|
1490
|
-
const
|
|
1209
|
+
const data = await client.request(GetStorefrontProductsDocument, {
|
|
1491
1210
|
page: params?.page || 1,
|
|
1492
1211
|
pageSize: params?.pageSize || 20,
|
|
1493
1212
|
collectionSlug: params?.collectionSlug,
|
|
1494
|
-
search: params?.search
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
return data.storefront_products;
|
|
1213
|
+
search: params?.search,
|
|
1214
|
+
productType: params?.productType
|
|
1215
|
+
});
|
|
1216
|
+
return mapProductConnection(data.storefront_products);
|
|
1498
1217
|
}
|
|
1499
1218
|
async function getStorefrontProductBySlug(config, slug) {
|
|
1500
1219
|
const client = createGraphQLClient(config);
|
|
1501
|
-
const data = await client.request(
|
|
1502
|
-
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
const variables = {
|
|
1507
|
-
page: params?.page || 1,
|
|
1508
|
-
pageSize: params?.pageSize || 4
|
|
1509
|
-
};
|
|
1510
|
-
const data = await client.request(GET_STOREFRONT_LATEST, variables);
|
|
1511
|
-
return data.storefront_latest;
|
|
1220
|
+
const data = await client.request(GetStorefrontProductBySlugDocument, { slug });
|
|
1221
|
+
if (!data.storefront_product_by_slug) {
|
|
1222
|
+
throw new Error(`Product not found: ${slug}`);
|
|
1223
|
+
}
|
|
1224
|
+
return mapProduct(data.storefront_product_by_slug);
|
|
1512
1225
|
}
|
|
1513
1226
|
async function getPopularProducts(config, params) {
|
|
1514
1227
|
const client = createGraphQLClient(config);
|
|
1515
|
-
const
|
|
1228
|
+
const data = await client.request(GetStorefrontPopularDocument, {
|
|
1516
1229
|
page: params?.page || 1,
|
|
1517
1230
|
pageSize: params?.pageSize || 4
|
|
1518
|
-
};
|
|
1519
|
-
|
|
1520
|
-
return data.storefront_popular;
|
|
1231
|
+
});
|
|
1232
|
+
return mapProductConnection(data.storefront_popular);
|
|
1521
1233
|
}
|
|
1522
1234
|
async function getFeaturedProducts(config, params) {
|
|
1523
1235
|
const client = createGraphQLClient(config);
|
|
1524
|
-
const
|
|
1236
|
+
const data = await client.request(GetStorefrontFeaturedDocument, {
|
|
1525
1237
|
page: params?.page || 1,
|
|
1526
1238
|
pageSize: params?.pageSize || 4
|
|
1527
|
-
};
|
|
1528
|
-
|
|
1529
|
-
return data.storefront_featured;
|
|
1239
|
+
});
|
|
1240
|
+
return mapProductConnection(data.storefront_featured);
|
|
1530
1241
|
}
|
|
1531
1242
|
async function getNewProducts(config, params) {
|
|
1532
1243
|
const client = createGraphQLClient(config);
|
|
1533
|
-
const
|
|
1244
|
+
const data = await client.request(GetStorefrontNewDocument, {
|
|
1534
1245
|
page: params?.page || 1,
|
|
1535
1246
|
pageSize: params?.pageSize || 4
|
|
1536
|
-
};
|
|
1537
|
-
|
|
1538
|
-
return data.storefront_new;
|
|
1247
|
+
});
|
|
1248
|
+
return mapProductConnection(data.storefront_new);
|
|
1539
1249
|
}
|
|
1540
1250
|
async function getOnSaleProducts(config, params) {
|
|
1541
1251
|
const client = createGraphQLClient(config);
|
|
1542
|
-
const
|
|
1543
|
-
page: params?.page || 1,
|
|
1544
|
-
pageSize: params?.pageSize || 4
|
|
1545
|
-
};
|
|
1546
|
-
const data = await client.request(GET_STOREFRONT_ON_SALE, variables);
|
|
1547
|
-
return data.storefront_on_sale;
|
|
1548
|
-
}
|
|
1549
|
-
async function getLowStockProducts(config, params) {
|
|
1550
|
-
const client = createGraphQLClient(config);
|
|
1551
|
-
const variables = {
|
|
1252
|
+
const data = await client.request(GetStorefrontOnSaleDocument, {
|
|
1552
1253
|
page: params?.page || 1,
|
|
1553
1254
|
pageSize: params?.pageSize || 4
|
|
1554
|
-
};
|
|
1555
|
-
|
|
1556
|
-
return data.storefront_low_stock;
|
|
1255
|
+
});
|
|
1256
|
+
return mapProductConnection(data.storefront_on_sale);
|
|
1557
1257
|
}
|
|
1558
1258
|
async function getRecommendedProducts(config, params) {
|
|
1559
1259
|
const client = createGraphQLClient(config);
|
|
1560
|
-
const
|
|
1260
|
+
const data = await client.request(GetStorefrontRecommendedDocument, {
|
|
1561
1261
|
page: params?.page || 1,
|
|
1562
1262
|
pageSize: params?.pageSize || 4,
|
|
1563
1263
|
excludeProductId: params?.excludeProductId
|
|
1564
|
-
};
|
|
1565
|
-
|
|
1566
|
-
return data.storefront_recommended;
|
|
1264
|
+
});
|
|
1265
|
+
return mapProductConnection(data.storefront_recommended);
|
|
1567
1266
|
}
|
|
1568
1267
|
|
|
1569
1268
|
// src/services/collection.service.ts
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
description
|
|
1580
|
-
image
|
|
1581
|
-
collection_type
|
|
1582
|
-
rules
|
|
1583
|
-
status
|
|
1584
|
-
sort_order
|
|
1585
|
-
created_at
|
|
1586
|
-
updated_at
|
|
1587
|
-
}
|
|
1588
|
-
total
|
|
1589
|
-
page
|
|
1590
|
-
page_size
|
|
1591
|
-
total_pages
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
`;
|
|
1595
|
-
var GET_STOREFRONT_COLLECTION_BY_SLUG = `
|
|
1596
|
-
query GetStorefrontCollectionBySlug($slug: String!) {
|
|
1597
|
-
storefront_collection_by_slug(slug: $slug) {
|
|
1598
|
-
id
|
|
1599
|
-
business_id
|
|
1600
|
-
name
|
|
1601
|
-
slug
|
|
1602
|
-
description
|
|
1603
|
-
image
|
|
1604
|
-
collection_type
|
|
1605
|
-
rules
|
|
1606
|
-
status
|
|
1607
|
-
sort_order
|
|
1608
|
-
created_at
|
|
1609
|
-
updated_at
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
`;
|
|
1613
|
-
function createGraphQLClient2(config) {
|
|
1614
|
-
const headers = {
|
|
1615
|
-
"Content-Type": "application/json",
|
|
1616
|
-
"Accept": "application/json",
|
|
1617
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1618
|
-
"X-Business-ID": config.businessId
|
|
1269
|
+
function mapCollection(raw) {
|
|
1270
|
+
return {
|
|
1271
|
+
...raw,
|
|
1272
|
+
business_id: raw.business_id ?? void 0,
|
|
1273
|
+
description: raw.description ?? void 0,
|
|
1274
|
+
image_url: raw.image_url ?? void 0,
|
|
1275
|
+
rules: raw.rules ?? void 0,
|
|
1276
|
+
created_at: raw.created_at,
|
|
1277
|
+
updated_at: raw.updated_at
|
|
1619
1278
|
};
|
|
1620
|
-
return new import_graphql_request2.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
1621
1279
|
}
|
|
1622
1280
|
async function getStorefrontCollections(config, params) {
|
|
1623
|
-
const client =
|
|
1624
|
-
const
|
|
1281
|
+
const client = createGraphQLClient(config);
|
|
1282
|
+
const data = await client.request(GetStorefrontCollectionsDocument, {
|
|
1625
1283
|
page: params?.page || 1,
|
|
1626
1284
|
pageSize: params?.pageSize || 20
|
|
1627
|
-
};
|
|
1628
|
-
|
|
1629
|
-
return data.storefront_collections;
|
|
1285
|
+
});
|
|
1286
|
+
return { ...data.storefront_collections, items: data.storefront_collections.items.map(mapCollection) };
|
|
1630
1287
|
}
|
|
1631
1288
|
async function getStorefrontCollectionBySlug(config, slug) {
|
|
1632
|
-
const client =
|
|
1633
|
-
const data = await client.request(
|
|
1634
|
-
|
|
1289
|
+
const client = createGraphQLClient(config);
|
|
1290
|
+
const data = await client.request(GetStorefrontCollectionBySlugDocument, { slug });
|
|
1291
|
+
if (!data.storefront_collection_by_slug) {
|
|
1292
|
+
throw new Error(`Collection not found: ${slug}`);
|
|
1293
|
+
}
|
|
1294
|
+
return mapCollection(data.storefront_collection_by_slug);
|
|
1635
1295
|
}
|
|
1636
1296
|
|
|
1637
1297
|
// src/services/wishlist.service.ts
|
|
1638
|
-
var import_graphql_request3 = require("graphql-request");
|
|
1639
|
-
var GET_STOREFRONT_WISHLIST = `
|
|
1640
|
-
query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
|
|
1641
|
-
storefront_wishlist(page: $page, pageSize: $pageSize) {
|
|
1642
|
-
items {
|
|
1643
|
-
id
|
|
1644
|
-
product_id
|
|
1645
|
-
notes
|
|
1646
|
-
created_at
|
|
1647
|
-
product_name
|
|
1648
|
-
product_slug
|
|
1649
|
-
product_price
|
|
1650
|
-
currency
|
|
1651
|
-
product_image
|
|
1652
|
-
}
|
|
1653
|
-
total
|
|
1654
|
-
page
|
|
1655
|
-
page_size
|
|
1656
|
-
total_pages
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
`;
|
|
1660
|
-
var CHECK_IN_STOREFRONT_WISHLIST = `
|
|
1661
|
-
query CheckInStorefrontWishlist($productId: String!) {
|
|
1662
|
-
check_in_storefront_wishlist(productId: $productId) {
|
|
1663
|
-
in_wishlist
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
`;
|
|
1667
|
-
function createGraphQLClient3(config, accessToken) {
|
|
1668
|
-
const headers = {
|
|
1669
|
-
"Content-Type": "application/json",
|
|
1670
|
-
"Accept": "application/json",
|
|
1671
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1672
|
-
"X-Business-ID": config.businessId
|
|
1673
|
-
};
|
|
1674
|
-
if (accessToken) {
|
|
1675
|
-
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1676
|
-
}
|
|
1677
|
-
return new import_graphql_request3.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
|
|
1678
|
-
}
|
|
1679
1298
|
async function getWishlist(config, accessToken, params) {
|
|
1680
|
-
const client =
|
|
1681
|
-
const
|
|
1299
|
+
const client = createGraphQLClient(config, accessToken);
|
|
1300
|
+
const data = await client.request(GetStorefrontWishlistDocument, {
|
|
1682
1301
|
page: params?.page || 1,
|
|
1683
1302
|
pageSize: params?.pageSize || 20
|
|
1303
|
+
});
|
|
1304
|
+
return {
|
|
1305
|
+
...data.storefront_wishlist,
|
|
1306
|
+
items: data.storefront_wishlist.items.map((item) => ({
|
|
1307
|
+
...item,
|
|
1308
|
+
created_at: item.created_at,
|
|
1309
|
+
notes: item.notes ?? void 0,
|
|
1310
|
+
product_name: item.product_name ?? void 0,
|
|
1311
|
+
product_slug: item.product_slug ?? void 0,
|
|
1312
|
+
product_price: item.product_price ?? void 0,
|
|
1313
|
+
currency: item.currency ?? void 0,
|
|
1314
|
+
product_image: item.product_image ?? void 0
|
|
1315
|
+
}))
|
|
1684
1316
|
};
|
|
1685
|
-
const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
|
|
1686
|
-
return data.storefront_wishlist;
|
|
1687
1317
|
}
|
|
1688
1318
|
async function checkInWishlist(config, accessToken, productId) {
|
|
1689
|
-
const client =
|
|
1690
|
-
const data = await client.request(
|
|
1319
|
+
const client = createGraphQLClient(config, accessToken);
|
|
1320
|
+
const data = await client.request(CheckInStorefrontWishlistDocument, { productId });
|
|
1691
1321
|
return data.check_in_storefront_wishlist;
|
|
1692
1322
|
}
|
|
1693
1323
|
async function addToWishlist(config, accessToken, productId, notes) {
|
|
1694
|
-
|
|
1324
|
+
return apiRequest(`${config.backendUrls.store}/wishlist/`, {
|
|
1695
1325
|
method: "POST",
|
|
1696
|
-
headers: {
|
|
1697
|
-
"Content-Type": "application/json",
|
|
1698
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1699
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1700
|
-
"X-Business-ID": config.businessId
|
|
1701
|
-
},
|
|
1326
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1702
1327
|
body: JSON.stringify({
|
|
1703
1328
|
product_id: productId,
|
|
1704
1329
|
notes: notes || void 0
|
|
1705
|
-
})
|
|
1330
|
+
}),
|
|
1331
|
+
fallbackErrorMessage: "Failed to add to wishlist"
|
|
1706
1332
|
});
|
|
1707
|
-
if (!response.ok) throw new Error("Failed to add to wishlist");
|
|
1708
|
-
return response.json();
|
|
1709
1333
|
}
|
|
1710
1334
|
async function removeFromWishlist(config, accessToken, itemId) {
|
|
1711
|
-
|
|
1335
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/${itemId}`, {
|
|
1712
1336
|
method: "DELETE",
|
|
1713
|
-
headers:
|
|
1714
|
-
|
|
1715
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1716
|
-
"X-Business-ID": config.businessId
|
|
1717
|
-
}
|
|
1337
|
+
headers: authHeaders(config, accessToken),
|
|
1338
|
+
fallbackErrorMessage: "Failed to remove from wishlist"
|
|
1718
1339
|
});
|
|
1719
|
-
if (!response.ok) throw new Error("Failed to remove from wishlist");
|
|
1720
1340
|
}
|
|
1721
1341
|
async function removeProductFromWishlist(config, accessToken, productId) {
|
|
1722
|
-
|
|
1342
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/product/${productId}`, {
|
|
1723
1343
|
method: "DELETE",
|
|
1724
|
-
headers:
|
|
1725
|
-
|
|
1726
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1727
|
-
"X-Business-ID": config.businessId
|
|
1728
|
-
}
|
|
1344
|
+
headers: authHeaders(config, accessToken),
|
|
1345
|
+
fallbackErrorMessage: "Failed to remove product from wishlist"
|
|
1729
1346
|
});
|
|
1730
|
-
if (!response.ok) throw new Error("Failed to remove product from wishlist");
|
|
1731
1347
|
}
|
|
1732
1348
|
|
|
1733
1349
|
// src/services/payment.service.ts
|
|
1350
|
+
function isValidUUID(str) {
|
|
1351
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
1352
|
+
}
|
|
1353
|
+
async function getAvailablePaymentMethods(config, currency, countryCode) {
|
|
1354
|
+
const params = {};
|
|
1355
|
+
if (currency) params.currency = currency;
|
|
1356
|
+
if (countryCode) params.country_code = countryCode;
|
|
1357
|
+
const query = new URLSearchParams(params).toString();
|
|
1358
|
+
return apiRequest(`${config.backendUrls.payment}/payments/storefront/methods${query ? `?${query}` : ""}`, {
|
|
1359
|
+
headers: storefrontHeaders(config),
|
|
1360
|
+
fallbackErrorMessage: "Failed to fetch available payment methods"
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1734
1363
|
async function createDedicatedAccount(config, accessToken, request) {
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1364
|
+
const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
|
|
1365
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
1366
|
+
if (accessToken) {
|
|
1367
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1368
|
+
}
|
|
1369
|
+
if (origin) {
|
|
1370
|
+
headers["Origin"] = origin;
|
|
1371
|
+
}
|
|
1372
|
+
return apiRequest(`${config.backendUrls.payment}/payments/storefront/dedicated-account`, {
|
|
1740
1373
|
method: "POST",
|
|
1741
|
-
headers
|
|
1742
|
-
"Content-Type": "application/json",
|
|
1743
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1744
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1745
|
-
"X-Business-ID": config.businessId
|
|
1746
|
-
},
|
|
1374
|
+
headers,
|
|
1747
1375
|
body: JSON.stringify({
|
|
1748
1376
|
order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
|
|
1749
1377
|
amount: request.amount,
|
|
1750
1378
|
customer_email: request.customer_email,
|
|
1751
1379
|
customer_name: request.customer_name,
|
|
1752
1380
|
currency: request.currency,
|
|
1381
|
+
gateway: request.gateway,
|
|
1753
1382
|
idempotency_key: request.idempotency_key
|
|
1754
|
-
})
|
|
1383
|
+
}),
|
|
1384
|
+
fallbackErrorMessage: "Failed to create dedicated account"
|
|
1755
1385
|
});
|
|
1756
|
-
if (!response.ok) throw new Error("Failed to create dedicated account");
|
|
1757
|
-
const data = await response.json();
|
|
1758
|
-
return data;
|
|
1759
1386
|
}
|
|
1760
1387
|
async function initiatePayment(config, accessToken, request) {
|
|
1761
|
-
const isValidUUID = (str) => {
|
|
1762
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1763
|
-
return uuidRegex.test(str);
|
|
1764
|
-
};
|
|
1765
1388
|
const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1389
|
+
const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
|
|
1390
|
+
const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
|
|
1391
|
+
if (accessToken) {
|
|
1392
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1393
|
+
}
|
|
1394
|
+
if (origin) {
|
|
1395
|
+
headers["Origin"] = origin;
|
|
1396
|
+
}
|
|
1397
|
+
const data = await apiRequest(
|
|
1398
|
+
`${config.backendUrls.payment}/payments/storefront/initiate`,
|
|
1399
|
+
{
|
|
1400
|
+
method: "POST",
|
|
1401
|
+
headers,
|
|
1402
|
+
body: JSON.stringify({
|
|
1403
|
+
amount: request.amount,
|
|
1404
|
+
currency: request.currency,
|
|
1405
|
+
// Same real backend default as getAvailablePaymentMethods above
|
|
1406
|
+
// (huma's own `default:"NG"` on this field) — omit rather than
|
|
1407
|
+
// hardcode a client-side copy of it.
|
|
1408
|
+
country_code: request.country_code,
|
|
1409
|
+
gateway: request.gateway,
|
|
1782
1410
|
order_id: validOrderId,
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1411
|
+
quote_id: request.quote_id,
|
|
1412
|
+
metadata_json: {
|
|
1413
|
+
customer_email: request.customer_email,
|
|
1414
|
+
customer_name: request.customer_name ?? "",
|
|
1415
|
+
order_id: validOrderId,
|
|
1416
|
+
...request.metadata ?? {}
|
|
1417
|
+
},
|
|
1418
|
+
idempotency_key: request.idempotency_key
|
|
1419
|
+
}),
|
|
1420
|
+
fallbackErrorMessage: "Failed to initiate payment"
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1790
1423
|
return {
|
|
1791
1424
|
id: data.id,
|
|
1792
1425
|
gateway_ref: data.gateway_ref,
|
|
@@ -1795,311 +1428,241 @@ async function initiatePayment(config, accessToken, request) {
|
|
|
1795
1428
|
checkout_url: data.metadata_json?.checkout_url ?? ""
|
|
1796
1429
|
};
|
|
1797
1430
|
}
|
|
1798
|
-
async function
|
|
1799
|
-
|
|
1800
|
-
method: "POST",
|
|
1801
|
-
headers: {
|
|
1802
|
-
"Content-Type": "application/json",
|
|
1803
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1804
|
-
"X-Business-ID": config.businessId
|
|
1805
|
-
},
|
|
1806
|
-
body: JSON.stringify({ amount })
|
|
1807
|
-
});
|
|
1808
|
-
if (!response.ok) throw new Error("Failed to request quote");
|
|
1809
|
-
const data = await response.json();
|
|
1810
|
-
return data;
|
|
1811
|
-
}
|
|
1812
|
-
async function verifyTransaction(configOrReference, reference) {
|
|
1813
|
-
if (typeof configOrReference === "string") {
|
|
1814
|
-
const ref2 = configOrReference;
|
|
1815
|
-
const response2 = await fetch(`/api/payments/verify/${ref2}`, {
|
|
1816
|
-
method: "POST",
|
|
1817
|
-
headers: { "Content-Type": "application/json" }
|
|
1818
|
-
});
|
|
1819
|
-
if (!response2.ok) throw new Error("Failed to verify transaction");
|
|
1820
|
-
return response2.json();
|
|
1821
|
-
}
|
|
1822
|
-
const config = configOrReference;
|
|
1823
|
-
const ref = reference || "";
|
|
1824
|
-
const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
|
|
1431
|
+
async function verifyTransaction(config, reference) {
|
|
1432
|
+
return apiRequest(`${config.backendUrls.payment}/payments/verify/${reference}`, {
|
|
1825
1433
|
method: "POST",
|
|
1826
|
-
headers: {
|
|
1827
|
-
|
|
1828
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1829
|
-
"X-Business-ID": config.businessId
|
|
1830
|
-
}
|
|
1434
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1435
|
+
fallbackErrorMessage: "Failed to verify transaction"
|
|
1831
1436
|
});
|
|
1832
|
-
if (!response.ok) throw new Error("Failed to verify transaction");
|
|
1833
|
-
const data = await response.json();
|
|
1834
|
-
return data;
|
|
1835
1437
|
}
|
|
1836
1438
|
async function getTransactionStatus(config, transactionId) {
|
|
1837
|
-
|
|
1838
|
-
headers:
|
|
1839
|
-
|
|
1840
|
-
|
|
1439
|
+
return apiRequest(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
|
|
1440
|
+
headers: storefrontHeaders(config),
|
|
1441
|
+
fallbackErrorMessage: "Failed to get transaction status"
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
async function getWalletBalance(config, accessToken) {
|
|
1445
|
+
return apiRequest(`${config.backendUrls.payment}/wallet/balance`, {
|
|
1446
|
+
headers: authHeaders(config, accessToken),
|
|
1447
|
+
fallbackErrorMessage: "Failed to fetch wallet balance"
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
async function getWalletLedger(config, accessToken, params) {
|
|
1451
|
+
const page = params?.page ?? 1;
|
|
1452
|
+
const pageSize = params?.page_size ?? 20;
|
|
1453
|
+
return apiRequest(
|
|
1454
|
+
`${config.backendUrls.payment}/wallet/ledger?page=${page}&page_size=${pageSize}`,
|
|
1455
|
+
{
|
|
1456
|
+
headers: authHeaders(config, accessToken),
|
|
1457
|
+
fallbackErrorMessage: "Failed to fetch wallet ledger"
|
|
1841
1458
|
}
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
async function claimWalletCredit(config, accessToken, claimToken) {
|
|
1462
|
+
return apiRequest(`${config.backendUrls.payment}/wallet/claim`, {
|
|
1463
|
+
method: "POST",
|
|
1464
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1465
|
+
body: JSON.stringify({ claim_token: claimToken }),
|
|
1466
|
+
fallbackErrorMessage: "Failed to claim wallet credit"
|
|
1842
1467
|
});
|
|
1843
|
-
if (!response.ok) throw new Error("Failed to get transaction status");
|
|
1844
|
-
const data = await response.json();
|
|
1845
|
-
return data;
|
|
1846
1468
|
}
|
|
1847
1469
|
var paymentService = {
|
|
1470
|
+
getAvailablePaymentMethods,
|
|
1848
1471
|
createDedicatedAccount,
|
|
1849
1472
|
initiatePayment,
|
|
1850
|
-
requestQuote,
|
|
1851
1473
|
verifyTransaction,
|
|
1852
|
-
getTransactionStatus
|
|
1474
|
+
getTransactionStatus,
|
|
1475
|
+
getWalletBalance,
|
|
1476
|
+
getWalletLedger,
|
|
1477
|
+
claimWalletCredit
|
|
1853
1478
|
};
|
|
1854
1479
|
|
|
1855
|
-
// src/services/
|
|
1856
|
-
async function
|
|
1857
|
-
|
|
1480
|
+
// src/services/logistics.service.ts
|
|
1481
|
+
async function getShippingRates(config, payload) {
|
|
1482
|
+
return apiRequest(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
1858
1483
|
method: "POST",
|
|
1859
|
-
headers: {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1863
|
-
"X-Business-ID": config.businessId
|
|
1864
|
-
},
|
|
1865
|
-
body: JSON.stringify(payload)
|
|
1866
|
-
});
|
|
1867
|
-
if (!response.ok) throw new Error("Failed to create consultation");
|
|
1868
|
-
return response.json();
|
|
1869
|
-
}
|
|
1870
|
-
async function getConsultations(config, accessToken) {
|
|
1871
|
-
const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
|
|
1872
|
-
headers: {
|
|
1873
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1874
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1875
|
-
"X-Business-ID": config.businessId
|
|
1876
|
-
}
|
|
1484
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1485
|
+
body: JSON.stringify(payload),
|
|
1486
|
+
fallbackErrorMessage: "Failed to get shipping rates"
|
|
1877
1487
|
});
|
|
1878
|
-
if (!response.ok) throw new Error("Failed to get consultations");
|
|
1879
|
-
return response.json();
|
|
1880
1488
|
}
|
|
1881
|
-
async function
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
}
|
|
1489
|
+
async function validateShippingAddress(config, payload) {
|
|
1490
|
+
return apiRequest(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
|
|
1491
|
+
method: "POST",
|
|
1492
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1493
|
+
body: JSON.stringify(payload),
|
|
1494
|
+
fallbackErrorMessage: "Failed to validate shipping address"
|
|
1888
1495
|
});
|
|
1889
|
-
if (!response.ok) throw new Error("Failed to get consultation");
|
|
1890
|
-
return response.json();
|
|
1891
1496
|
}
|
|
1892
|
-
async function
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1497
|
+
async function fetchLocationList(config, path, coords, fallbackErrorMessage) {
|
|
1498
|
+
const params = new URLSearchParams();
|
|
1499
|
+
if (coords) {
|
|
1500
|
+
params.set("latitude", String(coords.latitude));
|
|
1501
|
+
params.set("longitude", String(coords.longitude));
|
|
1502
|
+
}
|
|
1503
|
+
const qs = params.toString();
|
|
1504
|
+
return apiRequest(`${config.backendUrls.store}/logistics/${path}${qs ? `?${qs}` : ""}`, {
|
|
1505
|
+
headers: storefrontHeaders(config),
|
|
1506
|
+
fallbackErrorMessage
|
|
1902
1507
|
});
|
|
1903
1508
|
}
|
|
1904
|
-
async function
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
},
|
|
1913
|
-
body: JSON.stringify(payload)
|
|
1914
|
-
});
|
|
1915
|
-
if (!response.ok) throw new Error("Failed to accept quote");
|
|
1916
|
-
return response.json();
|
|
1917
|
-
}
|
|
1918
|
-
async function rejectQuote(config, accessToken, id, reason) {
|
|
1919
|
-
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
|
|
1920
|
-
method: "POST",
|
|
1921
|
-
headers: {
|
|
1922
|
-
"Content-Type": "application/json",
|
|
1923
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
1924
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1925
|
-
"X-Business-ID": config.businessId
|
|
1926
|
-
},
|
|
1927
|
-
body: JSON.stringify({ reason })
|
|
1928
|
-
});
|
|
1929
|
-
if (!response.ok) throw new Error("Failed to reject quote");
|
|
1930
|
-
return response.json();
|
|
1931
|
-
}
|
|
1932
|
-
var consultationService = {
|
|
1933
|
-
createConsultation,
|
|
1934
|
-
getConsultations,
|
|
1935
|
-
getConsultation,
|
|
1936
|
-
sendMessage,
|
|
1937
|
-
acceptQuote,
|
|
1938
|
-
rejectQuote
|
|
1939
|
-
};
|
|
1940
|
-
|
|
1941
|
-
// src/services/logistics.service.ts
|
|
1942
|
-
async function getShippingRates(config, payload) {
|
|
1943
|
-
const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
1509
|
+
async function listPickupLocations(config, coords) {
|
|
1510
|
+
return fetchLocationList(config, "pickup-locations", coords, "Failed to list pickup locations");
|
|
1511
|
+
}
|
|
1512
|
+
async function listBusinessLocations(config, coords) {
|
|
1513
|
+
return fetchLocationList(config, "locations", coords, "Failed to list business locations");
|
|
1514
|
+
}
|
|
1515
|
+
async function reverseGeocode(config, payload) {
|
|
1516
|
+
return apiRequest(`${config.backendUrls.store}/logistics/reverse-geocode`, {
|
|
1944
1517
|
method: "POST",
|
|
1945
|
-
headers: {
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
"X-Business-ID": config.businessId
|
|
1949
|
-
},
|
|
1950
|
-
body: JSON.stringify(payload)
|
|
1951
|
-
});
|
|
1952
|
-
if (!response.ok) throw new Error("Failed to get shipping rates");
|
|
1953
|
-
return response.json();
|
|
1954
|
-
}
|
|
1955
|
-
async function getSellerShippingAddress(config) {
|
|
1956
|
-
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
|
|
1957
|
-
headers: {
|
|
1958
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
1959
|
-
"X-Business-ID": config.businessId
|
|
1960
|
-
}
|
|
1518
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1519
|
+
body: JSON.stringify(payload),
|
|
1520
|
+
fallbackErrorMessage: "Failed to reverse geocode coordinates"
|
|
1961
1521
|
});
|
|
1962
|
-
if (!response.ok) throw new Error("Failed to get seller shipping address");
|
|
1963
|
-
return response.json();
|
|
1964
1522
|
}
|
|
1965
|
-
async function
|
|
1966
|
-
|
|
1523
|
+
async function decodePlusCode(config, payload) {
|
|
1524
|
+
return apiRequest(`${config.backendUrls.store}/logistics/plus-code/decode`, {
|
|
1967
1525
|
method: "POST",
|
|
1968
|
-
headers: {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1526
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1527
|
+
body: JSON.stringify(payload),
|
|
1528
|
+
fallbackErrorMessage: "Failed to decode Plus Code"
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
async function autocompleteAddress(config, q, country) {
|
|
1532
|
+
const params = new URLSearchParams();
|
|
1533
|
+
params.set("q", q);
|
|
1534
|
+
if (country) params.set("country", country);
|
|
1535
|
+
return apiRequest(`${config.backendUrls.store}/logistics/address/autocomplete?${params.toString()}`, {
|
|
1536
|
+
headers: storefrontHeaders(config),
|
|
1537
|
+
fallbackErrorMessage: "Failed to autocomplete address"
|
|
1974
1538
|
});
|
|
1975
|
-
if (!response.ok) throw new Error("Failed to validate shipping address");
|
|
1976
|
-
return response.json();
|
|
1977
1539
|
}
|
|
1978
1540
|
var logisticsService = {
|
|
1979
1541
|
getShippingRates,
|
|
1980
|
-
|
|
1981
|
-
|
|
1542
|
+
validateShippingAddress,
|
|
1543
|
+
listPickupLocations,
|
|
1544
|
+
listBusinessLocations,
|
|
1545
|
+
reverseGeocode,
|
|
1546
|
+
decodePlusCode,
|
|
1547
|
+
autocompleteAddress
|
|
1982
1548
|
};
|
|
1983
1549
|
|
|
1984
1550
|
// src/services/bespoke.service.ts
|
|
1985
1551
|
async function checkAvailability(config, product_id) {
|
|
1986
|
-
|
|
1987
|
-
headers:
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1552
|
+
return apiRequest(`${config.backendUrls.store}/bespoke/capacity/availability/${product_id}`, {
|
|
1553
|
+
headers: storefrontHeaders(config),
|
|
1554
|
+
fallbackErrorMessage: "Failed to check bespoke availability"
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
async function approveBespokeDeliverable(config, accessToken, orderId) {
|
|
1558
|
+
return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/approve`, {
|
|
1559
|
+
method: "POST",
|
|
1560
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1561
|
+
body: JSON.stringify({}),
|
|
1562
|
+
fallbackErrorMessage: "Failed to approve deliverable"
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
async function requestBespokeRevision(config, accessToken, orderId, notes) {
|
|
1566
|
+
return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/request-revision`, {
|
|
1567
|
+
method: "POST",
|
|
1568
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1569
|
+
body: JSON.stringify({ notes }),
|
|
1570
|
+
fallbackErrorMessage: "Failed to request revision"
|
|
1991
1571
|
});
|
|
1992
|
-
if (!response.ok) throw new Error("Failed to check bespoke availability");
|
|
1993
|
-
return response.json();
|
|
1994
1572
|
}
|
|
1995
1573
|
var bespokeService = {
|
|
1996
|
-
checkAvailability
|
|
1574
|
+
checkAvailability,
|
|
1575
|
+
approveBespokeDeliverable,
|
|
1576
|
+
requestBespokeRevision
|
|
1997
1577
|
};
|
|
1998
1578
|
|
|
1999
1579
|
// src/services/service-booking.service.ts
|
|
2000
|
-
async function getAvailableSlots(config,
|
|
2001
|
-
const
|
|
2002
|
-
|
|
1580
|
+
async function getAvailableSlots(config, productId, date, params) {
|
|
1581
|
+
const query = new URLSearchParams({ date });
|
|
1582
|
+
if (params?.staffId) query.set("staff_id", params.staffId);
|
|
1583
|
+
if (params?.locationId) query.set("location_id", params.locationId);
|
|
1584
|
+
if (params?.customerLatitude !== void 0) query.set("customer_latitude", String(params.customerLatitude));
|
|
1585
|
+
if (params?.customerLongitude !== void 0) query.set("customer_longitude", String(params.customerLongitude));
|
|
1586
|
+
return apiRequest(
|
|
1587
|
+
`${config.backendUrls.store}/catalog/products/${productId}/available-slots?${query.toString()}`,
|
|
2003
1588
|
{
|
|
2004
|
-
headers:
|
|
2005
|
-
|
|
2006
|
-
"X-Business-ID": config.businessId
|
|
2007
|
-
}
|
|
1589
|
+
headers: storefrontHeaders(config),
|
|
1590
|
+
fallbackErrorMessage: "Failed to get available slots"
|
|
2008
1591
|
}
|
|
2009
1592
|
);
|
|
2010
|
-
if (!response.ok) throw new Error("Failed to get available slots");
|
|
2011
|
-
return response.json();
|
|
2012
1593
|
}
|
|
2013
1594
|
async function bookAppointment(config, accessToken, payload) {
|
|
2014
|
-
|
|
1595
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/schedule`, {
|
|
2015
1596
|
method: "POST",
|
|
2016
|
-
headers: {
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
if (
|
|
2025
|
-
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
headers: {
|
|
2030
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
2031
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2032
|
-
"X-Business-ID": config.businessId
|
|
2033
|
-
}
|
|
1597
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1598
|
+
body: JSON.stringify(payload),
|
|
1599
|
+
fallbackErrorMessage: "Failed to book appointment"
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
async function getAppointments(config, accessToken, params) {
|
|
1603
|
+
const query = new URLSearchParams();
|
|
1604
|
+
if (params?.status) query.set("status", params.status);
|
|
1605
|
+
if (params?.page) query.set("page", String(params.page));
|
|
1606
|
+
if (params?.page_size) query.set("page_size", String(params.page_size));
|
|
1607
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/my?${query.toString()}`, {
|
|
1608
|
+
headers: authHeaders(config, accessToken),
|
|
1609
|
+
fallbackErrorMessage: "Failed to get appointments"
|
|
2034
1610
|
});
|
|
2035
|
-
if (!response.ok) throw new Error("Failed to get appointments");
|
|
2036
|
-
return response.json();
|
|
2037
1611
|
}
|
|
2038
1612
|
async function getAppointment(config, accessToken, id) {
|
|
2039
|
-
|
|
2040
|
-
headers:
|
|
2041
|
-
|
|
2042
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2043
|
-
"X-Business-ID": config.businessId
|
|
2044
|
-
}
|
|
1613
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}`, {
|
|
1614
|
+
headers: authHeaders(config, accessToken),
|
|
1615
|
+
fallbackErrorMessage: "Failed to get appointment"
|
|
2045
1616
|
});
|
|
2046
|
-
if (!response.ok) throw new Error("Failed to get appointment");
|
|
2047
|
-
return response.json();
|
|
2048
1617
|
}
|
|
2049
|
-
async function cancelAppointment(config, accessToken, id) {
|
|
2050
|
-
|
|
2051
|
-
method: "
|
|
2052
|
-
headers: {
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
"X-Business-ID": config.businessId
|
|
2056
|
-
}
|
|
1618
|
+
async function cancelAppointment(config, accessToken, id, payload) {
|
|
1619
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/cancel`, {
|
|
1620
|
+
method: "POST",
|
|
1621
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1622
|
+
body: JSON.stringify(payload ?? {}),
|
|
1623
|
+
fallbackErrorMessage: "Failed to cancel appointment"
|
|
2057
1624
|
});
|
|
2058
1625
|
}
|
|
2059
|
-
async function
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
}
|
|
1626
|
+
async function rescheduleAppointment(config, accessToken, id, payload) {
|
|
1627
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/reschedule`, {
|
|
1628
|
+
method: "POST",
|
|
1629
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1630
|
+
body: JSON.stringify(payload),
|
|
1631
|
+
fallbackErrorMessage: "Failed to reschedule appointment"
|
|
2066
1632
|
});
|
|
2067
|
-
if (!response.ok) throw new Error("Failed to get deliverables");
|
|
2068
|
-
return response.json();
|
|
2069
1633
|
}
|
|
2070
|
-
async function
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
{
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
1634
|
+
async function disputeAppointment(config, accessToken, id, payload) {
|
|
1635
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/dispute`, {
|
|
1636
|
+
method: "POST",
|
|
1637
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1638
|
+
body: JSON.stringify(payload),
|
|
1639
|
+
fallbackErrorMessage: "Failed to open dispute"
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
async function confirmAppointmentCompletion(config, accessToken, id, payload) {
|
|
1643
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/confirm`, {
|
|
1644
|
+
method: "POST",
|
|
1645
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1646
|
+
body: JSON.stringify(payload ?? {}),
|
|
1647
|
+
fallbackErrorMessage: "Failed to confirm completion"
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
async function getMilestones(config, accessToken, bookingId) {
|
|
1651
|
+
return apiRequest(`${config.backendUrls.store}/service/bookings/${bookingId}/milestones`, {
|
|
1652
|
+
headers: authHeaders(config, accessToken),
|
|
1653
|
+
fallbackErrorMessage: "Failed to get milestones"
|
|
1654
|
+
});
|
|
2086
1655
|
}
|
|
2087
|
-
async function
|
|
2088
|
-
|
|
2089
|
-
`${config.backendUrls.store}/service/
|
|
1656
|
+
async function approveMilestone(config, accessToken, bookingId, milestoneId, payload) {
|
|
1657
|
+
return apiRequest(
|
|
1658
|
+
`${config.backendUrls.store}/service/bookings/${bookingId}/milestones/${milestoneId}/approve`,
|
|
2090
1659
|
{
|
|
2091
1660
|
method: "POST",
|
|
2092
|
-
headers: {
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2096
|
-
"X-Business-ID": config.businessId
|
|
2097
|
-
},
|
|
2098
|
-
body: JSON.stringify({ approved: false, feedback })
|
|
1661
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1662
|
+
body: JSON.stringify(payload ?? {}),
|
|
1663
|
+
fallbackErrorMessage: "Failed to approve milestone"
|
|
2099
1664
|
}
|
|
2100
1665
|
);
|
|
2101
|
-
if (!response.ok) throw new Error("Failed to request revision");
|
|
2102
|
-
return response.json();
|
|
2103
1666
|
}
|
|
2104
1667
|
var serviceBookingService = {
|
|
2105
1668
|
getAvailableSlots,
|
|
@@ -2107,41 +1670,111 @@ var serviceBookingService = {
|
|
|
2107
1670
|
getAppointments,
|
|
2108
1671
|
getAppointment,
|
|
2109
1672
|
cancelAppointment,
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
1673
|
+
rescheduleAppointment,
|
|
1674
|
+
disputeAppointment,
|
|
1675
|
+
confirmAppointmentCompletion,
|
|
1676
|
+
getMilestones,
|
|
1677
|
+
approveMilestone
|
|
2113
1678
|
};
|
|
2114
1679
|
|
|
2115
1680
|
// src/services/notifications.service.ts
|
|
1681
|
+
function bearerHeaders(accessToken) {
|
|
1682
|
+
return { Authorization: `Bearer ${accessToken}` };
|
|
1683
|
+
}
|
|
2116
1684
|
async function sendContactEmail(config, payload) {
|
|
2117
|
-
|
|
1685
|
+
return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-email`, {
|
|
2118
1686
|
method: "POST",
|
|
2119
|
-
headers: {
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
"X-Business-ID": config.businessId
|
|
2123
|
-
},
|
|
2124
|
-
body: JSON.stringify(payload)
|
|
1687
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1688
|
+
body: JSON.stringify(payload),
|
|
1689
|
+
fallbackErrorMessage: "Failed to send contact email"
|
|
2125
1690
|
});
|
|
2126
|
-
if (!response.ok) throw new Error("Failed to send contact email");
|
|
2127
|
-
return response.json();
|
|
2128
1691
|
}
|
|
2129
1692
|
async function sendContactConfirmation(config, payload) {
|
|
2130
|
-
|
|
1693
|
+
return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
|
|
1694
|
+
method: "POST",
|
|
1695
|
+
headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
|
|
1696
|
+
body: JSON.stringify(payload),
|
|
1697
|
+
fallbackErrorMessage: "Failed to send contact confirmation"
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
async function getNotificationPreferences(config, accessToken) {
|
|
1701
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
|
|
1702
|
+
headers: bearerHeaders(accessToken),
|
|
1703
|
+
fallbackErrorMessage: "Failed to fetch notification preferences"
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
async function updateNotificationPreferences(config, accessToken, payload) {
|
|
1707
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
|
|
1708
|
+
method: "PATCH",
|
|
1709
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1710
|
+
body: JSON.stringify(payload),
|
|
1711
|
+
fallbackErrorMessage: "Failed to update notification preferences"
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
async function getVapidPublicKey(config) {
|
|
1715
|
+
return apiRequest(`${config.backendUrls.notifications}/push/vapid-public-key`, {
|
|
1716
|
+
fallbackErrorMessage: "Failed to fetch VAPID public key"
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
async function subscribeToPush(config, accessToken, params) {
|
|
1720
|
+
return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
|
|
1721
|
+
method: "POST",
|
|
1722
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1723
|
+
body: JSON.stringify(params),
|
|
1724
|
+
fallbackErrorMessage: "Failed to subscribe to push notifications"
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
async function unsubscribeFromPush(config, accessToken, endpoint) {
|
|
1728
|
+
return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
|
|
1729
|
+
method: "DELETE",
|
|
1730
|
+
headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
|
|
1731
|
+
body: JSON.stringify({ endpoint }),
|
|
1732
|
+
fallbackErrorMessage: "Failed to unsubscribe from push notifications"
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
async function getNotificationInbox(config, accessToken, params) {
|
|
1736
|
+
const query = new URLSearchParams();
|
|
1737
|
+
if (params?.page) query.set("page", String(params.page));
|
|
1738
|
+
if (params?.limit) query.set("limit", String(params.limit));
|
|
1739
|
+
if (params?.unread_only) query.set("unread_only", "true");
|
|
1740
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications?${query.toString()}`, {
|
|
1741
|
+
headers: bearerHeaders(accessToken),
|
|
1742
|
+
fallbackErrorMessage: "Failed to fetch notifications"
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
async function markNotificationRead(config, accessToken, notificationId) {
|
|
1746
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/read`, {
|
|
1747
|
+
method: "POST",
|
|
1748
|
+
headers: bearerHeaders(accessToken),
|
|
1749
|
+
fallbackErrorMessage: "Failed to mark notification as read"
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
async function markAllNotificationsRead(config, accessToken) {
|
|
1753
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/mark-all-read`, {
|
|
1754
|
+
method: "POST",
|
|
1755
|
+
headers: bearerHeaders(accessToken),
|
|
1756
|
+
fallbackErrorMessage: "Failed to mark all notifications as read"
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
async function trackNotificationClick(config, accessToken, notificationId) {
|
|
1760
|
+
return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/click`, {
|
|
2131
1761
|
method: "POST",
|
|
2132
|
-
headers:
|
|
2133
|
-
|
|
2134
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2135
|
-
"X-Business-ID": config.businessId
|
|
2136
|
-
},
|
|
2137
|
-
body: JSON.stringify(payload)
|
|
1762
|
+
headers: bearerHeaders(accessToken),
|
|
1763
|
+
fallbackErrorMessage: "Failed to track notification click"
|
|
2138
1764
|
});
|
|
2139
|
-
if (!response.ok) throw new Error("Failed to send contact confirmation");
|
|
2140
|
-
return response.json();
|
|
2141
1765
|
}
|
|
2142
1766
|
var notificationsService = {
|
|
2143
1767
|
sendContactEmail,
|
|
2144
|
-
sendContactConfirmation
|
|
1768
|
+
sendContactConfirmation,
|
|
1769
|
+
getNotificationPreferences,
|
|
1770
|
+
updateNotificationPreferences,
|
|
1771
|
+
getVapidPublicKey,
|
|
1772
|
+
subscribeToPush,
|
|
1773
|
+
unsubscribeFromPush,
|
|
1774
|
+
getNotificationInbox,
|
|
1775
|
+
markNotificationRead,
|
|
1776
|
+
markAllNotificationsRead,
|
|
1777
|
+
trackNotificationClick
|
|
2145
1778
|
};
|
|
2146
1779
|
|
|
2147
1780
|
// src/services/app.service.ts
|
|
@@ -2159,34 +1792,22 @@ async function googleTranslate(text, target, source = "en") {
|
|
|
2159
1792
|
|
|
2160
1793
|
// src/services/config.service.ts
|
|
2161
1794
|
async function getSupportedLanguages(config) {
|
|
2162
|
-
|
|
2163
|
-
headers:
|
|
2164
|
-
|
|
2165
|
-
"X-Business-ID": config.businessId
|
|
2166
|
-
}
|
|
1795
|
+
return apiRequest(`${config.backendUrls.payment}/config/supported-languages`, {
|
|
1796
|
+
headers: storefrontHeaders(config),
|
|
1797
|
+
fallbackErrorMessage: "Failed to get supported languages"
|
|
2167
1798
|
});
|
|
2168
|
-
if (!response.ok) throw new Error("Failed to get supported languages");
|
|
2169
|
-
return response.json();
|
|
2170
1799
|
}
|
|
2171
1800
|
async function getSupportedCurrencies(config) {
|
|
2172
|
-
|
|
2173
|
-
headers:
|
|
2174
|
-
|
|
2175
|
-
"X-Business-ID": config.businessId
|
|
2176
|
-
}
|
|
1801
|
+
return apiRequest(`${config.backendUrls.payment}/config/supported-currencies`, {
|
|
1802
|
+
headers: storefrontHeaders(config),
|
|
1803
|
+
fallbackErrorMessage: "Failed to get supported currencies"
|
|
2177
1804
|
});
|
|
2178
|
-
if (!response.ok) throw new Error("Failed to get supported currencies");
|
|
2179
|
-
return response.json();
|
|
2180
1805
|
}
|
|
2181
1806
|
async function getBusinessConfig(config) {
|
|
2182
|
-
|
|
2183
|
-
headers:
|
|
2184
|
-
|
|
2185
|
-
"X-Business-ID": config.businessId
|
|
2186
|
-
}
|
|
1807
|
+
return apiRequest(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
|
|
1808
|
+
headers: storefrontHeaders(config),
|
|
1809
|
+
fallbackErrorMessage: "Failed to get business config"
|
|
2187
1810
|
});
|
|
2188
|
-
if (!response.ok) throw new Error("Failed to get business config");
|
|
2189
|
-
return response.json();
|
|
2190
1811
|
}
|
|
2191
1812
|
var configService = {
|
|
2192
1813
|
getSupportedLanguages,
|
|
@@ -2195,134 +1816,293 @@ var configService = {
|
|
|
2195
1816
|
};
|
|
2196
1817
|
|
|
2197
1818
|
// src/services/cms.service.ts
|
|
2198
|
-
async function listCmsEntries(config, modelSlug, params) {
|
|
1819
|
+
async function listCmsEntries(config, businessUuid, modelSlug, params) {
|
|
2199
1820
|
const queryParams = new URLSearchParams();
|
|
2200
1821
|
queryParams.set("page", (params?.page || 1).toString());
|
|
2201
1822
|
queryParams.set("page_size", (params?.page_size || 50).toString());
|
|
2202
|
-
|
|
2203
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1823
|
+
return apiRequest(
|
|
1824
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries?${queryParams.toString()}`,
|
|
2204
1825
|
{
|
|
2205
|
-
headers:
|
|
2206
|
-
|
|
2207
|
-
"X-Business-ID": config.businessId
|
|
2208
|
-
}
|
|
1826
|
+
headers: storefrontHeaders(config),
|
|
1827
|
+
fallbackErrorMessage: "Failed to list CMS entries"
|
|
2209
1828
|
}
|
|
2210
1829
|
);
|
|
2211
|
-
if (!response.ok) throw new Error("Failed to list CMS entries");
|
|
2212
|
-
return response.json();
|
|
2213
1830
|
}
|
|
2214
|
-
async function getCmsEntry(config, modelSlug, entryId) {
|
|
2215
|
-
|
|
2216
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1831
|
+
async function getCmsEntry(config, businessUuid, modelSlug, entryId) {
|
|
1832
|
+
return apiRequest(
|
|
1833
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2217
1834
|
{
|
|
2218
|
-
headers:
|
|
2219
|
-
|
|
2220
|
-
"X-Business-ID": config.businessId
|
|
2221
|
-
}
|
|
1835
|
+
headers: storefrontHeaders(config),
|
|
1836
|
+
fallbackErrorMessage: "Failed to get CMS entry"
|
|
2222
1837
|
}
|
|
2223
1838
|
);
|
|
2224
|
-
if (!response.ok) throw new Error("Failed to get CMS entry");
|
|
2225
|
-
return response.json();
|
|
2226
1839
|
}
|
|
2227
|
-
async function createCmsEntry(config, accessToken, modelSlug, params) {
|
|
2228
|
-
|
|
2229
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1840
|
+
async function createCmsEntry(config, businessUuid, accessToken, modelSlug, params) {
|
|
1841
|
+
return apiRequest(
|
|
1842
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries`,
|
|
2230
1843
|
{
|
|
2231
1844
|
method: "POST",
|
|
2232
|
-
headers: {
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2236
|
-
"X-Business-ID": config.businessId
|
|
2237
|
-
},
|
|
2238
|
-
body: JSON.stringify(params)
|
|
1845
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1846
|
+
body: JSON.stringify(params),
|
|
1847
|
+
fallbackErrorMessage: "Failed to create CMS entry"
|
|
2239
1848
|
}
|
|
2240
1849
|
);
|
|
2241
|
-
if (!response.ok) throw new Error("Failed to create CMS entry");
|
|
2242
|
-
return response.json();
|
|
2243
1850
|
}
|
|
2244
|
-
async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
|
|
2245
|
-
|
|
2246
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1851
|
+
async function updateCmsEntry(config, businessUuid, accessToken, modelSlug, entryId, params) {
|
|
1852
|
+
return apiRequest(
|
|
1853
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2247
1854
|
{
|
|
2248
1855
|
method: "PUT",
|
|
2249
|
-
headers: {
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2253
|
-
"X-Business-ID": config.businessId
|
|
2254
|
-
},
|
|
2255
|
-
body: JSON.stringify(params)
|
|
1856
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
1857
|
+
body: JSON.stringify(params),
|
|
1858
|
+
fallbackErrorMessage: "Failed to update CMS entry"
|
|
2256
1859
|
}
|
|
2257
1860
|
);
|
|
2258
|
-
if (!response.ok) throw new Error("Failed to update CMS entry");
|
|
2259
|
-
return response.json();
|
|
2260
1861
|
}
|
|
2261
|
-
async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
|
|
2262
|
-
|
|
2263
|
-
`${config.backendUrls.cms}/sdk/${
|
|
1862
|
+
async function deleteCmsEntry(config, businessUuid, accessToken, modelSlug, entryId) {
|
|
1863
|
+
await apiRequest(
|
|
1864
|
+
`${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
|
|
2264
1865
|
{
|
|
2265
1866
|
method: "DELETE",
|
|
2266
|
-
headers:
|
|
2267
|
-
|
|
2268
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
2269
|
-
"X-Business-ID": config.businessId
|
|
2270
|
-
}
|
|
1867
|
+
headers: authHeaders(config, accessToken),
|
|
1868
|
+
fallbackErrorMessage: "Failed to delete CMS entry"
|
|
2271
1869
|
}
|
|
2272
1870
|
);
|
|
2273
|
-
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
// src/services/legal.service.ts
|
|
1874
|
+
async function getMerchantLegalDocument(config, businessUuid, documentType, fetchOptions) {
|
|
1875
|
+
if (!businessUuid || !config?.backendUrls?.cms) return null;
|
|
1876
|
+
try {
|
|
1877
|
+
const res = await fetch(
|
|
1878
|
+
`${config.backendUrls.cms}/cms/legal/storefront/${businessUuid}/${documentType}`,
|
|
1879
|
+
fetchOptions
|
|
1880
|
+
);
|
|
1881
|
+
if (!res.ok) return null;
|
|
1882
|
+
return await res.json();
|
|
1883
|
+
} catch {
|
|
1884
|
+
return null;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/services/review.service.ts
|
|
1889
|
+
function fetchWithConfig(url, config, options = {}) {
|
|
1890
|
+
const headers = {
|
|
1891
|
+
...JSON_HEADERS,
|
|
1892
|
+
Accept: "application/json",
|
|
1893
|
+
...options.headers
|
|
1894
|
+
};
|
|
1895
|
+
if (config.storefrontApiKey) headers["X-Storefront-Key"] = config.storefrontApiKey;
|
|
1896
|
+
if (config.businessId) headers["X-Business-ID"] = config.businessId;
|
|
1897
|
+
if (config.authToken) headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
1898
|
+
return apiRequest(url, { ...options, headers, fallbackErrorMessage: options.fallbackErrorMessage ?? "Request failed" });
|
|
1899
|
+
}
|
|
1900
|
+
async function createReview(reviewData, config) {
|
|
1901
|
+
const url = `${config.backendUrls.crm}/reviews`;
|
|
1902
|
+
return fetchWithConfig(url, config, {
|
|
1903
|
+
method: "POST",
|
|
1904
|
+
body: JSON.stringify(reviewData),
|
|
1905
|
+
fallbackErrorMessage: "Failed to create review"
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
async function updateReview(reviewId, reviewData, config) {
|
|
1909
|
+
const url = `${config.backendUrls.crm}/reviews/${reviewId}`;
|
|
1910
|
+
return fetchWithConfig(url, config, {
|
|
1911
|
+
method: "PUT",
|
|
1912
|
+
body: JSON.stringify(reviewData),
|
|
1913
|
+
fallbackErrorMessage: "Failed to update review"
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
async function getProductReviews(productId, params = {}, config) {
|
|
1917
|
+
const queryParams = new URLSearchParams();
|
|
1918
|
+
if (params.page) queryParams.append("page", params.page.toString());
|
|
1919
|
+
if (params.page_size) queryParams.append("page_size", params.page_size.toString());
|
|
1920
|
+
if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
|
|
1921
|
+
const url = `${config.backendUrls.crm}/products/${productId}/reviews?${queryParams.toString()}`;
|
|
1922
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product reviews" });
|
|
1923
|
+
}
|
|
1924
|
+
async function createComment(commentData, config) {
|
|
1925
|
+
const url = `${config.backendUrls.crm}/comments`;
|
|
1926
|
+
return fetchWithConfig(url, config, {
|
|
1927
|
+
method: "POST",
|
|
1928
|
+
body: JSON.stringify(commentData),
|
|
1929
|
+
fallbackErrorMessage: "Failed to create comment"
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
async function updateComment(commentId, commentData, config) {
|
|
1933
|
+
const url = `${config.backendUrls.crm}/comments/${commentId}`;
|
|
1934
|
+
return fetchWithConfig(url, config, {
|
|
1935
|
+
method: "PUT",
|
|
1936
|
+
body: JSON.stringify(commentData),
|
|
1937
|
+
fallbackErrorMessage: "Failed to update comment"
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
async function getProductComments(productId, params = {}, config) {
|
|
1941
|
+
const queryParams = new URLSearchParams();
|
|
1942
|
+
if (params.page) queryParams.append("page", params.page.toString());
|
|
1943
|
+
if (params.page_size) queryParams.append("page_size", params.page_size.toString());
|
|
1944
|
+
if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
|
|
1945
|
+
const url = `${config.backendUrls.crm}/products/${productId}/comments?${queryParams.toString()}`;
|
|
1946
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product comments" });
|
|
1947
|
+
}
|
|
1948
|
+
async function getPendingReviews(config) {
|
|
1949
|
+
const url = `${config.backendUrls.crm}/admin/reviews/pending`;
|
|
1950
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending reviews" });
|
|
1951
|
+
}
|
|
1952
|
+
async function getPendingComments(config) {
|
|
1953
|
+
const url = `${config.backendUrls.crm}/admin/comments/pending`;
|
|
1954
|
+
return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending comments" });
|
|
1955
|
+
}
|
|
1956
|
+
async function moderateReview(reviewId, action, config) {
|
|
1957
|
+
const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/moderate`;
|
|
1958
|
+
return fetchWithConfig(url, config, {
|
|
1959
|
+
method: "POST",
|
|
1960
|
+
body: JSON.stringify(action),
|
|
1961
|
+
fallbackErrorMessage: "Failed to moderate review"
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
async function moderateComment(commentId, action, config) {
|
|
1965
|
+
const url = `${config.backendUrls.crm}/admin/comments/${commentId}/moderate`;
|
|
1966
|
+
return fetchWithConfig(url, config, {
|
|
1967
|
+
method: "POST",
|
|
1968
|
+
body: JSON.stringify(action),
|
|
1969
|
+
fallbackErrorMessage: "Failed to moderate comment"
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
async function merchantReplyToReview(reviewId, replyData, config) {
|
|
1973
|
+
const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/reply`;
|
|
1974
|
+
return fetchWithConfig(url, config, {
|
|
1975
|
+
method: "POST",
|
|
1976
|
+
body: JSON.stringify(replyData),
|
|
1977
|
+
fallbackErrorMessage: "Failed to post merchant reply"
|
|
1978
|
+
});
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// src/services/media.service.ts
|
|
1982
|
+
async function uploadMediaFile(params) {
|
|
1983
|
+
const presignedUrlEndpoint = params.presignedUrlEndpoint ?? "/api/auth/media/presigned-url";
|
|
1984
|
+
const confirmUploadEndpoint = params.confirmUploadEndpoint ?? "/api/auth/media/confirm-upload";
|
|
1985
|
+
const { presigned_url, storage_path } = await apiRequest(presignedUrlEndpoint, {
|
|
1986
|
+
method: "POST",
|
|
1987
|
+
headers: JSON_HEADERS,
|
|
1988
|
+
credentials: "include",
|
|
1989
|
+
body: JSON.stringify({
|
|
1990
|
+
filename: params.file.name,
|
|
1991
|
+
content_type: params.file.type,
|
|
1992
|
+
context: params.context,
|
|
1993
|
+
entity_id: params.entityId,
|
|
1994
|
+
affiliation: params.affiliation,
|
|
1995
|
+
owner_id: params.ownerId
|
|
1996
|
+
}),
|
|
1997
|
+
fallbackErrorMessage: "Could not start upload"
|
|
1998
|
+
});
|
|
1999
|
+
const putResponse = await fetch(presigned_url, {
|
|
2000
|
+
method: "PUT",
|
|
2001
|
+
headers: { "Content-Type": params.file.type },
|
|
2002
|
+
body: params.file
|
|
2003
|
+
});
|
|
2004
|
+
if (!putResponse.ok) {
|
|
2005
|
+
throw new Error(`Failed to upload ${params.file.name}`);
|
|
2006
|
+
}
|
|
2007
|
+
return apiRequest(confirmUploadEndpoint, {
|
|
2008
|
+
method: "POST",
|
|
2009
|
+
headers: JSON_HEADERS,
|
|
2010
|
+
credentials: "include",
|
|
2011
|
+
body: JSON.stringify({
|
|
2012
|
+
storage_path,
|
|
2013
|
+
entity_id: params.entityId,
|
|
2014
|
+
original_filename: params.file.name,
|
|
2015
|
+
content_type: params.file.type,
|
|
2016
|
+
size: params.file.size,
|
|
2017
|
+
context: params.context,
|
|
2018
|
+
affiliation: params.affiliation,
|
|
2019
|
+
owner_id: params.ownerId
|
|
2020
|
+
}),
|
|
2021
|
+
fallbackErrorMessage: `Could not confirm upload of ${params.file.name}`
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
async function uploadMediaFiles(files, params) {
|
|
2025
|
+
const assets = [];
|
|
2026
|
+
const errors = [];
|
|
2027
|
+
for (const file of files) {
|
|
2028
|
+
try {
|
|
2029
|
+
assets.push(await uploadMediaFile({ ...params, file }));
|
|
2030
|
+
} catch (err) {
|
|
2031
|
+
errors.push({ file: file.name, message: err instanceof Error ? err.message : "Upload failed" });
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
return { assets, errors };
|
|
2274
2035
|
}
|
|
2275
2036
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2276
2037
|
0 && (module.exports = {
|
|
2277
|
-
acceptQuote,
|
|
2278
2038
|
addToCart,
|
|
2279
2039
|
addToGuestCart,
|
|
2280
2040
|
addToWishlist,
|
|
2281
|
-
|
|
2041
|
+
approveBespokeDeliverable,
|
|
2042
|
+
approveMilestone,
|
|
2043
|
+
autocompleteAddress,
|
|
2282
2044
|
bespokeService,
|
|
2283
2045
|
bookAppointment,
|
|
2284
2046
|
cancelAppointment,
|
|
2285
2047
|
cancelOrder,
|
|
2048
|
+
changePassword,
|
|
2286
2049
|
checkAvailability,
|
|
2287
2050
|
checkInWishlist,
|
|
2051
|
+
claimWalletCredit,
|
|
2288
2052
|
clearCart,
|
|
2289
2053
|
clearGuestCart,
|
|
2290
2054
|
clearTokens,
|
|
2291
2055
|
configService,
|
|
2292
|
-
|
|
2056
|
+
confirmAppointmentCompletion,
|
|
2057
|
+
confirmMediaUpload,
|
|
2058
|
+
createBespokeOrder,
|
|
2293
2059
|
createCmsEntry,
|
|
2060
|
+
createComment,
|
|
2294
2061
|
createConsultation,
|
|
2062
|
+
createCustomerAddress,
|
|
2295
2063
|
createDedicatedAccount,
|
|
2064
|
+
createFeedback,
|
|
2296
2065
|
createOrder,
|
|
2066
|
+
createReview,
|
|
2067
|
+
createServiceBookingOrder,
|
|
2068
|
+
deactivateCustomerAccount,
|
|
2069
|
+
decodePlusCode,
|
|
2297
2070
|
deleteCmsEntry,
|
|
2071
|
+
deleteCustomerAddress,
|
|
2072
|
+
disputeAppointment,
|
|
2298
2073
|
findOrder,
|
|
2299
|
-
|
|
2074
|
+
forgotPasswordCustomer,
|
|
2300
2075
|
getAppointment,
|
|
2301
2076
|
getAppointments,
|
|
2302
2077
|
getAuthUser,
|
|
2078
|
+
getAvailablePaymentMethods,
|
|
2303
2079
|
getAvailableSlots,
|
|
2304
2080
|
getBusinessConfig,
|
|
2305
2081
|
getCart,
|
|
2306
2082
|
getCmsEntry,
|
|
2307
|
-
|
|
2308
|
-
getConsultations,
|
|
2309
|
-
getDeliverables,
|
|
2083
|
+
getCustomerAddresses,
|
|
2310
2084
|
getFeaturedProducts,
|
|
2311
2085
|
getGuestCart,
|
|
2312
|
-
getGuestCartCount,
|
|
2313
2086
|
getGuestCartProductType,
|
|
2314
|
-
getGuestCartSubtotal,
|
|
2315
|
-
getLatestProducts,
|
|
2316
|
-
getLowStockProducts,
|
|
2317
2087
|
getMe,
|
|
2088
|
+
getMerchantLegalDocument,
|
|
2089
|
+
getMilestones,
|
|
2090
|
+
getMyFeedback,
|
|
2318
2091
|
getNewProducts,
|
|
2092
|
+
getNotificationInbox,
|
|
2093
|
+
getNotificationPreferences,
|
|
2319
2094
|
getOnSaleProducts,
|
|
2320
2095
|
getOrders,
|
|
2096
|
+
getPendingComments,
|
|
2097
|
+
getPendingReviews,
|
|
2321
2098
|
getPopularProducts,
|
|
2099
|
+
getPresignedUploadUrl,
|
|
2100
|
+
getProductComments,
|
|
2101
|
+
getProductReviews,
|
|
2322
2102
|
getRecommendedProducts,
|
|
2323
|
-
getSellerShippingAddress,
|
|
2324
2103
|
getShippingRates,
|
|
2325
2104
|
getStoredTokens,
|
|
2105
|
+
getStorefrontBusinessInfo,
|
|
2326
2106
|
getStorefrontCollectionBySlug,
|
|
2327
2107
|
getStorefrontCollections,
|
|
2328
2108
|
getStorefrontProductBySlug,
|
|
@@ -2330,39 +2110,65 @@ async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
|
|
|
2330
2110
|
getSupportedCurrencies,
|
|
2331
2111
|
getSupportedLanguages,
|
|
2332
2112
|
getTransactionStatus,
|
|
2113
|
+
getVapidPublicKey,
|
|
2114
|
+
getWalletBalance,
|
|
2115
|
+
getWalletLedger,
|
|
2333
2116
|
getWishlist,
|
|
2334
2117
|
googleTranslate,
|
|
2335
2118
|
initiatePayment,
|
|
2119
|
+
listBusinessLocations,
|
|
2336
2120
|
listCmsEntries,
|
|
2121
|
+
listPickupLocations,
|
|
2337
2122
|
loginCustomer,
|
|
2338
2123
|
logisticsService,
|
|
2339
2124
|
logout,
|
|
2340
2125
|
mapAuthUserToCustomer,
|
|
2126
|
+
markAllNotificationsRead,
|
|
2127
|
+
markNotificationRead,
|
|
2128
|
+
merchantReplyToReview,
|
|
2341
2129
|
mergeGuestCart,
|
|
2342
2130
|
mergeGuestCartIfPresent,
|
|
2131
|
+
moderateComment,
|
|
2132
|
+
moderateReview,
|
|
2343
2133
|
notificationsService,
|
|
2344
2134
|
paymentService,
|
|
2345
2135
|
refreshToken,
|
|
2346
2136
|
registerCustomer,
|
|
2347
|
-
rejectQuote,
|
|
2348
2137
|
removeFromCart,
|
|
2349
2138
|
removeFromGuestCart,
|
|
2350
2139
|
removeFromWishlist,
|
|
2351
2140
|
removeProductFromWishlist,
|
|
2352
|
-
|
|
2353
|
-
|
|
2141
|
+
requestBespokeRevision,
|
|
2142
|
+
requestCustomerOtp,
|
|
2143
|
+
requestCustomerReactivation,
|
|
2144
|
+
rescheduleAppointment,
|
|
2145
|
+
resetPasswordCustomer,
|
|
2146
|
+
resolveDigitalDownload,
|
|
2147
|
+
resolveDigitalDownloadFile,
|
|
2148
|
+
reverseGeocode,
|
|
2354
2149
|
sendContactConfirmation,
|
|
2355
2150
|
sendContactEmail,
|
|
2356
|
-
sendMessage,
|
|
2357
2151
|
serviceBookingService,
|
|
2358
2152
|
silentRefresh,
|
|
2359
2153
|
storeTokens,
|
|
2154
|
+
subscribeToPush,
|
|
2155
|
+
trackNotificationClick,
|
|
2360
2156
|
trackOrder,
|
|
2157
|
+
unsubscribeFromPush,
|
|
2361
2158
|
updateCartItem,
|
|
2362
2159
|
updateCmsEntry,
|
|
2160
|
+
updateComment,
|
|
2161
|
+
updateCustomerAddress,
|
|
2363
2162
|
updateGuestCartItemQuantity,
|
|
2163
|
+
updateNotificationPreferences,
|
|
2364
2164
|
updateProfile,
|
|
2165
|
+
updateReview,
|
|
2166
|
+
uploadMediaFile,
|
|
2167
|
+
uploadMediaFiles,
|
|
2168
|
+
validatePromoCode,
|
|
2365
2169
|
validateShippingAddress,
|
|
2170
|
+
verifyCustomerOtp,
|
|
2171
|
+
verifyCustomerReactivation,
|
|
2366
2172
|
verifySocialToken,
|
|
2367
2173
|
verifyTransaction
|
|
2368
2174
|
});
|