Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(wallet-mobile): new tx review stake pool details #3723

Merged
merged 17 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/wallet-mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"@emurgo/csl-mobile-bridge": "^7.1.0",
"@emurgo/msl-mobile-bridge": "^1.0.4",
"@emurgo/react-native-hid": "5.15.8",
"@emurgo/yoroi-lib": "^2.0.0",
"@emurgo/yoroi-lib": "2.2.0",
"@formatjs/intl-datetimeformat": "^6.7.0",
"@formatjs/intl-getcanonicallocales": "^2.1.0",
"@formatjs/intl-locale": "^3.2.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {Linking, StyleSheet, Text, TouchableOpacity, View} from 'react-native'

import {Space} from '../../../components/Space/Space'
import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet'
import {useStrings} from './hooks/useStrings'

export const ExplorerInfoLinks = ({id, type}: {id: string; type: 'token' | 'pool'}) => {
const {styles} = useStyles()
const {wallet} = useSelectedWallet()
const strings = useStrings()

const handleOpenLink = async (direction: 'cardanoscan' | 'adaex') => {
banklesss marked this conversation as resolved.
Show resolved Hide resolved
if (id == null) return
banklesss marked this conversation as resolved.
Show resolved Hide resolved
banklesss marked this conversation as resolved.
Show resolved Hide resolved
if (direction === 'cardanoscan') {
banklesss marked this conversation as resolved.
Show resolved Hide resolved
await Linking.openURL(wallet.networkManager.explorers.cardanoscan[type](id))
} else {
await Linking.openURL(wallet.networkManager.explorers.cexplorer[type](id))
}
}

return (
<View>
<Space width="sm" />

<Text style={styles.label}>{strings.details}</Text>

<View style={styles.linkGroup}>
<TouchableOpacity onPress={() => handleOpenLink('cardanoscan')}>
banklesss marked this conversation as resolved.
Show resolved Hide resolved
<Text style={styles.link}>Cardanoscan</Text>
banklesss marked this conversation as resolved.
Show resolved Hide resolved
</TouchableOpacity>

<TouchableOpacity onPress={() => handleOpenLink('adaex')}>
banklesss marked this conversation as resolved.
Show resolved Hide resolved
<Text style={styles.link}>Adaex</Text>
</TouchableOpacity>
</View>
</View>
)
}

const useStyles = () => {
const {atoms, color} = useTheme()

const styles = StyleSheet.create({
label: {
...atoms.body_2_md_regular,
color: color.text_gray_low,
},
link: {
...atoms.link_1_lg_underline,
color: color.text_primary_medium,
},
linkGroup: {
...atoms.flex_row,
...atoms.gap_lg,
},
})

const colors = {
copy: color.gray_900,
}

return {styles, colors} as const
}
215 changes: 215 additions & 0 deletions apps/wallet-mobile/src/features/ReviewTx/common/PoolDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import {FullPoolIfo} from '@emurgo/yoroi-lib'
import {useTheme} from '@yoroi/theme'
import {Image} from 'expo-image'
import * as React from 'react'
import {StyleSheet, Text, View} from 'react-native'
import {ScrollView} from 'react-native-gesture-handler'

import {Space} from '../../../components/Space/Space'
import {isEmptyString} from '../../../kernel/utils'
import {formatTokenWithText} from '../../../yoroi-wallets/utils/format'
import {asQuantity, Quantities} from '../../../yoroi-wallets/utils/utils'
import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet'
import {CopiableText} from './CopiableText'
import {ExplorerInfoLinks} from './ExplorerInfoLinks'
import {useStrings} from './hooks/useStrings'
import {generatePoolName} from './operations'

