@frak-labs/react-sdk 0.1.1-beta.d13d0e5d → 0.1.1-beta.df5fa6b3
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 +25 -0
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/package.json +6 -5
- package/src/hook/helper/useReferralInteraction.test.ts +358 -0
- package/src/hook/helper/useReferralInteraction.ts +78 -0
- package/src/hook/index.ts +10 -0
- package/src/hook/useDisplayModal.test.ts +275 -0
- package/src/hook/useDisplayModal.ts +68 -0
- package/src/hook/useFrakClient.test.ts +119 -0
- package/src/hook/useFrakClient.ts +11 -0
- package/src/hook/useFrakConfig.test.ts +184 -0
- package/src/hook/useFrakConfig.ts +22 -0
- package/src/hook/useGetMerchantInformation.ts +56 -0
- package/src/hook/useOpenSso.test.ts +202 -0
- package/src/hook/useOpenSso.ts +51 -0
- package/src/hook/usePrepareSso.test.ts +197 -0
- package/src/hook/usePrepareSso.ts +55 -0
- package/src/hook/useSendTransaction.test.ts +218 -0
- package/src/hook/useSendTransaction.ts +62 -0
- package/src/hook/useSiweAuthenticate.test.ts +258 -0
- package/src/hook/useSiweAuthenticate.ts +66 -0
- package/src/hook/useWalletStatus.test.ts +112 -0
- package/src/hook/useWalletStatus.ts +55 -0
- package/src/hook/utils/useFrakContext.test.ts +157 -0
- package/src/hook/utils/useFrakContext.ts +42 -0
- package/src/hook/utils/useMounted.test.ts +70 -0
- package/src/hook/utils/useMounted.ts +12 -0
- package/src/hook/utils/useWindowLocation.test.ts +54 -0
- package/src/hook/utils/useWindowLocation.ts +40 -0
- package/src/index.ts +25 -0
- package/src/provider/FrakConfigProvider.test.ts +246 -0
- package/src/provider/FrakConfigProvider.ts +54 -0
- package/src/provider/FrakIFrameClientProvider.test.tsx +209 -0
- package/src/provider/FrakIFrameClientProvider.ts +86 -0
- package/src/provider/index.ts +7 -0
package/README.md
CHANGED
|
@@ -6,3 +6,28 @@ Checkout our documentation for more information's about the usage:
|
|
|
6
6
|
- [React client usage](https://docs.frak.id/wallet-sdk/getting-started/react)
|
|
7
7
|
- [Core client usage](https://docs.frak.id/wallet-sdk/getting-started/javascript)
|
|
8
8
|
- [CDN / Browser usage](https://docs.frak.id/wallet-sdk/getting-started/cdn)
|
|
9
|
+
|
|
10
|
+
## Hooks
|
|
11
|
+
|
|
12
|
+
| Hook | Purpose |
|
|
13
|
+
|------|---------|
|
|
14
|
+
| `useWalletStatus` | Watch wallet connection state and account information |
|
|
15
|
+
| `useDisplayModal` | Trigger SDK modal display for user interactions |
|
|
16
|
+
| `useSiweAuthenticate` | SIWE (Sign-In with Ethereum) authentication flow |
|
|
17
|
+
| `useOpenSso` | Open SSO authentication flow |
|
|
18
|
+
| `usePrepareSso` | Prepare SSO data before opening authentication |
|
|
19
|
+
| `useSendTransactionAction` | Send blockchain transaction actions |
|
|
20
|
+
| `useGetMerchantInformation` | Query merchant info and available rewards |
|
|
21
|
+
| `useReferralInteraction` | Auto-submit referral interactions |
|
|
22
|
+
| `useFrakClient` | Access the FrakClient instance |
|
|
23
|
+
| `useFrakConfig` | Access SDK configuration |
|
|
24
|
+
|
|
25
|
+
## Providers
|
|
26
|
+
|
|
27
|
+
Wrap your application root with these providers:
|
|
28
|
+
|
|
29
|
+
- **`FrakConfigProvider`** — SDK configuration context. Required at app root.
|
|
30
|
+
- **`FrakIFrameClientProvider`** — Iframe client context for SDK communication.
|
|
31
|
+
|
|
32
|
+
Both providers export TypeScript types: `FrakConfigProviderProps`, `FrakIFrameClientProps`.
|
|
33
|
+
|
package/dist/index.d.cts
CHANGED
|
@@ -46,7 +46,7 @@ interface UseDisplayModalParams<T extends ModalStepTypes[] = ModalStepTypes[]> {
|
|
|
46
46
|
*
|
|
47
47
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.displayModal | `displayModal()`} action
|
|
48
48
|
*
|
|
49
|
-
* @param args
|
|
49
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
50
50
|
*
|
|
51
51
|
* @typeParam T
|
|
52
52
|
* The modal steps types to display (the result will correspond to the steps types asked in params)
|
|
@@ -88,7 +88,7 @@ declare function useFrakConfig(): _frak_labs_core_sdk0.FrakWalletSdkConfig;
|
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/hook/useGetMerchantInformation.d.ts
|
|
90
90
|
/** @ignore */
|
|
91
|
-
type QueryOptions = Omit<UseQueryOptions<GetMerchantInformationReturnType, FrakRpcError,
|
|
91
|
+
type QueryOptions = Omit<UseQueryOptions<GetMerchantInformationReturnType, FrakRpcError, GetMerchantInformationReturnType>, "queryKey" | "queryFn">;
|
|
92
92
|
/** @inline */
|
|
93
93
|
interface UseGetMerchantInformationParams {
|
|
94
94
|
/**
|
|
@@ -101,7 +101,7 @@ interface UseGetMerchantInformationParams {
|
|
|
101
101
|
*
|
|
102
102
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} action
|
|
103
103
|
*
|
|
104
|
-
* @param args
|
|
104
|
+
* @param args - Optional config object with `query` for customizing the underlying {@link @tanstack/react-query!useQuery | `useQuery()`}
|
|
105
105
|
*
|
|
106
106
|
* @group hooks
|
|
107
107
|
*
|
|
@@ -114,7 +114,7 @@ interface UseGetMerchantInformationParams {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function useGetMerchantInformation({
|
|
116
116
|
query
|
|
117
|
-
}?: UseGetMerchantInformationParams): _tanstack_react_query0.UseQueryResult<
|
|
117
|
+
}?: UseGetMerchantInformationParams): _tanstack_react_query0.UseQueryResult<GetMerchantInformationReturnType, FrakRpcError<undefined>>;
|
|
118
118
|
//#endregion
|
|
119
119
|
//#region src/hook/useOpenSso.d.ts
|
|
120
120
|
/** @ignore */
|
|
@@ -131,7 +131,7 @@ interface UseOpenSsoParams {
|
|
|
131
131
|
*
|
|
132
132
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.openSso | `openSso()`} action
|
|
133
133
|
*
|
|
134
|
-
* @param args
|
|
134
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
135
135
|
*
|
|
136
136
|
* @group hooks
|
|
137
137
|
*
|
|
@@ -201,7 +201,7 @@ interface UseSendTransactionParams {
|
|
|
201
201
|
*
|
|
202
202
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.sendTransaction | `sendTransaction()`} action
|
|
203
203
|
*
|
|
204
|
-
* @param args
|
|
204
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
205
205
|
*
|
|
206
206
|
* @group hooks
|
|
207
207
|
*
|
|
@@ -230,9 +230,9 @@ interface UseSiweAuthenticateParams {
|
|
|
230
230
|
/**
|
|
231
231
|
* Hook that return a mutation helping to send perform a SIWE authentication
|
|
232
232
|
*
|
|
233
|
-
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.
|
|
233
|
+
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.siweAuthenticate | `siweAuthenticate()`} action
|
|
234
234
|
*
|
|
235
|
-
* @param args
|
|
235
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
236
236
|
*
|
|
237
237
|
* @group hooks
|
|
238
238
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ interface UseDisplayModalParams<T extends ModalStepTypes[] = ModalStepTypes[]> {
|
|
|
46
46
|
*
|
|
47
47
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.displayModal | `displayModal()`} action
|
|
48
48
|
*
|
|
49
|
-
* @param args
|
|
49
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
50
50
|
*
|
|
51
51
|
* @typeParam T
|
|
52
52
|
* The modal steps types to display (the result will correspond to the steps types asked in params)
|
|
@@ -88,7 +88,7 @@ declare function useFrakConfig(): _frak_labs_core_sdk0.FrakWalletSdkConfig;
|
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/hook/useGetMerchantInformation.d.ts
|
|
90
90
|
/** @ignore */
|
|
91
|
-
type QueryOptions = Omit<UseQueryOptions<GetMerchantInformationReturnType, FrakRpcError,
|
|
91
|
+
type QueryOptions = Omit<UseQueryOptions<GetMerchantInformationReturnType, FrakRpcError, GetMerchantInformationReturnType>, "queryKey" | "queryFn">;
|
|
92
92
|
/** @inline */
|
|
93
93
|
interface UseGetMerchantInformationParams {
|
|
94
94
|
/**
|
|
@@ -101,7 +101,7 @@ interface UseGetMerchantInformationParams {
|
|
|
101
101
|
*
|
|
102
102
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.getMerchantInformation | `getMerchantInformation()`} action
|
|
103
103
|
*
|
|
104
|
-
* @param args
|
|
104
|
+
* @param args - Optional config object with `query` for customizing the underlying {@link @tanstack/react-query!useQuery | `useQuery()`}
|
|
105
105
|
*
|
|
106
106
|
* @group hooks
|
|
107
107
|
*
|
|
@@ -114,7 +114,7 @@ interface UseGetMerchantInformationParams {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function useGetMerchantInformation({
|
|
116
116
|
query
|
|
117
|
-
}?: UseGetMerchantInformationParams): _tanstack_react_query0.UseQueryResult<
|
|
117
|
+
}?: UseGetMerchantInformationParams): _tanstack_react_query0.UseQueryResult<GetMerchantInformationReturnType, FrakRpcError<undefined>>;
|
|
118
118
|
//#endregion
|
|
119
119
|
//#region src/hook/useOpenSso.d.ts
|
|
120
120
|
/** @ignore */
|
|
@@ -131,7 +131,7 @@ interface UseOpenSsoParams {
|
|
|
131
131
|
*
|
|
132
132
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.openSso | `openSso()`} action
|
|
133
133
|
*
|
|
134
|
-
* @param args
|
|
134
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
135
135
|
*
|
|
136
136
|
* @group hooks
|
|
137
137
|
*
|
|
@@ -201,7 +201,7 @@ interface UseSendTransactionParams {
|
|
|
201
201
|
*
|
|
202
202
|
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.sendTransaction | `sendTransaction()`} action
|
|
203
203
|
*
|
|
204
|
-
* @param args
|
|
204
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
205
205
|
*
|
|
206
206
|
* @group hooks
|
|
207
207
|
*
|
|
@@ -230,9 +230,9 @@ interface UseSiweAuthenticateParams {
|
|
|
230
230
|
/**
|
|
231
231
|
* Hook that return a mutation helping to send perform a SIWE authentication
|
|
232
232
|
*
|
|
233
|
-
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.
|
|
233
|
+
* It's a {@link @tanstack/react-query!home | `tanstack`} wrapper around the {@link @frak-labs/core-sdk!actions.siweAuthenticate | `siweAuthenticate()`} action
|
|
234
234
|
*
|
|
235
|
-
* @param args
|
|
235
|
+
* @param args - Optional config object with `mutations` for customizing the underlying {@link @tanstack/react-query!useMutation | `useMutation()`}
|
|
236
236
|
*
|
|
237
237
|
* @group hooks
|
|
238
238
|
*
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "https://twitter.com/QNivelais"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
|
-
"version": "0.1.1-beta.
|
|
14
|
+
"version": "0.1.1-beta.df5fa6b3",
|
|
15
15
|
"description": "React SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.",
|
|
16
16
|
"repository": {
|
|
17
17
|
"url": "https://github.com/frak-id/wallet",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"type": "module",
|
|
35
35
|
"files": [
|
|
36
|
-
"/dist"
|
|
36
|
+
"/dist",
|
|
37
|
+
"/src"
|
|
37
38
|
],
|
|
38
39
|
"main": "./dist/index.cjs",
|
|
39
40
|
"types": "./dist/index.d.cts",
|
|
@@ -66,8 +67,8 @@
|
|
|
66
67
|
"publish": "echo 'Publishing react...'"
|
|
67
68
|
},
|
|
68
69
|
"dependencies": {
|
|
69
|
-
"@frak-labs/frame-connector": "0.1.0-beta.
|
|
70
|
-
"@frak-labs/core-sdk": "0.1.1-beta.
|
|
70
|
+
"@frak-labs/frame-connector": "0.1.0-beta.df5fa6b3",
|
|
71
|
+
"@frak-labs/core-sdk": "0.1.1-beta.df5fa6b3"
|
|
71
72
|
},
|
|
72
73
|
"peerDependencies": {
|
|
73
74
|
"viem": "^2.x",
|
|
@@ -78,7 +79,7 @@
|
|
|
78
79
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
79
80
|
"@frak-labs/dev-tooling": "0.0.0",
|
|
80
81
|
"@frak-labs/test-foundation": "0.1.0",
|
|
81
|
-
"@frak-labs/wallet-shared": "0.0.
|
|
82
|
+
"@frak-labs/wallet-shared": "0.0.1",
|
|
82
83
|
"@tanstack/react-query": "^5.90.20",
|
|
83
84
|
"@testing-library/jest-dom": "^6.9.1",
|
|
84
85
|
"@testing-library/react": "^16.3.2",
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for useReferralInteraction hook
|
|
3
|
+
* Tests automatic referral interaction submission
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
vi.mock("@frak-labs/core-sdk/actions");
|
|
9
|
+
vi.mock("../useFrakClient");
|
|
10
|
+
vi.mock("../useWalletStatus");
|
|
11
|
+
vi.mock("../utils/useFrakContext");
|
|
12
|
+
|
|
13
|
+
import type { FrakContext, WalletStatusReturnType } from "@frak-labs/core-sdk";
|
|
14
|
+
import { processReferral } from "@frak-labs/core-sdk/actions";
|
|
15
|
+
import { ClientNotFound } from "@frak-labs/frame-connector";
|
|
16
|
+
import { renderHook, waitFor } from "@testing-library/react";
|
|
17
|
+
import { describe, expect, test } from "../../../tests/vitest-fixtures";
|
|
18
|
+
import { useFrakClient } from "../useFrakClient";
|
|
19
|
+
import { useWalletStatus } from "../useWalletStatus";
|
|
20
|
+
import { useFrakContext } from "../utils/useFrakContext";
|
|
21
|
+
import { useReferralInteraction } from "./useReferralInteraction";
|
|
22
|
+
|
|
23
|
+
describe("useReferralInteraction", () => {
|
|
24
|
+
test("should return processing when wallet status is not available", ({
|
|
25
|
+
queryWrapper,
|
|
26
|
+
mockFrakClient,
|
|
27
|
+
}) => {
|
|
28
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
29
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
30
|
+
frakContext: null,
|
|
31
|
+
updateContext: vi.fn(),
|
|
32
|
+
});
|
|
33
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
34
|
+
data: undefined,
|
|
35
|
+
isSuccess: false,
|
|
36
|
+
isPending: true,
|
|
37
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
38
|
+
|
|
39
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
40
|
+
wrapper: queryWrapper.wrapper,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Query is disabled when wallet status is not available, status remains pending
|
|
44
|
+
expect(result.current).toBe("processing");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("should process referral successfully", async ({
|
|
48
|
+
queryWrapper,
|
|
49
|
+
mockFrakClient,
|
|
50
|
+
}) => {
|
|
51
|
+
const mockReferralState = "success";
|
|
52
|
+
|
|
53
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
54
|
+
key: "connected",
|
|
55
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const mockFrakContext: FrakContext = {
|
|
59
|
+
r: "0x1234567890123456789012345678901234567890",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
63
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
64
|
+
frakContext: mockFrakContext,
|
|
65
|
+
updateContext: vi.fn(),
|
|
66
|
+
});
|
|
67
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
68
|
+
data: mockWalletStatus,
|
|
69
|
+
isSuccess: true,
|
|
70
|
+
isPending: false,
|
|
71
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
72
|
+
vi.mocked(processReferral).mockResolvedValue(mockReferralState);
|
|
73
|
+
|
|
74
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
75
|
+
wrapper: queryWrapper.wrapper,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await waitFor(() => {
|
|
79
|
+
expect(result.current).toEqual(mockReferralState);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(processReferral).toHaveBeenCalledWith(mockFrakClient, {
|
|
83
|
+
walletStatus: mockWalletStatus,
|
|
84
|
+
frakContext: mockFrakContext,
|
|
85
|
+
modalConfig: undefined,
|
|
86
|
+
options: undefined,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("should process referral with modalConfig", async ({
|
|
91
|
+
queryWrapper,
|
|
92
|
+
mockFrakClient,
|
|
93
|
+
}) => {
|
|
94
|
+
const mockReferralState = "success";
|
|
95
|
+
|
|
96
|
+
const modalConfig = {
|
|
97
|
+
metadata: {
|
|
98
|
+
logo: "https://example.com/logo.png",
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
103
|
+
key: "connected",
|
|
104
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
108
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
109
|
+
frakContext: { r: "0x4567890123456789012345678901234567890123" },
|
|
110
|
+
updateContext: vi.fn(),
|
|
111
|
+
});
|
|
112
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
113
|
+
data: mockWalletStatus,
|
|
114
|
+
isSuccess: true,
|
|
115
|
+
isPending: false,
|
|
116
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
117
|
+
vi.mocked(processReferral).mockResolvedValue(mockReferralState);
|
|
118
|
+
|
|
119
|
+
const { result } = renderHook(
|
|
120
|
+
() => useReferralInteraction({ modalConfig }),
|
|
121
|
+
{
|
|
122
|
+
wrapper: queryWrapper.wrapper,
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(result.current).toEqual(mockReferralState);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(processReferral).toHaveBeenCalledWith(
|
|
131
|
+
mockFrakClient,
|
|
132
|
+
expect.objectContaining({
|
|
133
|
+
modalConfig,
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("should process referral with options", async ({
|
|
139
|
+
queryWrapper,
|
|
140
|
+
mockFrakClient,
|
|
141
|
+
}) => {
|
|
142
|
+
const mockReferralState = "success";
|
|
143
|
+
|
|
144
|
+
const options = {
|
|
145
|
+
alwaysAppendUrl: true,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
149
|
+
key: "connected",
|
|
150
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
154
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
155
|
+
frakContext: { r: "0x7890123456789012345678901234567890123456" },
|
|
156
|
+
updateContext: vi.fn(),
|
|
157
|
+
});
|
|
158
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
159
|
+
data: mockWalletStatus,
|
|
160
|
+
isSuccess: true,
|
|
161
|
+
isPending: false,
|
|
162
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
163
|
+
vi.mocked(processReferral).mockResolvedValue(mockReferralState);
|
|
164
|
+
|
|
165
|
+
const { result } = renderHook(
|
|
166
|
+
() => useReferralInteraction({ options }),
|
|
167
|
+
{
|
|
168
|
+
wrapper: queryWrapper.wrapper,
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
await waitFor(() => {
|
|
173
|
+
expect(result.current).toEqual(mockReferralState);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(processReferral).toHaveBeenCalledWith(
|
|
177
|
+
mockFrakClient,
|
|
178
|
+
expect.objectContaining({
|
|
179
|
+
options,
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("should handle processing state", ({
|
|
185
|
+
queryWrapper,
|
|
186
|
+
mockFrakClient,
|
|
187
|
+
}) => {
|
|
188
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
189
|
+
key: "connected",
|
|
190
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
194
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
195
|
+
frakContext: { r: "0x9999999999999999999999999999999999999999" },
|
|
196
|
+
updateContext: vi.fn(),
|
|
197
|
+
});
|
|
198
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
199
|
+
data: mockWalletStatus,
|
|
200
|
+
isSuccess: true,
|
|
201
|
+
isPending: false,
|
|
202
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
203
|
+
|
|
204
|
+
// Mock processReferral to never resolve (simulate pending)
|
|
205
|
+
vi.mocked(processReferral).mockImplementation(
|
|
206
|
+
() => new Promise(() => {})
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
210
|
+
wrapper: queryWrapper.wrapper,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(result.current).toBe("processing");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("should handle errors", async ({ queryWrapper, mockFrakClient }) => {
|
|
217
|
+
const error = new Error("Referral processing failed");
|
|
218
|
+
|
|
219
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
220
|
+
key: "connected",
|
|
221
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
225
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
226
|
+
frakContext: { r: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" },
|
|
227
|
+
updateContext: vi.fn(),
|
|
228
|
+
});
|
|
229
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
230
|
+
data: mockWalletStatus,
|
|
231
|
+
isSuccess: true,
|
|
232
|
+
isPending: false,
|
|
233
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
234
|
+
vi.mocked(processReferral).mockRejectedValue(error);
|
|
235
|
+
|
|
236
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
237
|
+
wrapper: queryWrapper.wrapper,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await waitFor(() => {
|
|
241
|
+
expect(result.current).toEqual(error);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("should throw ClientNotFound when client is not available", async ({
|
|
246
|
+
queryWrapper,
|
|
247
|
+
}) => {
|
|
248
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
249
|
+
key: "connected",
|
|
250
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
vi.mocked(useFrakClient).mockReturnValue(undefined);
|
|
254
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
255
|
+
frakContext: { r: "0xcccccccccccccccccccccccccccccccccccccccc" },
|
|
256
|
+
updateContext: vi.fn(),
|
|
257
|
+
});
|
|
258
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
259
|
+
data: mockWalletStatus,
|
|
260
|
+
isSuccess: true,
|
|
261
|
+
isPending: false,
|
|
262
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
263
|
+
|
|
264
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
265
|
+
wrapper: queryWrapper.wrapper,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
await waitFor(() => {
|
|
269
|
+
expect(result.current).toBeInstanceOf(ClientNotFound);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("should update query key when referrer changes", async ({
|
|
274
|
+
queryWrapper,
|
|
275
|
+
mockFrakClient,
|
|
276
|
+
}) => {
|
|
277
|
+
const mockReferralState = "success";
|
|
278
|
+
|
|
279
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
280
|
+
key: "connected",
|
|
281
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
285
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
286
|
+
data: mockWalletStatus,
|
|
287
|
+
isSuccess: true,
|
|
288
|
+
isPending: false,
|
|
289
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
290
|
+
vi.mocked(processReferral).mockResolvedValue(mockReferralState);
|
|
291
|
+
|
|
292
|
+
// Start with one referrer
|
|
293
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
294
|
+
frakContext: { r: "0x1111111111111111111111111111111111111111" },
|
|
295
|
+
updateContext: vi.fn(),
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const { rerender } = renderHook(() => useReferralInteraction(), {
|
|
299
|
+
wrapper: queryWrapper.wrapper,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
await waitFor(() => {
|
|
303
|
+
expect(processReferral).toHaveBeenCalledTimes(1);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Change referrer
|
|
307
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
308
|
+
frakContext: { r: "0x2222222222222222222222222222222222222222" },
|
|
309
|
+
updateContext: vi.fn(),
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
rerender();
|
|
313
|
+
|
|
314
|
+
// Query should re-run with new referrer
|
|
315
|
+
await waitFor(() => {
|
|
316
|
+
expect(processReferral).toHaveBeenCalledTimes(2);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("should handle no referrer in context", async ({
|
|
321
|
+
queryWrapper,
|
|
322
|
+
mockFrakClient,
|
|
323
|
+
}) => {
|
|
324
|
+
const mockReferralState = "success";
|
|
325
|
+
|
|
326
|
+
const mockWalletStatus: WalletStatusReturnType = {
|
|
327
|
+
key: "connected",
|
|
328
|
+
wallet: "0x1234567890123456789012345678901234567890",
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
|
|
332
|
+
vi.mocked(useFrakContext).mockReturnValue({
|
|
333
|
+
frakContext: null, // No referrer
|
|
334
|
+
updateContext: vi.fn(),
|
|
335
|
+
});
|
|
336
|
+
vi.mocked(useWalletStatus).mockReturnValue({
|
|
337
|
+
data: mockWalletStatus,
|
|
338
|
+
isSuccess: true,
|
|
339
|
+
isPending: false,
|
|
340
|
+
} as ReturnType<typeof useWalletStatus>);
|
|
341
|
+
vi.mocked(processReferral).mockResolvedValue(mockReferralState);
|
|
342
|
+
|
|
343
|
+
const { result } = renderHook(() => useReferralInteraction(), {
|
|
344
|
+
wrapper: queryWrapper.wrapper,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
await waitFor(() => {
|
|
348
|
+
expect(result.current).toEqual(mockReferralState);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
expect(processReferral).toHaveBeenCalledWith(
|
|
352
|
+
mockFrakClient,
|
|
353
|
+
expect.objectContaining({
|
|
354
|
+
frakContext: null,
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { DisplayEmbeddedWalletParamsType } from "@frak-labs/core-sdk";
|
|
2
|
+
import {
|
|
3
|
+
type ProcessReferralOptions,
|
|
4
|
+
processReferral,
|
|
5
|
+
} from "@frak-labs/core-sdk/actions";
|
|
6
|
+
import { ClientNotFound } from "@frak-labs/frame-connector";
|
|
7
|
+
import { useQuery } from "@tanstack/react-query";
|
|
8
|
+
import { useMemo } from "react";
|
|
9
|
+
import { useFrakClient } from "../useFrakClient";
|
|
10
|
+
import { useWalletStatus } from "../useWalletStatus";
|
|
11
|
+
import { useFrakContext } from "../utils/useFrakContext";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Helper hook to automatically submit a referral interaction when detected
|
|
15
|
+
*
|
|
16
|
+
* @group hooks
|
|
17
|
+
*
|
|
18
|
+
* @param args
|
|
19
|
+
* @param args.modalConfig - The modal configuration to display if the user is not logged in
|
|
20
|
+
* @param args.options - Some options for the referral interaction
|
|
21
|
+
*
|
|
22
|
+
* @returns The resulting referral state, or a potential error
|
|
23
|
+
*
|
|
24
|
+
* @description This function will automatically handle the referral interaction process
|
|
25
|
+
*
|
|
26
|
+
* @see {@link @frak-labs/core-sdk!actions.processReferral | `processReferral()`} for more details on the automatic referral handling process
|
|
27
|
+
*/
|
|
28
|
+
export function useReferralInteraction({
|
|
29
|
+
modalConfig,
|
|
30
|
+
options,
|
|
31
|
+
}: {
|
|
32
|
+
modalConfig?: DisplayEmbeddedWalletParamsType;
|
|
33
|
+
options?: ProcessReferralOptions;
|
|
34
|
+
} = {}) {
|
|
35
|
+
// Get the frak client
|
|
36
|
+
const client = useFrakClient();
|
|
37
|
+
|
|
38
|
+
// Get the current frak context
|
|
39
|
+
const { frakContext } = useFrakContext();
|
|
40
|
+
|
|
41
|
+
// Get the wallet status
|
|
42
|
+
const { data: walletStatus } = useWalletStatus();
|
|
43
|
+
|
|
44
|
+
// Setup the query that will transmit the referral interaction
|
|
45
|
+
const {
|
|
46
|
+
data: referralState,
|
|
47
|
+
error,
|
|
48
|
+
status,
|
|
49
|
+
} = useQuery({
|
|
50
|
+
gcTime: 0,
|
|
51
|
+
staleTime: 0,
|
|
52
|
+
queryKey: [
|
|
53
|
+
"frak-sdk",
|
|
54
|
+
"auto-referral-interaction",
|
|
55
|
+
frakContext?.r ?? "no-referrer",
|
|
56
|
+
walletStatus?.key ?? "no-wallet-status",
|
|
57
|
+
],
|
|
58
|
+
queryFn: () => {
|
|
59
|
+
if (!client) {
|
|
60
|
+
throw new ClientNotFound();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return processReferral(client, {
|
|
64
|
+
walletStatus,
|
|
65
|
+
frakContext,
|
|
66
|
+
modalConfig,
|
|
67
|
+
options,
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
enabled: !!walletStatus,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return useMemo(() => {
|
|
74
|
+
if (status === "pending") return "processing";
|
|
75
|
+
if (status === "error") return error;
|
|
76
|
+
return referralState || "idle";
|
|
77
|
+
}, [referralState, status, error]);
|
|
78
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { useReferralInteraction } from "./helper/useReferralInteraction";
|
|
2
|
+
export { useDisplayModal } from "./useDisplayModal";
|
|
3
|
+
export { useFrakClient } from "./useFrakClient";
|
|
4
|
+
export { useFrakConfig } from "./useFrakConfig";
|
|
5
|
+
export { useGetMerchantInformation } from "./useGetMerchantInformation";
|
|
6
|
+
export { useOpenSso } from "./useOpenSso";
|
|
7
|
+
export { usePrepareSso } from "./usePrepareSso";
|
|
8
|
+
export { useSendTransactionAction } from "./useSendTransaction";
|
|
9
|
+
export { useSiweAuthenticate } from "./useSiweAuthenticate";
|
|
10
|
+
export { useWalletStatus } from "./useWalletStatus";
|