Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable import button on maximum #5557

Merged
merged 10 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@
"link_to_dashboard": "https://dashboard.internetcomputer.org/canister/$canisterId",
"add_index_canister": "Add Index Canister",
"add_index_description": "Transaction history is not available. To see this token’s transaction history in the NNS dapp, you need to provide an index canister. <strong>Note:</strong> not all tokens have index canisters.",
"failed_tooltip": "The NNS dapp couldn’t load an imported token. Please try again later, or contact the developers."
"failed_tooltip": "The NNS dapp couldn’t load an imported token. Please try again later, or contact the developers.",
"maximum_reached_tooltip": "You can import maximum $max tokens."
mstrasinskis marked this conversation as resolved.
Show resolved Hide resolved
}
}
49 changes: 39 additions & 10 deletions frontend/src/lib/pages/Tokens.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
import { i18n } from "$lib/stores/i18n";
import type { UserToken } from "$lib/types/tokens-page";
import { heightTransition } from "$lib/utils/transition.utils";
import { IconPlus, IconSettings } from "@dfinity/gix-components";
import { IconPlus, IconSettings, Tooltip } from "@dfinity/gix-components";
import { Popover } from "@dfinity/gix-components";
import { TokenAmountV2 } from "@dfinity/utils";
import { TokenAmountV2, nonNullish } from "@dfinity/utils";
import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store";
import ImportTokenModal from "$lib/modals/accounts/ImportTokenModal.svelte";
import { importedTokensStore } from "$lib/stores/imported-tokens.store";
import { MAX_IMPORTED_TOKENS } from "$lib/constants/imported-tokens.constants";
import { replacePlaceholders } from "$lib/utils/i18n.utils";

export let userTokensData: UserToken[];

Expand Down Expand Up @@ -43,6 +46,9 @@
};

let showImportTokenModal = false;
let maximumImportedTokensReached = false;
$: maximumImportedTokensReached =
($importedTokensStore.importedTokens?.length ?? 0) >= MAX_IMPORTED_TOKENS;

// TODO(Import token): After removing ENABLE_IMPORT_TOKEN combine divs -> <div slot="last-row" class="last-row">
</script>
Expand All @@ -63,7 +69,7 @@
>
</div>
<div slot="last-row">
{#if $ENABLE_IMPORT_TOKEN}
{#if $ENABLE_IMPORT_TOKEN && nonNullish($importedTokensStore.importedTokens)}
<div class="last-row">
{#if shouldHideZeroBalances}
<div class="show-all-button-container">
Expand All @@ -78,13 +84,32 @@
</div>
{/if}

<button
data-tid="import-token-button"
class="ghost with-icon import-token-button"
on:click={() => (showImportTokenModal = true)}
>
<IconPlus />{$i18n.import_token.import_token}
</button>
{#if maximumImportedTokensReached}
mstrasinskis marked this conversation as resolved.
Show resolved Hide resolved
<Tooltip
testId="maximum-imported-tokens-tooltip"
text={replacePlaceholders(
$i18n.import_token.maximum_reached_tooltip,
{ $max: `${MAX_IMPORTED_TOKENS}` }
)}
>
<button
data-tid="import-token-button"
class="ghost with-icon import-token-button"
disabled
>
<IconPlus />{$i18n.import_token.import_token}
</button>
</Tooltip>
{:else}
<button
data-tid="import-token-button"
class="ghost with-icon import-token-button"
on:click={() => (showImportTokenModal = true)}
disabled={maximumImportedTokensReached}
>
<IconPlus />{$i18n.import_token.import_token}
</button>
{/if}
</div>
{:else if shouldHideZeroBalances}
<div
Expand Down Expand Up @@ -183,6 +208,10 @@
.import-token-button {
gap: var(--padding);
color: var(--primary);

&:disabled {
color: var(--button-disable-color);
}
}
}
</style>
1 change: 1 addition & 0 deletions frontend/src/lib/types/i18n.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@ interface I18nImport_token {
add_index_canister: string;
add_index_description: string;
failed_tooltip: string;
maximum_reached_tooltip: string;
}

interface I18nNeuron_state {
Expand Down
45 changes: 44 additions & 1 deletion frontend/src/tests/lib/pages/Tokens.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { MAX_IMPORTED_TOKENS } from "$lib/constants/imported-tokens.constants";
import { NNS_TOKEN_DATA } from "$lib/constants/tokens.constants";
import TokensPage from "$lib/pages/Tokens.svelte";
import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store";
import { hideZeroBalancesStore } from "$lib/stores/hide-zero-balances.store";
import { importedTokensStore } from "$lib/stores/imported-tokens.store";
import type { UserTokenData } from "$lib/types/tokens-page";
import { UnavailableTokenAmount } from "$lib/utils/token.utils";
import { mockSnsToken, principal } from "$tests/mocks/sns-projects.mock";
Expand All @@ -12,7 +14,10 @@ import {
} from "$tests/mocks/tokens-page.mock";
import { TokensPagePo } from "$tests/page-objects/TokensPage.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import { advanceTime } from "$tests/utils/timers.test-utils";
import {
advanceTime,
runResolvedPromises,
} from "$tests/utils/timers.test-utils";
import { TokenAmountV2 } from "@dfinity/utils";
import { render } from "@testing-library/svelte";

Expand Down Expand Up @@ -65,6 +70,8 @@ describe("Tokens page", () => {
overrideFeatureFlagsStore.reset();
hideZeroBalancesStore.resetForTesting();
vi.useFakeTimers();

importedTokensStore.set({ importedTokens: [], certified: true });
});

it("should render the tokens table", async () => {
Expand Down Expand Up @@ -213,6 +220,42 @@ describe("Tokens page", () => {
expect(await po.getImportTokenButtonPo().isPresent()).toBe(true);
});

it("should not display import token button before imported tokens are available", async () => {
importedTokensStore.reset();
const po = renderPage([]);

expect(await po.getImportTokenButtonPo().isPresent()).toBe(false);

importedTokensStore.set({ importedTokens: [], certified: true });
await runResolvedPromises();
expect(await po.getImportTokenButtonPo().isPresent()).toBe(true);
});

it("should disable import token button when maximum imported", async () => {
const setImportedTokens = (count: number) =>
importedTokensStore.set({
importedTokens: Array.from({ length: count }, (_, i) => ({
ledgerCanisterId: principal(i),
indexCanisterId: undefined,
})),
certified: true,
});

setImportedTokens(MAX_IMPORTED_TOKENS - 1);
const po = renderPage([]);

mstrasinskis marked this conversation as resolved.
Show resolved Hide resolved
expect(await po.getImportTokenButtonPo().isPresent()).toBe(true);
expect(await po.getImportTokenButtonPo().isDisabled()).toBe(false);

setImportedTokens(MAX_IMPORTED_TOKENS);
await runResolvedPromises();
expect(await po.getImportTokenButtonPo().isDisabled()).toBe(true);

setImportedTokens(MAX_IMPORTED_TOKENS + 1);
await runResolvedPromises();
expect(await po.getImportTokenButtonPo().isDisabled()).toBe(true);
});

it("should open import token modal", async () => {
const po = renderPage([positiveBalance, zeroBalance]);

Expand Down