Skip to content

Commit 22d736c

Browse files
authored
Refactor wallet user API integration to use tw api (#7987)
1 parent bb89561 commit 22d736c

File tree

8 files changed

+3949
-2262
lines changed

8 files changed

+3949
-2262
lines changed

apps/dashboard/knip.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
],
99
"ignoreBinaries": ["only-allow"],
1010
"ignoreDependencies": [
11+
"@thirdweb-dev/api",
1112
"@thirdweb-dev/service-utils",
1213
"@thirdweb-dev/vault-sdk",
1314
"thirdweb",

apps/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@shazow/whatsabi": "0.22.2",
2424
"@tanstack/react-query": "5.81.5",
2525
"@tanstack/react-table": "^8.21.3",
26+
"@thirdweb-dev/api": "workspace:*",
2627
"@thirdweb-dev/service-utils": "workspace:*",
2728
"@thirdweb-dev/vault-sdk": "workspace:*",
2829
"@vercel/functions": "2.2.2",
Lines changed: 122 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,79 @@
1+
import type {
2+
ListUserWalletsData,
3+
ListUserWalletsResponses,
4+
} from "@thirdweb-dev/api";
5+
import { configure, listUserWallets } from "@thirdweb-dev/api";
16
import type { WalletUser } from "thirdweb/wallets";
2-
import { THIRDWEB_EWS_API_HOST } from "@/constants/urls";
7+
import { THIRDWEB_API_HOST } from "@/constants/urls";
38
import type { SearchType } from "./types";
49

10+
// Configure the API client to use the correct base URL
11+
configure({
12+
override: {
13+
baseUrl: THIRDWEB_API_HOST,
14+
},
15+
});
16+
17+
// Extract types from the generated API
18+
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
19+
type APIProfile = APIWallet["profiles"][0];
20+
21+
// Transform API response to match existing WalletUser format
22+
function transformToWalletUser(apiWallet: APIWallet): WalletUser {
23+
return {
24+
id: getProfileId(apiWallet.profiles[0]) || "",
25+
linkedAccounts: apiWallet.profiles.map((profile) => {
26+
// Create details object based on the profile data
27+
let details:
28+
| { email: string; [key: string]: string }
29+
| { phone: string; [key: string]: string }
30+
| { address: string; [key: string]: string }
31+
| { id: string; [key: string]: string };
32+
33+
const profileId = getProfileId(profile);
34+
35+
if ("email" in profile && profile.email) {
36+
details = { email: profile.email, id: profileId };
37+
} else if ("phone" in profile && profile.phone) {
38+
details = { phone: profile.phone, id: profileId };
39+
} else if ("walletAddress" in profile && profile.walletAddress) {
40+
details = { address: profile.walletAddress, id: profileId };
41+
} else {
42+
details = { id: profileId };
43+
}
44+
45+
return {
46+
type: profile.type,
47+
details,
48+
};
49+
}),
50+
wallets: apiWallet.address
51+
? [
52+
{
53+
address: apiWallet.address,
54+
createdAt: apiWallet.createdAt || new Date().toISOString(),
55+
type: "enclave" as const,
56+
},
57+
]
58+
: [],
59+
};
60+
}
61+
62+
// Helper function to safely get ID from any profile type
63+
function getProfileId(profile: APIProfile | undefined): string {
64+
if (!profile) return "";
65+
66+
if ("id" in profile) {
67+
return profile.id;
68+
} else if ("credentialId" in profile) {
69+
return profile.credentialId;
70+
} else if ("identifier" in profile) {
71+
return profile.identifier;
72+
}
73+
74+
return "";
75+
}
76+
577
export async function searchUsers(
678
authToken: string,
779
clientId: string | undefined,
@@ -10,50 +82,57 @@ export async function searchUsers(
1082
searchType: SearchType,
1183
query: string,
1284
): Promise<WalletUser[]> {
13-
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
85+
try {
86+
// Prepare query parameters
87+
const queryParams: ListUserWalletsData["query"] = {
88+
limit: 50,
89+
};
1490

15-
// Add clientId or ecosystemSlug parameter
16-
if (ecosystemSlug) {
17-
url.searchParams.append("ecosystemSlug", `ecosystem.${ecosystemSlug}`);
18-
} else if (clientId) {
19-
url.searchParams.append("clientId", clientId);
20-
}
91+
// Add search parameter based on search type
92+
switch (searchType) {
93+
case "email":
94+
queryParams.email = query;
95+
break;
96+
case "phone":
97+
queryParams.phone = query;
98+
break;
99+
case "id":
100+
queryParams.id = query;
101+
break;
102+
case "address":
103+
queryParams.address = query;
104+
break;
105+
case "externalWallet":
106+
queryParams.externalWalletAddress = query;
107+
break;
108+
}
21109

22-
// Add search parameter based on search type
23-
switch (searchType) {
24-
case "email":
25-
url.searchParams.append("email", query);
26-
break;
27-
case "phone":
28-
url.searchParams.append("phone", query);
29-
break;
30-
case "id":
31-
url.searchParams.append("id", query);
32-
break;
33-
case "address":
34-
url.searchParams.append("address", query);
35-
break;
36-
case "externalWallet":
37-
url.searchParams.append("externalWalletAddress", query);
38-
break;
39-
}
110+
// Use the generated API function with Bearer authentication
111+
const response = await listUserWallets({
112+
query: queryParams,
113+
headers: {
114+
Authorization: `Bearer ${authToken}`,
115+
"Content-Type": "application/json",
116+
"x-thirdweb-team-id": teamId,
117+
...(clientId && { "x-client-id": clientId }),
118+
...(ecosystemSlug && {
119+
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
120+
}),
121+
},
122+
});
40123

41-
const response = await fetch(url.toString(), {
42-
headers: {
43-
Authorization: `Bearer ${authToken}`,
44-
"Content-Type": "application/json",
45-
"x-thirdweb-team-id": teamId,
46-
...(clientId && { "x-client-id": clientId }),
47-
},
48-
method: "GET",
49-
});
50-
51-
if (!response.ok) {
52-
throw new Error(
53-
`Failed to search users: ${response.status} ${response.statusText}`,
54-
);
55-
}
124+
// Handle response
125+
if (response.error || !response.data) {
126+
console.error(
127+
"Error searching users:",
128+
response.error || "No data returned",
129+
);
130+
return [];
131+
}
56132

57-
const data = await response.json();
58-
return data.users as WalletUser[];
133+
return response.data.result.wallets.map(transformToWalletUser);
134+
} catch (error) {
135+
console.error("Error searching users:", error);
136+
return [];
137+
}
59138
}

apps/dashboard/src/@/constants/urls.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
export const THIRDWEB_EWS_API_HOST =
2-
process.env.NEXT_PUBLIC_THIRDWEB_EWS_API_HOST ||
3-
"https://in-app-wallet.thirdweb.com";
1+
export const THIRDWEB_API_HOST =
2+
process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb-dev.com";
43

54
export const THIRDWEB_PAY_DOMAIN =
65
process.env.NEXT_PUBLIC_PAY_URL || "pay.thirdweb-dev.com";

apps/dashboard/src/@/hooks/useEmbeddedWallets.ts

Lines changed: 113 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2+
import type {
3+
ListUserWalletsData,
4+
ListUserWalletsResponses,
5+
} from "@thirdweb-dev/api";
6+
import { configure, listUserWallets } from "@thirdweb-dev/api";
27
import { useActiveAccount } from "thirdweb/react";
38
import type { WalletUser } from "thirdweb/wallets";
4-
import { THIRDWEB_EWS_API_HOST } from "@/constants/urls";
9+
import { THIRDWEB_API_HOST } from "@/constants/urls";
510
import { embeddedWalletsKeys } from "../query-keys/cache-keys";
611

12+
// Configure the API client to use the correct base URL
13+
configure({
14+
override: {
15+
baseUrl: THIRDWEB_API_HOST,
16+
},
17+
});
18+
19+
// Extract types from the generated API
20+
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
21+
type APIProfile = APIWallet["profiles"][0];
22+
723
const fetchAccountList = ({
824
jwt,
925
clientId,
@@ -18,37 +34,104 @@ const fetchAccountList = ({
1834
pageNumber: number;
1935
}) => {
2036
return async () => {
21-
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
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+
};
2243

23-
// Add clientId or ecosystemSlug parameter
24-
if (ecosystemSlug) {
25-
url.searchParams.append("ecosystemSlug", `ecosystem.${ecosystemSlug}`);
26-
} else if (clientId) {
27-
url.searchParams.append("clientId", clientId);
28-
}
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+
});
2957

30-
url.searchParams.append("page", pageNumber.toString());
31-
32-
const res = await fetch(url.href, {
33-
headers: {
34-
Authorization: `Bearer ${jwt}`,
35-
"Content-Type": "application/json",
36-
"x-thirdweb-team-id": teamId,
37-
...(clientId && { "x-client-id": clientId }),
38-
},
39-
method: "GET",
40-
});
41-
if (!res.ok) {
42-
throw new Error(`Failed to fetch wallets: ${await res.text()}`);
43-
}
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+
}
4466

45-
const json = await res.json();
46-
return json as {
47-
users: WalletUser[];
48-
};
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+
}
4976
};
5077
};
5178

79+
// Transform API response to match existing WalletUser format
80+
function transformToWalletUser(apiWallet: APIWallet): WalletUser {
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+
};
118+
}
119+
120+
// Helper function to safely get ID from any profile type
121+
function getProfileId(profile: APIProfile | undefined): string {
122+
if (!profile) return "";
123+
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+
}
131+
132+
return "";
133+
}
134+
52135
export function useEmbeddedWallets(params: {
53136
clientId?: string;
54137
ecosystemSlug?: string;
@@ -98,6 +181,7 @@ export function useAllEmbeddedWallets(params: { authToken: string }) {
98181
while (true) {
99182
const res = await queryClient.fetchQuery<{
100183
users: WalletUser[];
184+
hasMore: boolean;
101185
}>({
102186
queryFn: fetchAccountList({
103187
clientId,
@@ -113,12 +197,13 @@ export function useAllEmbeddedWallets(params: { authToken: string }) {
113197
),
114198
});
115199

116-
if (res.users.length === 0) {
200+
responses.push(...res.users);
201+
202+
if (!res.hasMore) {
117203
break;
118204
}
119205

120206
page++;
121-
responses.push(...res.users);
122207
}
123208

124209
return responses;

0 commit comments

Comments
 (0)