Skip to content

Commit 27d72e5

Browse files
committed
[PRO-124] Dashboard: Project Wallet UI tweaks (#8559)
<!-- ## 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 focuses on refining the user interface and functionality of the `ProjectWallet` component in the dashboard application. It includes style adjustments, component updates, and the introduction of new dropdown menu options for better user interaction. ### Detailed summary - Adjusted the size of `ChevronDownIcon` in `select-with-search.tsx`. - Removed `XIcon` from `project-wallet.tsx` and updated the heading style. - Renamed `projectWallet` variables to `serverWallet` in `project-wallet.stories.tsx`. - Introduced a new `Variant` function for rendering `ProjectWalletSectionUI`. - Added new icons in `project-wallet-details.tsx` and refined the dropdown menu. - Enhanced wallet detail presentation with better layout and added new dropdown options for actions like Deposit, Withdraw, and Change Project Wallet. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added dropdown menu with wallet action options: Deposit Funds, Withdraw Funds, Swap Tokens, View Transactions, and Change Project Wallet. * Added copy-address button in the wallet header. * **Style** * Redesigned wallet header layout with improved visual structure. * Refined icon sizing and spacing throughout the wallet interface. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 151127d commit 27d72e5

4 files changed

Lines changed: 102 additions & 96 deletions

File tree

apps/dashboard/src/@/components/blocks/select-with-search.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export const SelectWithSearch = React.forwardRef<
125125
? renderOption(selectedOption)
126126
: selectedOption?.label || placeholder}
127127
</span>
128-
<ChevronDownIcon className="size-4 cursor-pointer text-muted-foreground" />
128+
<ChevronDownIcon className="size-3.5 cursor-pointer text-muted-foreground shrink-0" />
129129
</div>
130130
</Button>
131131
</PopoverTrigger>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx

