Skip to content

Commit

Permalink
Non NNS wallet more popup (#5394)
Browse files Browse the repository at this point in the history
# Motivation

With the introduction of the import token feature, a new token popup
with additional actions was added. Each token will have two entries:
"View in Dashboard" and "Token Details". Imported tokens will have an
extra entry: "Remove".

In this PR, we’ve added a popup with buttons similar to those in the NNS
wallet popup, for the ICRC, CKBTC, and SNS wallets.

# Changes

- Wrap IcrcWalletPage with the TestIdWrapper.
- Display canister links popup in ICRC wallet page component (it's used
on ICRC, CKBTC, and SNS wallet pages).
- Provide indexCanisterId from Icrc, CkBTC and Sns wallet pages.

# Tests

- Extend setSnsProjects to add custom indexCanisterId for tests.
- Added tests that  ICRC, CKBTC, and SNS wallet pages have the links.
- Tested manually (also available on beta).

<img width="276" alt="image"
src="https://github.com/user-attachments/assets/eb6a3c8f-9d63-4fcf-8f46-a45e09eb36ef">


# Todos

- [ ] Add entry to changelog (if necessary).
Not necessary.
  • Loading branch information
mstrasinskis authored Sep 2, 2024
1 parent 43f0b7e commit 4c55d52
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 97 deletions.
127 changes: 78 additions & 49 deletions frontend/src/lib/components/accounts/IcrcWalletPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
hasAccounts,
} from "$lib/utils/accounts.utils";
import { replacePlaceholders } from "$lib/utils/i18n.utils";
import { Island, Spinner } from "@dfinity/gix-components";
import { IconDots, Island, Spinner } from "@dfinity/gix-components";
import type { Principal } from "@dfinity/principal";
import { TokenAmountV2, isNullish, nonNullish } from "@dfinity/utils";
import type { Writable } from "svelte/store";
import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store";
import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte";
import WalletMorePopover from "./WalletMorePopover.svelte";
export let testId: string;
export let accountIdentifier: string | undefined | null = undefined;
export let ledgerCanisterId: Principal | undefined;
export let indexCanisterId: Principal | undefined;
export let token: IcrcTokenMetadata | undefined = undefined;
export let selectedAccountStore: Writable<WalletStore>;
export let reloadTransactions: () => Promise<void>;
Expand Down Expand Up @@ -142,58 +146,83 @@
ledgerCanisterId,
isSignedIn: $authSignedInStore,
}))();
let moreButton: HTMLButtonElement | undefined;
let morePopupVisible = false;
</script>

