Skip to content

Commit 3744fdb

Browse files
committed
Refactor wallet user API integration to use tw api
Migrates dashboard wallet user queries from manual fetch calls to the new @thirdweb-dev/api client, updating search, listing, and transformation logic in searchUsers.ts and useEmbeddedWallets.ts. Updates API client usage and types in sdk.gen.ts to match new endpoints and naming conventions. Adds @thirdweb-dev/api as a dependency in package.json. Closes BLD-243
1 parent 17d40af commit 3744fdb

File tree

6 files changed

+3944
-2258
lines changed

6 files changed

+3944
-2258
lines changed

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: 123 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,80 @@
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";
37
import type { SearchType } from "./types";
48

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

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-
}
92+
// Add search parameter based on search type
93+
switch (searchType) {
94+
case "email":
95+
queryParams.email = query;
96+
break;
97+
case "phone":
98+
queryParams.phone = query;
99+
break;
100+
case "id":
101+
queryParams.id = query;
102+
break;
103+
case "address":
104+
queryParams.address = query;
105+
break;
106+
case "externalWallet":
107+
queryParams.externalWalletAddress = query;
108+
break;
109+
}
21110

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-
}
111+
// Use the generated API function with Bearer authentication
112+
const response = await listUserWallets({
113+
query: queryParams,
114+
headers: {
115+
Authorization: `Bearer ${authToken}`,
116+
"Content-Type": "application/json",
117+
"x-thirdweb-team-id": teamId,
118+
...(clientId && { "x-client-id": clientId }),
119+
...(ecosystemSlug && {
120+
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
121+
}),
122+
},
123+
});
40124

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-
}
125+
// Handle response
126+
if (response.error || !response.data) {
127+
console.error(
128+
"Error searching users:",
129+
response.error || "No data returned",
130+
);
131+
return [];
132+
}
56133

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

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

Lines changed: 109 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
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";
59
import { embeddedWalletsKeys } from "../query-keys/cache-keys";
610

11+
// Configure the API client to use the correct base URL
12+
const THIRDWEB_API_HOST =
13+
process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb.com";
14+
configure({
15+
override: {
16+
baseUrl: THIRDWEB_API_HOST,
17+
},
18+
});
19+
20+
// Extract types from the generated API
21+
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
22+
type APIProfile = APIWallet["profiles"][0];
23+
724
const fetchAccountList = ({
825
jwt,
926
clientId,
@@ -18,37 +35,103 @@ const fetchAccountList = ({
1835
pageNumber: number;
1936
}) => {
2037
return async () => {
21-
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
38+
try {
39+
// Prepare query parameters for the new API
40+
const queryParams: ListUserWalletsData["query"] = {
41+
page: pageNumber,
42+
limit: 50, // Keep the same page size
43+
};
2244

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-
}
45+
// Use the generated API function with Bearer authentication
46+
const response = await listUserWallets({
47+
query: queryParams,
48+
headers: {
49+
Authorization: `Bearer ${jwt}`,
50+
"Content-Type": "application/json",
51+
"x-thirdweb-team-id": teamId,
52+
...(clientId && { "x-client-id": clientId }),
53+
...(ecosystemSlug && {
54+
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
55+
}),
56+
},
57+
});
2958

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-
}
59+
// Handle response
60+
if (response.error || !response.data) {
61+
const errorMessage =
62+
typeof response.error === "string"
63+
? response.error
64+
: "No data returned";
65+
throw new Error(errorMessage);
66+
}
4467

45-
const json = await res.json();
46-
return json as {
47-
users: WalletUser[];
48-
};
68+
// Transform the response to match the expected format
69+
return {
70+
users: response.data.result.wallets.map(transformToWalletUser),
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;

0 commit comments

Comments
 (0)