@kasuvia/sdk 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.d.mts +429 -0
- package/dist/hooks/index.d.ts +429 -0
- package/dist/hooks/index.js +3073 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/index.mjs +2962 -0
- package/dist/hooks/index.mjs.map +1 -0
- package/dist/index.d.mts +250 -1161
- package/dist/index.d.ts +250 -1161
- package/dist/index.js +1544 -2359
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1527 -2258
- package/dist/index.mjs.map +1 -1
- package/dist/sdk-context-Cy51kEKT.d.mts +565 -0
- package/dist/sdk-context-Cy51kEKT.d.ts +565 -0
- package/package.json +6 -2
- package/src/config/index.ts +10 -91
- package/src/constants.ts +13 -0
- package/src/context/sdk-context.tsx +70 -0
- package/src/graphql/collections.graphql.ts +2 -10
- package/src/graphql/products.graphql.ts +215 -65
- package/src/graphql/wishlist.graphql.ts +7 -6
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-auth.ts +82 -158
- package/src/hooks/use-bespoke-availability.ts +25 -8
- package/src/hooks/use-cart.ts +222 -119
- package/src/hooks/use-cms.ts +179 -86
- package/src/hooks/use-collections.ts +52 -15
- package/src/hooks/use-consultation-stream.ts +4 -3
- package/src/hooks/use-consultations.ts +120 -51
- package/src/hooks/use-countries.ts +35 -13
- package/src/hooks/use-currencies.ts +26 -13
- package/src/hooks/use-google-translate.ts +22 -8
- package/src/hooks/use-languages.ts +40 -20
- package/src/hooks/use-mobile.ts +23 -0
- package/src/hooks/use-order-stream.ts +9 -5
- package/src/hooks/use-orders.ts +99 -44
- package/src/hooks/use-payment.ts +108 -40
- package/src/hooks/use-products.ts +251 -53
- package/src/hooks/use-service-booking.ts +152 -90
- package/src/hooks/use-states.ts +35 -15
- package/src/hooks/use-wishlist.ts +92 -91
- package/src/index.ts +26 -30
- package/src/services/auth.service.ts +209 -167
- package/src/services/bespoke.service.ts +12 -4
- package/src/services/cart.service.ts +172 -70
- package/src/services/cms.service.ts +70 -35
- package/src/services/collection.service.ts +22 -5
- package/src/services/config.service.ts +34 -14
- package/src/services/consultation.service.ts +72 -18
- package/src/services/logistics.service.ts +35 -11
- package/src/services/notifications.service.ts +27 -12
- package/src/services/order.service.ts +74 -15
- package/src/services/payment.service.ts +86 -31
- package/src/services/product.service.ts +279 -39
- package/src/services/service-booking.service.ts +98 -26
- package/src/services/wishlist.service.ts +69 -25
- package/src/types/auth/index.ts +6 -4
- package/src/types/business/index.ts +7 -2
- package/src/types/payments/index.ts +3 -3
- package/src/types/services/index.ts +2 -5
- package/src/types/store/index.ts +38 -3
- package/src/utils/error-handler.ts +10 -5
- package/src/utils/storage.ts +48 -26
- package/src/utils/validators.ts +85 -0
- package/src/client/authClient.ts +0 -135
- package/src/client/graphqlClient.ts +0 -53
- package/src/client/httpClient.ts +0 -298
package/src/hooks/use-auth.ts
CHANGED
|
@@ -1,182 +1,106 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Auth
|
|
2
|
+
* Auth Hooks
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Stateless React Query hooks for authentication operations.
|
|
5
|
+
* The storefront should provide its own AuthProvider context that manages
|
|
6
|
+
* tokens and passes config to these hooks.
|
|
5
7
|
*/
|
|
6
|
-
import React, { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'
|
|
7
8
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
8
|
-
import { getAuthUser, loginCustomer, registerCustomer, updateProfile, logout as logoutService
|
|
9
|
-
import { tokenStore } from '../client/authClient'
|
|
10
|
-
import { resetGraphQLClient } from '../client/graphqlClient'
|
|
9
|
+
import { getAuthUser, loginCustomer, registerCustomer, updateProfile, logout as logoutService } from '../services/auth.service'
|
|
11
10
|
import { logger } from '../utils/logger'
|
|
12
11
|
import type {
|
|
13
12
|
CustomerLoginPayload,
|
|
14
13
|
CustomerRegisterPayload,
|
|
15
14
|
UpdateProfilePayload,
|
|
16
15
|
CustomerUser,
|
|
17
|
-
AuthContextValue,
|
|
18
16
|
} from '../types/auth'
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export const AuthCtx = React.createContext ? React.createContext<AuthContextValue | null>(null) : null
|
|
23
|
-
|
|
24
|
-
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
25
|
-
const [customer, setCustomer] = useState<CustomerUser | null>(null)
|
|
26
|
-
const [isLoading, setIsLoading] = useState(true)
|
|
27
|
-
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
28
|
-
|
|
29
|
-
// Rehydrate session from stored refresh token on app boot
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
let voided = false
|
|
32
|
-
;(async () => {
|
|
33
|
-
setIsLoading(true)
|
|
34
|
-
try {
|
|
35
|
-
const result = await silentRefresh()
|
|
36
|
-
if (!voided && result) {
|
|
37
|
-
setCustomer(result.user)
|
|
38
|
-
resetGraphQLClient()
|
|
39
|
-
}
|
|
40
|
-
} catch (error: unknown) {
|
|
41
|
-
logger.error('[AuthProvider] Session restore failed:', error)
|
|
42
|
-
if (!voided) setCustomer(null)
|
|
43
|
-
} finally {
|
|
44
|
-
if (!voided) setIsLoading(false)
|
|
45
|
-
}
|
|
46
|
-
})()
|
|
47
|
-
return () => {
|
|
48
|
-
voided = true
|
|
49
|
-
}
|
|
50
|
-
}, [])
|
|
51
|
-
|
|
52
|
-
const openModal = useCallback(() => setIsModalOpen(true), [])
|
|
53
|
-
const closeModal = useCallback(() => {
|
|
54
|
-
setIsModalOpen(false)
|
|
55
|
-
if (typeof window !== 'undefined' && (window.location.hash === '#login' || window.location.hash === '#signup')) {
|
|
56
|
-
window.history.replaceState(null, '', window.location.pathname + window.location.search)
|
|
57
|
-
}
|
|
58
|
-
}, [])
|
|
59
|
-
|
|
60
|
-
// Listen for #login and #signup hashes to open modal automatically
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
const handleHash = () => {
|
|
63
|
-
if (typeof window === 'undefined') return
|
|
64
|
-
if (window.location.hash === '#login' || window.location.hash === '#signup') {
|
|
65
|
-
if (!isLoading && customer) {
|
|
66
|
-
window.history.replaceState(null, '', window.location.pathname + window.location.search)
|
|
67
|
-
} else if (!isLoading && !customer) {
|
|
68
|
-
setIsModalOpen(true)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
handleHash()
|
|
73
|
-
window.addEventListener('hashchange', handleHash)
|
|
74
|
-
return () => window.removeEventListener('hashchange', handleHash)
|
|
75
|
-
}, [customer, isLoading])
|
|
76
|
-
|
|
77
|
-
// Reset GraphQL client when customer state changes to ensure auth headers are included
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
resetGraphQLClient()
|
|
80
|
-
}, [customer])
|
|
81
|
-
|
|
82
|
-
const handleLogout = useCallback(async () => {
|
|
83
|
-
await logoutService()
|
|
84
|
-
setCustomer(null)
|
|
85
|
-
setIsModalOpen(false)
|
|
86
|
-
resetGraphQLClient()
|
|
87
|
-
}, [])
|
|
88
|
-
|
|
89
|
-
const value: AuthContextValue = {
|
|
90
|
-
customer,
|
|
91
|
-
isLoading,
|
|
92
|
-
isModalOpen,
|
|
93
|
-
openModal,
|
|
94
|
-
closeModal,
|
|
95
|
-
setCustomer,
|
|
96
|
-
logout: handleLogout,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!AuthCtx) return children
|
|
100
|
-
return React.createElement(AuthCtx.Provider, { value }, children)
|
|
101
|
-
}
|
|
17
|
+
import type { SdkConfig } from '../config'
|
|
18
|
+
import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
102
19
|
|
|
103
20
|
// ── Hooks ────────────────────────────────────────────────────────────────────
|
|
104
21
|
|
|
105
|
-
export function useAuthUser() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
onSuccess: () => {
|
|
119
|
-
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
120
|
-
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
121
|
-
},
|
|
122
|
-
})
|
|
22
|
+
export function useAuthUser(config?: SdkConfig, accessToken?: string) {
|
|
23
|
+
const ctx = useSdkContext()
|
|
24
|
+
try {
|
|
25
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken ?? null, ctx)
|
|
26
|
+
return useQuery({
|
|
27
|
+
queryKey: ['auth-user'],
|
|
28
|
+
queryFn: () => getAuthUser(cfg, token ?? ''),
|
|
29
|
+
enabled: !!token,
|
|
30
|
+
})
|
|
31
|
+
} catch (error) {
|
|
32
|
+
logger.warn('[useAuthUser] Called outside QueryClientProvider, returning empty user')
|
|
33
|
+
return { data: undefined, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: undefined }) } as any
|
|
34
|
+
}
|
|
123
35
|
}
|
|
124
36
|
|
|
125
|
-
export function
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
37
|
+
export function useLogin(config?: SdkConfig) {
|
|
38
|
+
const ctx = useSdkContext()
|
|
39
|
+
try {
|
|
40
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
41
|
+
const queryClient = useQueryClient()
|
|
42
|
+
return useMutation({
|
|
43
|
+
mutationFn: (payload: Omit<CustomerLoginPayload, 'tenant_id'>) => loginCustomer(cfg, payload),
|
|
44
|
+
onSuccess: () => {
|
|
45
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
46
|
+
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
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
|
+
}
|
|
135
53
|
}
|
|
136
54
|
|
|
137
|
-
export function
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
55
|
+
export function useRegister(config?: SdkConfig) {
|
|
56
|
+
const ctx = useSdkContext()
|
|
57
|
+
try {
|
|
58
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
59
|
+
const queryClient = useQueryClient()
|
|
60
|
+
return useMutation({
|
|
61
|
+
mutationFn: (payload: Omit<CustomerRegisterPayload, 'tenant_id'>) => registerCustomer(cfg, payload),
|
|
62
|
+
onSuccess: () => {
|
|
63
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
64
|
+
queryClient.invalidateQueries({ queryKey: ['cart'] })
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.warn('[useRegister] Called outside QueryClientProvider, returning no-op mutation')
|
|
69
|
+
return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
|
|
70
|
+
}
|
|
146
71
|
}
|
|
147
72
|
|
|
148
|
-
export function
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
73
|
+
export function useUpdateProfile(config?: SdkConfig, accessToken?: string | null) {
|
|
74
|
+
const ctx = useSdkContext()
|
|
75
|
+
try {
|
|
76
|
+
const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
|
|
77
|
+
const queryClient = useQueryClient()
|
|
78
|
+
return useMutation({
|
|
79
|
+
mutationFn: (payload: UpdateProfilePayload) =>
|
|
80
|
+
token ? updateProfile(cfg, token, payload) : Promise.reject('No access token'),
|
|
81
|
+
onSuccess: () => {
|
|
82
|
+
queryClient.invalidateQueries({ queryKey: ['auth-user'] })
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.warn('[useUpdateProfile] Called outside QueryClientProvider, returning no-op mutation')
|
|
87
|
+
return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
|
|
88
|
+
}
|
|
157
89
|
}
|
|
158
90
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
isLoading: authUserQuery.isLoading,
|
|
174
|
-
isModalOpen: false,
|
|
175
|
-
openModal: () => {},
|
|
176
|
-
closeModal: () => {},
|
|
177
|
-
setCustomer: () => {},
|
|
178
|
-
logout: async () => {
|
|
179
|
-
await logoutMutation.mutateAsync()
|
|
180
|
-
},
|
|
91
|
+
export function useLogout(config?: SdkConfig, refreshToken?: string) {
|
|
92
|
+
const ctx = useSdkContext()
|
|
93
|
+
try {
|
|
94
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
95
|
+
const queryClient = useQueryClient()
|
|
96
|
+
return useMutation({
|
|
97
|
+
mutationFn: () => logoutService(cfg, refreshToken),
|
|
98
|
+
onSuccess: () => {
|
|
99
|
+
queryClient.clear()
|
|
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
|
|
181
105
|
}
|
|
182
106
|
}
|
|
@@ -2,19 +2,36 @@
|
|
|
2
2
|
* Bespoke Availability Hook
|
|
3
3
|
*
|
|
4
4
|
* React Query hook for checking bespoke service availability.
|
|
5
|
+
* Stateless - requires config parameter.
|
|
5
6
|
*/
|
|
6
7
|
import { useQuery } from '@tanstack/react-query'
|
|
7
|
-
import {
|
|
8
|
+
import { checkAvailability } from '../services/bespoke.service'
|
|
9
|
+
import type { SdkConfig } from '../config'
|
|
8
10
|
import type { BespokeAvailability } from '../types/consultations'
|
|
11
|
+
import { logger } from '../utils'
|
|
12
|
+
import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Get bespoke availability for a product
|
|
12
16
|
*/
|
|
13
|
-
export function useBespokeAvailability(product_id: string) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
export function useBespokeAvailability(product_id: string, config?: SdkConfig) {
|
|
18
|
+
const ctx = useSdkContext()
|
|
19
|
+
try {
|
|
20
|
+
const { config: cfg } = resolveHookArgs(config, undefined, ctx)
|
|
21
|
+
return useQuery({
|
|
22
|
+
queryKey: ['bespoke-availability', product_id],
|
|
23
|
+
queryFn: () => checkAvailability(cfg, product_id),
|
|
24
|
+
enabled: !!product_id,
|
|
25
|
+
retry: false,
|
|
26
|
+
})
|
|
27
|
+
} catch (error) {
|
|
28
|
+
logger.warn('[useBespokeAvailability] Called outside QueryClientProvider, returning undefined')
|
|
29
|
+
return {
|
|
30
|
+
data: undefined,
|
|
31
|
+
isLoading: false,
|
|
32
|
+
error: null,
|
|
33
|
+
isFetching: false,
|
|
34
|
+
refetch: () => Promise.resolve({ data: undefined }),
|
|
35
|
+
} as any
|
|
36
|
+
}
|
|
20
37
|
}
|