Skip to content

Commit

Permalink
Ledger neuron hotkey warning (#6061)
Browse files Browse the repository at this point in the history
# Motivation

To prevent missing rewards for ledger neurons, we display a warning on
the HW wallet page.

# Changes

- Add `LedgerNeuronHotkeyWarning` component.
- Display `LedgerNeuronHotkeyWarning` .

# Tests

- Added.
- Tested locally that the banner is closable.
<img width="744" alt="image"
src="https://github.com/user-attachments/assets/51b6fec2-3c57-4040-88d4-a07e4d190fbf"
/>

# Todos

- [ ] Add entry to changelog (if necessary).
Not necessary.
  • Loading branch information
mstrasinskis authored Dec 20, 2024
1 parent 37cc835 commit 8e54925
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import { browser } from "$app/environment";
import { i18n } from "$lib/stores/i18n";
import { IconInfo } from "@dfinity/gix-components";
import Banner from "../ui/Banner.svelte";
import BannerIcon from "../ui/BannerIcon.svelte";
import TestIdWrapper from "../common/TestIdWrapper.svelte";
const LOCAL_STORAGE_KEY = "isLedgerNeuronHotkeyWarningDisabled";
let isDismissed = browser
? Boolean(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) ?? "false"))
: false;
let isVisible = false;
$: isVisible = !isDismissed;
function dismissBanner() {
isDismissed = true;
localStorage.setItem(LOCAL_STORAGE_KEY, "true");
}
</script>

