Skip to content

Commit

Permalink
Show stake in USD on NNS neuron details (#6039)
Browse files Browse the repository at this point in the history
# Motivation

Want to show the stake in USD on the neuron details page similar to how
we show the account balance on the wallet page.

This PR does it for NNS neurons. Another PR will do SNS neurons.
And a third PR will make sure token prices are loaded when the neuron
page is deep linked.

# Changes

1. Use `HeadingSubtitleWithUsdValue` which was extracted in
#6037 in `NnsNeuronPageHeading`.
Some of the slot content is temporarily duplicate between with and
without feature flag.

# Tests

1. Unit tests added.
2. Manually at
https://qsgjb-riaaa-aaaaa-aaaga-cai.dskloet-ingress.devenv.dfinity.network/neuron/?u=qsgjb-riaaa-aaaaa-aaaga-cai&neuron=7894867686608507388

# Todos

- [ ] Add entry to changelog (if necessary).
not yet
  • Loading branch information
dskloetd authored Dec 18, 2024
1 parent 98b045d commit 6dbe83e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<script lang="ts">
import NeuronTag from "$lib/components/ui/NeuronTag.svelte";
import { LEDGER_CANISTER_ID } from "$lib/constants/canister-ids.constants";
import { NNS_MINIMUM_DISSOLVE_DELAY_TO_VOTE } from "$lib/constants/neurons.constants";
import { icpAccountsStore } from "$lib/derived/icp-accounts.derived";
import { authStore } from "$lib/stores/auth.store";
import { ENABLE_USD_VALUES_FOR_NEURONS } from "$lib/stores/feature-flags.store";
import { i18n } from "$lib/stores/i18n";
import { replacePlaceholders } from "$lib/utils/i18n.utils";
import {
Expand All @@ -11,11 +14,11 @@
type NeuronTagData,
} from "$lib/utils/neuron.utils";
import HeadingSubtitle from "../common/HeadingSubtitle.svelte";
import HeadingSubtitleWithUsdValue from "../common/HeadingSubtitleWithUsdValue.svelte";
import PageHeading from "../common/PageHeading.svelte";
import AmountDisplay from "../ic/AmountDisplay.svelte";
import type { NeuronInfo } from "@dfinity/nns";
import { ICPToken, TokenAmountV2 } from "@dfinity/utils";
import NeuronTag from "$lib/components/ui/NeuronTag.svelte";
export let neuron: NeuronInfo;
Expand All @@ -41,15 +44,32 @@

<PageHeading testId="nns-neuron-page-heading-component">
<AmountDisplay slot="title" {amount} size="huge" singleLine detailed />
<HeadingSubtitle slot="subtitle" testId="voting-power">
{#if canVote}
{replacePlaceholders($i18n.neuron_detail.voting_power_subtitle, {
$votingPower: formatVotingPower(neuron.votingPower),
})}
<svelte:fragment slot="subtitle">
{#if $ENABLE_USD_VALUES_FOR_NEURONS}
<HeadingSubtitleWithUsdValue
{amount}
ledgerCanisterId={LEDGER_CANISTER_ID}
>
{#if canVote}
{replacePlaceholders($i18n.neuron_detail.voting_power_subtitle, {
$votingPower: formatVotingPower(neuron.votingPower),
})}
{:else}
{$i18n.neuron_detail.voting_power_zero_subtitle}
{/if}
</HeadingSubtitleWithUsdValue>
{:else}
{$i18n.neuron_detail.voting_power_zero_subtitle}
<HeadingSubtitle testId="voting-power">
{#if canVote}
{replacePlaceholders($i18n.neuron_detail.voting_power_subtitle, {
$votingPower: formatVotingPower(neuron.votingPower),
})}
{:else}
{$i18n.neuron_detail.voting_power_zero_subtitle}
{/if}
</HeadingSubtitle>
{/if}
</HeadingSubtitle>
</svelte:fragment>
<svelte:fragment slot="tags">
{#each neuronTags as tag}
<NeuronTag size="large" {tag} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import NnsNeuronPageHeading from "$lib/components/neuron-detail/NnsNeuronPageHeading.svelte";
import { CKUSDC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckusdc-canister-ids.constants";
import { NNS_MINIMUM_DISSOLVE_DELAY_TO_VOTE } from "$lib/constants/neurons.constants";
import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store";
import { icpSwapTickersStore } from "$lib/stores/icp-swap.store";
import { mockIdentity, resetIdentity } from "$tests/mocks/auth.store.mock";
import {
mockHardwareWalletAccount,
mockMainAccount,
} from "$tests/mocks/icp-accounts.store.mock";
import { mockIcpSwapTicker } from "$tests/mocks/icp-swap.mock";
import { mockNeuron } from "$tests/mocks/neurons.mock";
import { NnsNeuronPageHeadingPo } from "$tests/page-objects/NnsNeuronPageHeading.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
Expand All @@ -26,6 +30,14 @@ describe("NnsNeuronPageHeading", () => {
beforeEach(() => {
resetIdentity();
resetAccountsForTesting();

icpSwapTickersStore.set([
{
...mockIcpSwapTicker,
base_id: CKUSDC_UNIVERSE_CANISTER_ID.toText(),
last_price: "10.00",
},
]);
});

it("should render the neuron's stake", async () => {
Expand Down Expand Up @@ -147,4 +159,37 @@ describe("NnsNeuronPageHeading", () => {

expect(await po.getNeuronTags()).toEqual(["Early Contributor Token"]);
});

it("should not display USD balance if feature flag is disabled", async () => {
overrideFeatureFlagsStore.setFlag("ENABLE_USD_VALUES_FOR_NEURONS", false);

const stake = 300_000_000n;
const po = renderComponent({
...mockNeuron,
fullNeuron: {
...mockNeuron.fullNeuron,
cachedNeuronStake: stake,
neuronFees: 0n,
},
});

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

it("should display USD balance if feature flag is enabled", async () => {
overrideFeatureFlagsStore.setFlag("ENABLE_USD_VALUES_FOR_NEURONS", true);

const stake = 300_000_000n;
const po = renderComponent({
...mockNeuron,
fullNeuron: {
...mockNeuron.fullNeuron,
cachedNeuronStake: stake,
neuronFees: 0n,
},
});

expect(await po.hasBalanceInUsd()).toBe(true);
expect(await po.getBalanceInUsd()).toBe("$30.00");
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AmountDisplayPo } from "$tests/page-objects/AmountDisplay.page-object";
import { BasePageObject } from "$tests/page-objects/base.page-object";
import type { PageObjectElement } from "$tests/types/page-object.types";
import { HeadingSubtitleWithUsdValuePo } from "./HeadingSubtitleWithUsdValue.page-object";
import { NeuronTagPo } from "./NeuronTag.page-object";

export class NnsNeuronPageHeadingPo extends BasePageObject {
Expand All @@ -12,6 +13,10 @@ export class NnsNeuronPageHeadingPo extends BasePageObject {
);
}

getHeadingSubtitleWithUsdValuePo(): HeadingSubtitleWithUsdValuePo {
return HeadingSubtitleWithUsdValuePo.under(this.root);
}

getAmountDisplayPo(): AmountDisplayPo {
return AmountDisplayPo.under(this.root);
}
Expand All @@ -28,4 +33,12 @@ export class NnsNeuronPageHeadingPo extends BasePageObject {
const elements = await NeuronTagPo.allUnder(this.root);
return Promise.all(elements.map((tag) => tag.getText()));
}

hasBalanceInUsd(): Promise<boolean> {
return this.getHeadingSubtitleWithUsdValuePo().hasAmountInUsd();
}

getBalanceInUsd(): Promise<string> {
return this.getHeadingSubtitleWithUsdValuePo().getAmountInUsd();
}
}

0 comments on commit 6dbe83e

Please sign in to comment.