Skip to content

Commit fc893ec

Browse files
feat: optimize invite UX and mobile UI
- Invite UX: New Hybrid page for invited signers with role-based components - Mobile UI: Add logo to header (center) and move wallet dropdown to sidebar - Fix mobile floating for wallet cards - Add self-indicator for creators to new wallet flow (create page)
1 parent 7bf83ee commit fc893ec

File tree

12 files changed

+731
-147
lines changed

12 files changed

+731
-147
lines changed

src/components/common/overall-layout/layout.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,21 @@ export default function RootLayout({
122122
{/* Mobile menu button */}
123123
<MobileNavigation isWalletPath={isWalletPath} />
124124

125-
{/* Wallet selection on mobile - centered */}
126-
{isLoggedIn && (
127-
<div className="flex-1 flex justify-center md:hidden">
128-
<WalletDropDown />
129-
</div>
130-
)}
125+
{/* Logo in mobile header - centered */}
126+
<div className="flex-1 flex justify-center md:hidden">
127+
<Link href="/" className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-800/50 transition-colors">
128+
<svg
129+
className="h-7 w-7 text-foreground flex-shrink-0"
130+
enableBackground="new 0 0 300 200"
131+
viewBox="0 0 300 200"
132+
xmlns="http://www.w3.org/2000/svg"
133+
fill="currentColor"
134+
>
135+
<path d="m289 127-45-60-45-60c-.9-1.3-2.4-2-4-2s-3.1.7-4 2l-37 49.3c-2 2.7-6 2.7-8 0l-37-49.3c-.9-1.3-2.4-2-4-2s-3.1.7-4 2l-45 60-45 60c-1.3 1.8-1.3 4.2 0 6l45 60c.9 1.3 2.4 2 4 2s3.1-.7 4-2l37-49.3c2-2.7 6-2.7 8 0l37 49.3c.9 1.3 2.4 2 4 2s3.1-.7 4-2l37-49.3c2-2.7 6-2.7 8 0l37 49.3c.9 1.3 2.4 2 4 2s3.1-.7 4-2l45-60c1.3-1.8 1.3-4.2 0-6zm-90-103.3 32.5 43.3c1.3 1.8 1.3 4.2 0 6l-32.5 43.3c-2 2.7-6 2.7-8 0l-32.5-43.3c-1.3-1.8-1.3-4.2 0-6l32.5-43.3c2-2.7 6-2.7 8 0zm-90 0 32.5 43.3c1.3 1.8 1.3 4.2 0 6l-32.5 43.3c-2 2.7-6 2.7-8 0l-32.5-43.3c-1.3-1.8-1.3-4.2 0-6l32.5-43.3c2-2.7 6-2.7 8 0zm-53 152.6-32.5-43.3c-1.3-1.8-1.3-4.2 0-6l32.5-43.3c2-2.7 6-2.7 8 0l32.5 43.3c1.3 1.8 1.3 4.2 0 6l-32.5 43.3c-2 2.7-6 2.7-8 0zm90 0-32.5-43.3c-1.3-1.8-1.3-4.2 0-6l32.5-43.3c2-2.7 6-2.7 8 0l32.5 43.3c1.3 1.8 1.3 4.2 0 6l-32.5 43.3c-2 2.7-6 2.7-8 0zm90 0-32.5-43.3c-1.3-1.8-1.3-4.2 0-6l32.5-43.3c2-2.7 6-2.7 8 0l32.5 43.3c1.3 1.8 1.3 4.2 0 6l-32.5 43.3c-2 2.7-6 2.7-8 0z" />
136+
</svg>
137+
<span className="text-base font-medium text-foreground whitespace-nowrap">Multi-Sig Platform</span>
138+
</Link>
139+
</div>
131140

132141
{/* Wallet selection + breadcrumb row on desktop */}
133142
{isLoggedIn && (

src/components/common/overall-layout/menus/multisig-wallet.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Banknote, Info, List, Signature, UserRoundPen } from "lucide-react";
1+
import { Banknote, Info, List, Signature, UserRoundPen, Landmark } from "lucide-react";
22
import { useRouter } from "next/router";
33
import MenuLink from "./menu-link";
44
import usePendingTransactions from "@/hooks/usePendingTransactions";
@@ -17,6 +17,15 @@ export default function MenuWallet() {
1717
return (
1818
<nav className="grid h-full items-start px-2 text-sm font-medium lg:px-4">
1919
<div className="grid items-start">
20+
<MenuLink
21+
href={`${baseUrl}governance`}
22+
className={
23+
router.pathname == "/wallets/[wallet]/governance" ? "text-white" : ""
24+
}
25+
>
26+
<Landmark className="h-5 w-5" />
27+
<div className="flex items-center gap-2">Governance</div>
28+
</MenuLink>
2029
<MenuLink
2130
href={`${baseUrl}transactions`}
2231
className={
@@ -25,7 +34,7 @@ export default function MenuWallet() {
2534
: ""
2635
}
2736
>
28-
<List className="h-7 w-7" />
37+
<List className="h-5 w-5" />
2938
<div className="flex items-center gap-2">
3039
Transactions
3140
{transactions && transactions.length > 0 && (
@@ -41,7 +50,7 @@ export default function MenuWallet() {
4150
router.pathname == "/wallets/[wallet]/signing" ? "text-white" : ""
4251
}
4352
>
44-
<UserRoundPen className="h-6 w-6" />
53+
<UserRoundPen className="h-5 w-5" />
4554
<div className="flex items-center gap-2">
4655
Signing
4756
{signables && signables.length > 0 && (
@@ -57,26 +66,26 @@ export default function MenuWallet() {
5766
router.pathname == "/wallets/[wallet]/assets" ? "text-white" : ""
5867
}
5968
>
60-
<Banknote className="h-6 w-6" />
61-
Assets
69+
<Banknote className="h-5 w-5" />
70+
<div className="flex items-center gap-2">Assets</div>
6271
</MenuLink>
6372
<MenuLink
6473
href={`${baseUrl}chat`}
6574
className={
6675
router.pathname == "/wallets/[wallet]/chat" ? "text-white" : ""
6776
}
6877
>
69-
<ChatBubbleIcon className="h-6 w-6" />
70-
Chat
78+
<ChatBubbleIcon className="h-5 w-5" />
79+
<div className="flex items-center gap-2">Chat</div>
7180
</MenuLink>
7281
<MenuLink
7382
href={`${baseUrl}info`}
7483
className={
7584
router.pathname == "/wallets/[wallet]/info" ? "text-white" : ""
7685
}
7786
>
78-
<Info className="h-6 w-6" />
79-
Info
87+
<Info className="h-5 w-5" />
88+
<div className="flex items-center gap-2">Info</div>
8089
</MenuLink>
8190
</div>
8291

src/components/common/overall-layout/menus/wallets.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ export default function MenuWallets() {
5757
</MenuLink>
5858
</div>
5959
)}
60-
<MenuLink
61-
href={
62-
router.pathname.startsWith("/wallets/[wallet]")
63-
? `${baseUrl}governance`
64-
: "/governance"
65-
}
66-
className={router.pathname.includes("governance") ? "text-white" : ""}
67-
>
68-
<Landmark className="h-5 w-5" />
69-
Governance
70-
</MenuLink>
60+
61+
{/* Global Governance - only when NOT in wallet context */}
62+
{!router.pathname.startsWith("/wallets/[wallet]") && (
63+
<MenuLink
64+
href="/governance"
65+
className={router.pathname.includes("governance") ? "text-white" : ""}
66+
>
67+
<Landmark className="h-5 w-5" />
68+
Governance
69+
</MenuLink>
70+
)}
7171
</nav>
7272
);
7373
}

src/components/common/overall-layout/wallet-drop-down.tsx

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ import useAppWallet from "@/hooks/useAppWallet";
1313
import { useState, useEffect } from "react";
1414
import WalletNavLink from "./wallet-nav-link";
1515

16-
export default function WalletDropDown() {
16+
interface WalletDropDownProps {
17+
forceMobile?: boolean;
18+
onPlusClick?: () => void;
19+
}
20+
21+
export default function WalletDropDown({ forceMobile = false, onPlusClick }: WalletDropDownProps) {
1722
const router = useRouter();
1823
const { wallets } = useUserWallets();
1924
const { appWallet } = useAppWallet();
@@ -43,13 +48,16 @@ export default function WalletDropDown() {
4348
};
4449
}, [router.events]);
4550

46-
return isDesktop ? (
51+
return (isDesktop && !forceMobile) ? (
4752
// Desktop: Select-Button als Trigger (Option 1)
4853
<div className="inline-flex items-center rounded-md border border-border overflow-hidden h-10">
4954
<button
5055
type="button"
5156
className="flex items-center px-3 h-full text-muted-foreground hover:text-foreground hover:bg-muted border-r border-border"
52-
onClick={() => router.push("/wallets/new-wallet-flow/save")}
57+
onClick={() => {
58+
router.push("/wallets/new-wallet-flow/save");
59+
onPlusClick?.();
60+
}}
5361
>
5462
<Plus className="h-5 w-5" />
5563
</button>
@@ -64,7 +72,7 @@ export default function WalletDropDown() {
6472
) : (
6573
<ChevronDown className="h-5 w-5" />
6674
)}
67-
<span className="flex items-center ml-2">
75+
<span className="flex items-center ml-2 max-w-[200px] truncate" title={appWallet?.name || "Select Wallet"}>
6876
{appWallet?.name || "Select Wallet"}
6977
</span>
7078
<Wallet2 className="mx-2 h-4 w-4" />
@@ -91,33 +99,32 @@ export default function WalletDropDown() {
9199
</DropdownMenu>
92100
</div>
93101
) : (
94-
// Mobile: Ganzer Container als Trigger (Option 2)
95-
<DropdownMenu open={open} onOpenChange={setOpen}>
96-
<DropdownMenuTrigger asChild>
97-
<div className="inline-flex items-center rounded-md border border-border overflow-hidden h-10">
98-
<button
99-
type="button"
100-
className="flex items-center px-3 h-full text-muted-foreground hover:text-foreground hover:bg-muted border-r border-border"
101-
onClick={(e) => {
102-
e.stopPropagation();
103-
router.push("/wallets/new-wallet-flow/save");
104-
}}
105-
>
106-
<Plus className="h-5 w-5" />
107-
</button>
108-
<div className="flex items-center px-3 h-full hover:bg-muted cursor-pointer">
102+
// Mobile: Plus Button außerhalb des Dropdown Triggers
103+
<div className="flex items-center rounded-md border border-border overflow-hidden h-10 w-full">
104+
<button
105+
type="button"
106+
className="flex items-center px-3 h-full text-muted-foreground hover:text-foreground hover:bg-muted border-r border-border"
107+
onClick={() => {
108+
router.push("/wallets/new-wallet-flow/save");
109+
onPlusClick?.();
110+
}}
111+
>
112+
<Plus className="h-5 w-5" />
113+
</button>
114+
<DropdownMenu open={open} onOpenChange={setOpen}>
115+
<DropdownMenuTrigger asChild>
116+
<div className="flex items-center px-3 h-full hover:bg-muted cursor-pointer w-full min-w-0">
109117
{open ? (
110-
<ChevronUp className="h-5 w-5" />
118+
<ChevronUp className="h-5 w-5 flex-shrink-0" />
111119
) : (
112-
<ChevronDown className="h-5 w-5" />
120+
<ChevronDown className="h-5 w-5 flex-shrink-0" />
113121
)}
114-
<span className="flex items-center ml-2">
122+
<span className="ml-2 min-w-0 flex-1 truncate text-left" title={appWallet?.name || "Select Wallet"}>
115123
{appWallet?.name || "Select Wallet"}
116124
</span>
117-
<Wallet2 className="mx-2 h-4 w-4" />
125+
<Wallet2 className="mx-2 h-4 w-4 flex-shrink-0" />
118126
</div>
119-
</div>
120-
</DropdownMenuTrigger>
127+
</DropdownMenuTrigger>
121128
<DropdownMenuContent
122129
align="center"
123130
className="mt-2 p-2 mx-4 max-w-[calc(100vw-2rem)]"
@@ -138,7 +145,8 @@ export default function WalletDropDown() {
138145
<WalletNavLink wallet={wallet} />
139146
</DropdownMenuItem>
140147
))}
141-
</DropdownMenuContent>
142-
</DropdownMenu>
148+
</DropdownMenuContent>
149+
</DropdownMenu>
150+
</div>
143151
);
144152
}

src/components/pages/homepage/wallets/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function PageWallets() {
3636
);
3737

3838
return (
39-
<>
39+
<div className="flex flex-col gap-4">
4040
<>
4141
<PageHeader pageTitle="Wallets">
4242
<Button size="sm" asChild>
@@ -97,7 +97,7 @@ export default function PageWallets() {
9797
{getUserNewWalletsNotOwner && getUserNewWalletsNotOwner.length > 0 && (
9898
<>
9999
<SectionTitle>
100-
Wallets you are invited and pending creation
100+
New Wallets awaiting creation
101101
</SectionTitle>
102102
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
103103
{getUserNewWalletsNotOwner
@@ -109,7 +109,7 @@ export default function PageWallets() {
109109
</>
110110
)}
111111
</>
112-
</>
112+
</div>
113113
);
114114
}
115115

@@ -162,7 +162,7 @@ function CardWalletInvite({
162162
<Link
163163
href={
164164
viewOnly
165-
? `/wallets/invite/info/${wallet.id}`
165+
? `/wallets/invite/${wallet.id}`
166166
: `/wallets/new-wallet-flow/create/${wallet.id}`
167167
}
168168
>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React from "react";
2+
import {
3+
Card,
4+
CardContent,
5+
CardHeader,
6+
CardTitle,
7+
} from "@/components/ui/card";
8+
import { Button } from "@/components/ui/button";
9+
import { Input } from "@/components/ui/input";
10+
import { Label } from "@/components/ui/label";
11+
12+
const MAX_SIGNER_NAME_LENGTH = 32;
13+
14+
interface JoinAsSignerCardProps {
15+
userAddress: string;
16+
stakeAddress: string;
17+
signerName: string;
18+
setSignerName: (name: string) => void;
19+
onJoin: () => void;
20+
loading: boolean;
21+
}
22+
23+
export default function JoinAsSignerCard({
24+
userAddress,
25+
stakeAddress,
26+
signerName,
27+
setSignerName,
28+
onJoin,
29+
loading
30+
}: JoinAsSignerCardProps) {
31+
return (
32+
<Card>
33+
<CardHeader>
34+
<CardTitle>Your Signer Info</CardTitle>
35+
</CardHeader>
36+
<CardContent>
37+
<div className="bg-muted/30 rounded-lg p-6">
38+
{/* Name Field - Editable */}
39+
<div className="grid sm:grid-cols-[120px_1fr] gap-2 sm:gap-4 items-start">
40+
<Label htmlFor="signerName" className="text-sm font-medium sm:pt-2">
41+
Your name <span className="text-gray-500 font-normal">(recommended)</span>
42+
</Label>
43+
<div className="space-y-2">
44+
<Input
45+
id="signerName"
46+
type="text"
47+
value={signerName}
48+
placeholder="John"
49+
onChange={(e) => {
50+
if (e.target.value.length <= MAX_SIGNER_NAME_LENGTH) {
51+
setSignerName(e.target.value);
52+
}
53+
}}
54+
/>
55+
<div className="space-y-1">
56+
<div className={`text-xs ${signerName.length >= MAX_SIGNER_NAME_LENGTH ? 'text-amber-600' : 'text-gray-500'}`}>
57+
<span>
58+
{signerName.length}/{MAX_SIGNER_NAME_LENGTH} characters
59+
</span>
60+
</div>
61+
<p className="text-xs text-gray-500">
62+
This helps other signers identify you in the wallet
63+
</p>
64+
</div>
65+
</div>
66+
</div>
67+
</div>
68+
</CardContent>
69+
</Card>
70+
);
71+
}

0 commit comments

Comments
 (0)