Skip to content

Commit 229aeb2

Browse files
committed
Add pagination support to embedded wallets fetching
Enhanced the fetchAccountList function and related hooks to handle paginated API responses using the hasMore flag. This ensures all wallet users are fetched across multiple pages, improving reliability and scalability of wallet data retrieval.
1 parent 51fe8c4 commit 229aeb2

File tree

1 file changed

+173
-170
lines changed

1 file changed

+173
-170
lines changed
Lines changed: 173 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
22
import type {
3-
ListUserWalletsData,
4-
ListUserWalletsResponses,
3+
ListUserWalletsData,
4+
ListUserWalletsResponses,
55
} from "@thirdweb-dev/api";
66
import { configure, listUserWallets } from "@thirdweb-dev/api";
77
import { useActiveAccount } from "thirdweb/react";
@@ -11,199 +11,202 @@ import { embeddedWalletsKeys } from "../query-keys/cache-keys";
1111

1212
// Configure the API client to use the correct base URL
1313
configure({
14-
override: {
15-
baseUrl: THIRDWEB_API_HOST,
16-
},
14+
override: {
15+
baseUrl: THIRDWEB_API_HOST,
16+
},
1717
});
1818

1919
// Extract types from the generated API
2020
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
2121
type APIProfile = APIWallet["profiles"][0];
2222

2323
const fetchAccountList = ({
24-
jwt,
25-
clientId,
26-
ecosystemSlug,
27-
teamId,
28-
pageNumber,
24+
jwt,
25+
clientId,
26+
ecosystemSlug,
27+
teamId,
28+
pageNumber,
2929
}: {
30-
jwt: string;
31-
clientId?: string;
32-
ecosystemSlug?: string;
33-
teamId: string;
34-
pageNumber: number;
30+
jwt: string;
31+
clientId?: string;
32+
ecosystemSlug?: string;
33+
teamId: string;
34+
pageNumber: number;
3535
}) => {
36-
return async () => {
37-
try {
38-
// Prepare query parameters for the new API
39-
const queryParams: ListUserWalletsData["query"] = {
40-
page: pageNumber,
41-
limit: 50, // Keep the same page size
42-
};
43-
44-
// Use the generated API function with Bearer authentication
45-
const response = await listUserWallets({
46-
query: queryParams,
47-
headers: {
48-
Authorization: `Bearer ${jwt}`,
49-
"Content-Type": "application/json",
50-
"x-thirdweb-team-id": teamId,
51-
...(clientId && { "x-client-id": clientId }),
52-
...(ecosystemSlug && {
53-
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
54-
}),
55-
},
56-
});
57-
58-
// Handle response
59-
if (response.error || !response.data) {
60-
const errorMessage =
61-
typeof response.error === "string"
62-
? response.error
63-
: "No data returned";
64-
throw new Error(errorMessage);
65-
}
66-
67-
// Transform the response to match the expected format
68-
return {
69-
users: response.data.result.wallets.map(transformToWalletUser),
70-
};
71-
} catch (error) {
72-
console.error("Failed to fetch wallets:", error);
73-
throw error;
74-
}
75-
};
36+
return async () => {
37+
try {
38+
// Prepare query parameters for the new API
39+
const queryParams: ListUserWalletsData["query"] = {
40+
page: pageNumber,
41+
limit: 50, // Keep the same page size
42+
};
43+
44+
// Use the generated API function with Bearer authentication
45+
const response = await listUserWallets({
46+
query: queryParams,
47+
headers: {
48+
Authorization: `Bearer ${jwt}`,
49+
"Content-Type": "application/json",
50+
"x-thirdweb-team-id": teamId,
51+
...(clientId && { "x-client-id": clientId }),
52+
...(ecosystemSlug && {
53+
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
54+
}),
55+
},
56+
});
57+
58+
// Handle response
59+
if (response.error || !response.data) {
60+
const errorMessage =
61+
typeof response.error === "string"
62+
? response.error
63+
: "No data returned";
64+
throw new Error(errorMessage);
65+
}
66+
67+
// Transform the response to match the expected format
68+
return {
69+
users: response.data.result.wallets.map(transformToWalletUser),
70+
hasMore: response.data.result.pagination.hasMore ?? false,
71+
};
72+
} catch (error) {
73+
console.error("Failed to fetch wallets:", error);
74+
throw error;
75+
}
76+
};
7677
};
7778

