diff --git a/packages/extension-polkagate/src/fullscreen/accountDetails/components/DisplayBalance.tsx b/packages/extension-polkagate/src/fullscreen/accountDetails/components/DisplayBalance.tsx index 39b806952..b85c72c9c 100644 --- a/packages/extension-polkagate/src/fullscreen/accountDetails/components/DisplayBalance.tsx +++ b/packages/extension-polkagate/src/fullscreen/accountDetails/components/DisplayBalance.tsx @@ -64,7 +64,7 @@ export default function DisplayBalance ({ amount, decimal, disabled, onClick, op stroke: `${disabled ? theme.palette.action.disabledBackground : theme.palette.secondary.light}`, strokeWidth: 1.5, transform: - openCollapse !== undefined + openCollapse !== undefined || disabled ? openCollapse ? 'rotate(-90deg)' : 'rotate(90deg)' diff --git a/packages/extension-polkagate/src/fullscreen/accountDetails/components/ReservedDisplayBalance.tsx b/packages/extension-polkagate/src/fullscreen/accountDetails/components/ReservedDisplayBalance.tsx index eb7ee5d8f..58b7e1249 100644 --- a/packages/extension-polkagate/src/fullscreen/accountDetails/components/ReservedDisplayBalance.tsx +++ b/packages/extension-polkagate/src/fullscreen/accountDetails/components/ReservedDisplayBalance.tsx @@ -7,11 +7,11 @@ import type { Balance } from '@polkadot/types/interfaces'; import type { BN } from '@polkadot/util'; import { Collapse, Divider, Grid, Skeleton, type SxProps, type Theme, Typography } from '@mui/material'; -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from '@polkadot/extension-polkagate/src/components/translate'; import useReservedDetails, { type Reserved } from '@polkadot/extension-polkagate/src/hooks/useReservedDetails'; -import { isOnAssetHub, isOnRelayChain } from '@polkadot/extension-polkagate/src/util/utils'; +import { isOnRelayChain } from '@polkadot/extension-polkagate/src/util/utils'; import { ShowValue } from '../../../components'; import { useInfo } from '../../../hooks'; @@ -19,8 +19,10 @@ import { toTitleCase } from '../../governance/utils/util'; import DisplayBalance from './DisplayBalance'; interface Props { + assetId: string | number | undefined, address: string | undefined; amount: BN | Balance | undefined; + assetToken?: string | undefined; price: number | undefined; disabled?: boolean; } @@ -64,6 +66,40 @@ function WaitForReserved ({ rows = 2, skeletonHeight = 20, skeletonWidth = 60, s const ReservedDetails = ({ reservedDetails, showReservedDetails }: ReservedDetailsType) => { const { t } = useTranslation(); + const [stillFetching, setStillFetching] = useState(false); + + useEffect(() => { + const reasons = Object.values(reservedDetails); + + const isStillFetchingSomething = reasons.some((reason) => reason === undefined); + + setStillFetching(isStillFetchingSomething); + }, [reservedDetails]); + + const reasonsToShow = useMemo(() => { + const reasons = Object.values(reservedDetails); + + // details are still fetching + if (reasons.length === 0) { + return undefined; + } + + const noReason = reasons.every((reason) => reason === null); + + // no reasons found + if (noReason) { + return null; + } + + // filter fetched reasons + const filteredReservedDetails = Object.fromEntries( + Object.entries(reservedDetails).filter(([_key, value]) => value && !value.isZero()) + ); + + return Object.values(filteredReservedDetails).length > 0 + ? filteredReservedDetails + : undefined; + }, [reservedDetails]); return ( @@ -72,9 +108,9 @@ const ReservedDetails = ({ reservedDetails, showReservedDetails }: ReservedDetai {t('Reasons')} - {Object.entries(reservedDetails)?.length + {reasonsToShow ? - {Object.entries(reservedDetails)?.map(([key, value], index) => ( + {Object.entries(reasonsToShow)?.map(([key, value], index) => ( {toTitleCase(key)} @@ -85,30 +121,37 @@ const ReservedDetails = ({ reservedDetails, showReservedDetails }: ReservedDetai )) } + {stillFetching && } - : + : reasonsToShow === null + ? + {t('No reasons found!')} + + : } ); }; -export default function ReservedDisplayBalance ({ address, amount, disabled, price }: Props): React.ReactElement { +function ReservedDisplayBalance ({ address, amount, assetId, assetToken, disabled, price }: Props): React.ReactElement { const { t } = useTranslation(); const reservedDetails = useReservedDetails(address); const { decimal, genesisHash, token } = useInfo(address); + const notOnNativeAsset = useMemo(() => (assetId !== undefined && Number(assetId) > 0) || assetToken?.toLowerCase() !== token?.toLowerCase(), [assetId, assetToken, token]); + const [showReservedDetails, setShowReservedDetails] = useState(false); useEffect(() => { setShowReservedDetails(false); // to reset collapsed area on chain change - }, [genesisHash]); + }, [address, genesisHash, assetId]); const toggleShowReservedDetails = useCallback(() => { reservedDetails && !amount?.isZero() && setShowReservedDetails(!showReservedDetails); }, [amount, reservedDetails, showReservedDetails]); - return !genesisHash || isOnAssetHub(genesisHash) + return !genesisHash || notOnNativeAsset ? <> : ( div': { bgcolor: 'unset', boxShadow: 'none' }, bgcolor: 'background.paper', borderRadius: '5px', boxShadow: '2px 3px 4px 0px rgba(0, 0, 0, 0.1)' }}> @@ -116,7 +159,7 @@ export default function ReservedDisplayBalance ({ address, amount, disabled, pri amount={amount} decimal={decimal} disabled={disabled} - onClick={isOnRelayChain(genesisHash) ? toggleShowReservedDetails : undefined} + onClick={isOnRelayChain(genesisHash) || !notOnNativeAsset ? toggleShowReservedDetails : undefined} openCollapse={showReservedDetails} price={price} title={t('Reserved')} @@ -129,3 +172,5 @@ export default function ReservedDisplayBalance ({ address, amount, disabled, pri ); } + +export default React.memo(ReservedDisplayBalance); diff --git a/packages/extension-polkagate/src/fullscreen/accountDetails/index.tsx b/packages/extension-polkagate/src/fullscreen/accountDetails/index.tsx index 549327371..9096f4d71 100644 --- a/packages/extension-polkagate/src/fullscreen/accountDetails/index.tsx +++ b/packages/extension-polkagate/src/fullscreen/accountDetails/index.tsx @@ -265,6 +265,8 @@ export default function AccountDetails (): React.ReactElement { diff --git a/packages/extension-polkagate/src/hooks/useReservedDetails.ts b/packages/extension-polkagate/src/hooks/useReservedDetails.ts index ef6b97b38..e5e87948d 100644 --- a/packages/extension-polkagate/src/hooks/useReservedDetails.ts +++ b/packages/extension-polkagate/src/hooks/useReservedDetails.ts @@ -1,27 +1,26 @@ // Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors // SPDX-License-Identifier: Apache-2.0 -// @ts-nocheck - -import type { Option } from '@polkadot/types'; +import type { Option, StorageKey } from '@polkadot/types'; import type { Balance } from '@polkadot/types/interfaces'; -import type { AccountId } from '@polkadot/types/interfaces/runtime'; -import type { PalletMultisigMultisig, PalletPreimageRequestStatus, PalletRecoveryRecoveryConfig, PalletReferendaReferendumInfoRankedCollectiveTally, PalletReferendaReferendumStatusRankedCollectiveTally, PalletSocietyBid, PalletSocietyCandidacy } from '@polkadot/types/lookup'; -import type { BN } from '@polkadot/util'; +// @ts-ignore +import type { PalletSocietyBid, PalletSocietyCandidacy } from '@polkadot/types/lookup'; +import type { AnyTuple, Codec } from '@polkadot/types-codec/types'; +import type { Proxy } from '../util/types'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { BN_ZERO } from '@polkadot/util'; +import { BN, BN_ZERO } from '@polkadot/util'; -import { PROXY_CHAINS } from '../util/constants'; +import { ASSET_HUBS, PROXY_CHAINS } from '../util/constants'; import useActiveRecoveries from './useActiveRecoveries'; import { useInfo } from '.'; -type Item = 'identity' | 'proxy' | 'bounty' | 'recovery' | 'referenda' | 'index' | 'society' | 'multisig' | 'preimage'; -export type Reserved = { [key in Item]?: Balance }; +type Item = 'identity' | 'proxy' | 'bounty' | 'recovery' | 'referenda' | 'index' | 'society' | 'multisig' | 'preimage' | 'assets' | 'uniques' | 'NFT'; +export type Reserved = { [key in Item]?: Balance | null }; export default function useReservedDetails (address: string | undefined): Reserved { - const { api, formatted, genesisHash } = useInfo(address); + const { api, decimal, formatted, genesisHash } = useInfo(address); const activeRecoveries = useActiveRecoveries(api); const [reserved, setReserved] = useState({}); @@ -38,9 +37,21 @@ export default function useReservedDetails (address: string | undefined): Reserv return undefined; } - return api.createType('Balance', value); + return api.createType('Balance', value) as unknown as Balance; }, [api]); + const setValue = useCallback((item: Item, value: BN | null | undefined) => { + setReserved((prev) => { + const newState = { ...prev }; + + newState[item] = value + ? value.isZero() ? null : toBalance(value) + : value; + + return newState; + }); + }, [toBalance]); + useEffect(() => { if (!api || !genesisHash) { return; @@ -50,201 +61,330 @@ export default function useReservedDetails (address: string | undefined): Reserv // TODO: needs to incorporate people chain? /** fetch identity */ api.query?.['identity']?.['identityOf'](formatted).then(async (id) => { + setValue('identity', undefined); const basicDeposit = api.consts['identity']['basicDeposit'] as unknown as BN; // const subAccountDeposit = api.consts['identity']['subAccountDeposit'] as unknown as BN; - const subs = await api.query['identity']['subsOf'](formatted); + const subs = await api.query['identity']['subsOf'](formatted) as unknown as BN[]; const subAccountsDeposit = (subs ? subs[0] : BN_ZERO) as unknown as BN; const sum = (basicDeposit.add(subAccountsDeposit)) as unknown as BN; - !id.isEmpty && setReserved((prev) => { - prev.identity = toBalance(sum); - - return prev; - }); - }).catch(console.error); + if (!id.isEmpty) { + setValue('identity', sum); + } else { + setValue('identity', null); + } + }).catch((error) => { + console.error(error); + setValue('identity', null); + }); /** fetch proxy */ if (api.query?.['proxy'] && PROXY_CHAINS.includes(genesisHash)) { - api.query['proxy']['proxies'](formatted).then((p) => { - const maybeDeposit = p?.[1] as BN; + setValue('proxy', undefined); + + api.query['proxy']['proxies'](formatted).then((proxyInformation) => { + type ProxiesInformation = [Proxy[], number]; + + const proxiesInformation = proxyInformation.toPrimitive() as ProxiesInformation; - if (!maybeDeposit?.isZero()) { - setReserved((prev) => { - prev.proxy = toBalance(maybeDeposit); + const maybeDeposit = proxiesInformation?.[1]; - return prev; - }); + if (maybeDeposit !== 0) { + setValue('proxy', new BN(maybeDeposit)); + } else { + setValue('proxy', null); } - }).catch(console.error); + }).catch((error) => { + console.error(error); + setValue('proxy', null); + }); } /** fetch social recovery */ - api.query?.['recovery']?.['recoverable'](formatted).then((r) => { - const recoveryInfo = r.isSome ? r.unwrap() as unknown as PalletRecoveryRecoveryConfig : null; + if (api.query?.['recovery']) { + setValue('recovery', undefined); + + api.query['recovery']['recoverable'](formatted).then((r) => { + interface RecoveryType { + delayPeriod: number; + deposit: number; + threshold: number; + friends: string[]; + } - recoveryInfo?.deposit && setReserved((prev) => { - prev.recovery = toBalance((recoveryInfo.deposit as unknown as BN).add(activeLost?.deposit as unknown as BN || BN_ZERO)); + const recoveryInfo = r.isEmpty ? null : r.toPrimitive() as unknown as RecoveryType; - return prev; + if (!recoveryInfo) { + setValue('recovery', null); + + return; + } + + const recoveryDeposit = (new BN(recoveryInfo.deposit)).add(activeLost?.deposit || BN_ZERO); + + setValue('recovery', recoveryDeposit); + }).catch((error) => { + console.error(error); + setValue('recovery', null); }); - }).catch(console.error); + } else { + setValue('recovery', null); + } /** Fetch referenda */ if (api.query?.['referenda']?.['referendumInfoFor']) { + setValue('referenda', undefined); + + interface ReferendaDeposit { + who: string; + amount: number; + } + + interface Referenda { + approved?: [number, null, null]; + timedOut?: [number, ReferendaDeposit, null]; + rejected?: [number, ReferendaDeposit, null]; + cancelled?: [number, ReferendaDeposit, null]; + ongoing?: { submissionDeposit: ReferendaDeposit, decisionDeposit: ReferendaDeposit }; + } + let referendaDepositSum = BN_ZERO; api.query['referenda']['referendumInfoFor'].entries().then((referenda) => { referenda.forEach(([_, value]) => { - if (value.isSome) { - const ref = (value.unwrap()) as PalletReferendaReferendumInfoRankedCollectiveTally | undefined; + if (!value.isEmpty) { + // @ts-ignore + const ref = value.toPrimitive() as Referenda; - if (!ref) { + if (!ref || 'approved' in ref) { return; } - const info = (ref.isCancelled - ? ref.asCancelled - : ref.isRejected - ? ref.asRejected - : ref.isOngoing - ? ref.asOngoing - : ref.isApproved ? ref.asApproved : undefined) as PalletReferendaReferendumStatusRankedCollectiveTally | undefined; + if (ref.timedOut || ref.rejected || ref.cancelled) { + const who = ref?.timedOut?.[1]?.who || ref?.rejected?.[1]?.who || ref?.cancelled?.[1]?.who; - if (info?.submissionDeposit && info.submissionDeposit.who.toString() === formatted) { - referendaDepositSum = referendaDepositSum.add(info.submissionDeposit.amount); + if (who === formatted) { + const amount = ref?.timedOut?.[1]?.amount ?? ref?.rejected?.[1]?.amount ?? ref?.cancelled?.[1]?.amount ?? 0; + + referendaDepositSum = referendaDepositSum.add(new BN(amount)); + } } - if (info?.decisionDeposit?.isSome) { - const decisionDeposit = info?.decisionDeposit.unwrap(); + if (ref.ongoing) { + if (ref.ongoing.submissionDeposit && ref.ongoing.submissionDeposit.who === formatted) { + referendaDepositSum = referendaDepositSum.add(new BN(ref.ongoing.submissionDeposit.amount)); + } - if (decisionDeposit.who.toString() === formatted) { - referendaDepositSum = referendaDepositSum.add(decisionDeposit.amount); + if (ref.ongoing.decisionDeposit && ref.ongoing.decisionDeposit.who === formatted) { + referendaDepositSum = referendaDepositSum.add(new BN(ref.ongoing.decisionDeposit.amount)); } } + + // if (info?.submissionDeposit && info.submissionDeposit.who.toString() === formatted) { + // referendaDepositSum = referendaDepositSum.add(info.submissionDeposit.amount); + // } + + // if (info?.decisionDeposit?.isSome) { + // const decisionDeposit = info?.decisionDeposit.unwrap(); + + // if (decisionDeposit.who.toString() === formatted) { + // referendaDepositSum = referendaDepositSum.add(decisionDeposit.amount); + // } + // } } }); - if (!referendaDepositSum.isZero()) { - setReserved((prev) => { - prev.referenda = toBalance(referendaDepositSum); - - return prev; - }); - } - }).catch(console.error); + setValue('referenda', referendaDepositSum); + }).catch((error) => { + console.error(error); + setValue('referenda', null); + }); + } else { + setValue('referenda', null); } /** Fetch bounties */ if (api.query?.['bounties']?.['bounties']) { + setValue('bounty', undefined); + let sum = BN_ZERO; api.query['bounties']['bounties'].entries().then((bounties) => { bounties.forEach(([_, value]) => { - if (value.isSome) { - const bounty = (value.unwrap()); + if (!value.isEmpty && decimal) { + interface Bounty { + bond: number; + curatorDeposit: number; + fee: number; + proposer: string; + value: number; + status: { + active: { + curator: string; + updateDue: number; + }; + }; + } + const bounty = value.toPrimitive() as unknown as Bounty; if (bounty.proposer.toString() === formatted) { - sum = sum.add(bounty.curatorDeposit); + sum = sum.add(new BN(bounty.curatorDeposit)); } } }); - if (!sum.isZero()) { - setReserved((prev) => { - prev.bounty = toBalance(sum); - - return prev; - }); - } - }).catch(console.error); + setValue('bounty', sum); + }).catch((error) => { + console.error(error); + setValue('bounty', null); + }); + } else { + setValue('bounty', null); } /** Fetch indices */ if (api.query?.['indices']?.['accounts']) { + setValue('index', undefined); + let sum = BN_ZERO; api.query['indices']['accounts'].entries().then((indices) => { indices.forEach(([_, value]) => { - if (value.isSome) { - const [address, deposit, _status] = value.unwrap() as [AccountId, BN, boolean]; + if (!value.isEmpty) { + const [address, deposit, _status] = value.toPrimitive() as [string, number, boolean]; if (address.toString() === formatted) { - sum = sum.add(deposit); + sum = sum.add(new BN(deposit)); } } }); - if (!sum.isZero()) { - setReserved((prev) => { - prev.index = toBalance(sum); - - return prev; - }); - } - }).catch(console.error); + setValue('index', sum); + }).catch((error) => { + console.error(error); + setValue('index', null); + }); + } else { + setValue('index', null); } /** Fetch multisig */ if (api.query?.['multisig']) { + setValue('multisig', undefined); + let sum = BN_ZERO; api.query['multisig']['multisigs'].entries().then((multisigs) => { multisigs.forEach(([_, value]) => { - if (value.isSome) { - const { deposit, depositor } = value.unwrap() as PalletMultisigMultisig; + if (!value.isEmpty) { + const { deposit, depositor } = value.toPrimitive() as { deposit: number, depositor: string }; - if (depositor.toString() === formatted) { - sum = sum.add(deposit); + if (depositor === formatted) { + sum = sum.add(new BN(deposit)); } } }); - if (!sum.isZero()) { - setReserved((prev) => { - prev.multisig = toBalance(sum); - - return prev; - }); - } - }).catch(console.error); + setValue('multisig', sum); + }).catch((error) => { + console.error(error); + setValue('multisig', null); + }); + } else { + setValue('multisig', null); } /** Fetch preImage */ if (api.query?.['preimage']?.['requestStatusFor']) { - let sum = BN_ZERO; + setValue('preimage', undefined); + + interface Preimage { + unrequested?: { + len: number; + ticket: [string, number]; // address, amount + deposit?: [string, number] | null; // address, amount (for old preimage) + }; + requested?: { + maybeTicket: [string, number]; // address, amount + deposit?: [string, number] | null; // address, amount (for old preimage) + } | null; + } + + const calculatePreimageDeposit = (preimages: [StorageKey, Codec][] | undefined, formatted: string): BN => { + let sum = new BN(0); + + if (!preimages) { + return sum; + } - api.query['preimage']['requestStatusFor'].entries().then((preimages) => { preimages.forEach(([_, value]) => { - if (value.isSome) { - const status = value.unwrap() as PalletPreimageRequestStatus; + if (value.isEmpty) { + return; + } + + const status = value.toPrimitive() as unknown as Preimage; - const request = status.isUnrequested ? status.asUnrequested : undefined; + // Helper function to add deposit if account matches + const addDepositIfMatched = (ticket: [string, number] | null | undefined) => { + if (!ticket) { + return; + } - if (request) { - const [accountId, deposit] = request.ticket; + const [accountId, deposit] = ticket; - if (accountId.toString() === formatted) { - sum = sum.add(deposit); - } + if (accountId === formatted) { + sum = sum.add(new BN(deposit)); } - } + }; + + // Check unrequested and requested preimage statuses + addDepositIfMatched(status?.unrequested?.ticket); + addDepositIfMatched(status?.requested?.maybeTicket); + addDepositIfMatched(status?.unrequested?.deposit); + addDepositIfMatched(status?.requested?.deposit); }); - if (!sum.isZero()) { - setReserved((prev) => { - prev.preimage = toBalance(sum); + return sum; + }; - return prev; - }); + const fetchPreimageDeposits = async () => { + if (!formatted) { + return; } - }).catch(console.error); + + try { + // Fetch both new and old preimage entries + const [newPreimage, oldPreimage] = await Promise.all([ + api.query['preimage']['requestStatusFor'].entries(), + api.query['preimage']['statusFor'].entries() + ]); + + // Calculate deposits for both new and old preimages + const totalSum = calculatePreimageDeposit(newPreimage, formatted).add(calculatePreimageDeposit(oldPreimage, formatted)); + + setValue('preimage', totalSum); + } catch (error) { + console.error(error); + setValue('preimage', null); + } + }; + + fetchPreimageDeposits() + .catch((error) => { + console.error(error); + setValue('preimage', null); + }); + } else { + setValue('preimage', null); } /** Fetch society */ if (api.query?.['society']) { + setValue('society', undefined); + let sum = BN_ZERO; api.query['society']['bids']().then(async (bids) => { @@ -265,23 +405,204 @@ export default function useReservedDetails (address: string | undefined): Reserv sum = sum.add(deposit); } - if (!sum.isZero()) { - setReserved((prev) => { - prev.society = toBalance(sum); + setValue('society', sum); + }).catch((error) => { + console.error(error); + setValue('society', null); + }); + } else { + setValue('society', null); + } + + /** assets on asset hubs */ + if (api.consts?.['assets'] && ASSET_HUBS.includes(genesisHash)) { + setValue('assets', undefined); - return prev; - }); + api.query['assets']['asset'].entries().then(async (assets) => { + interface Assets { + deposit: number; + owner: string; } - }).catch(console.error); + + const myAssets = assets.filter(([_id, asset]) => { + if (asset.isEmpty || _id.isEmpty) { + return false; + } + + const assetInPrimitive = asset.toPrimitive() as unknown as Assets; + + return assetInPrimitive.owner === formatted; + }); + + if (myAssets.length === 0) { + setValue('assets', null); + + return; + } + + const myAssetsId = myAssets.map(([assetId, _]) => { + const assetIdInHuman = assetId.toHuman() as string[]; + + return assetIdInHuman[0].replaceAll(',', ''); + }); + const assetDeposit = api.consts['assets']['assetDeposit'] as unknown as BN; + + interface AssetMetadata { + decimals: number; + deposit: number; + isFrozen: boolean; + } + + const myAssetsMetadata = await Promise.all(myAssetsId.map((assetId) => api.query['assets']['metadata'](assetId))) as unknown as (AssetMetadata | undefined)[]; + + const totalAssetDeposit = myAssetsMetadata.reduce((acc, metadata) => { + return acc.add(metadata?.deposit ? new BN(metadata?.deposit) : BN_ZERO); + }, BN_ZERO); + + const finalDeposit = totalAssetDeposit.add(assetDeposit.muln(myAssetsId.length)); + + setValue('assets', finalDeposit); + }).catch((error) => { + console.error(error); + setValue('assets', null); + }); + } else { + setValue('assets', null); } + + /** nft */ + // if (api.query?.['nfts']) { + // setValue('NFT', undefined); + + // api.query['nfts']['collection'].entries().then(async (collections) => { + // interface Collection { + // owner: string; + // ownerDeposit: number; + // items: number; + // itemMetadatas: number; + // itemConfigs: number; + // attributes: number; + // } + + // const my = collections.filter(([_, collection]) => { + // if (collection.isEmpty) { + // return false; + // } + + // const collectionInPrimitive = collection.toPrimitive() as unknown as Collection; + + // return collectionInPrimitive.owner === formatted; + // }); + + // const myCollections = my.map(([_, collection]) => collection.toPrimitive() as unknown as Collection); + + // console.log('myCollections :::', my.map(([id, collection]) => [id.toHuman(), collection.toPrimitive() as unknown as Collection])); + + // const totalCollectionDeposit = myCollections.reduce((acc, collectionInformation) => { + // if (!collectionInformation.ownerDeposit) { + // return acc.add(BN_ZERO); + // } + + // return acc.add(new BN(collectionInformation.ownerDeposit)); + // }, BN_ZERO); + + // // ATTRIBUTES + // const attributeDepositBase = api.consts['nfts']['attributeDepositBase'] as unknown as BN; + // const totalCollectionsAttribute = myCollections.reduce((acc, { attributes }) => { + // return acc + attributes; + // }, 0); + + // const totalAttributesDeposit = attributeDepositBase.muln(totalCollectionsAttribute); + + // interface NFTInformation { + // deposit: { + // account: string; + // amount: number; + // }, + // owner: string; + // } + + // const nft = await api.query['nfts']['item'].entries(); + + // const myNFTs = nft.filter(([nftId, nftInfo]) => { + // if (nftInfo.isEmpty || nftId.isEmpty) { + // return false; + // } + + // const nftInformation = nftInfo.toPrimitive() as unknown as NFTInformation; + + // return nftInformation.deposit.account === formatted; + // }).map(([id, nftInfo]) => { + // const nftInformation = nftInfo.toPrimitive() as unknown as NFTInformation; + // const nftId = id.toHuman() as [string, string]; // [collectionId, nftId] + + // nftId.forEach((value, index) => { + // nftId[index] = value.replaceAll(/,/g, ''); + // }); + + // return { nftId, nftInformation }; + // }); + + // console.log('myNFTs :::', myNFTs); + + // const totalItemDeposit = myNFTs.reduce((acc, { nftInformation }) => { + // return acc.add(new BN(nftInformation.deposit.amount)); + // }, BN_ZERO); + + // setValue('NFT', totalCollectionDeposit.add(totalItemDeposit).add(totalAttributesDeposit)); + // }).catch((error) => { + // console.error(error); + // setValue('NFT', null); + // }); + // } else { + // setValue('NFT', null); + // } + + /** uniques */ + // if (api.query?.['uniques']) { + // setValue('uniques', undefined); + + // interface Unique { + // admin: string; + // attributes: number; + // freeHolding: boolean; + // freezer: string; + // isFrozen: boolean; + // issuer: string; + // itemMetadatas: number; + // items: number; + // owner: string; + // totalDeposit: number; + // } + + // api.query['uniques']['class'].entries().then((classes) => { + // const myClasses = classes.filter(([_, uniqueInfo]) => { + // const uniqueInfoInPrimitive = uniqueInfo.toPrimitive() as unknown as Unique; + + // return uniqueInfoInPrimitive.owner === formatted; + // }) + // .map(([_, uniquesInfo]) => uniquesInfo.toPrimitive() as unknown as Unique); + + // console.log('myClasses:', myClasses); + + // const totalClassesDeposit = myClasses.reduce((acc, { totalDeposit }) => acc.add(new BN(totalDeposit)), BN_ZERO); + + // setValue('uniques', totalClassesDeposit); + // }).catch((error) => { + // console.error(error); + // setValue('uniques', null); + // }); + // } else { + // setValue('uniques', null); + // } } catch (e) { - console.error('Fatal error while fetching reserved details:', e) + console.error('Fatal error while fetching reserved details:', e); } - }, [activeLost?.deposit, api, formatted, genesisHash, toBalance]); + }, [activeLost?.deposit, api, decimal, formatted, genesisHash, setValue]); useEffect(() => { setReserved({}); - }, [genesisHash]); + }, [address, genesisHash]); return reserved; } diff --git a/packages/extension-polkagate/src/popup/account/ReservedReasons.tsx b/packages/extension-polkagate/src/popup/account/ReservedReasons.tsx index 772cd2674..407ed389d 100644 --- a/packages/extension-polkagate/src/popup/account/ReservedReasons.tsx +++ b/packages/extension-polkagate/src/popup/account/ReservedReasons.tsx @@ -12,7 +12,7 @@ import type { DeriveAccountRegistration } from '@polkadot/api-derive/types'; import type { AccountId } from '@polkadot/types/interfaces/runtime'; import { Container, Divider, Grid, Typography } from '@mui/material'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { toTitleCase } from '@polkadot/extension-polkagate/src/fullscreen/governance/utils/util'; @@ -54,6 +54,28 @@ export default function ReservedReasons ({ address, assetId, identity, setShow, setShow(false); }, [setShow]); + const reasonsToShow = useMemo(() => { + const details = Object.values(reservedDetails); + + if (details.length === 0) { + return undefined + } + + const noReason = details.every((deposit) => deposit === null); + + if (noReason) { + return null; + } + + const filteredReservedDetails = Object.fromEntries( + Object.entries(reservedDetails).filter(([_key, value]) => value && !value.isZero()) + ); + + return Object.values(filteredReservedDetails).length > 0 + ? filteredReservedDetails + : undefined + }, [reservedDetails]); + return ( @@ -80,9 +102,9 @@ export default function ReservedReasons ({ address, assetId, identity, setShow, - {Object.entries(reservedDetails)?.length + {reasonsToShow ? <> - {Object.entries(reservedDetails)?.map(([key, value], index) => ( + {Object.entries(reasonsToShow)?.map(([key, value], index) => ( @@ -110,13 +132,17 @@ export default function ReservedReasons ({ address, assetId, identity, setShow, ))} - : + : reasonsToShow === null + ? + {t('No reasons found!')} + + : } diff --git a/packages/extension/public/locales/en/translation.json b/packages/extension/public/locales/en/translation.json index f1a0b6f22..ff7824423 100644 --- a/packages/extension/public/locales/en/translation.json +++ b/packages/extension/public/locales/en/translation.json @@ -1284,6 +1284,7 @@ "Reasons": "", "Please wait a few seconds and don't close the window.": "", "Reserved Reasons": "", + "No reasons found!": "", "Profile Name": "", "New profile": "", "No user profile": "", diff --git a/packages/extension/public/locales/fr/translation.json b/packages/extension/public/locales/fr/translation.json index 6c750b090..99173f807 100644 --- a/packages/extension/public/locales/fr/translation.json +++ b/packages/extension/public/locales/fr/translation.json @@ -1278,6 +1278,7 @@ "Reasons": "Raisons", "Please wait a few seconds and don't close the window.": "Veuillez patienter quelques secondes et ne fermez pas la fenêtre.", "Reserved Reasons": "Raisons réservées", + "No reasons found!": "Aucune raison trouvée!", "Profile Name": "Nom de profil", "New profile": "Nouveau profil", "No user profile": "Aucun profil utilisateur", diff --git a/packages/extension/public/locales/hi/translation.json b/packages/extension/public/locales/hi/translation.json index be8496e6a..9f1eb23f1 100644 --- a/packages/extension/public/locales/hi/translation.json +++ b/packages/extension/public/locales/hi/translation.json @@ -1275,6 +1275,7 @@ "Reasons": "कारण", "Please wait a few seconds and don't close the window.": "कृपया कुछ सेकंड प्रतीक्षा करें और विंडो न बंद करें।", "Reserved Reasons": "आरक्षित कारण", + "No reasons found!": "कोई कारण नहीं मिला!", "Profile Name": "प्रोफाइल नाम", "New profile": "नई प्रोफाइल", "No user profile": "कोई उपयोगकर्ता प्रोफाइल नहीं है", diff --git a/packages/extension/public/locales/ru/translation.json b/packages/extension/public/locales/ru/translation.json index ccb7e1fb4..1de577564 100644 --- a/packages/extension/public/locales/ru/translation.json +++ b/packages/extension/public/locales/ru/translation.json @@ -1273,6 +1273,7 @@ "Reasons": "Поводы", "Please wait a few seconds and don't close the window.": "Подождите несколько секунд и не закрывайте окно.", "Reserved Reasons": "Зарезервированные причины", + "No reasons found!": "Причины не найдены!", "Profile Name": "Имя профиля", "New profile": "Новый профиль", "No user profile": "Нет профиля пользователя", diff --git a/packages/extension/public/locales/zh/translation.json b/packages/extension/public/locales/zh/translation.json index f3fcb23ef..845739c06 100644 --- a/packages/extension/public/locales/zh/translation.json +++ b/packages/extension/public/locales/zh/translation.json @@ -1282,6 +1282,7 @@ "Reasons": "原因", "Please wait a few seconds and don't close the window.": "请等待几秒钟,不要关闭窗口。", "Reserved Reasons": "保留原因", + "No reasons found!": "未找到原因!", "Profile Name": "个人资料名称", "New profile": "新个人资料", "No user profile": "无用户个人资料",