export const PoolDetails = ({poolInfo}: {poolInfo: FullPoolIfo}) => {
const {styles} = useStyles()
const strings = useStrings()
const {wallet} = useSelectedWallet()

const {chain, explorer} = poolInfo

const lastChainPoolInfo = chain?.history.at(-1) ?? null
const poolName = generatePoolName(poolInfo)

return (
<ScrollView bounces={false} style={styles.root}>
<PoolIcon imageUrl={explorer?.pic} />

<Space height="sm" />

<Row>
<Text style={styles.title}>{poolName}</Text>
</Row>

<Space height="xl" />

<PoolId poolId={explorer?.id} />

<Space height="lg" />

<PoolHash poolHash={explorer?.hash} />

<Space height="lg" />

<Info
label={strings.poolSize}
value={formatTokenWithText(asQuantity(explorer?.stake ?? Quantities.zero), wallet.portfolioPrimaryTokenInfo)}
/>

<Space height="sm" />

<Info label={strings.poolRoa} value={`${explorer?.roa ?? '-'}%`} />

<Space height="sm" />

<Info label={strings.poolShare} value={`${explorer?.share ?? '-'}%`} />

<Space height="sm" />

<Info label={strings.poolSaturation} value={`${explorer?.saturation ?? '-'}%`} />

<Space height="sm" />

<Info
label={strings.poolTaxFix}
value={formatTokenWithText(asQuantity(explorer?.taxFix ?? Quantities.zero), wallet.portfolioPrimaryTokenInfo)}
/>

<Space width="sm" />

<Info label={strings.poolTaxRatio} value={`${explorer?.taxRatio ?? '-'}%`} />

<Space width="sm" />

<Info
label={strings.poolPledge}
value={formatTokenWithText(
asQuantity(
(lastChainPoolInfo?.payload as {poolParams: {pledge: string}})?.['poolParams']?.['pledge'] ??
Quantities.zero,
),
wallet.portfolioPrimaryTokenInfo,
)}
/>

<Space height="lg" />

{poolInfo.explorer && !isEmptyString(poolInfo.explorer.id) && (
<ExplorerInfoLinks id={poolInfo.explorer.id} type="pool" />
)}
</ScrollView>
)
}

const PoolIcon = ({imageUrl}: {imageUrl: string | null | undefined}) => {
const {styles} = useStyles()

if (imageUrl == null) return null

return (
<View style={styles.imageContainer}>
<Image source={{uri: imageUrl}} style={styles.image} />
</View>
)
}

const PoolId = ({poolId}: {poolId: string | undefined}) => {
const {styles} = useStyles()
const strings = useStrings()

if (isEmptyString(poolId)) return null

return (
<Row>
<Text style={styles.label}>{strings.poolId}</Text>

<Space width="lg" />

<View style={styles.copiableText}>
<CopiableText textToCopy={poolId}>
<Text style={styles.value}>{poolId}</Text>
</CopiableText>
</View>
</Row>
)
}
const PoolHash = ({poolHash}: {poolHash?: string}) => {
const {styles} = useStyles()
const strings = useStrings()

if (isEmptyString(poolHash)) return null

return (
<Row>
<Text style={styles.label}>{strings.poolHash}</Text>

<Space width="lg" />

<View style={styles.copiableText}>
<CopiableText textToCopy={poolHash}>
<Text style={styles.value}>{poolHash}</Text>
</CopiableText>
</View>
</Row>
)
}

const Info = ({label, value}: {label: string; value?: string}) => {
const {styles} = useStyles()

if (isEmptyString(value)) return null

return (
<Row>
<Text style={styles.label}>{label}</Text>

<Text style={styles.value}>{value}</Text>
</Row>
)
}

const Row = ({children}: {children: React.ReactNode}) => {
const {styles} = useStyles()
return <View style={styles.row}>{children}</View>
}

