@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
|
@@ -4,67 +4,34 @@
|
|
|
4
4
|
* Handles wishlist operations.
|
|
5
5
|
* Stateless - all configuration passed as parameters.
|
|
6
6
|
*/
|
|
7
|
-
import { GraphQLClient } from 'graphql-request'
|
|
8
7
|
import type { SdkConfig } from '../config'
|
|
9
8
|
import type { WishlistItem, WishlistListResponse, WishlistCheckResponse } from '../types/store'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
storefront_wishlist(page: $page, pageSize: $pageSize) {
|
|
14
|
-
items {
|
|
15
|
-
id
|
|
16
|
-
product_id
|
|
17
|
-
notes
|
|
18
|
-
created_at
|
|
19
|
-
product_name
|
|
20
|
-
product_slug
|
|
21
|
-
product_price
|
|
22
|
-
currency
|
|
23
|
-
product_image
|
|
24
|
-
}
|
|
25
|
-
total
|
|
26
|
-
page
|
|
27
|
-
page_size
|
|
28
|
-
total_pages
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
const CHECK_IN_STOREFRONT_WISHLIST = `
|
|
34
|
-
query CheckInStorefrontWishlist($productId: String!) {
|
|
35
|
-
check_in_storefront_wishlist(productId: $productId) {
|
|
36
|
-
in_wishlist
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Create GraphQL client with provided config
|
|
43
|
-
*/
|
|
44
|
-
function createGraphQLClient(config: SdkConfig, accessToken?: string): GraphQLClient {
|
|
45
|
-
const headers: Record<string, string> = {
|
|
46
|
-
'Content-Type': 'application/json',
|
|
47
|
-
'Accept': 'application/json',
|
|
48
|
-
'X-Storefront-Key': config.storefrontApiKey,
|
|
49
|
-
'X-Business-ID': config.businessId,
|
|
50
|
-
}
|
|
51
|
-
if (accessToken) {
|
|
52
|
-
headers['Authorization'] = `Bearer ${accessToken}`
|
|
53
|
-
}
|
|
54
|
-
return new GraphQLClient(`${config.backendUrls.store}/graphql`, { headers })
|
|
55
|
-
}
|
|
9
|
+
import { createGraphQLClient } from '../utils/graphql-url'
|
|
10
|
+
import { GetStorefrontWishlistDocument, CheckInStorefrontWishlistDocument } from '../generated/graphql'
|
|
11
|
+
import { apiRequest, authHeaders, JSON_HEADERS } from '../utils/http-client'
|
|
56
12
|
|
|
57
13
|
/**
|
|
58
14
|
* Fetch the customer's wishlist for the current business.
|
|
59
15
|
*/
|
|
60
16
|
export async function getWishlist(config: SdkConfig, accessToken: string, params?: { page?: number; pageSize?: number }): Promise<WishlistListResponse> {
|
|
61
17
|
const client = createGraphQLClient(config, accessToken)
|
|
62
|
-
const
|
|
18
|
+
const data = await client.request(GetStorefrontWishlistDocument, {
|
|
63
19
|
page: params?.page || 1,
|
|
64
20
|
pageSize: params?.pageSize || 20,
|
|
21
|
+
})
|
|
22
|
+
return {
|
|
23
|
+
...data.storefront_wishlist,
|
|
24
|
+
items: data.storefront_wishlist.items.map((item) => ({
|
|
25
|
+
...item,
|
|
26
|
+
created_at: item.created_at as string,
|
|
27
|
+
notes: item.notes ?? undefined,
|
|
28
|
+
product_name: item.product_name ?? undefined,
|
|
29
|
+
product_slug: item.product_slug ?? undefined,
|
|
30
|
+
product_price: item.product_price ?? undefined,
|
|
31
|
+
currency: item.currency ?? undefined,
|
|
32
|
+
product_image: item.product_image ?? undefined,
|
|
33
|
+
})) satisfies WishlistItem[],
|
|
65
34
|
}
|
|
66
|
-
const data = await client.request(GET_STOREFRONT_WISHLIST, variables)
|
|
67
|
-
return data.storefront_wishlist
|
|
68
35
|
}
|
|
69
36
|
|
|
70
37
|
/**
|
|
@@ -72,7 +39,7 @@ export async function getWishlist(config: SdkConfig, accessToken: string, params
|
|
|
72
39
|
*/
|
|
73
40
|
export async function checkInWishlist(config: SdkConfig, accessToken: string, productId: string): Promise<WishlistCheckResponse> {
|
|
74
41
|
const client = createGraphQLClient(config, accessToken)
|
|
75
|
-
const data = await client.request(
|
|
42
|
+
const data = await client.request(CheckInStorefrontWishlistDocument, { productId })
|
|
76
43
|
return data.check_in_storefront_wishlist
|
|
77
44
|
}
|
|
78
45
|
|
|
@@ -80,49 +47,35 @@ export async function checkInWishlist(config: SdkConfig, accessToken: string, pr
|
|
|
80
47
|
* Add a product to the customer's wishlist.
|
|
81
48
|
*/
|
|
82
49
|
export async function addToWishlist(config: SdkConfig, accessToken: string, productId: string, notes?: string): Promise<WishlistItem> {
|
|
83
|
-
|
|
50
|
+
return apiRequest<WishlistItem>(`${config.backendUrls.store}/wishlist/`, {
|
|
84
51
|
method: 'POST',
|
|
85
|
-
headers: {
|
|
86
|
-
'Content-Type': 'application/json',
|
|
87
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
88
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
89
|
-
"X-Business-ID": config.businessId,
|
|
90
|
-
},
|
|
52
|
+
headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
|
|
91
53
|
body: JSON.stringify({
|
|
92
54
|
product_id: productId,
|
|
93
55
|
notes: notes || undefined,
|
|
94
56
|
}),
|
|
57
|
+
fallbackErrorMessage: 'Failed to add to wishlist',
|
|
95
58
|
})
|
|
96
|
-
if (!response.ok) throw new Error('Failed to add to wishlist')
|
|
97
|
-
return response.json()
|
|
98
59
|
}
|
|
99
60
|
|
|
100
61
|
/**
|
|
101
62
|
* Remove an item from the customer's wishlist by item ID.
|
|
102
63
|
*/
|
|
103
64
|
export async function removeFromWishlist(config: SdkConfig, accessToken: string, itemId: string): Promise<void> {
|
|
104
|
-
|
|
65
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/${itemId}`, {
|
|
105
66
|
method: 'DELETE',
|
|
106
|
-
headers:
|
|
107
|
-
|
|
108
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
109
|
-
"X-Business-ID": config.businessId,
|
|
110
|
-
},
|
|
67
|
+
headers: authHeaders(config, accessToken),
|
|
68
|
+
fallbackErrorMessage: 'Failed to remove from wishlist',
|
|
111
69
|
})
|
|
112
|
-
if (!response.ok) throw new Error('Failed to remove from wishlist')
|
|
113
70
|
}
|
|
114
71
|
|
|
115
72
|
/**
|
|
116
73
|
* Remove a product from the customer's wishlist by product ID.
|
|
117
74
|
*/
|
|
118
75
|
export async function removeProductFromWishlist(config: SdkConfig, accessToken: string, productId: string): Promise<void> {
|
|
119
|
-
|
|
76
|
+
await apiRequest(`${config.backendUrls.store}/wishlist/product/${productId}`, {
|
|
120
77
|
method: 'DELETE',
|
|
121
|
-
headers:
|
|
122
|
-
|
|
123
|
-
"X-Storefront-Key": config.storefrontApiKey,
|
|
124
|
-
"X-Business-ID": config.businessId,
|
|
125
|
-
},
|
|
78
|
+
headers: authHeaders(config, accessToken),
|
|
79
|
+
fallbackErrorMessage: 'Failed to remove product from wishlist',
|
|
126
80
|
})
|
|
127
|
-
if (!response.ok) throw new Error('Failed to remove product from wishlist')
|
|
128
81
|
}
|
package/src/types/auth/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface CustomerProfileFields {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface CustomerUser {
|
|
25
|
+
/** Scoped to this business only — the same email is a fully separate identity (and id) at any other business/storefront. Never a platform-wide user id. */
|
|
25
26
|
id: string;
|
|
26
27
|
email: string;
|
|
27
28
|
firstname?: string;
|
|
@@ -51,6 +52,7 @@ export interface UpdateProfilePayload {
|
|
|
51
52
|
firstname?: string;
|
|
52
53
|
lastname?: string;
|
|
53
54
|
phone?: string;
|
|
55
|
+
profile_picture?: string;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export interface NotificationPreferences {
|
|
@@ -73,24 +75,23 @@ export interface NotificationPreferences {
|
|
|
73
75
|
sms_delivery_updates: boolean;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
// ── Business Context (storefront is scoped to one business) ──────────────────
|
|
78
|
-
|
|
79
|
-
export interface BusinessContext {
|
|
80
|
-
id: string; // UUID
|
|
81
|
-
business_id: string; // B-XXXXXXXX — permanent, never changes
|
|
82
|
-
name: string;
|
|
83
|
-
logo_picture?: string | null;
|
|
84
|
-
display_currency?: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
78
|
// ── API Responses ─────────────────────────────────────────────────────────────
|
|
88
79
|
|
|
89
80
|
export interface CustomerAuthResponse {
|
|
90
81
|
access: string;
|
|
91
82
|
refresh: string;
|
|
92
83
|
user: CustomerUser;
|
|
93
|
-
|
|
84
|
+
// REAL BUG FIXED (2026-09-20): the backend used to embed the FULL business
|
|
85
|
+
// record here (tax_id, settlement_currency, notification_preferences, the
|
|
86
|
+
// full plan, postal_code, internal UUID `id`) reaching every customer's
|
|
87
|
+
// browser on login/register/passwordless-verify. Now uses the same
|
|
88
|
+
// CustomerFacingBusinessSerializer allow-list as GET /auth/storefront/
|
|
89
|
+
// business-info/ — identical shape, so reuse StorefrontBusinessInfo rather
|
|
90
|
+
// than keep a second, drifted type (the old `BusinessContext` type here
|
|
91
|
+
// had `id`/`display_currency` fields that never matched what the backend
|
|
92
|
+
// actually returned either, and had zero consumers anywhere in the SDK or
|
|
93
|
+
// storefront — confirmed via grep before removing it).
|
|
94
|
+
business: StorefrontBusinessInfo;
|
|
94
95
|
is_new?: boolean;
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -101,22 +102,36 @@ export interface RefreshTokenResponse {
|
|
|
101
102
|
|
|
102
103
|
// ── Request Payloads ──────────────────────────────────────────────────────────
|
|
103
104
|
|
|
104
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* POST /auth/login/customer/ — business is identified by the
|
|
107
|
+
* X-Storefront-Key + X-Business-ID headers (config.storefrontApiKey /
|
|
108
|
+
* config.businessId), not a body field (see plan: Customer Storefront
|
|
109
|
+
* Identity Enforcement).
|
|
110
|
+
*/
|
|
105
111
|
export interface CustomerLoginPayload {
|
|
106
|
-
tenant_id: string; // config.api.storefrontBusinessId
|
|
107
112
|
email: string;
|
|
108
113
|
password: string;
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
/** POST /auth/register/customer/ */
|
|
116
|
+
/** POST /auth/register/customer/ — business identified via headers, see CustomerLoginPayload. */
|
|
112
117
|
export interface CustomerRegisterPayload {
|
|
113
|
-
tenant_id: string; // config.api.storefrontBusinessId
|
|
114
118
|
first_name?: string;
|
|
115
119
|
last_name?: string;
|
|
116
120
|
email: string;
|
|
117
121
|
password: string;
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
/** POST /auth/login/customer/passwordless/request/ — business identified via headers, see CustomerLoginPayload. */
|
|
125
|
+
export interface CustomerPasswordlessRequestPayload {
|
|
126
|
+
email: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** POST /auth/login/customer/passwordless/verify/ — business identified via headers, see CustomerLoginPayload. */
|
|
130
|
+
export interface CustomerPasswordlessVerifyPayload {
|
|
131
|
+
email: string;
|
|
132
|
+
code: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
120
135
|
/** POST /auth/verify-otp/ */
|
|
121
136
|
export interface OTPVerifyPayload {
|
|
122
137
|
email: string;
|
|
@@ -134,6 +149,126 @@ export interface LogoutPayload {
|
|
|
134
149
|
refresh?: string;
|
|
135
150
|
}
|
|
136
151
|
|
|
152
|
+
/** POST /auth/forgot-password/customer/ */
|
|
153
|
+
export interface CustomerForgotPasswordPayload {
|
|
154
|
+
email: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** POST /auth/reset-password/customer/ */
|
|
158
|
+
export interface CustomerResetPasswordPayload {
|
|
159
|
+
email: string;
|
|
160
|
+
code: string;
|
|
161
|
+
new_password: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** POST /auth/customer/deactivate/ */
|
|
165
|
+
export interface CustomerDeactivatePayload {
|
|
166
|
+
reason?: string;
|
|
167
|
+
confirmation_code?: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The real backend (require_destructive_confirmation, kasuvia-auth/common/
|
|
172
|
+
* utils/destructive_confirmation.py:76) ALWAYS returns this shape with
|
|
173
|
+
* HTTP 409 on the first deactivate call (no confirmation_code yet) — this
|
|
174
|
+
* is not an error case, it's step 1 of a required two-step confirmation.
|
|
175
|
+
* The code is generated and returned by the server itself (not sent via
|
|
176
|
+
* email) — it exists to require an explicit second, deliberate action in
|
|
177
|
+
* the UI, not to verify identity out-of-band. Resubmit the identical
|
|
178
|
+
* request with `confirmation_code` set to this value to actually deactivate.
|
|
179
|
+
*/
|
|
180
|
+
export interface DeactivateConfirmationRequired {
|
|
181
|
+
message: string;
|
|
182
|
+
impact: string[];
|
|
183
|
+
confirmation_code: string;
|
|
184
|
+
expires_in_minutes: number;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export type DeactivateAccountResult =
|
|
188
|
+
| { status: 'confirmation_required'; data: DeactivateConfirmationRequired }
|
|
189
|
+
| { status: 'success'; detail: string };
|
|
190
|
+
|
|
191
|
+
/** POST /auth/change-password/ — identity-mode-agnostic (owner/staff/customer). */
|
|
192
|
+
export interface ChangePasswordPayload {
|
|
193
|
+
/** Omit only when the account has no password yet (social/passwordless-only). */
|
|
194
|
+
old_password?: string;
|
|
195
|
+
new_password: string;
|
|
196
|
+
confirm_password: string;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** POST /auth/customer/reactivate/ */
|
|
200
|
+
export interface CustomerReactivatePayload {
|
|
201
|
+
email: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** POST /auth/customer/reactivate/verify/ */
|
|
205
|
+
export interface CustomerReactivateVerifyPayload {
|
|
206
|
+
email: string;
|
|
207
|
+
code: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* One entry in a customer's saved-address book.
|
|
212
|
+
* GET/POST /auth/profile/addresses/, PATCH/DELETE /auth/profile/addresses/{id}/.
|
|
213
|
+
* Field names mirror `DeliveryAddress`/`ShippingLocation` exactly so a saved
|
|
214
|
+
* address can be used directly at checkout with no remapping.
|
|
215
|
+
*/
|
|
216
|
+
export interface CustomerAddress {
|
|
217
|
+
id: string;
|
|
218
|
+
label: string;
|
|
219
|
+
first_name: string;
|
|
220
|
+
last_name: string;
|
|
221
|
+
phone: string;
|
|
222
|
+
street: string;
|
|
223
|
+
city: string;
|
|
224
|
+
state: string;
|
|
225
|
+
lga: string;
|
|
226
|
+
country: string;
|
|
227
|
+
postal: string;
|
|
228
|
+
is_default: boolean;
|
|
229
|
+
created_at: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Fields a caller may set when creating a saved address - `id`/`created_at` are server-assigned. */
|
|
233
|
+
export type CreateCustomerAddressPayload = Omit<CustomerAddress, "id" | "created_at">;
|
|
234
|
+
|
|
235
|
+
/** Partial update to an existing saved address. */
|
|
236
|
+
export type UpdateCustomerAddressPayload = Partial<CreateCustomerAddressPayload>;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* GET /auth/storefront/business-info/ response.
|
|
240
|
+
* Public, unauthenticated (storefront-key-gated) business info for a
|
|
241
|
+
* storefront to render — e.g. footer/about section. An explicit allow-list
|
|
242
|
+
* on the backend (kasuvia-auth's PublicBusinessInfoView) — never owner
|
|
243
|
+
* identity, financial, or internal integration/logistics fields.
|
|
244
|
+
*/
|
|
245
|
+
export interface StorefrontBusinessInfo {
|
|
246
|
+
business_id: string;
|
|
247
|
+
name: string;
|
|
248
|
+
// CharField(max_length=140, blank=True, null=True) — real null on the wire
|
|
249
|
+
// when never set, unlike the blank=True-only fields below.
|
|
250
|
+
tagline: string | null;
|
|
251
|
+
business_type: string;
|
|
252
|
+
country: string;
|
|
253
|
+
// CharField/EmailField/TextField(blank=True) — always a string on the
|
|
254
|
+
// wire (possibly empty ""), never null. Only logo_picture is a real
|
|
255
|
+
// URLField(null=True) below.
|
|
256
|
+
business_contact_phone: string;
|
|
257
|
+
business_contact_email: string;
|
|
258
|
+
business_physical_address: string;
|
|
259
|
+
logo_picture: string | null;
|
|
260
|
+
social_links: Record<string, string>;
|
|
261
|
+
currency: string;
|
|
262
|
+
// Optional, business-chosen hex colors (e.g. "#RRGGBB") — null when never
|
|
263
|
+
// set. Added to PublicBusinessInfoView's allow-list 2026-09-22; previously
|
|
264
|
+
// stored on the backend but never returned here.
|
|
265
|
+
brand_color_primary: string | null;
|
|
266
|
+
brand_color_secondary: string | null;
|
|
267
|
+
brand_color_accent: string | null;
|
|
268
|
+
brand_color_tertiary: string | null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
137
272
|
// ── Auth Context ──────────────────────────────────────────────────────────────
|
|
138
273
|
|
|
139
274
|
export interface AuthContextValue {
|
|
@@ -144,6 +279,14 @@ export interface AuthContextValue {
|
|
|
144
279
|
closeModal: () => void;
|
|
145
280
|
setCustomer: (user: CustomerUser | null) => void;
|
|
146
281
|
logout: () => Promise<void>;
|
|
147
|
-
login: (payload:
|
|
148
|
-
|
|
282
|
+
login: (payload: CustomerLoginPayload) => Promise<void>;
|
|
283
|
+
// REAL BUG FIXED (2026-09-20): `requires_verification` was never a real
|
|
284
|
+
// backend concept for customers — CustomerRegisterView never sends an
|
|
285
|
+
// email OTP and registration is instant. Removed rather than kept as an
|
|
286
|
+
// always-false field.
|
|
287
|
+
register: (payload: CustomerRegisterPayload) => Promise<void>;
|
|
288
|
+
/** Current browser's guest cart session id — pass through to any auth call (e.g. OTP verify) not already routed through login()/register(), so kasuvia-auth's server-side post-login cart merge (see loginCustomer's doc comment) actually fires. */
|
|
289
|
+
guestSessionId: string | null;
|
|
290
|
+
/** Call after any auth flow not routed through login()/register() succeeds (e.g. OTP verify), once the server-side merge above has run — rotates to a fresh guest session id. */
|
|
291
|
+
rotateGuestSessionId: () => void;
|
|
149
292
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// REAL BUG FIXED (2026-09-21): `is_verified` was never a real field on this
|
|
2
|
+
// endpoint's response — kasuvia-auth's InternalBusinessDetailView
|
|
3
|
+
// (internal.py) explicitly renamed it away (its own comment: "REAL BUG
|
|
4
|
+
// FOUND AND FIXED... named 'is_verified' but meant 'has a name and is
|
|
5
|
+
// active'... Renamed to what it actually checks") to the two real fields
|
|
6
|
+
// below well before this SDK type was last touched. Not read by any current
|
|
7
|
+
// storefront consumer, but a landmine for the next one.
|
|
1
8
|
export interface BusinessConfig {
|
|
2
9
|
business_id: string;
|
|
3
10
|
storefront_business_id: string;
|
|
@@ -6,6 +13,7 @@ export interface BusinessConfig {
|
|
|
6
13
|
settlement_currency: string;
|
|
7
14
|
country: string;
|
|
8
15
|
region: string;
|
|
9
|
-
|
|
16
|
+
has_completed_onboarding: boolean;
|
|
17
|
+
owner_kyc_verified: boolean;
|
|
10
18
|
is_active: boolean;
|
|
11
19
|
}
|
package/src/types/cms/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface CmsField {
|
|
|
9
9
|
label: string
|
|
10
10
|
type: string
|
|
11
11
|
required: boolean
|
|
12
|
-
config: Record<string,
|
|
12
|
+
config: Record<string, unknown>
|
|
13
13
|
sub_fields?: CmsField[]
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -38,17 +38,102 @@ export interface CmsEntry {
|
|
|
38
38
|
id: string
|
|
39
39
|
business_id: string
|
|
40
40
|
model_slug: string
|
|
41
|
-
data: Record<string,
|
|
41
|
+
data: Record<string, unknown>
|
|
42
42
|
created_at: string
|
|
43
43
|
updated_at: string
|
|
44
44
|
created_by: string | null
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** Real value shape of a CmsField with type "media" (kasuvia-media-system asset reference). */
|
|
48
|
+
export interface CmsMediaValue {
|
|
49
|
+
id: string
|
|
50
|
+
url: string
|
|
51
|
+
alt?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Real value shape of a CmsField with type "icon". */
|
|
55
|
+
export interface CmsIconValue {
|
|
56
|
+
package: string
|
|
57
|
+
name: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The "blogs" CMS model's real field shape, as created by a merchant through
|
|
62
|
+
* kasuvia-cms's dynamic model builder. Field names are merchant-defined
|
|
63
|
+
* (this is a dynamic CMS, not a fixed schema) — this type documents the
|
|
64
|
+
* specific field set kasuvia-storefront's dedicated /blog pages render,
|
|
65
|
+
* confirmed live against a real "blogs" model. A storefront whose merchant
|
|
66
|
+
* named these fields differently needs its own type — this is a rendering
|
|
67
|
+
* convenience, not a backend contract.
|
|
68
|
+
*/
|
|
69
|
+
export interface BlogEntryData {
|
|
70
|
+
blog_title: string
|
|
71
|
+
blog_slug: string
|
|
72
|
+
blog_content: string
|
|
73
|
+
excerpt?: string
|
|
74
|
+
author: string
|
|
75
|
+
category: string
|
|
76
|
+
tags?: string
|
|
77
|
+
featured_image?: CmsMediaValue
|
|
78
|
+
published_date: string
|
|
79
|
+
is_published: boolean
|
|
80
|
+
is_featured?: boolean
|
|
81
|
+
featured_icon?: CmsIconValue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The "store-locations" CMS model's real field shape (kasuvia-cms/scripts/
|
|
86
|
+
* seed_dummy_models.py's STORE_LOCATIONS_MODEL — merchant-defined, dynamic
|
|
87
|
+
* CMS, this documents the real shape as configured, not a fixed schema).
|
|
88
|
+
*/
|
|
89
|
+
export interface StoreLocationEntryData {
|
|
90
|
+
store_name: string
|
|
91
|
+
address: string
|
|
92
|
+
city: string
|
|
93
|
+
store_type: 'Flagship' | 'Outlet' | 'Pop-up' | 'Franchise'
|
|
94
|
+
phone?: string
|
|
95
|
+
is_open: boolean
|
|
96
|
+
opening_time: string
|
|
97
|
+
closing_time: string
|
|
98
|
+
store_image?: CmsMediaValue
|
|
99
|
+
store_icon?: CmsIconValue
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The "flash-sales" CMS model's real field shape (same source as above). */
|
|
103
|
+
export interface FlashSaleEntryData {
|
|
104
|
+
event_title: string
|
|
105
|
+
event_description: string
|
|
106
|
+
start_date: string
|
|
107
|
+
end_date: string
|
|
108
|
+
countdown_datetime: string
|
|
109
|
+
discount_percentage: number
|
|
110
|
+
is_active: boolean
|
|
111
|
+
banner_image?: CmsMediaValue
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The "product-faqs" CMS model's real field shape (same source as above). */
|
|
115
|
+
export interface ProductFaqEntryData {
|
|
116
|
+
category: string
|
|
117
|
+
question: string
|
|
118
|
+
answer: string
|
|
119
|
+
is_featured: boolean
|
|
120
|
+
/** Free-text merchant-typed field (e.g. "Shipping Policy: /policies/shipping, Track Your Order: /orders/track") — not structured, rendered as plain text. */
|
|
121
|
+
related_links?: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// REAL BUG FIXED (2026-09-21): this used {entries, total, page, page_size} —
|
|
125
|
+
// kasuvia-cms's own real response (cms_schemas.py's CmsEntryListResponse)
|
|
126
|
+
// was renamed to the platform-standard paginated envelope
|
|
127
|
+
// {results, count, page, page_size, total_pages} back in 2026-09-17, with
|
|
128
|
+
// an explicit code comment flagging kasuvia-sdk/kasuvia-storefront as not
|
|
129
|
+
// yet updated (they were frozen at the time). Every CMS list call has been
|
|
130
|
+
// silently reading undefined `.entries`/`.total` since.
|
|
47
131
|
export interface CmsEntryListResponse {
|
|
48
|
-
|
|
49
|
-
|
|
132
|
+
results: CmsEntry[]
|
|
133
|
+
count: number
|
|
50
134
|
page: number
|
|
51
135
|
page_size: number
|
|
136
|
+
total_pages: number
|
|
52
137
|
}
|
|
53
138
|
|
|
54
139
|
export interface CmsIcon {
|
|
@@ -69,9 +154,9 @@ export interface ListCmsEntriesParams {
|
|
|
69
154
|
}
|
|
70
155
|
|
|
71
156
|
export interface CreateCmsEntryParams {
|
|
72
|
-
data: Record<string,
|
|
157
|
+
data: Record<string, unknown>
|
|
73
158
|
}
|
|
74
159
|
|
|
75
160
|
export interface UpdateCmsEntryParams {
|
|
76
|
-
data: Record<string,
|
|
161
|
+
data: Record<string, unknown>
|
|
77
162
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legal Document Types
|
|
3
|
+
*
|
|
4
|
+
* Types for merchant storefront legal pages generated by
|
|
5
|
+
* kasuvia-website-builder-system via kasuvia-cms.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface LegalSection {
|
|
9
|
+
heading: string;
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface MerchantLegalDocument {
|
|
14
|
+
document_type: string;
|
|
15
|
+
template_version: string;
|
|
16
|
+
rendered_sections: LegalSection[];
|
|
17
|
+
published_at: string;
|
|
18
|
+
}
|
|
@@ -1,74 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bespoke commission types for the customer-facing storefront.
|
|
3
|
+
*
|
|
4
|
+
* REAL BUG FIXED (2026-09-21): this file used to also declare a fictional
|
|
5
|
+
* "Consultation" resource (ConsultationStatus/Consultation/ConsultationMessage/
|
|
6
|
+
* etc.) — confirmed there is no /social/consultations/* route or Consultation
|
|
7
|
+
* model anywhere in kasuvia-store-management. The owner confirmed the
|
|
8
|
+
* feature no longer exists there. Removed along with its dead SDK service,
|
|
9
|
+
* hooks, and storefront pages/components — only the real bespoke types
|
|
10
|
+
* (used by bespoke.service.ts against real backend endpoints) remain here.
|
|
3
11
|
*/
|
|
4
12
|
|
|
5
|
-
export type ConsultationStatus =
|
|
6
|
-
| "pending"
|
|
7
|
-
| "quoted"
|
|
8
|
-
| "negotiating"
|
|
9
|
-
| "deposit_pending"
|
|
10
|
-
| "deposit_paid"
|
|
11
|
-
| "converting"
|
|
12
|
-
| "converted"
|
|
13
|
-
| "rejected";
|
|
14
|
-
|
|
15
|
-
export type ConsultationProductType = "bespoke" | "service";
|
|
16
|
-
|
|
17
|
-
export interface ConsultationMessage {
|
|
18
|
-
id: string;
|
|
19
|
-
consultation_id: string;
|
|
20
|
-
sender_id: string;
|
|
21
|
-
sender_role: "customer" | "merchant" | "system";
|
|
22
|
-
message: string;
|
|
23
|
-
attachments: string[];
|
|
24
|
-
is_read: boolean;
|
|
25
|
-
created_at: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface Consultation {
|
|
29
|
-
id: string;
|
|
30
|
-
business_id: string;
|
|
31
|
-
customer_id: string;
|
|
32
|
-
product_id: string | null;
|
|
33
|
-
title: string;
|
|
34
|
-
status: ConsultationStatus;
|
|
35
|
-
product_type: ConsultationProductType;
|
|
36
|
-
quote_amount: number | null;
|
|
37
|
-
agreed_price: number | null;
|
|
38
|
-
deposit_amount: number | null;
|
|
39
|
-
deposit_required: boolean;
|
|
40
|
-
is_physical_delivery: boolean;
|
|
41
|
-
expected_delivery_type: string | null;
|
|
42
|
-
structured_details: Record<string, unknown>;
|
|
43
|
-
rejection_reason: string | null;
|
|
44
|
-
converted_order_id: string | null;
|
|
45
|
-
slot_booking_id: string | null;
|
|
46
|
-
capacity_config_id: string | null;
|
|
47
|
-
created_at: string;
|
|
48
|
-
updated_at: string;
|
|
49
|
-
messages: ConsultationMessage[];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface ConsultationCreatePayload {
|
|
53
|
-
product_id?: string;
|
|
54
|
-
title: string;
|
|
55
|
-
description: string;
|
|
56
|
-
reference_images?: string[];
|
|
57
|
-
custom_measurements?: Record<string, string | number>;
|
|
58
|
-
preferred_timeline?: string;
|
|
59
|
-
special_instructions?: string;
|
|
60
|
-
product_type?: ConsultationProductType;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface ConsultationMessagePayload {
|
|
64
|
-
message: string;
|
|
65
|
-
attachments?: string[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface ConsultationQuoteAcceptPayload {
|
|
69
|
-
agreed_price: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
13
|
export interface BespokeAvailability {
|
|
73
14
|
available_slots: number;
|
|
74
15
|
next_available_date: string | null;
|
|
@@ -77,3 +18,54 @@ export interface BespokeAvailability {
|
|
|
77
18
|
production_days: number;
|
|
78
19
|
is_available: boolean;
|
|
79
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returned by all 3 bespoke deliverable-proofing action endpoints (POST
|
|
24
|
+
* .../bespoke/submit-deliverable, .../approve, .../request-revision) —
|
|
25
|
+
* matches BespokeStatusResponse (kasuvia-store-management/app/schemas/
|
|
26
|
+
* bespoke.py:120-128) exactly.
|
|
27
|
+
*/
|
|
28
|
+
export interface BespokeDeliverableStatus {
|
|
29
|
+
id: string;
|
|
30
|
+
order_status: string;
|
|
31
|
+
bespoke_status: string;
|
|
32
|
+
bespoke_deliverable_submitted_at: string | null;
|
|
33
|
+
bespoke_deliverable_url: string | null;
|
|
34
|
+
bespoke_deliverable_notes: string | null;
|
|
35
|
+
bespoke_buyer_approved_at: string | null;
|
|
36
|
+
bespoke_revision_count: number;
|
|
37
|
+
/**
|
|
38
|
+
* REAL GAP FIXED (2026-09-23) via the REST codegen initiative: the real
|
|
39
|
+
* backend response (BespokeStatusResponse, kasuvia-store-management's
|
|
40
|
+
* app/schemas/bespoke.py) has always included this field - this hand-
|
|
41
|
+
* written interface simply never declared it, so it was silently
|
|
42
|
+
* unavailable to every consumer even though the backend was already
|
|
43
|
+
* returning it on every deliverable-status response.
|
|
44
|
+
*/
|
|
45
|
+
bespoke_revision_notes: string | null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Embedded on an Order as `order.bespoke_fulfillment` — matches
|
|
50
|
+
* BespokeFulfillmentResponse (kasuvia-store-management/app/schemas/
|
|
51
|
+
* order.py:150-168) exactly. This is the real source of a bespoke order's
|
|
52
|
+
* current deliverable state; there is no separate list/GET endpoint for it.
|
|
53
|
+
*/
|
|
54
|
+
export interface BespokeFulfillment {
|
|
55
|
+
brief: string | null;
|
|
56
|
+
reference_images: string[] | null;
|
|
57
|
+
measurements: Record<string, unknown> | null;
|
|
58
|
+
preferred_timeline: string | null;
|
|
59
|
+
special_instructions: string | null;
|
|
60
|
+
deposit_ratio: number | null;
|
|
61
|
+
deposit_amount: number | null;
|
|
62
|
+
balance_amount: number | null;
|
|
63
|
+
status: string | null;
|
|
64
|
+
deliverable_submitted_at: string | null;
|
|
65
|
+
deliverable_url: string | null;
|
|
66
|
+
deliverable_notes: string | null;
|
|
67
|
+
buyer_approved_at: string | null;
|
|
68
|
+
revision_count: number;
|
|
69
|
+
revision_notes: string | null;
|
|
70
|
+
timeline_breached_at: string | null;
|
|
71
|
+
}
|