Skip to content

Commit ba586b2

Browse files
Update user search to use new Thirdweb wallet user type and API
Co-authored-by: joaquim.verges <[email protected]>
1 parent fc36f27 commit ba586b2

File tree

4 files changed

+120
-127
lines changed

4 files changed

+120
-127
lines changed

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/components/SearchResults.tsx

Lines changed: 100 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { format } from "date-fns";
44
import type { ThirdwebClient } from "thirdweb";
5+
import type { WalletUser } from "thirdweb/wallets";
56
import { WalletAddress } from "@/components/blocks/wallet-address";
67
import { Badge } from "@/components/ui/badge";
78
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -11,14 +12,20 @@ import {
1112
TooltipProvider,
1213
TooltipTrigger,
1314
} from "@/components/ui/tooltip";
14-
import type { UserSearchResult } from "./types";
1515

16-
const getUserIdentifier = (user: UserSearchResult) => {
17-
return user.email ?? user.phone ?? user.walletAddress ?? user.userId;
16+
const getUserIdentifier = (user: WalletUser) => {
17+
const mainDetail = user.linkedAccounts[0]?.details;
18+
return (
19+
mainDetail?.email ??
20+
mainDetail?.phone ??
21+
mainDetail?.address ??
22+
mainDetail?.id ??
23+
user.id
24+
);
1825
};
1926

2027
export function SearchResults(props: {
21-
results: UserSearchResult[];
28+
results: WalletUser[];
2229
client: ThirdwebClient;
2330
}) {
2431
if (props.results.length === 0) {
@@ -38,93 +45,105 @@ export function SearchResults(props: {
3845

3946
return (
4047
<div className="space-y-4">
41-
{props.results.map((user) => (
42-
<Card key={user.userId}>
43-
<CardHeader>
44-
<CardTitle className="text-lg">User Details</CardTitle>
45-
</CardHeader>
46-
<CardContent className="space-y-4">
47-
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
48-
<div>
49-
<p className="text-sm font-medium text-muted-foreground">
50-
User Identifier
51-
</p>
52-
<p className="text-sm">{getUserIdentifier(user)}</p>
53-
</div>
54-
55-
<div>
56-
<p className="text-sm font-medium text-muted-foreground">
57-
Wallet Address
58-
</p>
59-
<WalletAddress
60-
address={user.walletAddress}
61-
client={props.client}
62-
/>
63-
</div>
64-
65-
{user.email && (
48+
{props.results.map((user) => {
49+
const walletAddress = user.wallets?.[0]?.address;
50+
const createdAt = user.wallets?.[0]?.createdAt;
51+
const mainDetail = user.linkedAccounts?.[0]?.details;
52+
const email = mainDetail?.email as string | undefined;
53+
const phone = mainDetail?.phone as string | undefined;
54+
55+
return (
56+
<Card key={user.id}>
57+
<CardHeader>
58+
<CardTitle className="text-lg">User Details</CardTitle>
59+
</CardHeader>
60+
<CardContent className="space-y-4">
61+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
6662
<div>
6763
<p className="text-sm font-medium text-muted-foreground">
68-
Email
64+
User Identifier
6965
</p>
70-
<p className="text-sm">{user.email}</p>
66+
<p className="text-sm">{getUserIdentifier(user)}</p>
7167
</div>
72-
)}
7368

74-
{user.phone && (
69+
{walletAddress && (
70+
<div>
71+
<p className="text-sm font-medium text-muted-foreground">
72+
Wallet Address
73+
</p>
74+
<WalletAddress
75+
address={walletAddress}
76+
client={props.client}
77+
/>
78+
</div>
79+
)}
80+
81+
{email && (
82+
<div>
83+
<p className="text-sm font-medium text-muted-foreground">
84+
Email
85+
</p>
86+
<p className="text-sm">{email}</p>
87+
</div>
88+
)}
89+
90+
{phone && (
91+
<div>
92+
<p className="text-sm font-medium text-muted-foreground">
93+
Phone
94+
</p>
95+
<p className="text-sm">{phone}</p>
96+
</div>
97+
)}
98+
99+
{createdAt && (
100+
<div>
101+
<p className="text-sm font-medium text-muted-foreground">
102+
Created
103+
</p>
104+
<p className="text-sm">
105+
{format(new Date(createdAt), "MMM dd, yyyy")}
106+
</p>
107+
</div>
108+
)}
109+
75110
<div>
76111
<p className="text-sm font-medium text-muted-foreground">
77-
Phone
112+
Login Methods
78113
</p>
79-
<p className="text-sm">{user.phone}</p>
80-
</div>
81-
)}
82-
83-
<div>
84-
<p className="text-sm font-medium text-muted-foreground">
85-
Created
86-
</p>
87-
<p className="text-sm">
88-
{format(new Date(user.createdAt), "MMM dd, yyyy")}
89-
</p>
90-
</div>
91-
92-
<div>
93-
<p className="text-sm font-medium text-muted-foreground">
94-
Login Methods
95-
</p>
96-
<div className="flex flex-wrap gap-1">
97-
{user.linkedAccounts.map((account, index) => (
98-
<TooltipProvider
99-
key={`${user.userId}-${account.type}-${index}`}
100-
>
101-
<Tooltip>
102-
<TooltipTrigger>
103-
<Badge variant="secondary" className="text-xs">
104-
{account.type}
105-
</Badge>
106-
</TooltipTrigger>
107-
<TooltipContent>
108-
<div className="text-sm space-y-1">
109-
{Object.entries(account.details).map(
110-
([key, value]) => (
111-
<div key={key}>
112-
<span className="font-medium">{key}:</span>{" "}
113-
{String(value)}
114-
</div>
115-
),
116-
)}
117-
</div>
118-
</TooltipContent>
119-
</Tooltip>
120-
</TooltipProvider>
121-
))}
114+
<div className="flex flex-wrap gap-1">
115+
{user.linkedAccounts?.map((account, index) => (
116+
<TooltipProvider
117+
key={`${user.id}-${account.type}-${index}`}
118+
>
119+
<Tooltip>
120+
<TooltipTrigger>
121+
<Badge variant="secondary" className="text-xs">
122+
{account.type}
123+
</Badge>
124+
</TooltipTrigger>
125+
<TooltipContent>
126+
<div className="text-sm space-y-1">
127+
{Object.entries(account.details).map(
128+
([key, value]) => (
129+
<div key={key}>
130+
<span className="font-medium">{key}:</span>{" "}
131+
{String(value)}
132+
</div>
133+
),
134+
)}
135+
</div>
136+
</TooltipContent>
137+
</Tooltip>
138+
</TooltipProvider>
139+
))}
140+
</div>
122141
</div>
123142
</div>
124-
</div>
125-
</CardContent>
126-
</Card>
127-
))}
143+
</CardContent>
144+
</Card>
145+
);
146+
})}
128147
</div>
129148
);
130149
}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/users/components/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { SearchInput } from "./SearchInput";
2525
import { AdvancedSearchInput } from "./AdvancedSearchInput";
2626
import { SearchResults } from "./SearchResults";
2727
import { searchUsers } from "./searchUsers";
28-
import type { SearchType, UserSearchResult } from "./types";
28+
import type { SearchType } from "./types";
2929

3030
const getUserIdentifier = (accounts: WalletUser["linkedAccounts"]) => {
3131
const mainDetail = accounts[0]?.details;
@@ -115,7 +115,7 @@ export function InAppWalletUsersPageContent(props: {
115115

116116
const [activePage, setActivePage] = useState(1);
117117
const [searchValue, setSearchValue] = useState("");
118-
const [searchResults, setSearchResults] = useState<UserSearchResult[]>([]);
118+
const [searchResults, setSearchResults] = useState<WalletUser[]>([]);
119119
const [isSearching, setIsSearching] = useState(false);
120120
const [hasSearchResults, setHasSearchResults] = useState(false);
121121
const walletsQuery = useEmbeddedWallets({
@@ -157,7 +157,7 @@ export function InAppWalletUsersPageContent(props: {
157157
const handleSearch = async (searchType: SearchType, query: string) => {
158158
setIsSearching(true);
159159
try {
160-
const results = await searchUsers(props.authToken, searchType, query);
160+
const results = await searchUsers(props.authToken, props.projectClientId, searchType, query);
161161
setSearchResults(results);
162162
setHasSearchResults(true);
163163
} catch (error) {
Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
import type { SearchParams, SearchType, UserSearchResult } from "./types";
1+
import type { WalletUser } from "thirdweb/wallets";
2+
import { THIRDWEB_EWS_API_HOST } from "@/constants/urls";
3+
import type { SearchType } from "./types";
24

35
export async function searchUsers(
46
authToken: string,
7+
clientId: string,
58
searchType: SearchType,
69
query: string,
7-
): Promise<UserSearchResult[]> {
8-
const url = new URL(
9-
"https://in-app-wallet.thirdweb.com/api/2023-11-30/embedded-wallet/user-details",
10-
);
11-
12-
// Map search type to query parameter
13-
const queryByMap: Record<SearchType, string> = {
14-
email: "email",
15-
phone: "phone",
16-
id: "id",
17-
address: "walletAddress",
10+
): Promise<WalletUser[]> {
11+
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
12+
13+
// Add clientId parameter
14+
url.searchParams.append("clientId", clientId);
15+
16+
// Add filter parameter as JSON string
17+
const filter = {
18+
field: searchType === "address" ? "walletAddress" : searchType,
19+
value: query,
1820
};
19-
20-
const queryBy = queryByMap[searchType];
21-
url.searchParams.append("queryBy", queryBy);
22-
url.searchParams.append(queryBy, query);
21+
url.searchParams.append("filter", JSON.stringify(filter));
2322

2423
const response = await fetch(url.toString(), {
2524
headers: {
2625
Authorization: `Bearer ${authToken}`,
2726
"Content-Type": "application/json",
27+
"x-client-id": clientId,
2828
},
2929
method: "GET",
3030
});
@@ -36,5 +36,5 @@ export async function searchUsers(
3636
}
3737

3838
const data = await response.json();
39-
return data as UserSearchResult[];
39+
return data.users as WalletUser[];
4040
}
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1 @@
1-
export interface UserSearchResult {
2-
userId: string;
3-
walletAddress: string;
4-
email?: string;
5-
phone?: string;
6-
createdAt: string;
7-
linkedAccounts: {
8-
type: string;
9-
details: {
10-
phone?: string;
11-
email?: string;
12-
address?: string;
13-
id?: string;
14-
[key: string]: unknown;
15-
};
16-
}[];
17-
}
18-
191
export type SearchType = "email" | "phone" | "id" | "address";
20-
21-
export interface SearchParams {
22-
queryBy: SearchType | "walletAddress";
23-
email?: string;
24-
phone?: string;
25-
id?: string;
26-
walletAddress?: string;
27-
}

0 commit comments

Comments
 (0)