Skip to content

Commit

Permalink
TW-683: Assets rework. Tokens. Manage page. Fix: listing other accoun…
Browse files Browse the repository at this point in the history
…t tokens too
  • Loading branch information
alex-tsx committed Sep 22, 2023
1 parent 1e51586 commit 1b494af
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 26 deletions.
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
- Refactor `lib/assets/hooks`
- `useSlugsOf`
- `@deprecated isCollectibleTokenMetadata`
- Optimize balances store slice reducing
-
4 changes: 2 additions & 2 deletions src/app/hooks/use-metadata-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const useMetadataLoading = () => {
const dispatch = useDispatch();
const tezos = useTezos();

const tokens = useAccountAssetsSelector(account, chainId);
const collectibles = useAccountAssetsSelector(account, chainId, true);
const tokens = useAccountAssetsSelector(account, chainId, 'tokens');
const collectibles = useAccountAssetsSelector(account, chainId, 'collectibles');

const assetsMetadata = useTokensMetadataSelector();

Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/Collectibles/CollectiblesTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const CollectiblesTab = memo<Props>(({ scrollToTheTabsBar }) => {
const { popup } = useAppEnv();
const { publicKeyHash } = useAccount();

const assetsAreLoading = useAreAssetsLoading(true);
const assetsAreLoading = useAreAssetsLoading('collectibles');
const metadatasLoading = useTokensMetadataLoadingSelector();
const isSyncing = assetsAreLoading || metadatasLoading;

Expand Down
3 changes: 1 addition & 2 deletions src/app/pages/Home/OtherComponents/Tokens/Tokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { useEnabledAccountTokensSlugs } from 'lib/assets/hooks';
import { useFilteredAssetsSlugs } from 'lib/assets/use-filtered';
import { T, t } from 'lib/i18n';
import { useAccount } from 'lib/temple/front';
import { useMemoWithCompare } from 'lib/ui/hooks';
import { useLocalStorage } from 'lib/ui/local-storage';
import Popper, { PopperRenderProps } from 'lib/ui/Popper';
import { ZERO } from 'lib/utils/numbers';
Expand All @@ -45,7 +44,7 @@ export const TokensTab: FC = () => {
const { publicKeyHash } = useAccount();
const { popup } = useAppEnv();

const isSyncing = useAreAssetsLoading();
const isSyncing = useAreAssetsLoading('tokens');

const slugs = useEnabledAccountTokensSlugs();

Expand Down
4 changes: 2 additions & 2 deletions src/app/pages/ManageAssets/ManageCollectibles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export const ManageCollectiblesContent = memo(() => {

const slugs = useMemo(() => collectibles.map(c => c.slug), [collectibles]);

const tokensAreLoading = useAreAssetsLoading(true);
const assetsAreLoading = useAreAssetsLoading('collectibles');
const metadatasLoading = useTokensMetadataLoadingSelector();
const isLoading = tokensAreLoading || metadatasLoading;
const isLoading = assetsAreLoading || metadatasLoading;

const { filteredAssets, searchValue, setSearchValue } = useFilteredAssetsSlugs(slugs, false);

Expand Down
8 changes: 4 additions & 4 deletions src/app/pages/ManageAssets/ManageTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useAreAssetsLoading } from 'app/store/assets/selectors';
import { useTokensMetadataLoadingSelector } from 'app/store/tokens-metadata/selectors';
import SearchAssetField from 'app/templates/SearchAssetField';
import { TEMPLE_TOKEN_SLUG } from 'lib/assets';
import { useAccountTokens } from 'lib/assets/hooks';
import { useAllAvailableTokens } from 'lib/assets/hooks';
import { useFilteredAssetsSlugs } from 'lib/assets/use-filtered';
import { T, t } from 'lib/i18n';
import { useAccount, useChainId } from 'lib/temple/front';
Expand All @@ -26,16 +26,16 @@ export const ManageTokensContent = memo(() => {

const dispatch = useDispatch();

const tokens = useAccountTokens(publicKeyHash, chainId);
const tokens = useAllAvailableTokens(publicKeyHash, chainId);

const managebleSlugs = useMemo(
() => tokens.reduce<string[]>((acc, { slug }) => (slug === TEMPLE_TOKEN_SLUG ? acc : acc.concat(slug)), []),
[tokens]
);

const tokensAreLoading = useAreAssetsLoading();
const assetsAreLoading = useAreAssetsLoading('tokens');
const metadatasLoading = useTokensMetadataLoadingSelector();
const isLoading = tokensAreLoading || metadatasLoading;
const isLoading = assetsAreLoading || metadatasLoading;

const { filteredAssets, searchValue, setSearchValue } = useFilteredAssetsSlugs(managebleSlugs, false);

Expand Down
15 changes: 9 additions & 6 deletions src/app/store/assets/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import { useMemoWithCompare } from 'lib/ui/hooks';

import { useSelector } from '../root-state.selector';

export const useAccountAssetsSelector = (account: string, chainId: string, collectibles?: boolean) => {
const allAssets = useSelector(state => state.assets[collectibles ? 'collectibles' : 'tokens'].data);
type AssetsType = 'collectibles' | 'tokens';

export const useAllAssetsSelector = (type: AssetsType) => useSelector(state => state.assets[type].data);

export const useAccountAssetsSelector = (account: string, chainId: string, type: AssetsType) => {
const assets = useAllAssetsSelector(type);

return useMemoWithCompare(
() => allAssets.filter(t => t.account === account && t.chainId === chainId),
[allAssets],
() => assets.filter(t => t.account === account && t.chainId === chainId),
[assets],
isEqual
);
};

export const useAreAssetsLoading = (collectibles?: boolean) =>
useSelector(state => state.assets[collectibles ? 'collectibles' : 'tokens'].isLoading);
export const useAreAssetsLoading = (type: AssetsType) => useSelector(state => state.assets[type].isLoading);

export const useMainnetTokensWhitelistSelector = () => useSelector(state => state.assets.mainnetWhitelist);
1 change: 1 addition & 0 deletions src/app/store/balances/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ const EMPTY_BALANCES_RECORD = {};

export const useBalancesSelector = (publicKeyHash: string, chainId: string) => {
const publicKeyHashWithChainId = getKeyForBalancesRecord(publicKeyHash, chainId);

return useSelector(state => state.balances.balancesAtomic[publicKeyHashWithChainId]?.data ?? EMPTY_BALANCES_RECORD);
};
51 changes: 42 additions & 9 deletions src/lib/assets/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { useMemo } from 'react';
import { ChainIds } from '@taquito/taquito';
import { isEqual, sortBy, uniqBy } from 'lodash';

import { useAccountAssetsSelector, useMainnetTokensWhitelistSelector } from 'app/store/assets/selectors';
import {
useAllAssetsSelector,
useAccountAssetsSelector,
useMainnetTokensWhitelistSelector
} from 'app/store/assets/selectors';
import type { StoredAssetStatus } from 'app/store/assets/state';
import { useBalancesSelector } from 'app/store/balances/selectors';
import { useAccount, useChainId } from 'lib/temple/front';
Expand All @@ -21,10 +25,14 @@ interface AccountToken {
predefined?: boolean;
}

/**
* Sorting is needed to preserve some tokens order (avoid UI listing jumps)
* after merge of multiple sources (e.g. stored, predefined, whitelist)
*/
const TOKENS_SORT_ITERATEES: (keyof AccountToken)[] = ['predefined', 'slug'];

export const useAccountTokens = (account: string, chainId: string) => {
const stored = useAccountAssetsSelector(account, chainId);
const useAccountTokens = (account: string, chainId: string) => {
const stored = useAccountAssetsSelector(account, chainId, 'tokens');
const whitelistSlugs = useWhitelistSlugs(chainId);

const balances = useBalancesSelector(account, chainId);
Expand Down Expand Up @@ -60,20 +68,45 @@ export const useAccountTokens = (account: string, chainId: string) => {
}, []);

// Keep this order to preserve correct statuses & flags
const tokens = predefined.concat(storedReduced).concat(whitelisted);
const concatenated: AccountToken[] = predefined.concat(storedReduced).concat(whitelisted);

// Sorting is needed to preserve some tokens order (avoid UI listing jumps)
// after merge of multiple sources (stored, predefined, whitelist)
return sortBy(
uniqBy(tokens, t => t.slug),
uniqBy(concatenated, t => t.slug),
TOKENS_SORT_ITERATEES
);
},
[stored, chainId, whitelistSlugs, balances],
[chainId, stored, whitelistSlugs, balances],
isEqual
);
};

export const useAllAvailableTokens = (account: string, chainId: string) => {
const tokens = useAccountTokens(account, chainId);
const allTokensStored = useAllAssetsSelector('tokens');

return useMemo(() => {
const allTokens = allTokensStored.filter(t => t.chainId === chainId);

const removedSlugs = allTokens.reduce<string[]>(
(acc, t) => (t.status === 'removed' && t.account === account ? acc.concat(t.slug) : acc),
[]
);

const otherTokens = allTokens.reduce<AccountToken[]>((acc, curr) => {
if (curr.account === account || removedSlugs.includes(curr.slug)) return acc;

return acc.concat({ slug: curr.slug, status: 'disabled' });
}, []);

const concatenated = tokens.concat(otherTokens);

return sortBy(
uniqBy(concatenated, t => t.slug),
TOKENS_SORT_ITERATEES
);
}, [tokens, allTokensStored, account, chainId]);
};

export const useEnabledAccountTokensSlugs = () => {
const chainId = useChainId(true)!;
const { publicKeyHash } = useAccount();
Expand All @@ -97,7 +130,7 @@ const useWhitelistSlugs = (chainId: string) => {
};

export const useAccountCollectibles = (account: string, chainId: string) => {
const stored = useAccountAssetsSelector(account, chainId, true);
const stored = useAccountAssetsSelector(account, chainId, 'collectibles');

const balances = useBalancesSelector(account, chainId);

Expand Down

0 comments on commit 1b494af

Please sign in to comment.