7879
// Transform API response to match existing WalletUser format
7980
function transformToWalletUser(apiWallet: APIWallet): WalletUser {
80-
return {
81-
id: getProfileId(apiWallet.profiles[0]) || "",
82-
linkedAccounts: apiWallet.profiles.map((profile) => {
83-
// Create details object based on the profile data
84-
let details:
85-
| { email: string; [key: string]: string }
86-
| { phone: string; [key: string]: string }
87-
| { address: string; [key: string]: string }
88-
| { id: string; [key: string]: string };
89-
90-
const profileId = getProfileId(profile);
91-
92-
if ("email" in profile && profile.email) {
93-
details = { email: profile.email, id: profileId };
94-
} else if ("phone" in profile && profile.phone) {
95-
details = { phone: profile.phone, id: profileId };
96-
} else if ("walletAddress" in profile && profile.walletAddress) {
97-
details = { address: profile.walletAddress, id: profileId };
98-
} else {
99-
details = { id: profileId };
100-
}
101-
102-
return {
103-
type: profile.type,
104-
details,
105-
};
106-
}),
107-
wallets: apiWallet.address
108-
? [
109-
{
110-
address: apiWallet.address,
111-
createdAt: apiWallet.createdAt || new Date().toISOString(),
112-
type: "enclave" as const,
113-
},
114-
]
115-
: [],
116-
};
81+
return {
82+
id: getProfileId(apiWallet.profiles[0]) || "",
83+
linkedAccounts: apiWallet.profiles.map((profile) => {
84+
// Create details object based on the profile data
85+
let details:
86+
| { email: string; [key: string]: string }
87+
| { phone: string; [key: string]: string }
88+
| { address: string; [key: string]: string }
89+
| { id: string; [key: string]: string };
90+
91+
const profileId = getProfileId(profile);
92+
93+
if ("email" in profile && profile.email) {
94+
details = { email: profile.email, id: profileId };
95+
} else if ("phone" in profile && profile.phone) {
96+
details = { phone: profile.phone, id: profileId };
97+
} else if ("walletAddress" in profile && profile.walletAddress) {
98+
details = { address: profile.walletAddress, id: profileId };
99+
} else {
100+
details = { id: profileId };
101+
}
102+
103+
return {
104+
type: profile.type,
105+
details,
106+
};
107+
}),
108+
wallets: apiWallet.address
109+
? [
110+
{
111+
address: apiWallet.address,
112+
createdAt: apiWallet.createdAt || new Date().toISOString(),
113+
type: "enclave" as const,
114+
},
115+
]
116+
: [],
117+
};
117118
}
118119

119120
// Helper function to safely get ID from any profile type
120121
function getProfileId(profile: APIProfile | undefined): string {
121-
if (!profile) return "";
122+
if (!profile) return "";
122123

123-
if ("id" in profile) {
124-
return profile.id;
125-
} else if ("credentialId" in profile) {
126-
return profile.credentialId;
127-
} else if ("identifier" in profile) {
128-
return profile.identifier;
129-
}
124+
if ("id" in profile) {
125+
return profile.id;
126+
} else if ("credentialId" in profile) {
127+
return profile.credentialId;
128+
} else if ("identifier" in profile) {
129+
return profile.identifier;
130+
}
130131

131-
return "";
132+
return "";
132133
}
133134