Lines changed: 75 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import { zodResolver } from "@hookform/resolvers/zod";
44
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
55
import {
6+
ArrowDownToLineIcon,
67
ArrowLeftIcon,
78
ArrowLeftRightIcon,
9+
ArrowUpFromLineIcon,
810
EllipsisVerticalIcon,
11+
ListCollapseIcon,
912
RefreshCcwIcon,
10-
SendIcon,
11-
ShuffleIcon,
12-
WalletIcon,
13+
Settings2Icon,
1314
} from "lucide-react";
1415
import { useTheme } from "next-themes";
1516
import { useCallback, useMemo, useState } from "react";
@@ -49,6 +50,7 @@ import {
4950
DropdownMenu,
5051
DropdownMenuContent,
5152
DropdownMenuItem,
53+
DropdownMenuSeparator,
5254
DropdownMenuTrigger,
5355
} from "@/components/ui/dropdown-menu";
5456
import {
@@ -228,9 +230,12 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) {
228230
return (
229231
<div>
230232
<div className="rounded-xl border border-border bg-card">
231-
<div className="p-5 flex flex-col lg:flex-row gap-5">
232-
<div className="flex-1">
233-
<p className="text-sm text-foreground mb-1">Wallet Address</p>
233+
<div className="px-5 py-4 border-b border-dashed flex justify-between items-center">
234+
<div>
235+
<h2 className="text-base font-semibold text-foreground mb-0.5 tracking-tight">
236+
{projectWallet.label || "Project Wallet"}
237+
</h2>
238+
234239
<CopyTextButton
235240
textToShow={shortenAddress(projectWallet.address, 6)}
236241
textToCopy={projectWallet.address}
@@ -241,14 +246,66 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) {
241246
/>
242247
</div>
243248

244-
<div className="flex-1">
245-
<p className="text-sm text-foreground mb-1">Wallet Label</p>
246-
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
247-
<p className="text-sm break-all py-2 sm:py-0 text-muted-foreground">
248-
{projectWallet.label || "N/A"}
249-
</p>
250-
</div>
251-
</div>
249+
<DropdownMenu>
250+
<DropdownMenuTrigger asChild>
251+
<Button
252+
variant="ghost"
253+
size="sm"
254+
className="w-auto h-auto p-2 rounded-full"
255+
>
256+
<EllipsisVerticalIcon className="size-5 text-muted-foreground" />
257+
</Button>
258+
</DropdownMenuTrigger>
259+
<DropdownMenuContent
260+
align="end"
261+
className="w-56 rounded-xl"
262+
sideOffset={10}
263+
>
264+
<DropdownMenuItem
265+
className="flex items-center gap-2"
266+
onSelect={() => setIsReceiveOpen(true)}
267+
>
268+
<ArrowUpFromLineIcon className="size-4 text-muted-foreground" />
269+
Deposit Funds
270+
</DropdownMenuItem>
271+
<DropdownMenuItem
272+
className="flex items-center gap-2"
273+
onSelect={() => setIsSendOpen(true)}
274+
>
275+
<ArrowDownToLineIcon className="size-4 text-muted-foreground" />
276+
Withdraw Funds
277+
</DropdownMenuItem>
278+
<DropdownMenuItem
279+
className="flex items-center gap-2"
280+
onSelect={() => setIsSwapOpen(true)}
281+
>
282+
<ArrowLeftRightIcon className="size-4 text-muted-foreground" />
283+
Swap Tokens
284+
</DropdownMenuItem>
285+
{/* add line */}
286+
<DropdownMenuSeparator />
287+
<DropdownMenuItem
288+
className="flex items-center gap-2"
289+
onSelect={() =>
290+
router.push(
291+
`/team/${props.teamSlug}/${props.project.slug}/transactions`,
292+
)
293+
}
294+
>
295+
<ListCollapseIcon className="size-4 text-muted-foreground" />
296+
View Transactions
297+
</DropdownMenuItem>
298+
{canChangeWallet && (
299+
<DropdownMenuItem
300+
className="flex items-center gap-2"
301+
onSelect={() => setIsChangeWalletOpen(true)}
302+
>
303+
<Settings2Icon className="size-4 text-muted-foreground" />
304+
Change Project Wallet
305+
</DropdownMenuItem>
306+
)}
307+
</DropdownMenuContent>
308+
</DropdownMenu>
252309
</div>
253310

254311
<div className="p-5 border-t border-dashed flex flex-col gap-4 sm:flex-row sm:justify-between sm:items-center">
@@ -280,10 +337,10 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) {
280337
</div>
281338
</div>
282339

283-
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
340+
<div className="flex flex-col sm:flex-row sm:items-center">
284341
<SingleNetworkSelector
285342
chainId={selectedChainId}
286-
className="w-full sm:w-fit rounded-full bg-background hover:bg-accent/50"
343+
className="w-full sm:w-fit rounded-full bg-background hover:bg-accent/50 border-r-0 rounded-r-none"
287344
client={props.client}
288345
disableDeprecated
289346
disableChainId
@@ -302,76 +359,16 @@ export function ProjectWalletDetailsSection(props: ProjectWalletControlsProps) {
302359
chainId={selectedChainId}
303360
client={props.client}
304361
enabled={true}
362+
disableAddress={true}
305363
showCheck={true}
306364
addNativeTokenIfMissing={true}
307365
placeholder="Native token"
308-
className="w-full sm:w-fit rounded-full bg-background hover:bg-accent/50"
366+
className="w-full sm:w-fit rounded-full bg-background hover:bg-accent/50 rounded-l-none"
309367
popoverContentClassName="!w-[320px] rounded-xl overflow-hidden"
310368
align="end"
311369
/>
312370
</div>
313371
</div>
314-
315-
<div className="p-4 border-t border-border flex justify-end gap-2">
316-
<Button
317-
variant="outline"
318-
size="sm"
319-
className="gap-2 bg-background hover:bg-accent/50"
320-
onClick={() => setIsSendOpen(true)}
321-
>
322-
<SendIcon className="size-4" />
323-
Withdraw
324-
</Button>
325-
<Button
326-
variant="outline"
327-
size="sm"
328-
className="gap-2 bg-background hover:bg-accent/50"
329-
onClick={() => setIsSwapOpen(true)}
330-
>
331-
<ArrowLeftRightIcon className="size-4" />
332-
Swap
333-
</Button>
334-
<DropdownMenu>
335-
<DropdownMenuTrigger asChild>
336-
<Button
337-
variant="outline"
338-
size="sm"
339-
className="px-2 bg-background hover:bg-accent/50"
340-
>
341-
<EllipsisVerticalIcon className="size-4" />
342-
</Button>
343-
</DropdownMenuTrigger>
344-
<DropdownMenuContent align="end" className="w-48">
345-
<DropdownMenuItem
346-
className="flex items-center gap-2"
347-
onSelect={() => setIsReceiveOpen(true)}
348-
>
349-
<WalletIcon className="size-4 text-muted-foreground" />
350-
Deposit
351-
</DropdownMenuItem>
352-
<DropdownMenuItem
353-
className="flex items-center gap-2"
354-
onSelect={() =>
355-
router.push(
356-
`/team/${props.teamSlug}/${props.project.slug}/transactions`,
357-
)
358-
}
359-
>
360-
<ArrowLeftRightIcon className="size-4 text-muted-foreground" />
361-
Transactions
362-
</DropdownMenuItem>
363-
{canChangeWallet && (
364-
<DropdownMenuItem
365-
className="flex items-center gap-2"
366-
onSelect={() => setIsChangeWalletOpen(true)}
367-
>
368-
<ShuffleIcon className="size-4 text-muted-foreground" />
369-
Change Wallet
370-
</DropdownMenuItem>
371-
)}
372-
</DropdownMenuContent>
373-
</DropdownMenu>
374-
</div>
375372
</div>
376373

377374
<SendProjectWalletModal

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.stories.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { storybookThirdwebClient } from "@/storybook/utils";
55
import { ProjectWalletSectionUI } from "./project-wallet";
66

77
const meta = {
8-
component: ProjectWalletSectionUI,
8+
component: Variant,
99
title: "Project/ProjectWalletSection",
1010
parameters: {
1111
nextjs: {
@@ -35,16 +35,16 @@ projectWithManagedAccessToken.services = [
3535

3636
const projectWithoutManagedAccessToken = projectStub("foo", "bar");
3737

38-
const projectWallet1: ProjectWalletSummary = {
38+
const serverWallet1: ProjectWalletSummary = {
3939
id: "server-wallet-id",
4040
address: "0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37",
41-
label: "Project Wallet 1",
41+
label: "XYZ",
4242
};
4343

44-
const projectWallet2: ProjectWalletSummary = {
44+
const serverWallet2: ProjectWalletSummary = {
4545
id: "server-wallet-id-2",
4646
address: "0x83Dd93fA5D8343094f850f90B3fb90088C1bB425",
47-
label: "Project Wallet 2",
47+
label: "FooBar",
4848
};
4949

5050
export const NoProjectWalletSetNoManagedAccessToken: Story = {
@@ -84,7 +84,7 @@ export const NoProjectWalletSetWithManagedAccessTokenAndServerWallets: Story = {
8484
projectWallet: undefined,
8585
getProjectServerWallets: async () => {
8686
await new Promise((resolve) => setTimeout(resolve, 1000));
87-
return [projectWallet1, projectWallet2];
87+
return [serverWallet1, serverWallet2];
8888
},
8989
},
9090
};
@@ -98,7 +98,7 @@ export const NoProjectWalletSetLoading: Story = {
9898
projectWallet: undefined,
9999
getProjectServerWallets: async () => {
100100
await new Promise((resolve) => setTimeout(resolve, 100000));
101-
return [projectWallet1, projectWallet2];
101+
return [serverWallet1, serverWallet2];
102102
},
103103
},
104104
};
@@ -109,10 +109,10 @@ export const ProjectWalletSetMultipleServerWallets: Story = {
109109
project: projectWithManagedAccessToken,
110110
teamSlug: "bar",
111111
client: storybookThirdwebClient,
112-
projectWallet: projectWallet1,
112+
projectWallet: serverWallet1,
113113
getProjectServerWallets: async () => {
114114
await new Promise((resolve) => setTimeout(resolve, 1000));
115-
return [projectWallet1, projectWallet2];
115+
return [serverWallet1, serverWallet2];
116116
},
117117
},
118118
};
@@ -122,11 +122,23 @@ export const ProjectWalletSetSingleServerWallet: Story = {
122122
layout: "column",
123123
project: projectWithManagedAccessToken,
124124
teamSlug: "bar",
125-
projectWallet: projectWallet1,
125+
projectWallet: serverWallet1,
126126
client: storybookThirdwebClient,
127127
getProjectServerWallets: async () => {
128128
await new Promise((resolve) => setTimeout(resolve, 1000));
129-
return [projectWallet1];
129+
return [serverWallet1];
130130
},
131131
},
132132
};
133+
134+
function Variant(props: Parameters<typeof ProjectWalletSectionUI>[0]) {
135+
return (
136+
<div className="space-y-20">
137+
<ProjectWalletSectionUI {...props} />
138+
139+
<div className="max-w-[660px]">
140+
<ProjectWalletSectionUI {...props} />
141+
</div>
142+
</div>
143+
);
144+
}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet.tsx

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

33
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
44
import { UnderlineLink } from "@workspace/ui/components/UnderlineLink";
5-
import { ArrowUpRightIcon, ChevronDownIcon, XIcon } from "lucide-react";
5+
import { ArrowUpRightIcon, ChevronDownIcon } from "lucide-react";
66
import Link from "next/link";
77
import { useMemo, useState } from "react";
88
import { toast } from "sonner";
@@ -134,11 +134,8 @@ function CreateProjectWalletSection(props: {
134134

135135
return (
136136
<div className="rounded-xl border p-5 bg-card">
137-
<div className="rounded-full p-2 border bg-background inline-flex mb-4">
138-
<XIcon className="size-4 text-muted-foreground" />
139-
</div>
140-
<h2 className="text-base font-medium text-foreground mb-0.5">
141-
No Project Wallet set
137+
<h2 className="text-sm font-medium text-foreground mb-0.5 text-yellow-700 dark:text-yellow-500">
138+
No project wallet set
142139
</h2>
143140
<p className="text-sm text-muted-foreground">
144141
Set a project wallet to set the default sender in thirdweb API.

0 commit comments

Comments
 (0)