@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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
fragment CollectionFields on Collection {
|
|
2
|
+
id
|
|
3
|
+
business_id
|
|
4
|
+
name
|
|
5
|
+
slug
|
|
6
|
+
description
|
|
7
|
+
image_url
|
|
8
|
+
collection_type
|
|
9
|
+
rules
|
|
10
|
+
status
|
|
11
|
+
sort_order
|
|
12
|
+
created_at
|
|
13
|
+
updated_at
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
|
|
17
|
+
storefront_collections(page: $page, pageSize: $pageSize) {
|
|
18
|
+
items {
|
|
19
|
+
...CollectionFields
|
|
20
|
+
}
|
|
21
|
+
total
|
|
22
|
+
page
|
|
23
|
+
page_size
|
|
24
|
+
total_pages
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
query GetStorefrontCollectionBySlug($slug: String!) {
|
|
29
|
+
storefront_collection_by_slug(slug: $slug) {
|
|
30
|
+
...CollectionFields
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Shared field selection for every storefront product query. Replaces 7
|
|
2
|
+
# hand-duplicated copies of this exact selection that used to live inline in
|
|
3
|
+
# product.service.ts (see that file's normaliseProductType doc comment for
|
|
4
|
+
# why keeping them in sync by hand was the root cause of a platform-wide bug).
|
|
5
|
+
fragment ProductFields on Product {
|
|
6
|
+
id
|
|
7
|
+
business_id
|
|
8
|
+
name
|
|
9
|
+
slug
|
|
10
|
+
description
|
|
11
|
+
brand
|
|
12
|
+
product_type
|
|
13
|
+
requires_shipping
|
|
14
|
+
is_consumable
|
|
15
|
+
is_bespoke
|
|
16
|
+
is_physical
|
|
17
|
+
is_non_returnable
|
|
18
|
+
deposit_percentage
|
|
19
|
+
base_price
|
|
20
|
+
currency
|
|
21
|
+
sale_price
|
|
22
|
+
sale_start
|
|
23
|
+
sale_end
|
|
24
|
+
images
|
|
25
|
+
tags
|
|
26
|
+
custom_fields {
|
|
27
|
+
label
|
|
28
|
+
unit
|
|
29
|
+
required
|
|
30
|
+
field_type
|
|
31
|
+
options
|
|
32
|
+
}
|
|
33
|
+
is_published
|
|
34
|
+
is_featured
|
|
35
|
+
is_popular
|
|
36
|
+
is_new
|
|
37
|
+
is_temporary
|
|
38
|
+
average_rating
|
|
39
|
+
rating_count
|
|
40
|
+
source_channel
|
|
41
|
+
source_channel_ref_id
|
|
42
|
+
service_type
|
|
43
|
+
service_duration_minutes
|
|
44
|
+
service_location_type
|
|
45
|
+
service_coverage_radius_km
|
|
46
|
+
service_requires_consultation
|
|
47
|
+
service_max_capacity_per_slot
|
|
48
|
+
service_buffer_minutes
|
|
49
|
+
service_is_recurring
|
|
50
|
+
service_recurring_interval
|
|
51
|
+
service_project_based
|
|
52
|
+
digital_files {
|
|
53
|
+
id
|
|
54
|
+
file_key
|
|
55
|
+
display_name
|
|
56
|
+
sort_order
|
|
57
|
+
}
|
|
58
|
+
download_limit
|
|
59
|
+
download_expires_at
|
|
60
|
+
weight_kg
|
|
61
|
+
length_cm
|
|
62
|
+
width_cm
|
|
63
|
+
height_cm
|
|
64
|
+
created_at
|
|
65
|
+
updated_at
|
|
66
|
+
variants {
|
|
67
|
+
id
|
|
68
|
+
product_id
|
|
69
|
+
sku
|
|
70
|
+
attributes
|
|
71
|
+
price
|
|
72
|
+
images
|
|
73
|
+
weight_kg
|
|
74
|
+
is_active
|
|
75
|
+
inventory {
|
|
76
|
+
id
|
|
77
|
+
product_id
|
|
78
|
+
variant_id
|
|
79
|
+
quantity
|
|
80
|
+
reserved
|
|
81
|
+
reorder_point
|
|
82
|
+
reorder_quantity
|
|
83
|
+
track_quantity
|
|
84
|
+
allow_backorder
|
|
85
|
+
available
|
|
86
|
+
is_in_stock
|
|
87
|
+
is_low_stock
|
|
88
|
+
updated_at
|
|
89
|
+
}
|
|
90
|
+
created_at
|
|
91
|
+
updated_at
|
|
92
|
+
}
|
|
93
|
+
collections {
|
|
94
|
+
id
|
|
95
|
+
business_id
|
|
96
|
+
name
|
|
97
|
+
slug
|
|
98
|
+
description
|
|
99
|
+
image_url
|
|
100
|
+
collection_type
|
|
101
|
+
rules
|
|
102
|
+
status
|
|
103
|
+
sort_order
|
|
104
|
+
created_at
|
|
105
|
+
updated_at
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
query GetStorefrontProducts(
|
|
110
|
+
$page: Int!
|
|
111
|
+
$pageSize: Int!
|
|
112
|
+
$collectionSlug: String
|
|
113
|
+
$search: String
|
|
114
|
+
$productType: String
|
|
115
|
+
) {
|
|
116
|
+
storefront_products(
|
|
117
|
+
page: $page
|
|
118
|
+
pageSize: $pageSize
|
|
119
|
+
collectionSlug: $collectionSlug
|
|
120
|
+
search: $search
|
|
121
|
+
productType: $productType
|
|
122
|
+
) {
|
|
123
|
+
items {
|
|
124
|
+
...ProductFields
|
|
125
|
+
}
|
|
126
|
+
total
|
|
127
|
+
page
|
|
128
|
+
page_size
|
|
129
|
+
total_pages
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
query GetStorefrontProductBySlug($slug: String!) {
|
|
134
|
+
storefront_product_by_slug(slug: $slug) {
|
|
135
|
+
...ProductFields
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
|
|
140
|
+
storefront_popular(page: $page, pageSize: $pageSize) {
|
|
141
|
+
items {
|
|
142
|
+
...ProductFields
|
|
143
|
+
}
|
|
144
|
+
total
|
|
145
|
+
page
|
|
146
|
+
page_size
|
|
147
|
+
total_pages
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
|
|
152
|
+
storefront_featured(page: $page, pageSize: $pageSize) {
|
|
153
|
+
items {
|
|
154
|
+
...ProductFields
|
|
155
|
+
}
|
|
156
|
+
total
|
|
157
|
+
page
|
|
158
|
+
page_size
|
|
159
|
+
total_pages
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
query GetStorefrontNew($page: Int!, $pageSize: Int!) {
|
|
164
|
+
storefront_new(page: $page, pageSize: $pageSize) {
|
|
165
|
+
items {
|
|
166
|
+
...ProductFields
|
|
167
|
+
}
|
|
168
|
+
total
|
|
169
|
+
page
|
|
170
|
+
page_size
|
|
171
|
+
total_pages
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
|
|
176
|
+
storefront_on_sale(page: $page, pageSize: $pageSize) {
|
|
177
|
+
items {
|
|
178
|
+
...ProductFields
|
|
179
|
+
}
|
|
180
|
+
total
|
|
181
|
+
page
|
|
182
|
+
page_size
|
|
183
|
+
total_pages
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
query GetStorefrontRecommended($page: Int!, $pageSize: Int!, $excludeProductId: String) {
|
|
188
|
+
storefront_recommended(page: $page, pageSize: $pageSize, excludeProductId: $excludeProductId) {
|
|
189
|
+
items {
|
|
190
|
+
...ProductFields
|
|
191
|
+
}
|
|
192
|
+
total
|
|
193
|
+
page
|
|
194
|
+
page_size
|
|
195
|
+
total_pages
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
|
|
2
|
+
storefront_wishlist(page: $page, pageSize: $pageSize) {
|
|
3
|
+
items {
|
|
4
|
+
id
|
|
5
|
+
product_id
|
|
6
|
+
notes
|
|
7
|
+
created_at
|
|
8
|
+
product_name
|
|
9
|
+
product_slug
|
|
10
|
+
product_price
|
|
11
|
+
currency
|
|
12
|
+
product_image
|
|
13
|
+
}
|
|
14
|
+
total
|
|
15
|
+
page
|
|
16
|
+
page_size
|
|
17
|
+
total_pages
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
query CheckInStorefrontWishlist($productId: String!) {
|
|
22
|
+
check_in_storefront_wishlist(productId: $productId) {
|
|
23
|
+
in_wishlist
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
export * from './use-cart'
|
|
8
8
|
export * from './use-orders'
|
|
9
|
+
export * from './use-consultations'
|
|
10
|
+
export * from './use-feedback'
|
|
11
|
+
export * from './use-customer-address'
|
|
9
12
|
export * from './use-auth'
|
|
10
13
|
export * from './use-countries'
|
|
11
14
|
export * from './use-states'
|
|
@@ -16,13 +19,17 @@ export * from './use-collections'
|
|
|
16
19
|
export * from './use-products'
|
|
17
20
|
export * from './use-wishlist'
|
|
18
21
|
export * from './use-service-booking'
|
|
19
|
-
export * from './use-consultations'
|
|
20
|
-
export * from './use-consultation-stream'
|
|
21
22
|
export * from './use-order-stream'
|
|
23
|
+
export * from './use-reviews'
|
|
22
24
|
export * from './use-is-mounted'
|
|
23
25
|
export * from './use-mobile'
|
|
24
26
|
export * from './use-google-translate'
|
|
25
27
|
export * from './use-payment'
|
|
26
28
|
export * from './use-cms'
|
|
29
|
+
export * from './use-business-config'
|
|
30
|
+
export * from './use-notifications'
|
|
31
|
+
export * from './use-notification-stream'
|
|
32
|
+
export * from './use-push-notifications'
|
|
33
|
+
export * from './use-media-upload'
|
|
27
34
|
export * from '../context/sdk-context'
|
|
28
35
|
|
package/src/hooks/use-auth.ts
CHANGED
|
@@ -6,13 +6,34 @@
|
|
|
6
6
|
* tokens and passes config to these hooks.
|
|
7
7
|
*/
|
|
8
8
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
getAuthUser,
|
|
11
|
+
loginCustomer,
|
|
12
|
+
registerCustomer,
|
|
13
|
+
requestCustomerOtp,
|
|
14
|
+
verifyCustomerOtp,
|
|
15
|
+
updateProfile,
|
|
16
|
+
logout as logoutService,
|
|
17
|
+
forgotPasswordCustomer,
|
|
18
|
+
resetPasswordCustomer,
|
|
19
|
+
deactivateCustomerAccount,
|
|
20
|
+
requestCustomerReactivation,
|
|
21
|
+
verifyCustomerReactivation,
|
|
22
|
+
getStorefrontBusinessInfo,
|
|
23
|
+
changePassword,
|
|
24
|
+
} from '../services/auth.service'
|
|
11
25
|
import type {
|
|
12
26
|
CustomerLoginPayload,
|
|
13
27
|
CustomerRegisterPayload,
|
|
28
|
+
CustomerPasswordlessRequestPayload,
|
|
29
|
+
CustomerPasswordlessVerifyPayload,
|
|
30
|
+
CustomerForgotPasswordPayload,
|
|
31
|
+
CustomerResetPasswordPayload,
|
|
32
|
+
CustomerDeactivatePayload,
|
|
33
|
+
CustomerReactivatePayload,
|
|
34
|
+
CustomerReactivateVerifyPayload,
|
|
14
35
|
UpdateProfilePayload,
|
|
15
|
-
|
|
36
|
+
ChangePasswordPayload,
|
|
16
37
|
} from '../types/auth'
|
|
17
38
|
import type { SdkConfig } from '../config'
|
|
18
39
|
import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
@@ -21,86 +42,159 @@ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
|
21
42
|
|
|
22
43
|
export function useAuthUser(config?: SdkConfig, accessToken?: string) {
|
|
23
44
|
const ctx = useSdkContext()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken ?? null, ctx)
|
|
46
|
+
return useQuery({
|
|
47
|
+
queryKey: ['auth-user'],
|
|
48
|
+
queryFn: () => getAuthUser(cfg, token ?? ''),
|
|
49
|
+
enabled: !!token,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Real gap fixed 2026-09-17: GET /auth/storefront/business-info/ had no SDK
|
|
55
|
+
* hook — public/unauthenticated (only needs the storefront key), so unlike
|
|
56
|
+
* useAuthUser this is always enabled, never gated on an access token.
|
|
57
|
+
*/
|
|
58
|
+
export function useStorefrontBusinessInfo(config?: SdkConfig) {
|
|
59
|
+
const ctx = useSdkContext()
|
|
60
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
61
|
+
return useQuery({
|
|
62
|
+
queryKey: ['storefront-business-info', cfg.businessId],
|
|
63
|
+
queryFn: () => getStorefrontBusinessInfo(cfg),
|
|
64
|
+
staleTime: 5 * 60 * 1000, // business branding info changes rarely
|
|
65
|
+
})
|
|
35
66
|
}
|
|
36
67
|
|
|
37
68
|
export function useLogin(config?: SdkConfig) {
|
|
38
69
|
const ctx = useSdkContext()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
})
|
|
49
|
-
} catch (error) {
|
|
50
|
-
logger.warn('[useLogin] Called outside QueryClientProvider, returning no-op mutation')
|
|
51
|
-
return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
|
|
52
|
-
}
|
|
70
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
71
|
+
const queryClient = useQueryClient()
|
|
72
|
+
return useMutation({
|
|
73
|
+
mutationFn: (payload: CustomerLoginPayload) => loginCustomer(cfg, payload),
|
|
74
|
+
onSuccess: () => {
|
|
75
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
76
|
+
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
77
|
+
},
|
|
78
|
+
})
|
|
53
79
|
}
|
|
54
80
|
|
|
55
81
|
export function useRegister(config?: SdkConfig) {
|
|
56
82
|
const ctx = useSdkContext()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
83
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
84
|
+
const queryClient = useQueryClient()
|
|
85
|
+
return useMutation({
|
|
86
|
+
mutationFn: (payload: CustomerRegisterPayload) => registerCustomer(cfg, payload),
|
|
87
|
+
onSuccess: () => {
|
|
88
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
89
|
+
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function useRequestOtp(config?: SdkConfig) {
|
|
95
|
+
const ctx = useSdkContext()
|
|
96
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
97
|
+
return useMutation({
|
|
98
|
+
mutationFn: (payload: CustomerPasswordlessRequestPayload) => requestCustomerOtp(cfg, payload),
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function useVerifyOtp(config?: SdkConfig) {
|
|
103
|
+
const ctx = useSdkContext()
|
|
104
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
105
|
+
const queryClient = useQueryClient()
|
|
106
|
+
return useMutation({
|
|
107
|
+
mutationFn: (payload: CustomerPasswordlessVerifyPayload) => verifyCustomerOtp(cfg, payload),
|
|
108
|
+
onSuccess: () => {
|
|
109
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
110
|
+
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function useCustomerForgotPassword(config?: SdkConfig) {
|
|
116
|
+
const ctx = useSdkContext()
|
|
117
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
118
|
+
return useMutation({
|
|
119
|
+
mutationFn: (payload: CustomerForgotPasswordPayload) => forgotPasswordCustomer(cfg, payload),
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function useCustomerResetPassword(config?: SdkConfig) {
|
|
124
|
+
const ctx = useSdkContext()
|
|
125
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
126
|
+
return useMutation({
|
|
127
|
+
mutationFn: (payload: CustomerResetPasswordPayload) => resetPasswordCustomer(cfg, payload),
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function useCustomerDeactivateAccount(config?: SdkConfig, accessToken?: string | null) {
|
|
132
|
+
const ctx = useSdkContext()
|
|
133
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
134
|
+
const queryClient = useQueryClient()
|
|
135
|
+
return useMutation({
|
|
136
|
+
mutationFn: (payload?: CustomerDeactivatePayload) =>
|
|
137
|
+
token ? deactivateCustomerAccount(cfg, token, payload) : Promise.reject(new Error('No access token available')),
|
|
138
|
+
onSuccess: () => {
|
|
139
|
+
queryClient.clear()
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function useCustomerReactivateRequest(config?: SdkConfig) {
|
|
145
|
+
const ctx = useSdkContext()
|
|
146
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
147
|
+
return useMutation({
|
|
148
|
+
mutationFn: (payload: CustomerReactivatePayload) => requestCustomerReactivation(cfg, payload),
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function useCustomerReactivateVerify(config?: SdkConfig) {
|
|
153
|
+
const ctx = useSdkContext()
|
|
154
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
155
|
+
return useMutation({
|
|
156
|
+
mutationFn: (payload: CustomerReactivateVerifyPayload) => verifyCustomerReactivation(cfg, payload),
|
|
157
|
+
})
|
|
71
158
|
}
|
|
72
159
|
|
|
73
160
|
export function useUpdateProfile(config?: SdkConfig, accessToken?: string | null) {
|
|
74
161
|
const ctx = useSdkContext()
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
162
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
163
|
+
const queryClient = useQueryClient()
|
|
164
|
+
return useMutation({
|
|
165
|
+
mutationFn: (payload: UpdateProfilePayload) =>
|
|
166
|
+
token ? updateProfile(cfg, token, payload) : Promise.reject(new Error('No access token available')),
|
|
167
|
+
onSuccess: () => {
|
|
168
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
169
|
+
},
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* POST /auth/change-password/ — REAL GAP FIXED (2026-09-20): this endpoint
|
|
175
|
+
* is fully customer-reachable on the real backend (ChangePasswordView
|
|
176
|
+
* branches on identity_mode) but had zero SDK coverage at all until now —
|
|
177
|
+
* no storefront customer had any way to change their password once logged
|
|
178
|
+
* in (only the logged-out forgot/reset-password OTP flow existed).
|
|
179
|
+
*/
|
|
180
|
+
export function useChangePassword(config?: SdkConfig, accessToken?: string | null) {
|
|
181
|
+
const ctx = useSdkContext()
|
|
182
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
183
|
+
return useMutation({
|
|
184
|
+
mutationFn: (payload: ChangePasswordPayload) =>
|
|
185
|
+
token ? changePassword(cfg, token, payload) : Promise.reject(new Error('No access token available')),
|
|
186
|
+
})
|
|
89
187
|
}
|
|
90
188
|
|
|
91
189
|
export function useLogout(config?: SdkConfig, refreshToken?: string) {
|
|
92
190
|
const ctx = useSdkContext()
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
})
|
|
102
|
-
} catch (error) {
|
|
103
|
-
logger.warn('[useLogout] Called outside QueryClientProvider, returning no-op mutation')
|
|
104
|
-
return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
|
|
105
|
-
}
|
|
191
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
192
|
+
const queryClient = useQueryClient()
|
|
193
|
+
return useMutation({
|
|
194
|
+
mutationFn: () => logoutService(cfg, refreshToken),
|
|
195
|
+
onSuccess: () => {
|
|
196
|
+
queryClient.clear()
|
|
197
|
+
},
|
|
198
|
+
})
|
|
106
199
|
}
|
|
200
|
+
|
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
* React Query hook for checking bespoke service availability.
|
|
5
5
|
* Stateless - requires config parameter.
|
|
6
6
|
*/
|
|
7
|
-
import { useQuery } from '@tanstack/react-query'
|
|
8
|
-
import { checkAvailability } from '../services/bespoke.service'
|
|
7
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
8
|
+
import { checkAvailability, approveBespokeDeliverable, requestBespokeRevision } from '../services/bespoke.service'
|
|
9
9
|
import type { SdkConfig } from '../config'
|
|
10
|
-
import type { BespokeAvailability } from '../types/consultations'
|
|
11
|
-
import { logger } from '../utils'
|
|
12
10
|
import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
13
11
|
|
|
14
12
|
/**
|
|
@@ -16,22 +14,41 @@ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
|
16
14
|
*/
|
|
17
15
|
export function useBespokeAvailability(product_id: string, config?: SdkConfig) {
|
|
18
16
|
const ctx = useSdkContext()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
18
|
+
return useQuery({
|
|
19
|
+
queryKey: ['bespoke-availability', product_id],
|
|
20
|
+
queryFn: () => checkAvailability(cfg, product_id),
|
|
21
|
+
enabled: !!product_id,
|
|
22
|
+
retry: false,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Buyer approves a bespoke order's submitted deliverable. */
|
|
27
|
+
export function useApproveBespokeDeliverable(config?: SdkConfig, accessToken?: string | null) {
|
|
28
|
+
const ctx = useSdkContext()
|
|
29
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
30
|
+
const queryClient = useQueryClient()
|
|
31
|
+
return useMutation({
|
|
32
|
+
mutationFn: (orderId: string) =>
|
|
33
|
+
token ? approveBespokeDeliverable(cfg, token, orderId) : Promise.reject(new Error('No access token available')),
|
|
34
|
+
onSuccess: (_data, orderId) => {
|
|
35
|
+
queryClient.invalidateQueries({ queryKey: ['order', orderId] })
|
|
36
|
+
queryClient.invalidateQueries({ queryKey: ['orders'] })
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Buyer requests a revision on a bespoke order's submitted deliverable. */
|
|
42
|
+
export function useRequestBespokeRevision(config?: SdkConfig, accessToken?: string | null) {
|
|
43
|
+
const ctx = useSdkContext()
|
|
44
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
45
|
+
const queryClient = useQueryClient()
|
|
46
|
+
return useMutation({
|
|
47
|
+
mutationFn: ({ orderId, notes }: { orderId: string; notes: string }) =>
|
|
48
|
+
token ? requestBespokeRevision(cfg, token, orderId, notes) : Promise.reject(new Error('No access token available')),
|
|
49
|
+
onSuccess: (_data, variables) => {
|
|
50
|
+
queryClient.invalidateQueries({ queryKey: ['order', variables.orderId] })
|
|
51
|
+
queryClient.invalidateQueries({ queryKey: ['orders'] })
|
|
52
|
+
},
|
|
53
|
+
})
|
|
37
54
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Config Hook
|
|
3
|
+
*
|
|
4
|
+
* Resolves the business's internal UUID (and currency/branding fields) via
|
|
5
|
+
* kasuvia-auth's internal business-detail endpoint. Several other backends
|
|
6
|
+
* (kasuvia-cms's SDK routes, notably) key their data by this UUID rather
|
|
7
|
+
* than the public BID a storefront's own config carries — this hook is the
|
|
8
|
+
* shared, cached way to resolve it instead of every caller re-fetching.
|
|
9
|
+
* Cached aggressively: a business's UUID never changes.
|
|
10
|
+
*/
|
|
11
|
+
import { useCallback } from 'react'
|
|
12
|
+
import { useQuery } from '@tanstack/react-query'
|
|
13
|
+
import { getBusinessConfig } from '../services/config.service'
|
|
14
|
+
import type { SdkConfig } from '../config'
|
|
15
|
+
import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
16
|
+
import { formatPrice as formatPriceFn } from '../utils/format'
|
|
17
|
+
|
|
18
|
+
export function useBusinessConfig(config?: SdkConfig) {
|
|
19
|
+
const ctx = useSdkContext()
|
|
20
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
21
|
+
return useQuery({
|
|
22
|
+
queryKey: ['business-config', cfg.businessId],
|
|
23
|
+
queryFn: () => getBusinessConfig(cfg),
|
|
24
|
+
staleTime: Infinity,
|
|
25
|
+
gcTime: Infinity,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* REAL GAP FIXED (2026-09-22): `formatPrice(amount, currency)` is stateless
|
|
31
|
+
* and requires the caller to already have the real business currency in
|
|
32
|
+
* hand — every consuming app was left to resolve that currency itself, and
|
|
33
|
+
* kasuvia-storefront's `AppProvider` ended up hand-rolling its own,
|
|
34
|
+
* slightly different copy of the same `Intl.NumberFormat` currency logic
|
|
35
|
+
* (silently falling back to a bare number instead of formatPrice's
|
|
36
|
+
* explicit "N/A" marker when currency is unresolved). This hook is the one
|
|
37
|
+
* real, complete answer: resolves the business's currency via
|
|
38
|
+
* `useBusinessConfig` and returns a ready-to-call formatter, so no
|
|
39
|
+
* consuming app ever needs to reimplement currency formatting again.
|
|
40
|
+
*/
|
|
41
|
+
export function useFormatPrice(config?: SdkConfig) {
|
|
42
|
+
const { data: businessConfig } = useBusinessConfig(config)
|
|
43
|
+
const currency = businessConfig?.currency ?? null
|
|
44
|
+
|
|
45
|
+
const formatPrice = useCallback(
|
|
46
|
+
(amount: number | null | undefined) => formatPriceFn(amount, currency),
|
|
47
|
+
[currency]
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return { formatPrice, currency }
|
|
51
|
+
}
|