134135
export function useEmbeddedWallets(params: {
135-
clientId?: string;
136-
ecosystemSlug?: string;
137-
teamId: string;
138-
page: number;
139-
authToken: string;
136+
clientId?: string;
137+
ecosystemSlug?: string;
138+
teamId: string;
139+
page: number;
140+
authToken: string;
140141
}) {
141-
const { clientId, ecosystemSlug, teamId, page, authToken } = params;
142-
const address = useActiveAccount()?.address;
143-
144-
return useQuery({
145-
enabled: !!address && !!(clientId || ecosystemSlug),
146-
queryFn: fetchAccountList({
147-
clientId,
148-
ecosystemSlug,
149-
teamId,
150-
jwt: authToken,
151-
pageNumber: page,
152-
}),
153-
queryKey: embeddedWalletsKeys.embeddedWallets(
154-
address || "",
155-
clientId || ecosystemSlug || "",
156-
page,
157-
),
158-
});
142+
const { clientId, ecosystemSlug, teamId, page, authToken } = params;
143+
const address = useActiveAccount()?.address;
144+
145+
return useQuery({
146+
enabled: !!address && !!(clientId || ecosystemSlug),
147+
queryFn: fetchAccountList({
148+
clientId,
149+
ecosystemSlug,
150+
teamId,
151+
jwt: authToken,
152+
pageNumber: page,
153+
}),
154+
queryKey: embeddedWalletsKeys.embeddedWallets(
155+
address || "",
156+
clientId || ecosystemSlug || "",
157+
page,
158+
),
159+
});
159160
}
160161

161162
// TODO: fetching list of all users needs to be improved
162163
export function useAllEmbeddedWallets(params: { authToken: string }) {
163-
const { authToken } = params;
164-
const queryClient = useQueryClient();
165-
const address = useActiveAccount()?.address;
166-
167-
return useMutation({
168-
mutationFn: async ({
169-
clientId,
170-
ecosystemSlug,
171-
teamId,
172-
}: {
173-
clientId?: string;
174-
ecosystemSlug?: string;
175-
teamId: string;
176-
}) => {
177-
const responses: WalletUser[] = [];
178-
let page = 1;
179-
180-
while (true) {
181-
const res = await queryClient.fetchQuery<{
182-
users: WalletUser[];
183-
}>({
184-
queryFn: fetchAccountList({
185-
clientId,
186-
ecosystemSlug,
187-
teamId,
188-
jwt: authToken,
189-
pageNumber: page,
190-
}),
191-
queryKey: embeddedWalletsKeys.embeddedWallets(
192-
address || "",
193-
clientId || ecosystemSlug || "",
194-
page,
195-
),
196-
});
197-
198-
if (res.users.length === 0) {
199-
break;
200-
}
201-
202-
page++;
203-
responses.push(...res.users);
204-
}
205-
206-
return responses;
207-
},
208-
});
164+
const { authToken } = params;
165+
const queryClient = useQueryClient();
166+
const address = useActiveAccount()?.address;
167+
168+
return useMutation({
169+
mutationFn: async ({
170+
clientId,
171+
ecosystemSlug,
172+
teamId,
173+
}: {
174+
clientId?: string;
175+
ecosystemSlug?: string;
176+
teamId: string;
177+
}) => {
178+
const responses: WalletUser[] = [];
179+
let page = 1;
180+
181+
while (true) {
182+
const res = await queryClient.fetchQuery<{
183+
users: WalletUser[];
184+
hasMore: boolean;
185+
}>({
186+
queryFn: fetchAccountList({
187+
clientId,
188+
ecosystemSlug,
189+
teamId,
190+
jwt: authToken,
191+
pageNumber: page,
192+
}),
193+
queryKey: embeddedWalletsKeys.embeddedWallets(
194+
address || "",
195+
clientId || ecosystemSlug || "",
196+
page,
197+
),
198+
});
199+
200+
responses.push(...res.users);
201+
202+
if (!res.hasMore) {
203+
break;
204+
}
205+
206+
page++;
207+
}
208+
209+
return responses;
210+
},
211+
});
209212
}

0 commit comments

Comments
 (0)