diff --git a/src/frontend/src/lib/components/exchange/ExchangeBalance.svelte b/src/frontend/src/lib/components/exchange/ExchangeBalance.svelte
index 27051ee5d3..d24dafd353 100644
--- a/src/frontend/src/lib/components/exchange/ExchangeBalance.svelte
+++ b/src/frontend/src/lib/components/exchange/ExchangeBalance.svelte
@@ -1,4 +1,5 @@
@@ -55,7 +59,9 @@
{/if}
-
+ {#if sendAction}
+
+ {/if}
{#if isTransactionsPage}
{#if convertEth}
diff --git a/src/frontend/src/lib/derived/balances.derived.ts b/src/frontend/src/lib/derived/balances.derived.ts
index a74f7f3f1d..a9f413fcf3 100644
--- a/src/frontend/src/lib/derived/balances.derived.ts
+++ b/src/frontend/src/lib/derived/balances.derived.ts
@@ -1,6 +1,7 @@
import { balancesStore } from '$lib/stores/balances.store';
import { token } from '$lib/stores/token.store';
import type { OptionBalance } from '$lib/types/balance';
+import { checkAnyNonZeroBalance } from '$lib/utils/balances.utils';
import { nonNullish } from '@dfinity/utils';
import { derived, type Readable } from 'svelte/store';
@@ -17,3 +18,7 @@ export const balanceZero: Readable = derived(
nonNullish($balanceStore?.[$token.id]) &&
$balanceStore[$token.id]?.data.isZero() === true
);
+
+export const anyBalanceNonZero: Readable = derived([balancesStore], ([$balanceStore]) =>
+ checkAnyNonZeroBalance($balanceStore)
+);
diff --git a/src/frontend/src/lib/i18n/en.json b/src/frontend/src/lib/i18n/en.json
index e6897bf950..38f67a379c 100644
--- a/src/frontend/src/lib/i18n/en.json
+++ b/src/frontend/src/lib/i18n/en.json
@@ -182,6 +182,7 @@
"hero": {
"text": {
"available_balance": "Available balance",
+ "top_up": "Top up your wallet to start using it!",
"learn_more_about_erc20_icp": "Learn more about ERC20 ICP on Ethereum."
}
},
diff --git a/src/frontend/src/lib/types/i18n.d.ts b/src/frontend/src/lib/types/i18n.d.ts
index d0b707957f..ee5eb8ee4f 100644
--- a/src/frontend/src/lib/types/i18n.d.ts
+++ b/src/frontend/src/lib/types/i18n.d.ts
@@ -160,7 +160,7 @@ interface I18nInit {
}
interface I18nHero {
- text: { available_balance: string; learn_more_about_erc20_icp: string };
+ text: { available_balance: string; top_up: string; learn_more_about_erc20_icp: string };
}
interface I18nSettings {
diff --git a/src/frontend/src/lib/utils/balances.utils.ts b/src/frontend/src/lib/utils/balances.utils.ts
new file mode 100644
index 0000000000..9141462abe
--- /dev/null
+++ b/src/frontend/src/lib/utils/balances.utils.ts
@@ -0,0 +1,10 @@
+import { type BalancesData } from '$lib/stores/balances.store';
+import type { CertifiedStoreData } from '$lib/stores/certified.store';
+import type { TokenId } from '$lib/types/token';
+import { nonNullish } from '@dfinity/utils';
+
+export const checkAnyNonZeroBalance = ($balancesStore: CertifiedStoreData): boolean =>
+ nonNullish($balancesStore) &&
+ Object.getOwnPropertySymbols($balancesStore).some(
+ (tokenId) => !($balancesStore[tokenId as TokenId]?.data?.isZero() ?? true)
+ );
diff --git a/src/frontend/src/tests/lib/utils/balances.utils.spec.ts b/src/frontend/src/tests/lib/utils/balances.utils.spec.ts
new file mode 100644
index 0000000000..6fed121b2b
--- /dev/null
+++ b/src/frontend/src/tests/lib/utils/balances.utils.spec.ts
@@ -0,0 +1,60 @@
+import { ZERO } from '$lib/constants/app.constants';
+import type { BalancesData } from '$lib/stores/balances.store';
+import type { CertifiedStoreData } from '$lib/stores/certified.store';
+import { checkAnyNonZeroBalance } from '$lib/utils/balances.utils';
+import { bn1 } from '$tests/mocks/balances.mock';
+
+describe('checkAnyNonZeroBalance', () => {
+ it('should return true if there is at least one non-zero balance', () => {
+ const mockBalancesStore: CertifiedStoreData = {
+ [Symbol('token1')]: { data: bn1 },
+ [Symbol('token2')]: { data: ZERO }
+ } as unknown as CertifiedStoreData;
+
+ expect(checkAnyNonZeroBalance(mockBalancesStore)).toBe(true);
+ });
+
+ it('should return true if there is at least one non-zero balance and one nullish balance', () => {
+ const mockBalancesStore = {
+ [Symbol('token1')]: { data: bn1 },
+ [Symbol('token2')]: undefined
+ } as unknown as CertifiedStoreData;
+
+ expect(checkAnyNonZeroBalance(mockBalancesStore)).toBe(true);
+ });
+
+ it('should return false if all balances are zero', () => {
+ const mockBalancesStore = {
+ [Symbol('token1')]: { data: ZERO },
+ [Symbol('token2')]: { data: ZERO }
+ } as unknown as CertifiedStoreData;
+
+ expect(checkAnyNonZeroBalance(mockBalancesStore)).toBe(false);
+ });
+
+ it('should return false if balances data are nullish', () => {
+ const mockBalancesStore = {
+ [Symbol('token1')]: { data: null },
+ [Symbol('token2')]: { data: undefined }
+ } as unknown as CertifiedStoreData;
+
+ expect(checkAnyNonZeroBalance(mockBalancesStore)).toBe(false);
+ });
+
+ it('should return false if balances are nullish', () => {
+ const mockBalancesStore = {
+ [Symbol('token1')]: null,
+ [Symbol('token2')]: undefined
+ } as unknown as CertifiedStoreData;
+
+ expect(checkAnyNonZeroBalance(mockBalancesStore)).toBe(false);
+ });
+
+ it('should return false if store is empty', () => {
+ expect(checkAnyNonZeroBalance({} as unknown as CertifiedStoreData)).toBe(false);
+ });
+
+ it('should return false if store is not initialized', () => {
+ expect(checkAnyNonZeroBalance(undefined)).toBe(false);
+ });
+});