<Island {testId}>
<main class="legacy">
<section>
{#if loaded && nonNullish(ledgerCanisterId)}
{#if nonNullish($selectedAccountStore.account) && nonNullish(token)}
<IcrcBalancesObserver
{ledgerCanisterId}
accounts={[$selectedAccountStore.account]}
reload={reloadOnlyAccountFromStore}
/>
{/if}
<WalletPageHeader
universe={$selectedUniverseStore}
walletAddress={$selectedAccountStore.account?.identifier}
/>
<WalletPageHeading
accountName={$selectedAccountStore.account?.name ??
$i18n.accounts.main}
balance={nonNullish($selectedAccountStore.account) &&
nonNullish(token)
? TokenAmountV2.fromUlps({
amount: $selectedAccountStore.account.balanceUlps,
token,
})
: undefined}
>
<slot name="header-actions" />
<SignInGuard />
</WalletPageHeading>

{#if $$slots["info-card"]}
<div class="content-cell-island info-card">
<slot name="info-card" />
<TestIdWrapper {testId}>
<Island>
<main class="legacy">
<section>
{#if loaded && nonNullish(ledgerCanisterId)}
{#if nonNullish($selectedAccountStore.account) && nonNullish(token)}
<IcrcBalancesObserver
{ledgerCanisterId}
accounts={[$selectedAccountStore.account]}
reload={reloadOnlyAccountFromStore}
/>
{/if}
<WalletPageHeader
universe={$selectedUniverseStore}
walletAddress={$selectedAccountStore.account?.identifier}
>
<svelte:fragment slot="actions">
{#if $ENABLE_IMPORT_TOKEN}
<button
bind:this={moreButton}
class="icon-only"
data-tid="more-button"
on:click={() => (morePopupVisible = true)}
>
<IconDots />
</button>
{/if}
</svelte:fragment>
</WalletPageHeader>
<WalletPageHeading
accountName={$selectedAccountStore.account?.name ??
$i18n.accounts.main}
balance={nonNullish($selectedAccountStore.account) &&
nonNullish(token)
? TokenAmountV2.fromUlps({
amount: $selectedAccountStore.account.balanceUlps,
token,
})
: undefined}
>
<slot name="header-actions" />
<SignInGuard />
</WalletPageHeading>

{#if $$slots["info-card"]}
<div class="content-cell-island info-card">
<slot name="info-card" />
</div>
{/if}

<Separator spacing="none" />

<!-- Transactions and the explanation go together. -->
<div>
<slot name="page-content" />
</div>
{:else}
<Spinner />
{/if}

<Separator spacing="none" />

<!-- Transactions and the explanation go together. -->
<div>
<slot name="page-content" />
</div>
{:else}
<Spinner />
{/if}
</section>
</main>

<slot name="footer-actions" />
</Island>
</section>
</main>

<slot name="footer-actions" />
</Island>

<WalletMorePopover
bind:visible={morePopupVisible}
anchor={moreButton}
{ledgerCanisterId}
{indexCanisterId}
/>
</TestIdWrapper>

<style lang="scss">
section {
Expand Down
42 changes: 42 additions & 0 deletions frontend/src/lib/components/accounts/WalletMorePopover.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import { i18n } from "$lib/stores/i18n";
import { Popover } from "@dfinity/gix-components";
import type { Principal } from "@dfinity/principal";
import { nonNullish } from "@dfinity/utils";
import LinkToDashboardCanister from "$lib/components/tokens/LinkToDashboardCanister.svelte";
import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte";
export let anchor: HTMLElement | undefined;
export let visible: boolean | undefined;
export let ledgerCanisterId: Principal | undefined;
export let indexCanisterId: Principal | undefined;
</script>

<TestIdWrapper testId="wallet-more-popover-component">
<Popover bind:visible {anchor} direction="rtl" invisibleBackdrop>
<div class="content">
{#if nonNullish(ledgerCanisterId)}
<LinkToDashboardCanister
testId="link-to-ledger-canister"
label={$i18n.tokens.ledger_canister}
canisterId={ledgerCanisterId}
/>
{/if}
{#if nonNullish(indexCanisterId)}
<LinkToDashboardCanister
testId="link-to-index-canister"
label={$i18n.tokens.index_canister}
canisterId={indexCanisterId}
/>
{/if}
</div>
</Popover>
</TestIdWrapper>

<style lang="scss">
.content {
display: flex;
flex-direction: column;
gap: var(--padding-2x);
}
</style>
1 change: 1 addition & 0 deletions frontend/src/lib/pages/CkBTCWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
{accountIdentifier}
token={token?.token}
ledgerCanisterId={$selectedCkBTCUniverseIdStore}
indexCanisterId={canisters?.indexCanisterId}
{selectedAccountStore}
bind:this={wallet}
{reloadTransactions}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/pages/IcrcWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
{accountIdentifier}
{token}
ledgerCanisterId={$selectedIcrcTokenUniverseIdStore}
{indexCanisterId}
{selectedAccountStore}
bind:this={wallet}
{reloadTransactions}
Expand Down
31 changes: 6 additions & 25 deletions frontend/src/lib/pages/NnsWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
mapToSelfTransactions,
sortTransactionsByIdDescendingOrder,
} from "$lib/utils/icp-transactions.utils";
import { IconDots, Island, Popover, Spinner } from "@dfinity/gix-components";
import { IconDots, Island, Spinner } from "@dfinity/gix-components";
import {
ICPToken,
TokenAmountV2,
Expand All @@ -68,12 +68,12 @@
} from "@dfinity/utils";
import { onMount, onDestroy, setContext } from "svelte";
import { writable, type Readable } from "svelte/store";
import LinkToDashboardCanister from "$lib/components/tokens/LinkToDashboardCanister.svelte";
import {
INDEX_CANISTER_ID,
LEDGER_CANISTER_ID,
} from "$lib/constants/canister-ids.constants";
import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store";
import WalletMorePopover from "$lib/components/accounts/WalletMorePopover.svelte";
$: if ($authSignedInStore) {
pollAccounts();
Expand Down Expand Up @@ -392,25 +392,12 @@
/>
{/if}

<Popover
<WalletMorePopover
bind:visible={morePopupVisible}
anchor={moreButton}
direction="rtl"
invisibleBackdrop
>
<div class="more">
<LinkToDashboardCanister
testId="link-to-ledger-canister"
label={$i18n.tokens.ledger_canister}
canisterId={LEDGER_CANISTER_ID}
/>
<LinkToDashboardCanister
testId="link-to-index-canister"
label={$i18n.tokens.index_canister}
canisterId={INDEX_CANISTER_ID}
/>
</div>
</Popover>
ledgerCanisterId={LEDGER_CANISTER_ID}
indexCanisterId={INDEX_CANISTER_ID}
/>
</TestIdWrapper>

<style lang="scss">
Expand All @@ -419,10 +406,4 @@
flex-direction: column;
gap: var(--padding-4x);
}
.more {
display: flex;
flex-direction: column;
gap: var(--padding-2x);
}
</style>
1 change: 1 addition & 0 deletions frontend/src/lib/pages/SnsWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
{accountIdentifier}
{token}
{ledgerCanisterId}
{indexCanisterId}
{selectedAccountStore}
bind:this={wallet}
{reloadTransactions}
Expand Down
22 changes: 21 additions & 1 deletion frontend/src/tests/lib/pages/CkBTCWallet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as ckbtcMinterApi from "$lib/api/ckbtc-minter.api";
import * as icrcIndexApi from "$lib/api/icrc-index.api";
import * as icrcLedgerApi from "$lib/api/icrc-ledger.api";
import {
CKTESTBTC_INDEX_CANISTER_ID,
CKTESTBTC_LEDGER_CANISTER_ID,
CKTESTBTC_UNIVERSE_CANISTER_ID,
} from "$lib/constants/ckbtc-canister-ids.constants";
Expand All @@ -18,6 +19,7 @@ import { page } from "$mocks/$app/stores";
import CkBTCAccountsTest from "$tests/lib/components/accounts/CkBTCAccountsTest.svelte";
import { resetIdentity, setNoIdentity } from "$tests/mocks/auth.store.mock";
import {
mockBTCAddressTestnet,
mockCkBTCMainAccount,
mockCkBTCToken,
} from "$tests/mocks/ckbtc-accounts.mock";
Expand All @@ -34,7 +36,6 @@ import {
import type { RetrieveBtcStatusV2WithId } from "@dfinity/ckbtc";
import { render, waitFor } from "@testing-library/svelte";
import { get } from "svelte/store";
import { mockBTCAddressTestnet } from "../../mocks/ckbtc-accounts.mock";

const expectedBalanceAfterTransfer = 11_111n;
const testnetBtcAddress = "mziXLoUuJs427ATrgn5bMdxtUnXZMZCc3L";
Expand Down Expand Up @@ -507,4 +508,23 @@ describe("CkBTCWallet", () => {
});
});
});

it('should have canister links in "more" popup', async () => {
const po = await renderWallet();
const morePopoverPo = po.getWalletMorePopoverPo();

await po.getMoreButton().click();
await runResolvedPromises();

expect(await morePopoverPo.isPresent()).toBe(true);
expect(await morePopoverPo.getLinkToLedgerCanisterPo().getHref()).toBe(
`https://dashboard.internetcomputer.org/canister/${CKTESTBTC_LEDGER_CANISTER_ID.toText()}`
);
expect(await morePopoverPo.getLinkToIndexCanisterPo().isPresent()).toBe(
true
);
expect(await morePopoverPo.getLinkToIndexCanisterPo().getHref()).toBe(
`https://dashboard.internetcomputer.org/canister/${CKTESTBTC_INDEX_CANISTER_ID.toText()}`
);
});
});
Loading

0 comments on commit 4c55d52

Please sign in to comment.