diff --git a/.gitignore b/.gitignore index 8f322f0..9c289b9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ # misc .DS_Store +.vscode *.pem # debug diff --git a/components/dataViews/AccountView/BalancePill.tsx b/components/dataViews/AccountView/BalancePill.tsx deleted file mode 100644 index c0df9a7..0000000 --- a/components/dataViews/AccountView/BalancePill.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { printableCoin } from "@/lib/displayHelpers"; -import { Coin } from "@cosmjs/amino"; -import { useChains } from "../../../context/ChainsContext"; -import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"; -import { Badge } from "../../ui/badge"; - -interface BalancePillProps { - readonly coin: Coin; -} - -export default function BalancePill({ coin }: BalancePillProps) { - const { chain } = useChains(); - - const foundAsset = chain.assets.find((asset) => asset.base === coin.denom); - const logo = foundAsset?.logo_URIs?.svg || foundAsset?.logo_URIs?.png || ""; - const macroCoin = printableCoin(coin, chain); - - return ( - - - - - {coin.denom.slice(1, 2).toUpperCase()} - - - {macroCoin} - - ); -} diff --git a/components/dataViews/AccountView/BalancesList.tsx b/components/dataViews/AccountView/BalancesList.tsx deleted file mode 100644 index 7c1a023..0000000 --- a/components/dataViews/AccountView/BalancesList.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { toastError } from "@/lib/utils"; -import { Coin } from "@cosmjs/amino"; -import { StargateClient } from "@cosmjs/stargate"; -import { useEffect, useState } from "react"; -import { useChains } from "../../../context/ChainsContext"; -import BalancePill from "./BalancePill"; - -interface BalancesListProps { - readonly walletAddress: string; -} - -export default function BalancesList({ walletAddress }: BalancesListProps) { - const { chain } = useChains(); - const [balances, setBalances] = useState([]); - - useEffect(() => { - (async function () { - if (!walletAddress) { - return; - } - - try { - const client = await StargateClient.connect(chain.nodeAddress); - const newBalances = await client.getAllBalances(walletAddress); - setBalances(newBalances); - } catch (e) { - console.error("Failed to get balances:", e); - toastError({ - description: "Failed to get balances", - fullError: e instanceof Error ? e : undefined, - }); - } - })(); - }, [chain.nodeAddress, walletAddress]); - - return balances.length ? ( - - - Balances - - - {balances.map((coin) => ( - - ))} - - - ) : null; -} diff --git a/components/dataViews/AccountView/BalancesTable.tsx b/components/dataViews/AccountView/BalancesTable.tsx new file mode 100644 index 0000000..b52c1c3 --- /dev/null +++ b/components/dataViews/AccountView/BalancesTable.tsx @@ -0,0 +1,66 @@ +import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table"; +import { printableCoin, thinSpace } from "@/lib/displayHelpers"; +import { toastError } from "@/lib/utils"; +import { Coin } from "@cosmjs/amino"; +import { StargateClient } from "@cosmjs/stargate"; +import { useEffect, useState } from "react"; +import { useChains } from "../../../context/ChainsContext"; +import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"; + +interface BalancesTableProps { + readonly walletAddress: string; +} + +export default function BalancesTable({ walletAddress }: BalancesTableProps) { + const { chain } = useChains(); + const [balances, setBalances] = useState([]); + + useEffect(() => { + (async function () { + if (!walletAddress) { + return; + } + + try { + const client = await StargateClient.connect(chain.nodeAddress); + const newBalances = await client.getAllBalances(walletAddress); + setBalances(newBalances); + } catch (e) { + console.error("Failed to get balances:", e); + toastError({ + description: "Failed to get balances", + fullError: e instanceof Error ? e : undefined, + }); + } + })(); + }, [chain.nodeAddress, walletAddress]); + + return balances.length ? ( + + + {balances.map((coin) => { + const foundAsset = chain.assets.find((asset) => asset.base === coin.denom); + const logo = foundAsset?.logo_URIs?.svg || foundAsset?.logo_URIs?.png || ""; + const [macroAmount, macroDenom] = printableCoin(coin, chain).split(thinSpace); + + return ( + + + + + + {coin.denom.slice(1, 2).toUpperCase()} + + + + {macroDenom} + {macroAmount} + + ); + })} + +
+ ) : ( + "No tokens found" + ); +} diff --git a/components/dataViews/AccountView/ButtonConnectWallet.tsx b/components/dataViews/AccountView/ButtonConnectWallet.tsx index 54bb960..9aad8f8 100644 --- a/components/dataViews/AccountView/ButtonConnectWallet.tsx +++ b/components/dataViews/AccountView/ButtonConnectWallet.tsx @@ -1,10 +1,10 @@ -import { toastError } from "@/lib/utils"; +import { cn, toastError } from "@/lib/utils"; import { LoadingStates, WalletInfo, WalletType } from "@/types/signing"; import { makeCosmoshubPath } from "@cosmjs/amino"; import { toBase64 } from "@cosmjs/encoding"; import { LedgerSigner } from "@cosmjs/ledger-amino"; import TransportWebUSB from "@ledgerhq/hw-transport-webusb"; -import { Loader2 } from "lucide-react"; +import { Loader2, Unplug } from "lucide-react"; import Image from "next/image"; import { Dispatch, SetStateAction, useCallback, useLayoutEffect, useState } from "react"; import { useChains } from "../../../context/ChainsContext"; @@ -108,17 +108,27 @@ export default function ButtonConnectWallet({ const isLoading = (walletType === "Keplr" && loading.keplr) || (walletType === "Ledger" && loading.ledger); - return ( - + ) : ( + - ) : null} - -
-

Public key

- -
- - ) : null} - - {walletInfo?.type ? ( - - ) : ( -
- - -
- )} -
+ +
+ + +
+
{walletInfo?.address ? ( - + + + Account info + + +
{ + copy(walletInfo.address); + toast(`Copied address to clipboard`, { description: walletInfo.address }); + }} + className=" flex items-center space-x-4 rounded-md border p-4 transition-colors hover:cursor-pointer hover:bg-muted/50" + > + +
+

Address

+

{walletInfo.address}

+
+
+
{ + copy(walletInfo.pubKey); + toast(`Copied public key to clipboard`, { description: walletInfo.pubKey }); + }} + className=" flex items-center space-x-4 rounded-md border p-4 transition-colors hover:cursor-pointer hover:bg-muted/50" + > + +
+

Public key

+

{walletInfo.pubKey}

+
+
+ {explorerLink ? ( + + ) : null} +
+
+ ) : null} + {walletInfo?.address ? ( + + + Balances + + Your list of tokens on {chain.chainDisplayName || "Cosmos Hub"} + + + + + + ) : null} ); diff --git a/components/forms/FindMultisigForm.tsx b/components/forms/FindMultisigForm.tsx index c5f4d22..dc544d5 100644 --- a/components/forms/FindMultisigForm.tsx +++ b/components/forms/FindMultisigForm.tsx @@ -59,7 +59,7 @@ const FindMultisigForm = ({ router }: FindMultisigFormProps) => { return ( - Already have a {chain.chainDisplayName || "Cosmos Hub"} multisig? + Already have a multisig on {chain.chainDisplayName || "Cosmos Hub"}? Enter its address below to view its transactions and create new ones. diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..71a5c32 --- /dev/null +++ b/components/ui/breadcrumb.tsx @@ -0,0 +1,115 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode + } +>(({ ...props }, ref) =>