From 0a8e45143f755f511b98335055ead3142e45e95e Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Thu, 28 Mar 2024 19:04:36 +0200 Subject: [PATCH 1/9] feat: polish balance page Signed-off-by: Eugene Panteleymonchuk --- .../nova/address/AddressBalance.scss | 26 ++++++++++--------- .../nova/address/AddressBalance.tsx | 4 ++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/client/src/app/components/nova/address/AddressBalance.scss b/client/src/app/components/nova/address/AddressBalance.scss index 4c38a109c..9dedf1dd8 100644 --- a/client/src/app/components/nova/address/AddressBalance.scss +++ b/client/src/app/components/nova/address/AddressBalance.scss @@ -3,7 +3,6 @@ .balance-wrapper { display: flex; flex-direction: row; - align-items: center; .icon { margin-right: 16px; @@ -11,19 +10,27 @@ .balance-wrapper__inner { display: flex; - flex-direction: column; - + flex-direction: row; + gap: 40px; + @include tablet-down { + flex-direction: column; + } .balance-wrapper__base-token { margin-bottom: 12px; + } .balance-wrapper__base-token, .balance-wrapper__mana { display: flex; - flex-direction: row; + flex-direction: column; + gap: 20px; + flex: 1; + .balance { display: flex; flex-direction: column; + gap: 10px; .icon { align-self: center; @@ -34,8 +41,6 @@ } &:not(:last-child) { - margin-right: 40px; - @include tablet-down { margin-right: 0px; } @@ -60,6 +65,7 @@ .balance-fiat { color: #b0bfd9; font-size: 18px; + white-space: nowrap; } .balance-heading { @@ -74,12 +80,8 @@ .balance__mana { display: flex; - align-items: center; - margin-left: 8px; - - .value { - margin-left: 4px; - } + flex-direction: column; + margin-left: 0; } } } diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index 42e773c8e..6bf404626 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -82,7 +82,9 @@ const AddressBalance: React.FC = ({ return (
- +
+ +
{baseTokenBalanceView( From 7efcccae7a903fe91a5f8d2242a05d0da0985764 Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Tue, 2 Apr 2024 16:42:13 +0300 Subject: [PATCH 2/9] fix formatting Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/nova/address/AddressBalance.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/app/components/nova/address/AddressBalance.scss b/client/src/app/components/nova/address/AddressBalance.scss index 9dedf1dd8..9c547b54c 100644 --- a/client/src/app/components/nova/address/AddressBalance.scss +++ b/client/src/app/components/nova/address/AddressBalance.scss @@ -17,7 +17,6 @@ } .balance-wrapper__base-token { margin-bottom: 12px; - } .balance-wrapper__base-token, From 0d638f180e132f75cdf8ffbae6d0b2f5fc0575fe Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Wed, 17 Apr 2024 23:04:00 +0300 Subject: [PATCH 3/9] feat: Polish balance section in address page Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/CardInfo.scss | 82 +++++++++++++ client/src/app/components/CardInfo.tsx | 80 +++++++++++++ .../nova/address/AddressBalance.scss | 5 +- .../nova/address/AddressBalance.tsx | 111 ++++++++++++------ 4 files changed, 241 insertions(+), 37 deletions(-) create mode 100644 client/src/app/components/CardInfo.scss create mode 100644 client/src/app/components/CardInfo.tsx diff --git a/client/src/app/components/CardInfo.scss b/client/src/app/components/CardInfo.scss new file mode 100644 index 000000000..3ed47d1bc --- /dev/null +++ b/client/src/app/components/CardInfo.scss @@ -0,0 +1,82 @@ +@import "../../scss/fonts"; +@import "../../scss/mixins"; +@import "../../scss/media-queries"; +@import "../../scss/variables"; + +.card-info { + width: 100%; + background: var(--card-body); + border-radius: 6px; + padding: 24px; + font-family: $inter; + + .card-info--title, + .card-info--detail-title { + font-size: 12px; + font-weight: 500; + color: var(--card-color); + } + + .card-info--amount, + .card-info--detail-amount { + cursor: pointer; + font-weight: 500; + color: var(--body-color); + } + + .card-info--header-title { + margin-bottom: 6px; + display: flex; + align-items: center; + } + .card-info--tooltip { + margin-left: 6px; + + .material-icons { + font-size: 18px; + color: #b0bfd9; + padding-left: 5px; + } + .tooltip { + height: 18px; + } + } + + .card-info--amount-wrap { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + } + + .card-info--amount { + font-size: 20px; + } + .card-info--copy { + display: flex; + align-items: center; + margin-left: 6px; + } + .card-info--details-divider { + margin-top: 16px; + border-top: 1px solid $gray-3; + } + .card-info--details { + display: flex; + flex-direction: column; + gap: 16px; + } + .card-info--detail { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + gap: 8px; + } + .card-info--detail-amount { + font-size: 12px; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + } +} diff --git a/client/src/app/components/CardInfo.tsx b/client/src/app/components/CardInfo.tsx new file mode 100644 index 000000000..da15b7cdd --- /dev/null +++ b/client/src/app/components/CardInfo.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import { BaseTokenResponse } from "@iota/sdk-wasm-nova/web"; + +import "./CardInfo.scss"; +import { formatAmount } from "~helpers/stardust/valueFormatHelper"; +import CopyButton from "~app/components/CopyButton"; +import Tooltip from "~app/components/Tooltip"; + +interface CardInfoDetail { + title: string; + amount?: number | string | null; + onClickAmount?: () => void; + copyAmount?: string; +} + +interface CardInfoProps { + /** + * The title of the card. + */ + title: string; + tooltip?: string; + amount?: number | string | null; + tokenInfo: BaseTokenResponse; + onClickAmount?: () => void; + copyAmount?: string; + details?: (CardInfoDetail | null)[]; +} + +export const CardInfo = ({ details, tooltip, title, amount, tokenInfo, onClickAmount = () => {}, copyAmount }: CardInfoProps) => { + + const detailsFiltered = details?.filter((i) => i !== null) as CardInfoDetail[] || []; + + return ( +
+
+
+
+ + {title} +
+ {!!tooltip && ( +
+ + info + +
+ )} +
+ {!!amount && ( +
+
{amount}
+ {copyAmount && ( +
+ +
+ )} +
+ )} +
+ {!!detailsFiltered.length && ( +
+
+ {detailsFiltered?.map((detail, idx) => ( +
+
{detail.title}
+
+ {detail.amount !== null ? detail.amount : "-"} + {detail.copyAmount && parseInt(detail.copyAmount) !== 0 && ( +
+ +
+ )} +
+
+ ))} +
+ )} +
+ ); +}; diff --git a/client/src/app/components/nova/address/AddressBalance.scss b/client/src/app/components/nova/address/AddressBalance.scss index 9c547b54c..71529007f 100644 --- a/client/src/app/components/nova/address/AddressBalance.scss +++ b/client/src/app/components/nova/address/AddressBalance.scss @@ -2,13 +2,14 @@ .balance-wrapper { display: flex; - flex-direction: row; + flex-direction: column; + gap: 24px; .icon { margin-right: 16px; } - .balance-wrapper__inner { + .balance-wrapper--row { display: flex; flex-direction: row; gap: 40px; diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index 6bf404626..d57a773ba 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -7,6 +7,7 @@ import CopyButton from "../../CopyButton"; import Icon from "../../Icon"; import Tooltip from "../../Tooltip"; import "./AddressBalance.scss"; +import { CardInfo } from "~app/components/CardInfo"; interface AddressBalanceProps { /** @@ -80,46 +81,86 @@ const AddressBalance: React.FC = ({ const conditionalPotentialMana = availablePotentialMana === null || totalPotentialMana === null ? null : totalPotentialMana - availablePotentialMana; + const availableBaseTokenAmount = (() => { + const balance = shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance; + return balance && balance > 0 ? formatAmount(balance, tokenInfo, formatBaseTokenBalanceFull) : 0; + })(); + + const manaFactory = ( + mana: bigint | number | null | undefined, + title: string, + isFormat: boolean, + setFormat: React.Dispatch> + ) => { + if (mana !== null && mana !== undefined && mana > 0) { + return { + title: title, + amount: formatAmount(mana, manaInfo, isFormat), + copyAmount: String(mana), + onClickAmount: () => setFormat(!isFormat) + }; + } + + return null; + }; + + return (
-
- +
+ setFormatBaseTokenBalanceFull(!formatBaseTokenBalanceFull)} + tokenInfo={tokenInfo} + copyAmount={String(availableBaseTokenAmount)} + details={[]} + /> + {shouldShowExtendedBalance && ( + setFormatConditionalBalanceFull(!formatConditionalBalanceFull)} + tokenInfo={tokenInfo} + copyAmount={String(conditionalBaseTokenBalance)} + tooltip={CONDITIONAL_BALANCE_INFO} + /> + )} + + setFormatStorageBalanceFull(!formatStorageBalanceFull)} + tokenInfo={tokenInfo} + copyAmount={String(storageDeposit)} + />
-
-
- {baseTokenBalanceView( - "Available Base Token", - formatBaseTokenBalanceFull, - setFormatBaseTokenBalanceFull, - false, - shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance, - )} - {shouldShowExtendedBalance && - baseTokenBalanceView( - "Conditionally Locked Base Token", - formatConditionalBalanceFull, - setFormatConditionalBalanceFull, - true, - conditionalBaseTokenBalance, - )} - {baseTokenBalanceView("Storage Deposit", formatStorageBalanceFull, setFormatStorageBalanceFull, false, storageDeposit)} -
+
+ + +
+
- {(availableStoredMana !== null || - availablePotentialMana !== null || - availableDecayMana !== null || - blockIssuanceCredits !== null) && - manaBalanceView( - "Available Mana", - formatManaBalanceFull, - setFormatManaBalanceFull, - availableStoredMana, - availableDecayMana, - availablePotentialMana, - blockIssuanceCredits, - manaRewards, - )} + {(conditionalStoredMana !== null || conditionalPotentialMana !== null) && manaBalanceView( "Conditionally Locked Mana", From 53cf98726eb6239cc0bec87aada3d981d9ff4fc4 Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Thu, 18 Apr 2024 12:29:42 +0300 Subject: [PATCH 4/9] feat: CardInfo. Rename props, clean code. Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/CardInfo.scss | 139 ++++++------ client/src/app/components/CardInfo.tsx | 69 +++--- .../nova/address/AddressBalance.tsx | 205 ++---------------- 3 files changed, 122 insertions(+), 291 deletions(-) diff --git a/client/src/app/components/CardInfo.scss b/client/src/app/components/CardInfo.scss index 3ed47d1bc..8fee3f0da 100644 --- a/client/src/app/components/CardInfo.scss +++ b/client/src/app/components/CardInfo.scss @@ -4,79 +4,84 @@ @import "../../scss/variables"; .card-info { - width: 100%; - background: var(--card-body); - border-radius: 6px; - padding: 24px; - font-family: $inter; + width: 100%; + background: var(--card-body); + border-radius: 6px; + padding: 24px; + font-family: $inter; - .card-info--title, - .card-info--detail-title { - font-size: 12px; - font-weight: 500; - color: var(--card-color); - } + .card-info__title, + .card-info__detail-title { + font-size: 12px; + font-weight: 500; + color: var(--card-color); + } + + .card-info__value, + .card-info__detail-value { + cursor: pointer; + font-weight: 500; + color: var(--body-color); + } + + .card-info--header-title { + margin-bottom: 6px; + display: flex; + align-items: center; + } + + .card-info--tooltip { + margin-left: 6px; + + .material-icons { + font-size: 18px; + color: #b0bfd9; + padding-left: 5px; + } + + .tooltip { + height: 18px; + } + } + + .card-info__value-wrap { + display: flex; + flex-flow: row nowrap; + } - .card-info--amount, - .card-info--detail-amount { - cursor: pointer; - font-weight: 500; - color: var(--body-color); - } + .card-info__value { + font-size: 20px; + } - .card-info--header-title { - margin-bottom: 6px; - display: flex; - align-items: center; - } - .card-info--tooltip { - margin-left: 6px; + .card-info__copy { + display: flex; + align-items: center; + margin-left: 6px; + } - .material-icons { - font-size: 18px; - color: #b0bfd9; - padding-left: 5px; + .card-info__details-divider { + margin-top: 16px; + border-top: 1px solid $gray-3; } - .tooltip { - height: 18px; + + .card-info__details { + display: flex; + flex-direction: column; + gap: 16px; } - } - .card-info--amount-wrap { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - } + .card-info__detail { + display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; + gap: 8px; + } - .card-info--amount { - font-size: 20px; - } - .card-info--copy { - display: flex; - align-items: center; - margin-left: 6px; - } - .card-info--details-divider { - margin-top: 16px; - border-top: 1px solid $gray-3; - } - .card-info--details { - display: flex; - flex-direction: column; - gap: 16px; - } - .card-info--detail { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - justify-content: space-between; - gap: 8px; - } - .card-info--detail-amount { - font-size: 12px; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - } + .card-info__detail-value { + font-size: 12px; + display: flex; + flex-flow: row nowrap; + color: var(--body-color); + } } diff --git a/client/src/app/components/CardInfo.tsx b/client/src/app/components/CardInfo.tsx index da15b7cdd..ea1d06379 100644 --- a/client/src/app/components/CardInfo.tsx +++ b/client/src/app/components/CardInfo.tsx @@ -1,16 +1,13 @@ import React from "react"; -import { BaseTokenResponse } from "@iota/sdk-wasm-nova/web"; - -import "./CardInfo.scss"; -import { formatAmount } from "~helpers/stardust/valueFormatHelper"; import CopyButton from "~app/components/CopyButton"; import Tooltip from "~app/components/Tooltip"; +import "./CardInfo.scss"; -interface CardInfoDetail { +export interface CardInfoDetail { title: string; - amount?: number | string | null; - onClickAmount?: () => void; - copyAmount?: string; + value?: number | string | null; + onClickValue?: () => void; + showCopyBtn?: boolean; } interface CardInfoProps { @@ -19,25 +16,20 @@ interface CardInfoProps { */ title: string; tooltip?: string; - amount?: number | string | null; - tokenInfo: BaseTokenResponse; - onClickAmount?: () => void; - copyAmount?: string; + value?: number | string | null; + onClickValue?: () => void; + showCopyBtn?: boolean; details?: (CardInfoDetail | null)[]; } -export const CardInfo = ({ details, tooltip, title, amount, tokenInfo, onClickAmount = () => {}, copyAmount }: CardInfoProps) => { - - const detailsFiltered = details?.filter((i) => i !== null) as CardInfoDetail[] || []; +export const CardInfo = ({ details, tooltip, title, value, onClickValue = () => {}, showCopyBtn }: CardInfoProps) => { + const detailsFiltered = (details?.filter((i) => i !== null) as CardInfoDetail[]) || []; return (
-
- - {title} -
+
{title}
{!!tooltip && (
@@ -46,28 +38,28 @@ export const CardInfo = ({ details, tooltip, title, amount, tokenInfo, onClickAm
)}
- {!!amount && ( -
-
{amount}
- {copyAmount && ( -
- + {!!value && ( +
+
{value}
+ {isValueNotZero(value) && showCopyBtn && ( +
+
)}
)}
{!!detailsFiltered.length && ( -
-
+
+
{detailsFiltered?.map((detail, idx) => ( -
-
{detail.title}
-
- {detail.amount !== null ? detail.amount : "-"} - {detail.copyAmount && parseInt(detail.copyAmount) !== 0 && ( -
- +
+
{detail.title}
+
+ {detail.value !== null ? detail.value : "-"} + {isValueNotZero(detail.value) && detail.showCopyBtn && ( +
+
)}
@@ -78,3 +70,12 @@ export const CardInfo = ({ details, tooltip, title, amount, tokenInfo, onClickAm
); }; + +function isValueNotZero(value: number | string | null | undefined): boolean { + if (typeof value === "number") { + return value !== 0; + } else if (typeof value === "string") { + return parseFloat(value) !== 0; + } + return false; +} diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index d57a773ba..53d123031 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -1,13 +1,9 @@ -import { BaseTokenResponse } from "@iota/sdk-wasm-nova/web"; import React, { useState } from "react"; import { useNetworkInfoNova } from "~/helpers/nova/networkInfo"; import { IManaBalance } from "~/models/api/nova/address/IAddressBalanceResponse"; import { formatAmount } from "~helpers/stardust/valueFormatHelper"; -import CopyButton from "../../CopyButton"; -import Icon from "../../Icon"; -import Tooltip from "../../Tooltip"; import "./AddressBalance.scss"; -import { CardInfo } from "~app/components/CardInfo"; +import { CardInfo, CardInfoDetail } from "~app/components/CardInfo"; interface AddressBalanceProps { /** @@ -62,9 +58,6 @@ const AddressBalance: React.FC = ({ return null; } - const baseTokenBalanceView = buildBaseTokenBalanceView(tokenInfo); - const manaBalanceView = buildManaBalanceView(manaInfo); - const conditionalBaseTokenBalance = !availableBaseTokenBalance || !totalBaseTokenBalance ? undefined : totalBaseTokenBalance - availableBaseTokenBalance; const shouldShowExtendedBalance = conditionalBaseTokenBalance !== undefined && availableBaseTokenBalance !== undefined; @@ -90,55 +83,49 @@ const AddressBalance: React.FC = ({ mana: bigint | number | null | undefined, title: string, isFormat: boolean, - setFormat: React.Dispatch> - ) => { + setFormat: React.Dispatch>, + ): CardInfoDetail | null => { if (mana !== null && mana !== undefined && mana > 0) { return { title: title, - amount: formatAmount(mana, manaInfo, isFormat), - copyAmount: String(mana), - onClickAmount: () => setFormat(!isFormat) + value: formatAmount(mana, manaInfo, isFormat), + onClickValue: () => setFormat(!isFormat), + showCopyBtn: true, }; } return null; }; - return (
setFormatBaseTokenBalanceFull(!formatBaseTokenBalanceFull)} - tokenInfo={tokenInfo} - copyAmount={String(availableBaseTokenAmount)} - details={[]} + value={availableBaseTokenAmount} + onClickValue={() => setFormatBaseTokenBalanceFull(!formatBaseTokenBalanceFull)} + showCopyBtn /> {shouldShowExtendedBalance && ( setFormatConditionalBalanceFull(!formatConditionalBalanceFull)} - tokenInfo={tokenInfo} - copyAmount={String(conditionalBaseTokenBalance)} + value={formatAmount(conditionalBaseTokenBalance, tokenInfo, formatConditionalBalanceFull)} + onClickValue={() => setFormatConditionalBalanceFull(!formatConditionalBalanceFull)} tooltip={CONDITIONAL_BALANCE_INFO} + showCopyBtn /> )} setFormatStorageBalanceFull(!formatStorageBalanceFull)} - tokenInfo={tokenInfo} - copyAmount={String(storageDeposit)} + value={storageDeposit ? formatAmount(storageDeposit, tokenInfo, formatStorageBalanceFull) : 0} + onClickValue={() => setFormatStorageBalanceFull(!formatStorageBalanceFull)} + showCopyBtn />
= ({ = ({ ]} />
-
-
- - {(conditionalStoredMana !== null || conditionalPotentialMana !== null) && - manaBalanceView( - "Conditionally Locked Mana", - formatStorageBalanceFull, - setFormatStorageBalanceFull, - conditionalStoredMana, - conditionalDecayMana, - conditionalPotentialMana, - )} -
-
); }; -function buildBaseTokenBalanceView(tokenInfo: BaseTokenResponse) { - const baseTokenBalanceView = ( - label: string, - isFormatFull: boolean, - setIsFormatFull: React.Dispatch>, - showInfo: boolean, - amount?: number | null, - ) => ( -
-
-
{label}
- {showInfo && ( - - info - - )} -
-
- {amount && amount > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)} className="balance-base-token pointer margin-r-5"> - {formatAmount(amount, tokenInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
- ); - - return baseTokenBalanceView; -} - -function buildManaBalanceView(manaInfo: BaseTokenResponse) { - const manaTokenBalanceView = ( - label: string, - isFormatFull: boolean, - setIsFormatFull: React.Dispatch>, - storedMana: number | null, - decayMana: number | null, - potentialMana: number | null, - blockIssuanceCredits: bigint | null = null, - manaRewards: bigint | null = null, - ) => ( -
-
-
{label}
-
-
-
Stored:
-
- {storedMana !== null && storedMana > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)}> - {formatAmount(storedMana, manaInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
-
-
Decay:
-
- {decayMana !== null && decayMana > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)}> - {formatAmount(decayMana, manaInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
-
-
Potential:
-
- {potentialMana !== null && potentialMana > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)}> - {formatAmount(potentialMana, manaInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
- {blockIssuanceCredits !== null && ( -
-
Block issuance credits:
-
- {blockIssuanceCredits && blockIssuanceCredits > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)}> - {formatAmount(blockIssuanceCredits.toString(), manaInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
- )} - {manaRewards !== null && ( -
-
Mana rewards:
-
- {manaRewards && manaRewards > 0 ? ( -
-
- setIsFormatFull(!isFormatFull)}> - {formatAmount(manaRewards.toString(), manaInfo, isFormatFull)} - - -
-
- ) : ( - 0 - )} -
-
- )} -
- ); - - return manaTokenBalanceView; -} - AddressBalance.defaultProps = { totalBaseTokenBalance: null, availableBaseTokenBalance: null, From 9bfa14e9250e51829035110f8060c8f193068b93 Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Fri, 19 Apr 2024 15:23:23 +0300 Subject: [PATCH 5/9] feat: cover case not show blockIssuanceCredits || manaRewards if null; Signed-off-by: Eugene Panteleymonchuk --- .../components/nova/address/AddressBalance.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index 53d123031..bf9593c3b 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -94,7 +94,12 @@ const AddressBalance: React.FC = ({ }; } - return null; + return { + title: title, + value: 0, + onClickValue: () => {}, + showCopyBtn: false, + }; }; return ( @@ -130,8 +135,12 @@ const AddressBalance: React.FC = ({ manaFactory(availableStoredMana, "Stored:", formatManaBalanceFull, setFormatManaBalanceFull), manaFactory(availableDecayMana, "Decay:", formatManaBalanceFull, setFormatManaBalanceFull), manaFactory(availablePotentialMana, "Potential:", formatManaBalanceFull, setFormatManaBalanceFull), - manaFactory(blockIssuanceCredits, "Block issuance credits:", formatManaBalanceFull, setFormatManaBalanceFull), - manaFactory(manaRewards, "Mana rewards:", formatManaBalanceFull, setFormatManaBalanceFull), + blockIssuanceCredits !== null + ? manaFactory(blockIssuanceCredits, "Block issuance credits:", formatManaBalanceFull, setFormatManaBalanceFull) + : null, + manaRewards !== null + ? manaFactory(manaRewards, "Mana rewards:", formatManaBalanceFull, setFormatManaBalanceFull) + : null, ]} /> From ce33e9d748bf1c4c56e938e0aaeb831aafaf4c50 Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Fri, 19 Apr 2024 18:16:03 +0300 Subject: [PATCH 6/9] Fix overwriting styles. Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/nova/address/AddressBalance.scss | 2 +- client/src/app/components/nova/address/AddressBalance.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/app/components/nova/address/AddressBalance.scss b/client/src/app/components/nova/address/AddressBalance.scss index 71529007f..c8d06783a 100644 --- a/client/src/app/components/nova/address/AddressBalance.scss +++ b/client/src/app/components/nova/address/AddressBalance.scss @@ -1,6 +1,6 @@ @import "../../../../scss/media-queries"; -.balance-wrapper { +.balance-wrapper.nova { display: flex; flex-direction: column; gap: 24px; diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index bf9593c3b..c3858b8c4 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -103,7 +103,7 @@ const AddressBalance: React.FC = ({ }; return ( -
+
Date: Fri, 19 Apr 2024 18:36:33 +0300 Subject: [PATCH 7/9] Allow negative value. Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/nova/address/AddressBalance.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index c3858b8c4..7fad1ef57 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -85,7 +85,7 @@ const AddressBalance: React.FC = ({ isFormat: boolean, setFormat: React.Dispatch>, ): CardInfoDetail | null => { - if (mana !== null && mana !== undefined && mana > 0) { + if (mana !== null && mana !== undefined) { return { title: title, value: formatAmount(mana, manaInfo, isFormat), From 0dab93e1fefc716e7f4e94e81da98c30ba6b77cd Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Fri, 19 Apr 2024 19:58:56 +0300 Subject: [PATCH 8/9] Add units. Show value if zero. Copy base amount. Show total available mana. Signed-off-by: Eugene Panteleymonchuk --- client/src/app/components/CardInfo.tsx | 35 ++++++++-------- .../nova/address/AddressBalance.tsx | 40 ++++++++++++++----- client/src/helpers/numberHelper.ts | 13 ++++++ 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/client/src/app/components/CardInfo.tsx b/client/src/app/components/CardInfo.tsx index ea1d06379..c53f29a8b 100644 --- a/client/src/app/components/CardInfo.tsx +++ b/client/src/app/components/CardInfo.tsx @@ -1,13 +1,15 @@ import React from "react"; import CopyButton from "~app/components/CopyButton"; import Tooltip from "~app/components/Tooltip"; +import classNames from "classnames"; + import "./CardInfo.scss"; export interface CardInfoDetail { title: string; value?: number | string | null; onClickValue?: () => void; - showCopyBtn?: boolean; + copyValue?: string; } interface CardInfoProps { @@ -18,16 +20,19 @@ interface CardInfoProps { tooltip?: string; value?: number | string | null; onClickValue?: () => void; - showCopyBtn?: boolean; + copyValue?: string; details?: (CardInfoDetail | null)[]; + options?: { + headerDirectionRow?: boolean; + }; } -export const CardInfo = ({ details, tooltip, title, value, onClickValue = () => {}, showCopyBtn }: CardInfoProps) => { +export const CardInfo = ({ options, details, tooltip, title, value, onClickValue = () => {}, copyValue }: CardInfoProps) => { const detailsFiltered = (details?.filter((i) => i !== null) as CardInfoDetail[]) || []; return (
-
+
{title}
{!!tooltip && ( @@ -38,16 +43,14 @@ export const CardInfo = ({ details, tooltip, title, value, onClickValue = () =>
)}
- {!!value && ( -
-
{value}
- {isValueNotZero(value) && showCopyBtn && ( -
- -
- )} -
- )} +
+
{value}
+ {isValueNotZero(value) && !!copyValue && ( +
+ +
+ )} +
{!!detailsFiltered.length && (
@@ -57,9 +60,9 @@ export const CardInfo = ({ details, tooltip, title, value, onClickValue = () =>
{detail.title}
{detail.value !== null ? detail.value : "-"} - {isValueNotZero(detail.value) && detail.showCopyBtn && ( + {isValueNotZero(detail.value) && !!detail.copyValue && (
- +
)}
diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index 7fad1ef57..efddab508 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -4,6 +4,7 @@ import { IManaBalance } from "~/models/api/nova/address/IAddressBalanceResponse" import { formatAmount } from "~helpers/stardust/valueFormatHelper"; import "./AddressBalance.scss"; import { CardInfo, CardInfoDetail } from "~app/components/CardInfo"; +import { NumberHelper } from "~helpers/numberHelper"; interface AddressBalanceProps { /** @@ -75,8 +76,11 @@ const AddressBalance: React.FC = ({ availablePotentialMana === null || totalPotentialMana === null ? null : totalPotentialMana - availablePotentialMana; const availableBaseTokenAmount = (() => { - const balance = shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance; - return balance && balance > 0 ? formatAmount(balance, tokenInfo, formatBaseTokenBalanceFull) : 0; + const balance = (shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance) || 0; + return { + formatted: formatAmount(balance, tokenInfo, formatBaseTokenBalanceFull), + full: balance, + }; })(); const manaFactory = ( @@ -90,26 +94,34 @@ const AddressBalance: React.FC = ({ title: title, value: formatAmount(mana, manaInfo, isFormat), onClickValue: () => setFormat(!isFormat), - showCopyBtn: true, + copyValue: String(mana), }; } return { title: title, - value: 0, + value: formatAmount(0, manaInfo, isFormat), onClickValue: () => {}, - showCopyBtn: false, + copyValue: "0", }; }; + const availableManaSum = NumberHelper.sumValues( + availableStoredMana, + availableDecayMana, + availablePotentialMana, + blockIssuanceCredits, + manaRewards, + ); + const conditionallyLockedManaSum = NumberHelper.sumValues(conditionalStoredMana, conditionalDecayMana, conditionalPotentialMana); return (
setFormatBaseTokenBalanceFull(!formatBaseTokenBalanceFull)} - showCopyBtn + copyValue={String(availableBaseTokenAmount.full)} /> {shouldShowExtendedBalance && ( = ({ value={formatAmount(conditionalBaseTokenBalance, tokenInfo, formatConditionalBalanceFull)} onClickValue={() => setFormatConditionalBalanceFull(!formatConditionalBalanceFull)} tooltip={CONDITIONAL_BALANCE_INFO} - showCopyBtn + copyValue={String(conditionalBaseTokenBalance)} /> )} setFormatStorageBalanceFull(!formatStorageBalanceFull)} - showCopyBtn + copyValue={String(storageDeposit || 0)} />
setFormatManaBalanceFull(!formatManaBalanceFull)} + copyValue={String(availableManaSum)} + options={{ headerDirectionRow: true }} details={[ manaFactory(availableStoredMana, "Stored:", formatManaBalanceFull, setFormatManaBalanceFull), manaFactory(availableDecayMana, "Decay:", formatManaBalanceFull, setFormatManaBalanceFull), @@ -146,6 +162,10 @@ const AddressBalance: React.FC = ({ setFormatStorageBalanceFull(!formatStorageBalanceFull)} + copyValue={String(conditionallyLockedManaSum)} + options={{ headerDirectionRow: true }} details={[ manaFactory(conditionalStoredMana, "Stored:", formatStorageBalanceFull, setFormatStorageBalanceFull), manaFactory(conditionalDecayMana, "Decay:", formatStorageBalanceFull, setFormatStorageBalanceFull), diff --git a/client/src/helpers/numberHelper.ts b/client/src/helpers/numberHelper.ts index 924d46406..67db01358 100644 --- a/client/src/helpers/numberHelper.ts +++ b/client/src/helpers/numberHelper.ts @@ -16,4 +16,17 @@ export class NumberHelper { public static isNumber(value?: number | null): boolean { return value !== null && value !== undefined && !isNaN(value); } + + public static sumValues(...args: (bigint | number | string | null | undefined)[]): number { + return args.reduce((acc, cur) => { + const value = cur || 0; // Convert null or undefined to 0 + if (typeof value === "bigint" || typeof value === "number") { + return acc + Number(value); + } else if (typeof value === "string") { + return acc + Number(value) || 0; + } else { + return acc; + } + }, 0); + } } From 0af61cd8a15200d510e415ba6d946c9d2c56da8c Mon Sep 17 00:00:00 2001 From: Eugene Panteleymonchuk Date: Mon, 22 Apr 2024 14:16:58 +0300 Subject: [PATCH 9/9] Toggle between units isolated. Signed-off-by: Eugene Panteleymonchuk --- .../nova/address/AddressBalance.tsx | 103 +++++++++++++----- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/client/src/app/components/nova/address/AddressBalance.tsx b/client/src/app/components/nova/address/AddressBalance.tsx index efddab508..1b7b2e4d2 100644 --- a/client/src/app/components/nova/address/AddressBalance.tsx +++ b/client/src/app/components/nova/address/AddressBalance.tsx @@ -37,6 +37,21 @@ interface AddressBalanceProps { readonly storageDeposit?: number | null; } +type FormatField = + | "baseTokenBalance" + | "conditionalBaseTokenBalance" + | "storageDeposit" + | "availableManaBalance" + | "availableStoredMana" + | "availableDecayMana" + | "availablePotentialMana" + | "blockIssuanceCredits" + | "manaRewards" + | "conditionallyLockedMana" + | "conditionalStoredMana" + | "conditionalDecayMana" + | "conditionalPotentialMana"; + const CONDITIONAL_BALANCE_INFO = "These funds reside within outputs with additional unlock conditions which might be potentially un-lockable"; @@ -50,10 +65,23 @@ const AddressBalance: React.FC = ({ storageDeposit, }) => { const { tokenInfo, manaInfo } = useNetworkInfoNova((s) => s.networkInfo); - const [formatBaseTokenBalanceFull, setFormatBaseTokenBalanceFull] = useState(false); - const [formatManaBalanceFull, setFormatManaBalanceFull] = useState(false); - const [formatConditionalBalanceFull, setFormatConditionalBalanceFull] = useState(false); - const [formatStorageBalanceFull, setFormatStorageBalanceFull] = useState(false); + const [isFormat, setIsFormat] = useState<{ [k in FormatField]: boolean }>({ + baseTokenBalance: false, + conditionalBaseTokenBalance: false, + storageDeposit: false, + + availableManaBalance: false, + availableStoredMana: false, + availableDecayMana: false, + availablePotentialMana: false, + blockIssuanceCredits: false, + manaRewards: false, + + conditionallyLockedMana: false, + conditionalStoredMana: false, + conditionalDecayMana: false, + conditionalPotentialMana: false, + }); if (totalBaseTokenBalance === null) { return null; @@ -78,7 +106,7 @@ const AddressBalance: React.FC = ({ const availableBaseTokenAmount = (() => { const balance = (shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance) || 0; return { - formatted: formatAmount(balance, tokenInfo, formatBaseTokenBalanceFull), + formatted: formatAmount(balance, tokenInfo, isFormat.baseTokenBalance), full: balance, }; })(); @@ -87,13 +115,13 @@ const AddressBalance: React.FC = ({ mana: bigint | number | null | undefined, title: string, isFormat: boolean, - setFormat: React.Dispatch>, + toggleFormat: () => void, ): CardInfoDetail | null => { if (mana !== null && mana !== undefined) { return { title: title, value: formatAmount(mana, manaInfo, isFormat), - onClickValue: () => setFormat(!isFormat), + onClickValue: toggleFormat, copyValue: String(mana), }; } @@ -101,7 +129,7 @@ const AddressBalance: React.FC = ({ return { title: title, value: formatAmount(0, manaInfo, isFormat), - onClickValue: () => {}, + onClickValue: toggleFormat, copyValue: "0", }; }; @@ -114,20 +142,25 @@ const AddressBalance: React.FC = ({ manaRewards, ); const conditionallyLockedManaSum = NumberHelper.sumValues(conditionalStoredMana, conditionalDecayMana, conditionalPotentialMana); + + const toggleFormat = (field: FormatField) => () => { + setIsFormat((prev) => ({ ...prev, [field]: !prev[field] })); + }; + return (
setFormatBaseTokenBalanceFull(!formatBaseTokenBalanceFull)} + onClickValue={toggleFormat("baseTokenBalance")} copyValue={String(availableBaseTokenAmount.full)} /> {shouldShowExtendedBalance && ( setFormatConditionalBalanceFull(!formatConditionalBalanceFull)} + value={formatAmount(conditionalBaseTokenBalance, tokenInfo, isFormat.conditionalBaseTokenBalance)} + onClickValue={toggleFormat("conditionalBaseTokenBalance")} tooltip={CONDITIONAL_BALANCE_INFO} copyValue={String(conditionalBaseTokenBalance)} /> @@ -135,41 +168,61 @@ const AddressBalance: React.FC = ({ setFormatStorageBalanceFull(!formatStorageBalanceFull)} + value={formatAmount(storageDeposit || 0, tokenInfo, isFormat.storageDeposit)} + onClickValue={toggleFormat("storageDeposit")} copyValue={String(storageDeposit || 0)} />
setFormatManaBalanceFull(!formatManaBalanceFull)} + value={formatAmount(availableManaSum, manaInfo, isFormat.availableManaBalance)} + onClickValue={toggleFormat("availableManaBalance")} copyValue={String(availableManaSum)} options={{ headerDirectionRow: true }} details={[ - manaFactory(availableStoredMana, "Stored:", formatManaBalanceFull, setFormatManaBalanceFull), - manaFactory(availableDecayMana, "Decay:", formatManaBalanceFull, setFormatManaBalanceFull), - manaFactory(availablePotentialMana, "Potential:", formatManaBalanceFull, setFormatManaBalanceFull), + manaFactory(availableStoredMana, "Stored:", isFormat.availableStoredMana, toggleFormat("availableStoredMana")), + manaFactory(availableDecayMana, "Decay:", isFormat.availableDecayMana, toggleFormat("availableDecayMana")), + manaFactory( + availablePotentialMana, + "Potential:", + isFormat.availablePotentialMana, + toggleFormat("availablePotentialMana"), + ), blockIssuanceCredits !== null - ? manaFactory(blockIssuanceCredits, "Block issuance credits:", formatManaBalanceFull, setFormatManaBalanceFull) + ? manaFactory( + blockIssuanceCredits, + "Block issuance credits:", + isFormat.blockIssuanceCredits, + toggleFormat("blockIssuanceCredits"), + ) : null, manaRewards !== null - ? manaFactory(manaRewards, "Mana rewards:", formatManaBalanceFull, setFormatManaBalanceFull) + ? manaFactory(manaRewards, "Mana rewards:", isFormat.manaRewards, toggleFormat("manaRewards")) : null, ]} /> setFormatStorageBalanceFull(!formatStorageBalanceFull)} + value={formatAmount(conditionallyLockedManaSum, manaInfo, isFormat.conditionallyLockedMana)} + onClickValue={toggleFormat("conditionallyLockedMana")} copyValue={String(conditionallyLockedManaSum)} options={{ headerDirectionRow: true }} details={[ - manaFactory(conditionalStoredMana, "Stored:", formatStorageBalanceFull, setFormatStorageBalanceFull), - manaFactory(conditionalDecayMana, "Decay:", formatStorageBalanceFull, setFormatStorageBalanceFull), - manaFactory(conditionalPotentialMana, "Potential:", formatStorageBalanceFull, setFormatStorageBalanceFull), + manaFactory( + conditionalStoredMana, + "Stored:", + isFormat.conditionalStoredMana, + toggleFormat("conditionalStoredMana"), + ), + manaFactory(conditionalDecayMana, "Decay:", isFormat.conditionalDecayMana, toggleFormat("conditionalDecayMana")), + manaFactory( + conditionalPotentialMana, + "Potential:", + isFormat.conditionalPotentialMana, + toggleFormat("conditionalPotentialMana"), + ), ]} />