<TestIdWrapper testId="ledger-neuron-hotkey-warning-component">
{#if isVisible}
<Banner
isClosable
on:nnsClose={dismissBanner}
htmlText={$i18n.losing_rewards.hw_hotkey_warning}
>
<BannerIcon slot="icon">
<IconInfo />
</BannerIcon>
</Banner>
{/if}
</TestIdWrapper>
3 changes: 2 additions & 1 deletion frontend/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,8 @@
"losing_rewards": {
"description": "ICP neurons that are inactive for $period start missing voting rewards. To avoid missing rewards, vote manually, edit, or confirm your following.",
"confirming": "Confirming following. This may take a moment.",
"confirm": "Confirm Following"
"confirm": "Confirm Following",
"hw_hotkey_warning": "You may have neurons that are not added to the NNS dapp. If you want to view your neurons and get alerts in case they start missing voting rewards, you can add them by clicking <strong>Show Neurons > Add to NNS Dapp</strong>."
},
"losing_rewards_banner": {
"confirm_title": "Confirm following or vote manually to avoid missing rewards",
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/pages/NnsWallet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
} from "@dfinity/utils";
import { onDestroy, onMount, setContext } from "svelte";
import { writable, type Readable } from "svelte/store";
import { ENABLE_PERIODIC_FOLLOWING_CONFIRMATION } from "$lib/stores/feature-flags.store";
import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte";
$: if ($authSignedInStore) {
pollAccounts();
Expand Down Expand Up @@ -381,6 +383,10 @@
<SignInGuard />
</WalletPageHeading>

{#if $ENABLE_PERIODIC_FOLLOWING_CONFIRMATION && isHardwareWallet}
<LedgerNeuronHotkeyWarning />
{/if}

<Separator spacing="none" />

{#if $selectedAccountStore.account !== undefined}
Expand Down
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 @@ -408,6 +408,7 @@ interface I18nLosing_rewards {
description: string;
confirming: string;
confirm: string;
hw_hotkey_warning: string;
}

interface I18nLosing_rewards_banner {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte";
import { LedgerNeuronHotkeyWarningPo } from "$tests/page-objects/LedgerNeuronHotkeyWarning.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import { render } from "@testing-library/svelte";

describe("LedgerNeuronHotkeyWarning", () => {
const localStorageKey = "isLedgerNeuronHotkeyWarningDisabled";
const renderComponent = () => {
const { container } = render(LedgerNeuronHotkeyWarning);
return LedgerNeuronHotkeyWarningPo.under(
new JestPageObjectElement(container)
);
};

beforeEach(() => {
localStorage.clear();
});

it("should be shown when localStorageKey not set", async () => {
const po = await renderComponent();
expect(localStorage.getItem(localStorageKey)).toBeNull();

expect(await po.isBannerVisible()).toBe(true);
});

it("should not render when localStorageKey is set to true", async () => {
localStorage.setItem(localStorageKey, "true");
const po = await renderComponent();

expect(await po.isBannerVisible()).toBe(false);
});

it("should be closable", async () => {
const po = await renderComponent();

expect(await po.isBannerVisible()).toBe(true);
expect(localStorage.getItem(localStorageKey)).toBeNull();

await po.getBannerPo().clickClose();

expect(await po.isBannerVisible()).toBe(false);
expect(localStorage.getItem(localStorageKey)).toEqual("true");
});
});
36 changes: 36 additions & 0 deletions frontend/src/tests/lib/pages/NnsWallet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { AppPath } from "$lib/constants/routes.constants";
import { pageStore } from "$lib/derived/page.derived";
import NnsWallet from "$lib/pages/NnsWallet.svelte";
import { cancelPollAccounts } from "$lib/services/icp-accounts.services";
import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store";
import { icpTransactionsStore } from "$lib/stores/icp-transactions.store";
import { neuronsStore } from "$lib/stores/neurons.store";
import { getSwapCanisterAccount } from "$lib/utils/sns.utils";
Expand Down Expand Up @@ -408,6 +409,17 @@ describe("NnsWallet", () => {
expect(await po.getWalletPageHeadingPo().getTitle()).toBe("4.32 ICP");
});

it("should not render Ledger neuron hotkey warning for not HW wallet", async () => {
overrideFeatureFlagsStore.setFlag(
"ENABLE_PERIODIC_FOLLOWING_CONFIRMATION",
true
);
const po = await renderWallet(props);
expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(
false
);
});

it("should reload balance on open", async () => {
const oldBalance = 135_000_000n;
const oldBalanceFormatted = "1.35 ICP";
Expand Down Expand Up @@ -1008,6 +1020,30 @@ describe("NnsWallet", () => {
expect(await po.getShowHardwareWalletButtonPo().isPresent()).toBe(true);
});

it("should display Ledger neuron hotkey warning", async () => {
overrideFeatureFlagsStore.setFlag(
"ENABLE_PERIODIC_FOLLOWING_CONFIRMATION",
true
);
const po = await renderWallet(props);

expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(
true
);
});

it("should not display Ledger neuron hotkey warning when feature flag off", async () => {
overrideFeatureFlagsStore.setFlag(
"ENABLE_PERIODIC_FOLLOWING_CONFIRMATION",
false
);
const po = await renderWallet(props);

expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(
false
);
});

describe("when there are staking transactions", () => {
const neuronController = testHwPrincipal;
const memo = 54321n;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { BasePageObject } from "$tests/page-objects/base.page-object";
import type { PageObjectElement } from "$tests/types/page-object.types";
import { BannerPo } from "./Banner.page-object";

export class LedgerNeuronHotkeyWarningPo extends BasePageObject {
private static readonly TID = "ledger-neuron-hotkey-warning-component";

static under(element: PageObjectElement): LedgerNeuronHotkeyWarningPo {
return new LedgerNeuronHotkeyWarningPo(
element.byTestId(LedgerNeuronHotkeyWarningPo.TID)
);
}

getBannerPo(): BannerPo {
return BannerPo.under(this.root);
}

async isBannerVisible(): Promise<boolean> {
return this.getBannerPo().isPresent();
}
}
5 changes: 5 additions & 0 deletions frontend/src/tests/page-objects/NnsWallet.page-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { WalletPageHeaderPo } from "$tests/page-objects/WalletPageHeader.page-ob
import { WalletPageHeadingPo } from "$tests/page-objects/WalletPageHeading.page-object";
import { BasePageObject } from "$tests/page-objects/base.page-object";
import type { PageObjectElement } from "$tests/types/page-object.types";
import { LedgerNeuronHotkeyWarningPo } from "./LedgerNeuronHotkeyWarning.page-object";
import { UiTransactionsListPo } from "./UiTransactionsList.page-object";

export class NnsWalletPo extends BasePageObject {
Expand Down Expand Up @@ -51,6 +52,10 @@ export class NnsWalletPo extends BasePageObject {
return this.getButton("ledger-list-button");
}

getLedgerNeuronHotkeyWarningPo(): LedgerNeuronHotkeyWarningPo {
return LedgerNeuronHotkeyWarningPo.under(this.root);
}

getShowHardwareWalletButtonPo(): ButtonPo {
return this.getButton("ledger-show-button");
}
Expand Down

0 comments on commit 8e54925

Please sign in to comment.