Skip to content

Commit

Permalink
chore(portfolio): wip wire up
Browse files Browse the repository at this point in the history
  • Loading branch information
stackchain committed Apr 27, 2024
1 parent 90cee78 commit 68284a3
Show file tree
Hide file tree
Showing 34 changed files with 460 additions and 283 deletions.
3 changes: 2 additions & 1 deletion apps/wallet-mobile/.storybook/storybook.requires.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

75 changes: 0 additions & 75 deletions apps/wallet-mobile/src/TxHistory/AssetList/ActionsBanner.tsx

This file was deleted.

36 changes: 1 addition & 35 deletions apps/wallet-mobile/src/TxHistory/AssetList/AssetList.tsx
Expand Up @@ -3,20 +3,17 @@ import {FlashList, FlashListProps} from '@shopify/flash-list'
import {useTheme} from '@yoroi/theme'
import {Balance} from '@yoroi/types'
import React from 'react'
import {defineMessages, useIntl} from 'react-intl'
import {Alert, Linking, StyleSheet, TouchableOpacity, View} from 'react-native'
import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native'

import {AmountItem, AmountItemProps} from '../../components/AmountItem/AmountItem'
import {Spacer} from '../../components/Spacer'
import {usePrivacyMode} from '../../features/Settings/PrivacyMode/PrivacyMode'
import {useSelectedWallet} from '../../features/WalletManager/Context'
import globalMessages, {actionMessages} from '../../i18n/global-messages'
import {useMetrics} from '../../metrics/metricsManager'
import {sortTokenInfos} from '../../utils'
import {getNetworkConfigById} from '../../yoroi-wallets/cardano/networks'
import {useBalances, useTokenInfos} from '../../yoroi-wallets/hooks'
import {Amounts} from '../../yoroi-wallets/utils'
import {ActionsBanner} from './ActionsBanner'

type ListProps = FlashListProps<Balance.TokenInfo>
type Props = Partial<ListProps> & {
Expand All @@ -25,7 +22,6 @@ type Props = Partial<ListProps> & {
onRefresh: () => void
}
export const AssetList = (props: Props) => {
const strings = useStrings()
const styles = useStyles()
const wallet = useSelectedWallet()
const balances = useBalances(wallet)
Expand All @@ -37,10 +33,6 @@ export const AssetList = (props: Props) => {
}, [track]),
)

const handleOnPressNFTs = () => Alert.alert(strings.soon, strings.soon)
const handleOnPressTokens = () => Alert.alert(strings.soon, strings.soon)
const handleSearch = () => Alert.alert(strings.soon, strings.soon)

const config = getNetworkConfigById(wallet.networkId)

