Skip to content

Commit 908142f

Browse files
committed
[PRO-116] Move Server wallets table to separate page (#8467)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a new `Wallets` section to the application, enhancing the wallet management interface. It updates the routing and adds functionality to handle EVM and Solana wallets, including error handling and data fetching improvements. ### Detailed summary - Added a new route for `Wallets` in `layout.tsx`. - Updated the redirect path in `page.tsx` for unauthorized access. - Removed deprecated error handling for EVM wallets. - Implemented new logic for fetching and displaying wallets, including Solana accounts. - Enhanced error handling for wallet retrieval and connection issues. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 4d065c3 commit 908142f

File tree

3 files changed

+143
-36
lines changed

3 files changed

+143
-36
lines changed

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/layout.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ export default async function Layout(props: {
5757
name: "Configuration",
5858
path: `${basePath}/configuration`,
5959
},
60+
{
61+
name: "Wallets",
62+
path: `${basePath}/wallets`,
63+
},
6064
]}
6165
>
6266
{props.children}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/page.tsx

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { NEXT_PUBLIC_THIRDWEB_VAULT_URL } from "@/constants/public-envs";
66
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
77
import { loginRedirect } from "@/utils/redirects";
88
import { TransactionsAnalyticsPageContent } from "../../transactions/analytics/analytics-page";
9-
import { ServerWalletsTable } from "../../transactions/components/server-wallets-table.client";
109
import type { Wallet } from "../../transactions/server-wallets/wallet-table/types";
1110
import { listSolanaAccounts } from "../../transactions/solana-wallets/lib/vault.client";
1211
import type { SolanaWallet } from "../../transactions/solana-wallets/wallet-table/types";
@@ -16,9 +15,6 @@ export const dynamic = "force-dynamic";
1615
export default async function Page(props: {
1716
params: Promise<{ team_slug: string; project_slug: string }>;
1817
searchParams: Promise<{
19-
from?: string | string[];
20-
to?: string | string[];
21-
interval?: string | string[];
2218
testTxWithWallet?: string | string[];
2319
testSolanaTxWithWallet?: string | string[];
2420
page?: string;
@@ -33,7 +29,7 @@ export default async function Page(props: {
3329

3430
if (!authToken) {
3531
loginRedirect(
36-
`/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets`,
32+
`/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/wallets`,
3733
);
3834
}
3935

@@ -103,9 +99,6 @@ export default async function Page(props: {
10399
};
104100
}
105101

106-
const isSolanaPermissionError =
107-
solanaAccounts.error?.message.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
108-
109102
const testTxWithWallet =
110103
typeof searchParams.testTxWithWallet === "string"
111104
? searchParams.testTxWithWallet
@@ -139,34 +132,6 @@ export default async function Page(props: {
139132
testTxWithWallet={testTxWithWallet}
140133
wallets={wallets}
141134
/>
142-
143-
{eoas.error ? (
144-
<div className="rounded-xl border border-destructive/50 bg-destructive/10 p-4">
145-
<p className="text-destructive font-semibold mb-2">
146-
EVM Wallet Error
147-
</p>
148-
<p className="text-sm text-muted-foreground">{eoas.error.message}</p>
149-
</div>
150-
) : (
151-
<ServerWalletsTable
152-
client={client}
153-
evmCurrentPage={currentPage}
154-
evmTotalPages={Math.ceil(eoas.data.totalRecords / pageSize)}
155-
evmTotalRecords={eoas.data.totalRecords}
156-
evmWallets={wallets}
157-
pageSize={pageSize}
158-
project={project}
159-
solanaCurrentPage={solanaCurrentPage}
160-
solanaTotalPages={Math.ceil(
161-
solanaAccounts.data.totalRecords / pageSize,
162-
)}
163-
solanaTotalRecords={solanaAccounts.data.totalRecords}
164-
solanaWallets={solanaAccounts.data.items}
165-
teamSlug={params.team_slug}
166-
solanaPermissionError={isSolanaPermissionError}
167-
authToken={authToken}
168-
/>
169-
)}
170135
</div>
171136
);
172137
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { createVaultClient, listEoas } from "@thirdweb-dev/vault-sdk";
2+
import { redirect } from "next/navigation";
3+
import { getAuthToken } from "@/api/auth-token";
4+
import { getProject } from "@/api/project/projects";
5+
import { NEXT_PUBLIC_THIRDWEB_VAULT_URL } from "@/constants/public-envs";
6+
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
7+
import { loginRedirect } from "@/utils/redirects";
8+
import { ServerWalletsTable } from "../../../transactions/components/server-wallets-table.client";
9+
import type { Wallet } from "../../../transactions/server-wallets/wallet-table/types";
10+
import { listSolanaAccounts } from "../../../transactions/solana-wallets/lib/vault.client";
11+
import type { SolanaWallet } from "../../../transactions/solana-wallets/wallet-table/types";
12+
13+
export const dynamic = "force-dynamic";
14+
15+
export default async function Page(props: {
16+
params: Promise<{ team_slug: string; project_slug: string }>;
17+
searchParams: Promise<{
18+
page?: string;
19+
solana_page?: string;
20+
}>;
21+
}) {
22+
const [params, searchParams, authToken] = await Promise.all([
23+
props.params,
24+
props.searchParams,
25+
getAuthToken(),
26+
]);
27+
28+
if (!authToken) {
29+
loginRedirect(
30+
`/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets`,
31+
);
32+
}
33+
34+
const [vaultClient, project] = await Promise.all([
35+
createVaultClient({
36+
baseUrl: NEXT_PUBLIC_THIRDWEB_VAULT_URL,
37+
}).catch(() => undefined),
38+
getProject(params.team_slug, params.project_slug),
39+
]);
40+
41+
if (!project) {
42+
redirect(`/team/${params.team_slug}`);
43+
}
44+
45+
if (!vaultClient) {
46+
return <div>Error: Failed to connect to Vault</div>;
47+
}
48+
49+
const projectEngineCloudService = project.services.find(
50+
(service) => service.name === "engineCloud",
51+
);
52+
53+
const managementAccessToken =
54+
projectEngineCloudService?.managementAccessToken;
55+
56+
const pageSize = 10;
57+
const currentPage = Number.parseInt(searchParams.page ?? "1");
58+
const solanaCurrentPage = Number.parseInt(searchParams.solana_page ?? "1");
59+
60+
const eoas = managementAccessToken
61+
? await listEoas({
62+
client: vaultClient,
63+
request: {
64+
auth: {
65+
accessToken: managementAccessToken,
66+
},
67+
options: {
68+
page: currentPage - 1,
69+
// @ts-expect-error - TODO: fix this
70+
page_size: pageSize,
71+
},
72+
},
73+
})
74+
: { data: { items: [], totalRecords: 0 }, error: null, success: true };
75+
76+
const wallets = (eoas.data?.items as Wallet[] | undefined) ?? [];
77+
78+
let solanaAccounts: {
79+
data: { items: SolanaWallet[]; totalRecords: number };
80+
error: Error | null;
81+
success: boolean;
82+
};
83+
84+
if (managementAccessToken) {
85+
solanaAccounts = await listSolanaAccounts({
86+
managementAccessToken,
87+
page: solanaCurrentPage,
88+
limit: pageSize,
89+
projectId: project.id,
90+
});
91+
} else {
92+
solanaAccounts = {
93+
data: { items: [], totalRecords: 0 },
94+
error: null,
95+
success: true,
96+
};
97+
}
98+
99+
const isSolanaPermissionError =
100+
solanaAccounts.error?.message.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
101+
102+
const client = getClientThirdwebClient({
103+
jwt: authToken,
104+
teamId: project.teamId,
105+
});
106+
107+
return (
108+
<div className="flex flex-col gap-10">
109+
{eoas.error ? (
110+
<div className="rounded-xl border border-destructive/50 bg-destructive/10 p-4">
111+
<p className="text-destructive font-semibold mb-2">
112+
EVM Wallet Error
113+
</p>
114+
<p className="text-sm text-muted-foreground">{eoas.error.message}</p>
115+
</div>
116+
) : (
117+
<ServerWalletsTable
118+
client={client}
119+
evmCurrentPage={currentPage}
120+
evmTotalPages={Math.ceil(eoas.data.totalRecords / pageSize)}
121+
evmTotalRecords={eoas.data.totalRecords}
122+
evmWallets={wallets}
123+
pageSize={pageSize}
124+
project={project}
125+
solanaCurrentPage={solanaCurrentPage}
126+
solanaTotalPages={Math.ceil(
127+
solanaAccounts.data.totalRecords / pageSize,
128+
)}
129+
solanaTotalRecords={solanaAccounts.data.totalRecords}
130+
solanaWallets={solanaAccounts.data.items}
131+
teamSlug={params.team_slug}
132+
solanaPermissionError={isSolanaPermissionError}
133+
authToken={authToken}
134+
/>
135+
)}
136+
</div>
137+
);
138+
}

0 commit comments

Comments
 (0)