From 346974d6c099f73fe4ec9884559e23bd4167929a Mon Sep 17 00:00:00 2001 From: Radu Mojic Date: Mon, 6 Nov 2023 17:09:50 +0200 Subject: [PATCH] show the first transaction date on the account overview card --- src/hooks/adapter/helpers.ts | 4 +- .../AccountDetailsCard/AccountDetailsCard.tsx | 30 ++++++++++---- src/layouts/AccountLayout/AccountLayout.tsx | 35 +++++++++++++++- src/redux/reducers.ts | 2 + src/redux/selectors/accountExtra.ts | 11 +++++ src/redux/selectors/index.ts | 1 + src/redux/slices/accountExtra.ts | 31 ++++++++++++++ src/redux/slices/index.ts | 1 + src/types/account.types.ts | 6 +++ src/types/adapter.types.ts | 41 ++++++++----------- 10 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 src/redux/selectors/accountExtra.ts create mode 100644 src/redux/slices/accountExtra.ts diff --git a/src/hooks/adapter/helpers.ts b/src/hooks/adapter/helpers.ts index e582e191e..d0758ee51 100644 --- a/src/hooks/adapter/helpers.ts +++ b/src/hooks/adapter/helpers.ts @@ -33,6 +33,7 @@ export function getTransactionsParams({ miniBlockHash, search, token, + order, withUsername = true }: GetTransactionsType) { const params: AdapterProviderPropsType['params'] = { @@ -50,7 +51,8 @@ export function getTransactionsParams({ ...(status ? { status } : {}), ...(miniBlockHash ? { miniBlockHash } : {}), ...(search ? { search } : {}), - ...(token ? { token } : {}) + ...(token ? { token } : {}), + ...(order ? { order } : {}) }; return params; diff --git a/src/layouts/AccountLayout/AccountDetailsCard/AccountDetailsCard.tsx b/src/layouts/AccountLayout/AccountDetailsCard/AccountDetailsCard.tsx index bbfc6abe7..91b97a498 100644 --- a/src/layouts/AccountLayout/AccountDetailsCard/AccountDetailsCard.tsx +++ b/src/layouts/AccountLayout/AccountDetailsCard/AccountDetailsCard.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { DECIMALS } from 'config'; import { useSelector } from 'react-redux'; import { ELLIPSIS } from 'appConstants'; @@ -19,6 +18,7 @@ import { FormatUSD, Overlay } from 'components'; +import { DECIMALS } from 'config'; import { isContract, urlBuilder, formatDate, formatHerotag } from 'helpers'; import { useAdapter } from 'hooks'; import { faClock, faExclamationTriangle, faInfoCircle } from 'icons/regular'; @@ -29,7 +29,11 @@ import { faHexagonVerticalNft, faShieldCheck } from 'icons/solid'; -import { activeNetworkSelector, accountSelector } from 'redux/selectors'; +import { + activeNetworkSelector, + accountSelector, + accountExtraSelector +} from 'redux/selectors'; import { AccountUpgradeType } from 'types'; import { AccountUsdValueCardItem } from './components/AccountUsdValueCardItem'; @@ -39,6 +43,7 @@ export const AccountDetailsCard = () => { const ref = useRef(null); const { account } = useSelector(accountSelector); + const { accountExtra } = useSelector(accountExtraSelector); const { address, balance, @@ -59,6 +64,7 @@ export const AccountDetailsCard = () => { activeGuardianAddress, activeGuardianServiceUid } = account; + const { firstTransactionDate } = accountExtra; const { id: activeNetworkId, adapter } = useSelector(activeNetworkSelector); const { getProvider, @@ -100,11 +106,6 @@ export const AccountDetailsCard = () => { } }; - React.useEffect(() => { - fetchProviderDetails(); - fetchUpgradesDetails(); - }, [activeNetworkId, address]); - const fetchAccountTokensCount = () => { if (tokensActive) { getAccountTokensCount({ address, includeMetaESDT: true }).then( @@ -141,6 +142,12 @@ export const AccountDetailsCard = () => { ); } }; + + useEffect(() => { + fetchProviderDetails(); + fetchUpgradesDetails(); + }, [activeNetworkId, address]); + useEffect(() => { fetchAccountNftsCount(); fetchAccountTokensCount(); @@ -515,6 +522,15 @@ export const AccountDetailsCard = () => { <>N/A )} + {firstTransactionDate && ( + + + + )} diff --git a/src/layouts/AccountLayout/AccountLayout.tsx b/src/layouts/AccountLayout/AccountLayout.tsx index 79323bf0c..3f89acb16 100644 --- a/src/layouts/AccountLayout/AccountLayout.tsx +++ b/src/layouts/AccountLayout/AccountLayout.tsx @@ -11,8 +11,13 @@ import { Loader } from 'components'; import { addressIsBech32, getTotalTokenUsdValue } from 'helpers'; import { useAdapter, useGetPage } from 'hooks'; import { activeNetworkSelector } from 'redux/selectors'; -import { setAccount, setAccountStaking } from 'redux/slices'; -import { IdentityType, ProviderType, DelegationType } from 'types'; +import { setAccount, setAccountExtra, setAccountStaking } from 'redux/slices'; +import { + IdentityType, + ProviderType, + DelegationType, + SortOrderEnum +} from 'types'; import { AccountDetailsCard } from './AccountDetailsCard'; import { FailedAccount } from './FailedAccount'; @@ -28,6 +33,7 @@ export const AccountLayout = () => { const { getAccount, getAccountTokens, + getAccountTransfers, getAccountDelegationLegacy, getAccountDelegation, getAccountStake, @@ -68,6 +74,30 @@ export const AccountLayout = () => { } }; + const fetchFirstTransactionDate = () => { + if (address) { + getAccountTransfers({ + address, + size: 1, + order: SortOrderEnum.asc, + fields: 'timestamp' + }).then(({ data, success }) => { + let firstTransactionDate = undefined; + if (success && data && data.length > 0) { + firstTransactionDate = data[0]?.['timestamp']; + } + dispatch( + setAccountExtra({ + accountExtra: { + firstTransactionDate + }, + isFetched: success + }) + ); + }); + } + }; + const fetchStakingDetails = () => { if (address) { Promise.all([ @@ -323,6 +353,7 @@ export const AccountLayout = () => { useEffect(() => { fetchStakingDetails(); + fetchFirstTransactionDate(); }, [address, activeNetworkId]); useEffect(() => { diff --git a/src/redux/reducers.ts b/src/redux/reducers.ts index 91b9ffe65..994ec56f7 100644 --- a/src/redux/reducers.ts +++ b/src/redux/reducers.ts @@ -4,6 +4,7 @@ import storage from 'redux-persist/lib/storage'; // import sessionStorage from 'redux-persist/lib/storage/session'; import { accountReducer } from './slices/account'; +import { accountExtraReducer } from './slices/accountExtra'; import { accountStakingReducer } from './slices/accountStaking'; import { collectionReducer } from './slices/collection'; import { economicsReducer } from './slices/economics'; @@ -51,6 +52,7 @@ export const customIgnoredSlices = { interface: interfaceReducer, account: accountReducer, + accountExtra: accountExtraReducer, accountStaking: accountStakingReducer, collection: collectionReducer, economics: economicsReducer, diff --git a/src/redux/selectors/accountExtra.ts b/src/redux/selectors/accountExtra.ts new file mode 100644 index 000000000..962cfd074 --- /dev/null +++ b/src/redux/selectors/accountExtra.ts @@ -0,0 +1,11 @@ +import { createSelector } from 'reselect'; +import { RootState } from '../store'; + +const stateSelector = (state: RootState) => { + return state.accountExtra; +}; + +export const accountExtraSelector = createSelector( + stateSelector, + (state) => state +); diff --git a/src/redux/selectors/index.ts b/src/redux/selectors/index.ts index a5d664663..33e6cd64a 100644 --- a/src/redux/selectors/index.ts +++ b/src/redux/selectors/index.ts @@ -1,4 +1,5 @@ export * from './account'; +export * from './accountExtra'; export * from './accountStaking'; export * from './collection'; export * from './economics'; diff --git a/src/redux/slices/accountExtra.ts b/src/redux/slices/accountExtra.ts new file mode 100644 index 000000000..02a55731d --- /dev/null +++ b/src/redux/slices/accountExtra.ts @@ -0,0 +1,31 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { AccountExtraSliceType } from 'types/account.types'; + +export const getInitialAccountExtraState = (): AccountExtraSliceType => { + return { + accountExtra: { + firstTransactionDate: undefined + }, + isFetched: false + }; +}; + +export const accountExtraSlice = createSlice({ + name: 'accountExtraSlice', + initialState: getInitialAccountExtraState(), + reducers: { + setAccountExtra: ( + state: AccountExtraSliceType, + action: PayloadAction + ) => { + state.accountExtra.firstTransactionDate = + action.payload.accountExtra.firstTransactionDate; + + state.isFetched = action.payload.isFetched; + } + } +}); + +export const { setAccountExtra } = accountExtraSlice.actions; + +export const accountExtraReducer = accountExtraSlice.reducer; diff --git a/src/redux/slices/index.ts b/src/redux/slices/index.ts index e5fbb171c..f67a7bea2 100644 --- a/src/redux/slices/index.ts +++ b/src/redux/slices/index.ts @@ -1,4 +1,5 @@ export * from './account'; +export * from './accountExtra'; export * from './accountStaking'; export * from './collection'; export * from './economics'; diff --git a/src/types/account.types.ts b/src/types/account.types.ts index 71c2151cb..a0ba2a7bb 100644 --- a/src/types/account.types.ts +++ b/src/types/account.types.ts @@ -64,6 +64,12 @@ export interface AccountStakingSliceType { delegationLegacyIdentity: IdentityType | undefined; } +export interface AccountExtraSliceType extends SliceType { + accountExtra: { + firstTransactionDate: number | undefined; + }; +} + export interface AccountAssetType { name: string; description?: string; diff --git a/src/types/adapter.types.ts b/src/types/adapter.types.ts index 62000ce0f..b8f4043b7 100644 --- a/src/types/adapter.types.ts +++ b/src/types/adapter.types.ts @@ -1,30 +1,32 @@ -export interface GetBlocksType { +import { SortOrderEnum } from 'types'; + +export interface BaseApiType { page?: number; size?: number; + fields?: string; + extract?: string; +} + +export interface GetBlocksType extends BaseApiType { shard?: number; epoch?: number; proposer?: string; withProposerIdentity?: boolean; } -export interface GetTokensType { - fields?: string; - page?: number; - size?: number; +export interface GetTokensType extends BaseApiType { type?: string; search?: string; name?: string; identifier?: string; identifiers?: string; sort?: string; - order?: string; + order?: SortOrderEnum; includeMetaESDT?: boolean; withUsername?: boolean; } -export interface GetNftsType { - page?: number; - size?: number; +export interface GetNftsType extends BaseApiType { search?: string; identifiers?: string; type?: string; @@ -40,10 +42,7 @@ export interface GetNftsType { source?: string; } -export interface GetCollectionsType { - fields?: string; - page?: number; - size?: number; +export interface GetCollectionsType extends BaseApiType { search?: string; identifiers?: string; type?: string; @@ -54,7 +53,7 @@ export interface GetCollectionsType { withOwner?: boolean; } -export interface GetNodesType { +export interface GetNodesType extends BaseApiType { search?: string; issues?: string; online?: boolean; @@ -62,19 +61,15 @@ export interface GetNodesType { shard?: string; status?: string; count?: boolean; - page?: number; - size?: number; identity?: string; sort?: string; - order?: string; + order?: SortOrderEnum; pagination?: boolean; provider?: string; fullHistory?: string; } -export interface GetTransactionsType { - page?: number; - size?: number; +export interface GetTransactionsType extends BaseApiType { address?: string; senderShard?: number; receiverShard?: number; @@ -88,12 +83,12 @@ export interface GetTransactionsType { search?: string; token?: string; withUsername?: boolean; + order?: SortOrderEnum; } -export interface GetProvidersType { +export interface GetProvidersType extends BaseApiType { identity?: string; providers?: string; - fields?: string; } export type AdapterProviderType = ( @@ -131,7 +126,7 @@ export interface AdapterProviderPropsType { identities?: string; provider?: string; sort?: string; - order?: string; + order?: SortOrderEnum; online?: boolean; collection?: string; identifier?: string;