const tokenInfos = useTokenInfos({
Expand All @@ -50,14 +42,6 @@ export const AssetList = (props: Props) => {

return (
<View style={styles.assetList} testID="assetList">
<ActionsBanner
tokensLabel={strings.tokens(tokenInfos.length)}
nftsLabel={strings.nfts(0)}
onPressNFTs={handleOnPressNFTs}
onPressTokens={handleOnPressTokens}
onSearch={handleSearch}
/>

<FlashList
{...props}
data={sortTokenInfos({wallet, tokenInfos})}
Expand Down Expand Up @@ -114,21 +98,3 @@ const useStyles = () => {

return styles
}

const messages = defineMessages({
unknownAsset: {
id: 'components.send.assetselectorscreen.unknownAsset',
defaultMessage: '!!!Unknown asset',
},
})

const useStrings = () => {
const intl = useIntl()

return {
unknown: intl.formatMessage(messages.unknownAsset),
tokens: (qty: number) => `${intl.formatMessage(globalMessages.tokens, {qty})} (${qty})`,
nfts: (qty: number) => `${intl.formatMessage(globalMessages.nfts, {qty})} (${qty})`,
soon: intl.formatMessage(actionMessages.soon),
}
}
@@ -0,0 +1,34 @@
import {action} from '@storybook/addon-actions'
import {storiesOf} from '@storybook/react-native'
import React from 'react'

import {FilterBalancesByType} from './FilterBalancesByType'

storiesOf('TxHistory Filter Balances By Type', module).add('all (initial)', () => (
<FilterBalancesByType<'all' | 'assets' | 'tokens'>
chips={[
{
label: 'All',
value: 'all',
onPress: () => {
action('all')
},
} as const,
{
label: 'Assets',
value: 'assets',
onPress: () => {
action('assets')
},
} as const,
{
label: 'Tokens',
value: 'tokens',
onPress: () => {
action('tokens')
},
} as const,
]}
selectedValue="all"
/>
))
@@ -0,0 +1,53 @@
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {StyleSheet, View} from 'react-native'

import {Spacer} from '../../components/Spacer'
import {ChipButton} from './ChipButton'

type Props<T> = {
selectedValue: T
chips: ReadonlyArray<{
label: string
value: T
onPress: () => void
disabled?: boolean
}>
}

export const FilterBalancesByType = <T,>({chips, selectedValue}: Props<T>) => {
const {styles} = useStyles()

return (
<View style={styles.root}>
{chips.map(({label, disabled, onPress, value}, index) => (
<>
<ChipButton
key={index}
label={label}
disabled={disabled}
onPress={onPress}
selected={selectedValue === value}
/>

{index != chips.length - 1 && <Spacer width={12} />}
</>
))}
</View>
)
}

const useStyles = () => {
const {theme} = useTheme()
const {padding} = theme
const styles = StyleSheet.create({
root: {
display: 'flex',
...padding['x-l'],
...padding['b-xxs'],
justifyContent: 'flex-start',
flexDirection: 'row',
},
})
return {styles}
}
122 changes: 122 additions & 0 deletions apps/wallet-mobile/src/TxHistory/AssetList/ListBalances.tsx
@@ -0,0 +1,122 @@
import {useFocusEffect} from '@react-navigation/native'
import {FlashList, FlashListProps} from '@shopify/flash-list'
import {useTheme} from '@yoroi/theme'
import {Portfolio} from '@yoroi/types'
import * as React from 'react'
import {useIntl} from 'react-intl'
import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native'

import {Spacer} from '../../components/Spacer'
import {TokenAmountItem, TokenAmountItemProps} from '../../components/TokenAmountItem/TokenAmountItem'
import {useExplorers} from '../../features/Explorer/common/useExplorers'
import {usePortfolioBalances} from '../../features/Portfolio/common/hooks/usePortfolioBalances'
import {usePrivacyMode} from '../../features/Settings/PrivacyMode/PrivacyMode'
import {useSelectedWallet} from '../../features/WalletManager/Context'
import globalMessages from '../../i18n/global-messages'
import {useMetrics} from '../../metrics/metricsManager'
import {FilterBalancesByType} from './FilterBalancesByType'

type ListProps = FlashListProps<Portfolio.Token.Amount>
type Props = Partial<ListProps> & {
onScroll: ListProps['onScroll']
refreshing: boolean
onRefresh: () => void
}
export const ListBalances = (props: Props) => {
const strings = useStrings()
const styles = useStyles()
const {track} = useMetrics()
const wallet = useSelectedWallet()
const balances = usePortfolioBalances({wallet})
const explorers = useExplorers(wallet.network)
const {isPrivacyOff, privacyPlaceholder} = usePrivacyMode()

const [filteringBy, setFilteringBy] = React.useState<keyof typeof balances>('all')
const [isPending, startTransition] = React.useTransition()

useFocusEffect(
React.useCallback(() => {
track.assetsPageViewed()
}, [track]),
)

const handleOnPressNFTs = React.useCallback(() => startTransition(() => setFilteringBy('nfts')), [])
const handleOnPressFTs = React.useCallback(() => startTransition(() => setFilteringBy('fts')), [])
const handleOnPressAll = React.useCallback(() => startTransition(() => setFilteringBy('all')), [])
const chips = [
{label: strings.tokens(balances.fts.length), onPress: handleOnPressFTs, value: 'fts', disabled: isPending},
{label: strings.nfts(balances.nfts.length), onPress: handleOnPressNFTs, value: 'nfts', disabled: isPending},
{label: strings.all, onPress: handleOnPressAll, value: 'all', disabled: isPending},
]

return (
<View style={styles.assetList} testID="assetList">
<FilterBalancesByType selectedValue={filteringBy} chips={chips} />

<FlashList
{...props}
data={balances[filteringBy]}
renderItem={({item: amount}) => (
<ExplorableAssetItem
isMainnet={wallet.isMainnet}
privacyPlaceholder={privacyPlaceholder}
isPrivacyOff={isPrivacyOff}
amount={amount}
onPress={() => Linking.openURL(explorers.cardanoscan.token(amount.info.id))}
/>
)}
ItemSeparatorComponent={() => <Spacer height={16} />}
contentContainerStyle={styles.content}
keyExtractor={(_, index) => index.toString()}
estimatedItemSize={78}
/>
</View>
)
}

type ExplorableAssetItemProps = TokenAmountItemProps & {
onPress(): void
}
const ExplorableAssetItem = ({onPress, ...tokenAmountProps}: ExplorableAssetItemProps) => {
const styles = useStyles()
return (
<TouchableOpacity style={styles.button} onPress={onPress} testID="assetSelectorItem">
<TokenAmountItem {...tokenAmountProps} />
</TouchableOpacity>
)
}

const useStyles = () => {
const {theme} = useTheme()
const {color, padding} = theme
const styles = StyleSheet.create({
content: {
...padding['t-l'],
...padding['x-l'],
...padding['b-s'],
},
assetList: {flex: 1},
button: {
...padding['m'],
backgroundColor: color.gray.min,
shadowColor: color.gray[100],
borderRadius: 8,
elevation: 2,
shadowOffset: {width: 0, height: -2},
shadowRadius: 10,
shadowOpacity: 0.08,
},
})

return styles
}

const useStrings = () => {
const intl = useIntl()

return React.useRef({
tokens: (qty: number) => `${intl.formatMessage(globalMessages.tokens, {qty})} (${qty})`,
nfts: (qty: number) => `${intl.formatMessage(globalMessages.nfts, {qty})} (${qty})`,
all: intl.formatMessage(globalMessages.all),
}).current
}

0 comments on commit 68284a3

Please sign in to comment.