Skip to content

Commit

Permalink
PoC: multsend for assets
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Jun 22, 2023
1 parent 434da9f commit 919aed9
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 457 deletions.
175 changes: 55 additions & 120 deletions src/components/balances/AssetsTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ReactElement, useMemo, useContext } from 'react'
import { Button, Tooltip, Typography, SvgIcon, IconButton, Box, Checkbox, Skeleton } from '@mui/material'
import { type ReactElement, Dispatch, SetStateAction, useCallback } from 'react'
import { Tooltip, Typography, SvgIcon, Box, Skeleton, Checkbox } from '@mui/material'
import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { TokenType } from '@safe-global/safe-gateway-typescript-sdk'
import css from './styles.module.css'
Expand All @@ -8,18 +8,8 @@ import TokenAmount from '@/components/common/TokenAmount'
import TokenIcon from '@/components/common/TokenIcon'
import EnhancedTable, { type EnhancedTableProps } from '@/components/common/EnhancedTable'
import TokenExplorerLink from '@/components/common/TokenExplorerLink'
import Track from '@/components/common/Track'
import { ASSETS_EVENTS } from '@/services/analytics/events/assets'
import InfoIcon from '@/public/images/notifications/info.svg'
import { VisibilityOutlined } from '@mui/icons-material'
import TokenMenu from '../TokenMenu'
import useBalances from '@/hooks/useBalances'
import useHiddenTokens from '@/hooks/useHiddenTokens'
import { useHideAssets } from './useHideAssets'
import CheckWallet from '@/components/common/CheckWallet'
import useSpendingLimit from '@/hooks/useSpendingLimit'
import { TxModalContext } from '@/components/tx-flow'
import TokenTransferFlow from '@/components/tx-flow/flows/TokenTransfer'

