Skip to content

Commit

Permalink
feat(tx-review): send feature
Browse files Browse the repository at this point in the history
  • Loading branch information
banklesss committed Sep 20, 2024
1 parent 26eefda commit d1c07bc
Show file tree
Hide file tree
Showing 11 changed files with 658 additions and 124 deletions.
34 changes: 31 additions & 3 deletions apps/wallet-mobile/src/features/ReviewTx/common/Address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,43 @@ import * as React from 'react'
import {StyleSheet, Text, TextStyle, TouchableOpacity, View} from 'react-native'

import {Icon} from '../../../components/Icon'
import {Space} from '../../../components/Space/Space'
import {useCopy} from '../../../hooks/useCopy'

export const Address = ({address, textStyle}: {address: string; textStyle?: TextStyle}) => {
export const Address = ({
address,
index,
textStyle,
multiline = false,
}: {
address: string
index?: number
textStyle?: TextStyle
multiline?: boolean
}) => {
const {styles, colors} = useStyles()
const [, copy] = useCopy()

return (
<View style={styles.address}>
<Text style={[styles.addressText, textStyle]} numberOfLines={1} ellipsizeMode="middle">
<Text
style={[styles.addressText, textStyle]}
numberOfLines={!multiline ? 1 : undefined}
ellipsizeMode={!multiline ? 'middle' : undefined}
>
{address}
</Text>

{index !== undefined && (
<>
<Space width="sm" />

<Text style={styles.index}>{`#${index}`}</Text>

<Space width="sm" />
</>
)}

<TouchableOpacity onPress={() => copy(address)} activeOpacity={0.5}>
<Icon.Copy size={24} color={colors.copy} />
</TouchableOpacity>
Expand All @@ -27,7 +52,6 @@ const useStyles = () => {
const styles = StyleSheet.create({
address: {
...atoms.flex_row,
...atoms.align_center,
...atoms.flex_row,
...atoms.justify_between,
},
Expand All @@ -36,6 +60,10 @@ const useStyles = () => {
...atoms.body_2_md_regular,
color: color.gray_900,
},
index: {
...atoms.body_2_md_medium,
color: color.text_gray_medium,
},
})

const colors = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {Animated, LayoutAnimation, StyleSheet, Text, TouchableOpacity, View} from 'react-native'

import {Icon} from '../../../components/Icon'

export const CollapsibleSection = ({label, children}: {label: string; children: React.ReactNode}) => {
const {styles, colors} = useStyles()
const [isOpen, setIsOpen] = React.useState(false)
const animatedHeight = React.useRef(new Animated.Value(0)).current

const toggleSection = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsOpen(!isOpen)
Animated.timing(animatedHeight, {
toValue: isOpen ? 0 : 1,
duration: 300,
useNativeDriver: false,
}).start()
}

return (
<>
<View style={styles.sectionHeader}>
<Text style={styles.sectionHeaderText}>{label}</Text>

<TouchableOpacity activeOpacity={0.5} onPress={() => setIsOpen((isOpen) => !isOpen)}>
<TouchableOpacity activeOpacity={0.5} onPress={toggleSection}>
<Icon.Chevron direction={isOpen ? 'up' : 'down'} size={28} color={colors.chevron} />
</TouchableOpacity>
</View>

{isOpen && children}
<Animated.View
style={[
styles.childrenContainer,
{
maxHeight: animatedHeight.interpolate({
inputRange: [0, 1],
outputRange: [0, 1000],
}),
opacity: animatedHeight,
},
]}
>
{children}
</Animated.View>
</>
)
}
Expand All @@ -34,6 +58,9 @@ const useStyles = () => {
...atoms.body_1_lg_medium,
color: color.gray_900,
},
childrenContainer: {
overflow: 'hidden',
},
})

const colors = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,7 @@ export const useFormattedInputs = (
) => {
const query = useQuery<FormattedInputs>(
['useFormattedInputs', inputs],
async () => {
const inputss = await formatInputs(wallet, inputs, tokenInfosResult)
console.log('inputs', inputs)
console.log('inputss', inputss)
return inputss
},
async () => formatInputs(wallet, inputs, tokenInfosResult),
{
suspense: true,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useIntl} from 'react-intl'
import {defineMessages, useIntl} from 'react-intl'

import {txLabels} from '../../../../kernel/i18n/global-messages'

Expand All @@ -7,5 +7,73 @@ export const useStrings = () => {

return {
signTransaction: intl.formatMessage(txLabels.signingTx),
confirm: intl.formatMessage(messages.confirm),
utxosTab: intl.formatMessage(messages.utxosTab),
overviewTab: intl.formatMessage(messages.overviewTab),
walletLabel: intl.formatMessage(messages.walletLabel),
feeLabel: intl.formatMessage(messages.feeLabel),
myWalletLabel: intl.formatMessage(messages.myWalletLabel),
sendLabel: intl.formatMessage(messages.sendLabel),
receiveToLabel: intl.formatMessage(messages.receiveToLabel),
receiveToScriptLabel: intl.formatMessage(messages.receiveToScriptLabel),
utxosInputsLabel: intl.formatMessage(messages.utxosInputsLabel),
utxosOutputsLabel: intl.formatMessage(messages.utxosOutputsLabel),
utxosYourAddressLabel: intl.formatMessage(messages.utxosYourAddressLabel),
utxosForeignAddressLabel: intl.formatMessage(messages.utxosForeignAddressLabel),
}
}

const messages = defineMessages({
confirm: {
id: 'txReview.confirm',
defaultMessage: '!!!Confirm',
},
utxosTab: {
id: 'txReview.tabLabel.utxos',
defaultMessage: '!!!UTxOs',
},
overviewTab: {
id: 'txReview.tabLabel.overview',
defaultMessage: '!!!Overview',
},
walletLabel: {
id: 'txReview.overview.wallet',
defaultMessage: '!!!Wallet',
},
feeLabel: {
id: 'txReview.fee',
defaultMessage: '!!!Fee',
},
myWalletLabel: {
id: 'txReview.overview.myWalletLabel',
defaultMessage: '!!!Your Wallet',
},
sendLabel: {
id: 'txReview.overview.sendLabel',
defaultMessage: '!!!Send',
},
receiveToLabel: {
id: 'txReview.overview.receiveToLabel',
defaultMessage: '!!!receiveToLabel',
},
receiveToScriptLabel: {
id: 'txReview.overview.receiveToScriptLabel',
defaultMessage: '!!!To script',
},
utxosInputsLabel: {
id: 'txReview.utxos.utxosInputsLabel',
defaultMessage: '!!!Inputs',
},
utxosOutputsLabel: {
id: 'txReview.utxos.utxosOutputsLabel',
defaultMessage: '!!!Outputs',
},
utxosYourAddressLabel: {
id: 'txReview.utxos.utxosYourAddressLabel',
defaultMessage: '!!!Your address',
},
utxosForeignAddressLabel: {
id: 'txReview.utxos.utxosForeignAddressLabel',
defaultMessage: '!!!Foreign address',
},
})
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// 🚧 TODO: grouping by staking address 🚧

import {Blockies} from '@yoroi/identicon'
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
Expand All @@ -14,11 +16,13 @@ import {Address} from '../../../common/Address'
import {CollapsibleSection} from '../../../common/CollapsibleSection'
import {Divider} from '../../../common/Divider'
import {useAddressType} from '../../../common/hooks/useAddressType'
import {useStrings} from '../../../common/hooks/useStrings'
import {TokenItem} from '../../../common/TokenItem'
import {FormattedOutputs, FormattedTx} from '../../../common/types'

export const OverviewTab = ({tx}: {tx: FormattedTx}) => {
const {styles} = useStyles()

const notOwnedOutputs = React.useMemo(() => tx.outputs.filter((output) => !output.ownAddress), [tx.outputs])
const ownedOutputs = React.useMemo(() => tx.outputs.filter((output) => output.ownAddress), [tx.outputs])

Expand All @@ -37,6 +41,7 @@ export const OverviewTab = ({tx}: {tx: FormattedTx}) => {

const WalletInfoSection = ({tx}: {tx: FormattedTx}) => {
const {styles} = useStyles()
const strings = useStrings()
const {wallet, meta} = useSelectedWallet()
const {walletManager} = useWalletManager()
const {plate, seed} = walletManager.checksum(wallet.publicKeyHex)
Expand All @@ -45,7 +50,7 @@ const WalletInfoSection = ({tx}: {tx: FormattedTx}) => {
return (
<>
<View style={styles.infoItem}>
<Text style={styles.infoLabel}>Wallet</Text>
<Text style={styles.infoLabel}>{strings.walletLabel}</Text>

<View style={styles.plate}>
<Icon.WalletAvatar image={seedImage} style={styles.walletChecksum} size={24} />
Expand All @@ -65,10 +70,11 @@ const WalletInfoSection = ({tx}: {tx: FormattedTx}) => {

const FeeInfoItem = ({fee}: {fee: string}) => {
const {styles} = useStyles()
const strings = useStrings()

return (
<View style={styles.infoItem}>
<Text style={styles.infoLabel}>Fee</Text>
<Text style={styles.infoLabel}>{strings.feeLabel}</Text>

<Text style={styles.fee}>{fee}</Text>
</View>
Expand All @@ -84,10 +90,11 @@ const SenderSection = ({
notOwnedOutputs: FormattedOutputs
ownedOutputs: FormattedOutputs
}) => {
const strings = useStrings()
const address = ownedOutputs[0]?.rewardAddress ?? ownedOutputs[0]?.address

return (
<CollapsibleSection label="Your Wallet">
<CollapsibleSection label={strings.myWalletLabel}>
<Space height="lg" />

<Address address={address} />
Expand All @@ -101,8 +108,10 @@ const SenderSection = ({
)
}

// 🚧 TODO: ADD MULTIRECEIVER SUPPORT 🚧
const SenderTokens = ({tx, notOwnedOutputs}: {tx: FormattedTx; notOwnedOutputs: FormattedOutputs}) => {
const {styles} = useStyles()

const {wallet} = useSelectedWallet()

const totalPrimaryTokenSent = React.useMemo(
Expand Down Expand Up @@ -142,21 +151,23 @@ const SenderTokens = ({tx, notOwnedOutputs}: {tx: FormattedTx; notOwnedOutputs:

const SenderSectionLabel = () => {
const {styles, colors} = useStyles()
const strings = useStrings()

return (
<View style={styles.tokensSectionLabel}>
<Icon.Send size={30} color={colors.send} />

<Space width="_2xs" />

<Text style={styles.tokenSectionLabel}>Send</Text>
<Text style={styles.tokenSectionLabel}>{strings.sendLabel}</Text>
</View>
)
}

const ReceiverSection = ({notOwnedOutputs}: {notOwnedOutputs: FormattedOutputs}) => {
const address = notOwnedOutputs[0]?.rewardAddress ?? notOwnedOutputs[0]?.address
const {styles} = useStyles()
const strings = useStrings()
const addressType = useAddressType(address)
const isScriptAddress = addressType === 'script'

Expand All @@ -165,7 +176,7 @@ const ReceiverSection = ({notOwnedOutputs}: {notOwnedOutputs: FormattedOutputs})
<Space height="sm" />

<View style={styles.receiverAddress}>
<Text>{isScriptAddress ? 'To script' : `To`}:</Text>
<Text>{isScriptAddress ? strings.receiveToScriptLabel : strings.receiveToLabel}:</Text>

<Address address={address} textStyle={styles.receiverSectionAddress} />
</View>
Expand Down Expand Up @@ -245,9 +256,9 @@ const useStyles = () => {
return {styles, colors} as const
}

// WORK IN PROGRESS BELOW
// 🚧 WORK IN PROGRESS BELOW 🚧

// TODO: WIP
// 🚧 TODO: WIP 🚧
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const CreatedByInfoItem = () => {
const {styles} = useStyles()
Expand All @@ -269,7 +280,7 @@ const CreatedByInfoItem = () => {
)
}

// TODO: WIP
// 🚧 TODO: WIP 🚧
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const ReceiverTokensSectionMultiReceiver = () => {
const {styles} = useStyles()
Expand Down Expand Up @@ -328,7 +339,7 @@ const ReceiverTokensSectionMultiReceiver = () => {
)
}

// TODO: WIP
// 🚧 TODO: WIP 🚧
const ReceiverSectionLabel = () => {
const {styles, colors} = useStyles()

Expand Down
Loading

0 comments on commit d1c07bc

Please sign in to comment.