From 40accaa7601fe8a6040dfc9c424b1cf4a2092080 Mon Sep 17 00:00:00 2001 From: IHUOMA NKECHI BRIDGET Date: Tue, 28 Jul 2026 02:11:33 +0100 Subject: [PATCH] Harden wallet address handling in dashboard --- apps/dashboard/app/members/page.tsx | 50 ++++++++- .../components/WalletAddressText.tsx | 9 +- apps/dashboard/lib/address.ts | 19 ++++ apps/dashboard/lib/clipboard.ts | 9 ++ apps/dashboard/test/address.test.ts | 102 ++++++++++++++++++ apps/dashboard/test/clipboard.test.ts | 69 ++++++++++++ 6 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 apps/dashboard/lib/clipboard.ts create mode 100644 apps/dashboard/test/address.test.ts create mode 100644 apps/dashboard/test/clipboard.test.ts diff --git a/apps/dashboard/app/members/page.tsx b/apps/dashboard/app/members/page.tsx index dfd0bee..11e55ed 100644 --- a/apps/dashboard/app/members/page.tsx +++ b/apps/dashboard/app/members/page.tsx @@ -8,6 +8,7 @@ import StatusBadge from "@/components/StatusBadge"; import WalletAddressText from "@/components/WalletAddressText"; import UnsupportedBanner from "@/components/UnsupportedBanner"; import { ApiClientError, readApiResult } from "@/lib/api-client"; +import { tryNormaliseAddress } from "@/lib/address"; import { getClientApiMode } from "@/lib/client-env"; import { useSession } from "@/lib/hooks/useSession"; import { useOptimisticMutation } from "@/lib/hooks/useOptimisticMutation"; @@ -101,6 +102,7 @@ function MembersPageContent() { const [isInviteOpen, setIsInviteOpen] = useState(false); const [inviteLoading, setInviteLoading] = useState(false); const [form, setForm] = useState({ name: "", wallet: "" }); + const [walletError, setWalletError] = useState(null); const updateFilterQuery = useCallback( (updates: { search?: string; status?: MemberStatusFilter; role?: MemberRoleFilter; guild?: string; page?: number | null }) => { @@ -477,10 +479,33 @@ function MembersPageContent() {

Invite Member

setForm({ ...form, name: e.target.value })} className="w-full rounded-lg border border-slate-200 p-2" /> - setForm({ ...form, wallet: e.target.value })} className="w-full rounded-lg border border-slate-200 p-2" /> +
+ { + setForm({ ...form, wallet: e.target.value }); + if (walletError) setWalletError(null); + }} + aria-invalid={walletError ? true : undefined} + aria-describedby={walletError ? "invite-wallet-error" : undefined} + className={`w-full rounded-lg border p-2 ${walletError ? "border-red-400" : "border-slate-200"}`} + /> + {walletError && ( +

+ {walletError} +

+ )} +
-