const skeletonCells: EnhancedTableProps['rows'][0]['cells'] = {
asset: {
Expand Down Expand Up @@ -62,102 +52,73 @@ const isNativeToken = (tokenInfo: TokenInfo) => {
return tokenInfo.type === TokenType.NATIVE_TOKEN
}

const headCells = [
{
id: 'asset',
label: 'Asset',
width: '60%',
},
{
id: 'balance',
label: 'Balance',
width: '20%',
},
{
id: 'value',
label: 'Value',
width: '20%',
},
{
id: 'actions',
label: '',
width: '20%',
sticky: true,
},
]

const SendButton = ({
tokenInfo,
onClick,
}: {
tokenInfo: TokenInfo
onClick: (tokenAddress: string) => void
}): ReactElement => {
const spendingLimit = useSpendingLimit(tokenInfo)

return (
<CheckWallet allowSpendingLimit={!!spendingLimit}>
{(isOk) => (
<Track {...ASSETS_EVENTS.SEND}>
<Button
variant="contained"
color="primary"
size="small"
onClick={() => onClick(tokenInfo.address)}
disabled={!isOk}
>
Send
</Button>
</Track>
)}
</CheckWallet>
)
type AssetsTableProps = {
selectedTokens: string[]
setSelectedTokens: Dispatch<SetStateAction<string[]>>
}

const AssetsTable = ({
showHiddenAssets,
setShowHiddenAssets,
}: {
showHiddenAssets: boolean
setShowHiddenAssets: (hidden: boolean) => void
}): ReactElement => {
const hiddenAssets = useHiddenTokens()
const AssetsTable = ({ selectedTokens, setSelectedTokens }: AssetsTableProps): ReactElement => {
const { balances, loading } = useBalances()
const { setTxFlow } = useContext(TxModalContext)

const { isAssetSelected, toggleAsset, hidingAsset, hideAsset, cancel, deselectAll, saveChanges } = useHideAssets(() =>
setShowHiddenAssets(false),
const allAssets = balances.items || []

const onCheckboxClick = useCallback(
(e: React.ChangeEvent<HTMLInputElement>, item: string) => {
e.stopPropagation()
const { checked } = e.target
setSelectedTokens((prev) => (checked ? prev.concat(item) : prev.filter((el) => el !== item)))
},
[setSelectedTokens],
)

const visibleAssets = useMemo(
() =>
showHiddenAssets
? balances.items
: balances.items?.filter((item) => !hiddenAssets.includes(item.tokenInfo.address)),
[hiddenAssets, balances.items, showHiddenAssets],
const onSelectAll = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setSelectedTokens(e.target.checked ? allAssets.map((item) => item.tokenInfo.address) : [])
},
[allAssets],
)

const selectedAssetCount = visibleAssets?.filter((item) => isAssetSelected(item.tokenInfo.address)).length || 0

const onSendClick = (tokenAddress: string) => {
setTxFlow(<TokenTransferFlow tokenAddress={tokenAddress} />)
}
const headCells = [
{
id: 'asset',
label: 'Asset',
width: '60%',
},
{
id: 'balance',
label: 'Balance',
width: '20%',
},
{
id: 'value',
label: 'Value',
width: '20%',
},
{
id: 'actions',
label: '',
width: '20%',
sticky: true,
content: (
<Checkbox
checked={selectedTokens.length > 0 && selectedTokens.length === allAssets.length}
onChange={onSelectAll}
title="Select all"
/>
),
},
]

const rows = loading
? skeletonRows
: (visibleAssets || []).map((item) => {
: allAssets.map((item) => {
const rawFiatValue = parseFloat(item.fiatBalance)
const isNative = isNativeToken(item.tokenInfo)
const isSelected = isAssetSelected(item.tokenInfo.address)

return {
key: item.tokenInfo.address,
selected: isSelected,
collapsed: item.tokenInfo.address === hidingAsset,
cells: {
asset: {
rawValue: item.tokenInfo.name,
collapsed: item.tokenInfo.address === hidingAsset,
content: (
<div className={css.token}>
<TokenIcon logoUri={item.tokenInfo.logoUri} tokenSymbol={item.tokenInfo.symbol} />
Expand All @@ -170,7 +131,6 @@ const AssetsTable = ({
},
balance: {
rawValue: Number(item.balance) / 10 ** item.tokenInfo.decimals,
collapsed: item.tokenInfo.address === hidingAsset,
content: (
<TokenAmount
value={item.balance}
Expand All @@ -181,7 +141,6 @@ const AssetsTable = ({
},
value: {
rawValue: rawFiatValue,
collapsed: item.tokenInfo.address === hidingAsset,
content: (
<>
<FiatValue value={item.fiatBalance} />
Expand All @@ -204,28 +163,12 @@ const AssetsTable = ({
actions: {
rawValue: '',
sticky: true,
collapsed: item.tokenInfo.address === hidingAsset,
content: (
<Box display="flex" flexDirection="row" gap={1} alignItems="center">
<>
<SendButton tokenInfo={item.tokenInfo} onClick={() => onSendClick(item.tokenInfo.address)} />

{showHiddenAssets ? (
<Checkbox size="small" checked={isSelected} onClick={() => toggleAsset(item.tokenInfo.address)} />
) : (
<Track {...ASSETS_EVENTS.HIDE_TOKEN}>
<Tooltip title="Hide asset" arrow disableInteractive>
<IconButton
disabled={hidingAsset !== undefined}
size="medium"
onClick={() => hideAsset(item.tokenInfo.address)}
>
<VisibilityOutlined fontSize="small" />
</IconButton>
</Tooltip>
</Track>
)}
</>
<Checkbox
checked={selectedTokens.includes(item.tokenInfo.address)}
onChange={(e) => onCheckboxClick(e, item.tokenInfo.address)}
/>
</Box>
),
},
Expand All @@ -235,14 +178,6 @@ const AssetsTable = ({

return (
<>
<TokenMenu
saveChanges={saveChanges}
cancel={cancel}
deselectAll={deselectAll}
selectedAssetCount={selectedAssetCount}
showHiddenAssets={showHiddenAssets}
/>

<div className={css.container}>
<EnhancedTable rows={rows} headCells={headCells} />
</div>
Expand Down
93 changes: 0 additions & 93 deletions src/components/balances/AssetsTable/useHideAssets.ts

This file was deleted.

Loading

0 comments on commit 919aed9

Please sign in to comment.