Skip to content

Commit 84a376b

Browse files
Refactor UX of Onboarding and SendCoins flows
1 parent cbaf6bc commit 84a376b

File tree

19 files changed

+262
-123
lines changed

19 files changed

+262
-123
lines changed

apps/web/app/(authenticated)/onboarding/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function OnboardingPage() {
2020

2121
return (
2222
<div className="flex items-center justify-center w-full h-full">
23-
<div className="max-w-md w-full flex flex-col gap-2 items-center">
23+
<div className="max-w-lg w-full flex flex-col gap-2 items-center">
2424
<h1 className="font-display text-2xl font-bold">
2525
<VerticalCutReveal
2626
splitBy="characters"

apps/web/app/(authenticated)/page.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default function Home() {
4141

4242
return (
4343
<div className="flex items-center justify-center w-full h-full">
44-
<div className="max-w-md w-full flex flex-col gap-2 items-center">
44+
<div className="max-w-lg w-full flex flex-col gap-2 items-center">
4545
<h1 className="font-display text-2xl font-bold">
4646
<VerticalCutReveal
4747
splitBy="characters"
@@ -83,7 +83,11 @@ export default function Home() {
8383
animate={{ opacity: 1, y: 0 }}
8484
transition={{ duration: 0.3, delay: vaults.length * 0.1 }}
8585
>
86-
<Button asChild variant="secondary" data-testid="authenticated-create-vault-button">
86+
<Button
87+
asChild
88+
variant="secondary"
89+
data-testid="authenticated-create-vault-button"
90+
>
8791
<Link href="/onboarding" className="w-full">
8892
Create Vault
8993
</Link>

apps/web/app/(authenticated)/vault/[vaultId]/(dashboard)/page.tsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AnimatePresence, motion } from "motion/react";
55
import { useMemo } from "react";
66
import { parseUnits } from "@aptos-labs/js-pro";
77
import { Skeleton } from "@/components/ui/skeleton";
8+
import CoinAvatar from "@/components/CoinAvatar";
89

910
export default function VaultPage() {
1011
const { coins } = useCoins();
@@ -88,7 +89,6 @@ export default function VaultPage() {
8889

8990
const symbol = metadata?.symbol || balance.metadata.symbol;
9091
const name = metadata?.name || balance.metadata.name;
91-
const logoUrl = metadata?.logo_url;
9292

9393
// Calculate USD value if price is available
9494
const usdValue = price?.usd
@@ -107,19 +107,7 @@ export default function VaultPage() {
107107
transition={{ delay: index * 0.05 }}
108108
className="flex items-center gap-4 p-4 rounded-lg border hover:bg-accent/50 transition-colors"
109109
>
110-
<div className="h-10 w-10 rounded-full bg-accent/30 flex items-center justify-center overflow-hidden">
111-
{logoUrl ? (
112-
<img
113-
src={logoUrl}
114-
alt={symbol}
115-
width={40}
116-
height={40}
117-
className="object-cover"
118-
/>
119-
) : (
120-
<div className="font-bold text-lg">{symbol?.[0]}</div>
121-
)}
122-
</div>
110+
<CoinAvatar coin={coin} size="lg" />
123111

124112
<div className="flex-1">
125113
<div className="font-medium font-display">{name}</div>

apps/web/app/(authenticated)/vault/[vaultId]/settings/export/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ export default function ExportSettingsPage() {
3030
</div>
3131
<section>
3232
<CardHeader>
33-
<CardTitle className="font-medium">Export JSON</CardTitle>
33+
<CardTitle className="font-medium">Export Backup File</CardTitle>
3434
<CardDescription>
35-
This JSON can be used to import all your vaults onto other
35+
This backup file can be used to import all your vaults onto other
3636
devices.
3737
</CardDescription>
3838
</CardHeader>
@@ -51,7 +51,7 @@ export default function ExportSettingsPage() {
5151
download="petra-vaults-export.json"
5252
>
5353
<DownloadIcon />
54-
Download JSON
54+
Download Backup File
5555
</a>
5656
</Button>
5757

apps/web/app/(authenticated)/vault/[vaultId]/settings/page.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,9 @@ export default function VaultSettingsPage() {
190190
<CardHeader>
191191
<CardTitle className="font-medium">Delete Vault</CardTitle>
192192
<CardDescription>
193-
Permanently delete this vault from local storage. This action
194-
cannot be undone.
193+
Remove this vault from local storage. This action cannot be
194+
undone. The vault will still be available on-chain and can be
195+
re-imported using a backup file or vault address.
195196
</CardDescription>
196197
</CardHeader>
197198
<CardContent>
@@ -203,16 +204,16 @@ export default function VaultSettingsPage() {
203204
data-testid="delete-vault-button"
204205
>
205206
<TrashIcon />
206-
Delete Vault
207+
Remove Vault
207208
</Button>
208209
</AlertDialogTrigger>
209210
<AlertDialogContent>
210211
<AlertDialogHeader>
211-
<AlertDialogTitle>Delete Vault</AlertDialogTitle>
212+
<AlertDialogTitle>Remove Vault</AlertDialogTitle>
212213
<AlertDialogDescription>
213-
Permanently delete this vault from local storage. This
214-
action cannot be undone. The vault will still be available
215-
on the blockchain.
214+
Remove this vault from local storage. This action cannot
215+
be undone. The vault will still be available on-chain and
216+
can be re-imported using a backup file or vault address.
216217
</AlertDialogDescription>
217218
</AlertDialogHeader>
218219

@@ -229,7 +230,7 @@ export default function VaultSettingsPage() {
229230
}}
230231
data-testid="confirm-delete-vault-button"
231232
>
232-
Delete Vault
233+
Remove Vault
233234
</Button>
234235
</AlertDialogAction>
235236
</AlertDialogFooter>

apps/web/components/AppSidebar.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import { usePathname } from "next/navigation";
1717
import {
1818
FilePlusIcon,
1919
GearIcon,
20+
GlobeIcon,
2021
HomeIcon,
2122
Pencil1Icon,
2223
} from "@radix-ui/react-icons";
2324
import { NavItemGroup } from "./NavItemGroup";
25+
import { getExplorerUrl } from "@aptos-labs/js-pro";
2426

2527
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
2628
const pathname = usePathname();
@@ -61,6 +63,17 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
6163
],
6264

6365
management: [
66+
{
67+
name: "View in Explorer",
68+
url: activeVaultId
69+
? getExplorerUrl({
70+
network: parseVaultId(activeVaultId)?.network,
71+
path: `account/${parseVaultId(activeVaultId)?.address.toString()}`,
72+
})
73+
: undefined,
74+
icon: GlobeIcon,
75+
target: "_blank",
76+
},
6477
{
6578
name: "Settings",
6679
url: activeVaultId ? `/vault/${activeVaultId}/settings` : undefined,

apps/web/components/CoinAvatar.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { ProcessedCoin } from "@/context/CoinsProvider";
2+
import { Avatar } from "@radix-ui/react-avatar";
3+
import { AvatarFallback, AvatarImage } from "./ui/avatar";
4+
import { AptosCoinAvatar } from "aptos-avatars-react";
5+
import { cn } from "@/lib/utils";
6+
import { isApt } from "@/lib/address";
7+
import { cva } from "class-variance-authority";
8+
9+
export type CoinAvatarProps = {
10+
className?: string;
11+
size?: "sm" | "md" | "lg";
12+
} & (
13+
| {
14+
coin: ProcessedCoin;
15+
}
16+
| {
17+
asset: string;
18+
logoUrl?: string;
19+
fallbackUrl?: string;
20+
}
21+
);
22+
23+
export default function CoinAvatar({
24+
className,
25+
size = "md",
26+
...props
27+
}: CoinAvatarProps) {
28+
const asset =
29+
"coin" in props ? props.coin.balance.metadata.assetType : props.asset;
30+
31+
const logoUrl = isApt(asset)
32+
? "/aptos_coin.svg"
33+
: "coin" in props
34+
? (props.coin.metadata?.logo_url ?? props.coin.balance.metadata.iconUri)
35+
: (props.logoUrl ?? props.fallbackUrl);
36+
37+
const sizeClass = cva("", {
38+
variants: { size: { sm: "w-4 h-4", md: "w-8 h-8", lg: "w-10 h-10" } },
39+
defaultVariants: { size: "md" },
40+
});
41+
42+
return (
43+
<Avatar className={cn(sizeClass({ size }), className)}>
44+
<AvatarFallback
45+
className={cn(
46+
"aspect-square [&>div]:!bg-transparent",
47+
sizeClass({ size }),
48+
className
49+
)}
50+
>
51+
<AptosCoinAvatar
52+
value={asset}
53+
size={size === "sm" ? 16 : size === "md" ? 32 : 40}
54+
/>
55+
</AvatarFallback>
56+
{logoUrl && <AvatarImage src={logoUrl} />}
57+
</Avatar>
58+
);
59+
}

apps/web/components/OnboardingAddOrImport.tsx

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { useAccount, useClients, useNetwork } from "@aptos-labs/react";
1111
import { AptosAvatar } from "aptos-avatars-react";
1212
import { ExternalLinkIcon } from "lucide-react";
1313
import { truncateAddress } from "@aptos-labs/wallet-adapter-react";
14-
import { DownloadIcon } from "@radix-ui/react-icons";
1514
import { useOnboarding } from "@/context/OnboardingProvider";
1615
import ExpandingContainer from "./ExpandingContainer";
1716
import { hasWindow } from "@/lib/utils";
@@ -103,7 +102,7 @@ export default function OnboardingAddOrImport() {
103102
exit={{ opacity: 0, y: -10 }}
104103
transition={{ duration: 0.3, ease: [0.19, 1, 0.22, 1] }}
105104
>
106-
<Card className="w-full max-w-md">
105+
<Card className="w-full">
107106
<CardContent>
108107
<MultisigNameForm
109108
onSubmit={(values) => {
@@ -127,7 +126,7 @@ export default function OnboardingAddOrImport() {
127126
</div>
128127
<div className="flex gap-2">
129128
<Input
130-
placeholder="Search for a vault"
129+
placeholder="Enter a vault address"
131130
value={importVaultAddress.current}
132131
onChange={(e) => importVaultAddress.set(e.target.value)}
133132
/>
@@ -147,10 +146,15 @@ export default function OnboardingAddOrImport() {
147146
</div>
148147
<Card className="flex gap-2 mt-2 p-0">
149148
<CardContent className="py-6">
150-
<div className="flex items-center justify-between">
151-
<h3 className="font-display text-sm font-semibold">
152-
Discovered Vaults
153-
</h3>
149+
<div className="flex items-center justify-between mb-2">
150+
<div>
151+
<h3 className="font-display text-sm font-semibold">
152+
Discovered Vaults
153+
</h3>
154+
<p className="font-display text-xs text-muted-foreground">
155+
Import an existing vault related to your wallet
156+
</p>
157+
</div>
154158
<Dialog>
155159
<DialogTrigger asChild>
156160
<Button
@@ -159,7 +163,7 @@ export default function OnboardingAddOrImport() {
159163
className="py-0 text-xs h-fit"
160164
data-testid="import-vaults-json-button"
161165
>
162-
JSON Import
166+
Backup Import
163167
</Button>
164168
</DialogTrigger>
165169
<UploadImportJSONModal onImport={handleImportVaults} />
@@ -195,6 +199,23 @@ export default function OnboardingAddOrImport() {
195199
<p className="font-display text-sm font-medium ml-1">
196200
{truncateAddress(e.toString())}
197201
</p>
202+
<Button
203+
size="icon"
204+
variant="ghost"
205+
className="size-7"
206+
asChild
207+
>
208+
<a
209+
href={getExplorerUrl({
210+
network: network.network,
211+
path: `account/${e.toString()}`,
212+
})}
213+
target="_blank"
214+
rel="noopener noreferrer"
215+
>
216+
<ExternalLinkIcon />
217+
</a>
218+
</Button>
198219
<div className="flex items-center gap-2 ml-auto">
199220
<Button
200221
variant="link"
@@ -204,24 +225,7 @@ export default function OnboardingAddOrImport() {
204225
handleLookUpAndImportAccount(e.toString());
205226
}}
206227
>
207-
<DownloadIcon />
208-
</Button>
209-
<Button
210-
size="icon"
211-
variant="ghost"
212-
className="size-7"
213-
asChild
214-
>
215-
<a
216-
href={getExplorerUrl({
217-
network: network.network,
218-
path: `account/${e.toString()}`,
219-
})}
220-
target="_blank"
221-
rel="noopener noreferrer"
222-
>
223-
<ExternalLinkIcon />
224-
</a>
228+
Import
225229
</Button>
226230
</div>
227231
</div>

apps/web/components/OnboardingImportSetName.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default function OnboardingImportSetName() {
4343
damping: 21,
4444
}}
4545
>
46-
<Card className="w-full max-w-md">
46+
<Card className="w-full max-w-lg">
4747
<CardContent>
4848
<VaultImportNameForm
4949
address={importVaultAddress.current}

0 commit comments

Comments
 (0)