const useStyles = () => {
const {atoms, color} = useTheme()

const styles = StyleSheet.create({
root: {
...atoms.flex_1,
...atoms.px_lg,
},
imageContainer: {
...atoms.justify_center,
...atoms.align_center,
},
image: {
width: 80,
height: 80,
},
label: {
...atoms.body_2_md_regular,
color: color.text_gray_low,
},
value: {
...atoms.flex_1,
...atoms.text_right,
...atoms.body_2_md_regular,
color: color.text_gray_max,
},
copiableText: {
...atoms.flex_1,
...atoms.align_center,
},
row: {
...atoms.flex_row,
...atoms.justify_center,
},
title: {
color: color.text_gray_medium,
...atoms.body_1_lg_medium,
},
})

const colors = {
copy: color.gray_900,
}

return {styles, colors} as const
}
54 changes: 8 additions & 46 deletions apps/wallet-mobile/src/features/ReviewTx/common/TokenDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {usePortfolioTokenDiscovery} from '@yoroi/portfolio'
import {useTheme} from '@yoroi/theme'
import {Portfolio} from '@yoroi/types'
import * as React from 'react'
import {Linking, ScrollView, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {ScrollView, StyleSheet, Text, TouchableOpacity, View} from 'react-native'

import {useCopy} from '../../../components/Clipboard/ClipboardProvider'
import {Icon} from '../../../components/Icon'
Expand All @@ -13,11 +13,14 @@ import {time} from '../../../kernel/constants'
import {isEmptyString} from '../../../kernel/utils'
import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet'
import {CopiableText} from './CopiableText'
import {ExplorerInfoLinks} from './ExplorerInfoLinks'
import {useStrings} from './hooks/useStrings'

export const TokenDetails = ({tokenInfo}: {tokenInfo: Portfolio.Token.Info}) => {
export const TokenDetails = ({tokenInfo}: {tokenInfo: Portfolio.Token.Info | undefined}) => {
const {styles} = useStyles()

if (tokenInfo == null) return null

return (
<View style={styles.root}>
<Header info={tokenInfo} />
Expand All @@ -31,7 +34,7 @@ export const TokenDetails = ({tokenInfo}: {tokenInfo: Portfolio.Token.Info}) =>

const Header = ({info}: {info: Portfolio.Token.Info}) => {
const {styles} = useStyles()
const [policyId, assetName] = info.id.split('.')
const [policyId, assetName] = info?.id.split('.') ?? ['', '']

const title = !isEmptyString(info.ticker) ? info.ticker : !isEmptyString(info.name) ? info.name : ''

Expand Down Expand Up @@ -146,7 +149,7 @@ const Overview = ({

<Description info={info} />

<Links info={info} />
<ExplorerInfoLinks id={info.id} type="token" />
</ScrollView>
)
}
Expand All @@ -156,7 +159,7 @@ const Overview = ({

<Description info={info} />

<Links info={info} />
<ExplorerInfoLinks id={info.id} type="token" />
</ScrollView>
)
}
Expand Down Expand Up @@ -273,39 +276,6 @@ const Description = ({info}: {info: Portfolio.Token.Info}) => {
)
}

const Links = ({info}: {info: Portfolio.Token.Info}) => {
const {styles} = useStyles()
const {wallet} = useSelectedWallet()
const strings = useStrings()

const handleOpenLink = async (direction: 'cardanoscan' | 'adaex') => {
if (info == null) return
if (direction === 'cardanoscan') {
await Linking.openURL(wallet.networkManager.explorers.cardanoscan.token(info.id))
} else {
await Linking.openURL(wallet.networkManager.explorers.cexplorer.token(info.id))
}
}

return (
<View>
<Space width="sm" />

<Text style={styles.label}>{strings.details}</Text>

<View style={styles.linkGroup}>
<TouchableOpacity onPress={() => handleOpenLink('cardanoscan')}>
<Text style={styles.link}>Cardanoscan</Text>
</TouchableOpacity>

<TouchableOpacity onPress={() => handleOpenLink('adaex')}>
<Text style={styles.link}>Adaex</Text>
</TouchableOpacity>
</View>
</View>
)
}

const Row = ({children}: {children: React.ReactNode}) => {
const {styles} = useStyles()
return <View style={styles.row}>{children}</View>
Expand Down Expand Up @@ -349,14 +319,6 @@ const useStyles = () => {
tabs: {
...atoms.flex_row,
},
link: {
...atoms.link_1_lg_underline,
color: color.text_primary_medium,
},
linkGroup: {
...atoms.flex_row,
...atoms.gap_lg,
},
copiableText: {
...atoms.flex_1,
...atoms.align_center,
Expand Down
Loading
Loading