From 76167e60e38f9d50ae01e24763fa7f6036cf1b16 Mon Sep 17 00:00:00 2001 From: JCNoguera Date: Mon, 19 Feb 2024 17:28:23 +0100 Subject: [PATCH] feat: add mana dropdown to the output page --- .../app/components/nova/KeyValueEntries.tsx | 40 +++++++++++++++++++ .../src/app/components/nova/OutputView.scss | 39 ++++++++++++++++++ client/src/app/components/nova/OutputView.tsx | 15 ++++--- client/src/app/lib/interfaces/index.ts | 1 + .../lib/interfaces/key-value.interfaces.ts | 8 ++++ client/src/app/routes/nova/OutputPage.tsx | 8 +++- client/src/helpers/nova/manaUtils.ts | 29 ++++++++++++++ 7 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 client/src/app/components/nova/KeyValueEntries.tsx create mode 100644 client/src/app/lib/interfaces/key-value.interfaces.ts diff --git a/client/src/app/components/nova/KeyValueEntries.tsx b/client/src/app/components/nova/KeyValueEntries.tsx new file mode 100644 index 000000000..841c1bd7a --- /dev/null +++ b/client/src/app/components/nova/KeyValueEntries.tsx @@ -0,0 +1,40 @@ +import classNames from "classnames"; +import React, { useState } from "react"; +import { IKeyValue, IKeyValueEntries } from "~/app/lib/interfaces"; +import DropdownIcon from "~assets/dropdown-arrow.svg?react"; + +function KeyValuePair({ label, value }: IKeyValue): React.JSX.Element { + return ( + <> + {value !== undefined && value !== null && ( +
+
{label}
+
{value}
+
+ )} + + ); +} + +export default function KeyValueEntries({ label, value, entries }: IKeyValueEntries): React.JSX.Element { + const [isExpanded, setIsExpanded] = useState(false); + + return ( +
+
setIsExpanded(!isExpanded)}> +
+ +
+ +
+ + {entries && entries.length > 0 && isExpanded && ( +
+ {entries.map((entry, idx) => ( + + ))} +
+ )} +
+ ); +} diff --git a/client/src/app/components/nova/OutputView.scss b/client/src/app/components/nova/OutputView.scss index 244e76f56..867404790 100644 --- a/client/src/app/components/nova/OutputView.scss +++ b/client/src/app/components/nova/OutputView.scss @@ -1,5 +1,7 @@ @import "../../../scss/media-queries"; @import "../../../scss/variables"; +@import "../../../scss/mixins"; +@import "../../../scss/fonts"; .card--content__output { padding: 0 30px; @@ -65,6 +67,43 @@ } } +.key-value-wrapper { + display: flex; + flex-direction: column; + + .key-value--row { + display: flex; + align-items: center; + margin-bottom: 12px; + } + + .key-value { + display: flex; + align-items: center; + margin-bottom: 10px; + + .entry--key, + .entry--value { + @include font-size(12px); + font-family: $inter; + font-weight: 500; + letter-spacing: 0.5px; + white-space: nowrap; + color: var(--card-color); + margin-top: 8px; + } + + .entry--value { + color: var(--body-color); + margin-left: 8px; + } + } + + .key-value-entries { + margin-bottom: 12px; + } +} + .card--content--dropdown { margin-right: 8px; cursor: pointer; diff --git a/client/src/app/components/nova/OutputView.tsx b/client/src/app/components/nova/OutputView.tsx index 5fe292f08..22b68728e 100644 --- a/client/src/app/components/nova/OutputView.tsx +++ b/client/src/app/components/nova/OutputView.tsx @@ -4,7 +4,6 @@ import classNames from "classnames"; import { Output, OutputType, - BasicOutput, CommonOutput, AccountOutput, AnchorOutput, @@ -23,6 +22,8 @@ import FeatureView from "./FeaturesView"; import TruncatedId from "../stardust/TruncatedId"; import { HexHelper } from "~/helpers/stardust/hexHelper"; import bigInt from "big-integer"; +import { OutputManaDetails, getManaKeyValueEntries } from "~/helpers/nova/manaUtils"; +import KeyValueEntries from "./KeyValueEntries"; import "./OutputView.scss"; interface OutputViewProps { @@ -31,9 +32,10 @@ interface OutputViewProps { showCopyAmount: boolean; isPreExpanded?: boolean; isLinksDisabled?: boolean; + manaDetails: OutputManaDetails | null; } -const OutputView: React.FC = ({ outputId, output, showCopyAmount, isPreExpanded, isLinksDisabled }) => { +const OutputView: React.FC = ({ outputId, output, showCopyAmount, isPreExpanded, isLinksDisabled, manaDetails }) => { const [isExpanded, setIsExpanded] = useState(isPreExpanded ?? false); const [isFormattedBalance, setIsFormattedBalance] = useState(true); const { bech32Hrp, name: network } = useNetworkInfoNova((s) => s.networkInfo); @@ -41,6 +43,7 @@ const OutputView: React.FC = ({ outputId, output, showCopyAmoun const aliasOrNftBech32 = buildAddressForAliasOrNft(outputId, output, bech32Hrp); const outputIdTransactionPart = `${outputId.slice(0, 8)}....${outputId.slice(-8, -4)}`; const outputIdIndexPart = outputId.slice(-4); + const manaEntries = getManaKeyValueEntries(manaDetails); const header = (
setIsExpanded(!isExpanded)} className="card--value card-header--wrapper"> @@ -158,12 +161,8 @@ const OutputView: React.FC = ({ outputId, output, showCopyAmoun {(output.type === OutputType.Basic || output.type === OutputType.Account || output.type === OutputType.Anchor || - output.type === OutputType.Nft) && ( - -
Stored mana:
-
{(output as BasicOutput).mana?.toString()}
-
- )} + output.type === OutputType.Nft) && + manaDetails?.totalMana && } {output.type === OutputType.Delegation && (
Delegated amount:
diff --git a/client/src/app/lib/interfaces/index.ts b/client/src/app/lib/interfaces/index.ts index 204986b69..9d55bc6d7 100644 --- a/client/src/app/lib/interfaces/index.ts +++ b/client/src/app/lib/interfaces/index.ts @@ -1 +1,2 @@ export * from "./routes.interfaces"; +export * from "./key-value.interfaces"; diff --git a/client/src/app/lib/interfaces/key-value.interfaces.ts b/client/src/app/lib/interfaces/key-value.interfaces.ts new file mode 100644 index 000000000..ecff91434 --- /dev/null +++ b/client/src/app/lib/interfaces/key-value.interfaces.ts @@ -0,0 +1,8 @@ +export interface IKeyValue { + label: string; + value: string | number | null | undefined; +} + +export interface IKeyValueEntries extends IKeyValue { + entries?: IKeyValue[]; +} diff --git a/client/src/app/routes/nova/OutputPage.tsx b/client/src/app/routes/nova/OutputPage.tsx index 1abdfaf8d..17006ce17 100644 --- a/client/src/app/routes/nova/OutputPage.tsx +++ b/client/src/app/routes/nova/OutputPage.tsx @@ -81,7 +81,13 @@ const OutputPage: React.FC> = ({
- +
diff --git a/client/src/helpers/nova/manaUtils.ts b/client/src/helpers/nova/manaUtils.ts index 255c013ea..06f29cd44 100644 --- a/client/src/helpers/nova/manaUtils.ts +++ b/client/src/helpers/nova/manaUtils.ts @@ -1,4 +1,5 @@ import { BasicOutput, ManaRewardsResponse, Output, ProtocolParameters, Utils } from "@iota/sdk-wasm-nova/web"; +import { IKeyValueEntries } from "~/app/lib/interfaces"; export interface OutputManaDetails { storedMana: string; @@ -33,3 +34,31 @@ export function buildManaDetailsForOutput( totalMana: totalMana.toString(), }; } + +export function getManaKeyValueEntries(manaDetails: OutputManaDetails | null): IKeyValueEntries { + const showDecayMana = manaDetails?.storedMana && manaDetails?.storedManaDecayed; + const decay = showDecayMana ? Number(manaDetails?.storedMana ?? 0) - Number(manaDetails?.storedManaDecayed ?? 0) : undefined; + + return { + label: "Mana:", + value: manaDetails?.totalMana, + entries: [ + { + label: "Stored:", + value: manaDetails?.storedMana, + }, + { + label: "Decay:", + value: decay, + }, + { + label: "Potential:", + value: manaDetails?.potentialMana, + }, + { + label: "Delegation Rewards:", + value: manaDetails?.delegationRewards, + }, + ], + }; +}