diff --git a/apps/wallet-dashboard/components/Coins/CoinItem.tsx b/apps/wallet-dashboard/components/Coins/CoinItem.tsx
deleted file mode 100644
index a055f87def1..00000000000
--- a/apps/wallet-dashboard/components/Coins/CoinItem.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2024 IOTA Stiftung
-// SPDX-License-Identifier: Apache-2.0
-
-import { useFormatCoin } from '@iota/core';
-import React from 'react';
-
-interface CoinItemProps {
- coinType: string;
- balance: bigint;
- onClick?: () => void;
-}
-
-function CoinItem({ coinType, balance, onClick }: CoinItemProps): React.JSX.Element {
- const [formattedCoin, coinSymbol, { data: coinMeta }] = useFormatCoin(balance, coinType);
-
- return (
-
-
-
- {coinMeta?.name}
-
-
-
- {formattedCoin} {coinSymbol}
-
-
-
-
- );
-}
-
-export default CoinItem;
diff --git a/apps/wallet-dashboard/components/Coins/MyCoins.tsx b/apps/wallet-dashboard/components/Coins/MyCoins.tsx
deleted file mode 100644
index 6fb6e8eed49..00000000000
--- a/apps/wallet-dashboard/components/Coins/MyCoins.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2024 IOTA Stiftung
-// SPDX-License-Identifier: Apache-2.0
-
-import React from 'react';
-import { useCurrentAccount, useIotaClientQuery } from '@iota/dapp-kit';
-import { CoinItem, SendCoinPopup } from '@/components';
-import { usePopups } from '@/hooks';
-import { CoinBalance } from '@iota/iota-sdk/client';
-import {
- COINS_QUERY_REFETCH_INTERVAL,
- COINS_QUERY_STALE_TIME,
- filterAndSortTokenBalances,
- useSortedCoinsByCategories,
-} from '@iota/core';
-
-function MyCoins(): React.JSX.Element {
- const { openPopup, closePopup } = usePopups();
- const account = useCurrentAccount();
- const activeAccountAddress = account?.address;
-
- const { data: coinBalances } = useIotaClientQuery(
- 'getAllBalances',
- { owner: activeAccountAddress! },
- {
- enabled: !!activeAccountAddress,
- staleTime: COINS_QUERY_STALE_TIME,
- refetchInterval: COINS_QUERY_REFETCH_INTERVAL,
- select: filterAndSortTokenBalances,
- },
- );
- const { recognized, unrecognized } = useSortedCoinsByCategories(coinBalances ?? []);
-
- function openSendTokenPopup(coin: CoinBalance, address: string): void {
- if (coinBalances) {
- openPopup(
- ,
- );
- }
- }
-
- return (
-
-
My Coins:
- {recognized?.map((coin, index) => {
- return (
- openSendTokenPopup(coin, account?.address ?? '')}
- />
- );
- })}
- Unrecognized coins
- {unrecognized?.map((coin, index) => {
- return (
- openSendTokenPopup(coin, account?.address ?? '')}
- />
- );
- })}
-
- );
-}
-
-export default MyCoins;
diff --git a/apps/wallet-dashboard/components/ImageIcon.tsx b/apps/wallet-dashboard/components/ImageIcon.tsx
new file mode 100644
index 00000000000..06939516971
--- /dev/null
+++ b/apps/wallet-dashboard/components/ImageIcon.tsx
@@ -0,0 +1,80 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+import { useState } from 'react';
+import Image from 'next/image';
+import cn from 'clsx';
+
+export enum ImageIconSize {
+ Small = 'w-5 h-5',
+ Medium = 'w-8 h-8',
+ Large = 'w-10 h-10',
+ Full = 'w-full h-full',
+}
+
+interface FallBackAvatarProps {
+ text: string;
+ rounded?: boolean;
+ size?: ImageIconSize;
+}
+function FallBackAvatar({ text, rounded, size = ImageIconSize.Large }: FallBackAvatarProps) {
+ const textSize = (() => {
+ switch (size) {
+ case ImageIconSize.Small:
+ return 'text-label-sm';
+ case ImageIconSize.Medium:
+ return 'text-label-md';
+ case ImageIconSize.Large:
+ return 'text-title-md';
+ case ImageIconSize.Full:
+ return 'text-title-lg';
+ }
+ })();
+
+ return (
+
+ {text.slice(0, 2)}
+
+ );
+}
+export interface ImageIconProps {
+ src: string | null | undefined;
+ label: string;
+ fallbackText: string;
+ alt?: string;
+ rounded?: boolean;
+ size?: ImageIconSize;
+}
+
+export function ImageIcon({
+ src,
+ label,
+ alt = label,
+ fallbackText,
+ rounded,
+ size,
+}: ImageIconProps) {
+ const [error, setError] = useState(false);
+ return (
+
+ {error || !src ? (
+
+ ) : (
+ setError(true)}
+ layout="fill"
+ objectFit="cover"
+ />
+ )}
+
+ );
+}
diff --git a/apps/wallet-dashboard/components/coins/CoinIcon.tsx b/apps/wallet-dashboard/components/coins/CoinIcon.tsx
new file mode 100644
index 00000000000..a5c24107baa
--- /dev/null
+++ b/apps/wallet-dashboard/components/coins/CoinIcon.tsx
@@ -0,0 +1,45 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+import { useCoinMetadata } from '@iota/core';
+import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
+import { IotaLogoMark } from '@iota/ui-icons';
+import cx from 'clsx';
+import { ImageIcon, ImageIconSize } from '../ImageIcon';
+
+interface NonIotaCoinProps {
+ coinType: string;
+ size?: ImageIconSize;
+ rounded?: boolean;
+}
+
+function NonIotaCoin({ coinType, size = ImageIconSize.Full, rounded }: NonIotaCoinProps) {
+ const { data: coinMeta } = useCoinMetadata(coinType);
+ return (
+
+
+
+ );
+}
+
+export interface CoinIconProps {
+ coinType: string;
+ size?: ImageIconSize;
+ rounded?: boolean;
+}
+
+export function CoinIcon({ coinType, size = ImageIconSize.Full, rounded }: CoinIconProps) {
+ return coinType === IOTA_TYPE_ARG ? (
+
+
+
+ ) : (
+
+ );
+}
diff --git a/apps/wallet-dashboard/components/coins/CoinItem.tsx b/apps/wallet-dashboard/components/coins/CoinItem.tsx
new file mode 100644
index 00000000000..29e8be5aa35
--- /dev/null
+++ b/apps/wallet-dashboard/components/coins/CoinItem.tsx
@@ -0,0 +1,61 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+import {
+ Card,
+ CardAction,
+ CardActionType,
+ CardBody,
+ CardImage,
+ CardType,
+ ImageType,
+} from '@iota/apps-ui-kit';
+import { useFormatCoin } from '@iota/core';
+import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
+import { type ReactNode } from 'react';
+import { ImageIconSize } from '../ImageIcon';
+import { CoinIcon } from './CoinIcon';
+
+interface CoinItemProps {
+ coinType: string;
+ balance: bigint;
+ onClick?: () => void;
+ icon?: ReactNode;
+ clickableAction?: ReactNode;
+ usd?: number;
+}
+
+function CoinItem({
+ coinType,
+ balance,
+ onClick,
+ icon,
+ clickableAction,
+ usd,
+}: CoinItemProps): React.JSX.Element {
+ const [formatted, symbol, { data: coinMeta }] = useFormatCoin(balance, coinType);
+ const isIota = coinType === IOTA_TYPE_ARG;
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default CoinItem;
diff --git a/apps/wallet-dashboard/components/coins/MyCoins.tsx b/apps/wallet-dashboard/components/coins/MyCoins.tsx
new file mode 100644
index 00000000000..bf3a3d6a8f7
--- /dev/null
+++ b/apps/wallet-dashboard/components/coins/MyCoins.tsx
@@ -0,0 +1,145 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+import React, { useState } from 'react';
+import { useCurrentAccount, useIotaClientQuery } from '@iota/dapp-kit';
+import { CoinItem, SendCoinPopup } from '@/components';
+import { usePopups } from '@/hooks';
+import { CoinBalance } from '@iota/iota-sdk/client';
+import {
+ COINS_QUERY_REFETCH_INTERVAL,
+ COINS_QUERY_STALE_TIME,
+ filterAndSortTokenBalances,
+ useSortedCoinsByCategories,
+} from '@iota/core';
+import {
+ ButtonSegment,
+ Panel,
+ SegmentedButton,
+ SegmentedButtonType,
+ Title,
+} from '@iota/apps-ui-kit';
+import { RecognizedBadge } from '@iota/ui-icons';
+
+enum TokenCategory {
+ All = 'All',
+ Recognized = 'Recognized',
+ Unrecognized = 'Unrecognized',
+}
+
+const TOKEN_CATEGORIES = [
+ {
+ label: 'All',
+ value: TokenCategory.All,
+ },
+ {
+ label: 'Recognized',
+ value: TokenCategory.Recognized,
+ },
+ {
+ label: 'Unrecognized',
+ value: TokenCategory.Unrecognized,
+ },
+];
+
+function MyCoins(): React.JSX.Element {
+ const [selectedTokenCategory, setSelectedTokenCategory] = useState(TokenCategory.All);
+
+ const { openPopup, closePopup } = usePopups();
+ const account = useCurrentAccount();
+ const activeAccountAddress = account?.address;
+
+ const { data: coinBalances } = useIotaClientQuery(
+ 'getAllBalances',
+ { owner: activeAccountAddress! },
+ {
+ enabled: !!activeAccountAddress,
+ staleTime: COINS_QUERY_STALE_TIME,
+ refetchInterval: COINS_QUERY_REFETCH_INTERVAL,
+ select: filterAndSortTokenBalances,
+ },
+ );
+ const { recognized, unrecognized } = useSortedCoinsByCategories(coinBalances ?? []);
+
+ function openSendTokenPopup(coin: CoinBalance, address: string): void {
+ if (coinBalances) {
+ openPopup(
+ ,
+ );
+ }
+ }
+
+ return (
+
+
+
+
+
+
+ {TOKEN_CATEGORIES.map(({ label, value }) => {
+ const recognizedButEmpty =
+ value === TokenCategory.Recognized ? !recognized.length : false;
+ const notRecognizedButEmpty =
+ value === TokenCategory.Unrecognized
+ ? !unrecognized?.length
+ : false;
+
+ return (
+ setSelectedTokenCategory(value)}
+ label={label}
+ selected={selectedTokenCategory === value}
+ disabled={recognizedButEmpty || notRecognizedButEmpty}
+ />
+ );
+ })}
+
+
+
+ {[TokenCategory.All, TokenCategory.Recognized].includes(
+ selectedTokenCategory,
+ ) &&
+ recognized?.map((coin, index) => {
+ return (
+
+ openSendTokenPopup(coin, account?.address ?? '')
+ }
+ icon={
+
+ }
+ />
+ );
+ })}
+ {[TokenCategory.All, TokenCategory.Unrecognized].includes(
+ selectedTokenCategory,
+ ) &&
+ unrecognized?.map((coin, index) => {
+ return (
+
+ openSendTokenPopup(coin, account?.address ?? '')
+ }
+ />
+ );
+ })}
+
+
+
+
+ );
+}
+
+export default MyCoins;
diff --git a/apps/wallet-dashboard/components/Coins/index.ts b/apps/wallet-dashboard/components/coins/index.ts
similarity index 86%
rename from apps/wallet-dashboard/components/Coins/index.ts
rename to apps/wallet-dashboard/components/coins/index.ts
index d1519105eec..51468194c31 100644
--- a/apps/wallet-dashboard/components/Coins/index.ts
+++ b/apps/wallet-dashboard/components/coins/index.ts
@@ -3,3 +3,4 @@
export { default as MyCoins } from './MyCoins';
export { default as CoinItem } from './CoinItem';
+export * from './CoinIcon';
diff --git a/apps/wallet-dashboard/components/index.ts b/apps/wallet-dashboard/components/index.ts
index e7f010c273f..aff0cf01ce8 100644
--- a/apps/wallet-dashboard/components/index.ts
+++ b/apps/wallet-dashboard/components/index.ts
@@ -13,8 +13,9 @@ export { default as TransactionIcon } from './TransactionIcon';
export { default as Dropdown } from './Dropdown';
export * from './account-balance/AccountBalance';
-export * from './Coins';
+export * from './coins';
export * from './Popup';
export * from './AppList';
export * from './Cards';
export * from './Buttons';
+export * from './ImageIcon';