diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/Address.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/Address.tsx index aad8711413..ac2f68b9c8 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/Address.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/Address.tsx @@ -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 ( - + {address} + {index !== undefined && ( + <> + + + {`#${index}`} + + + + )} + copy(address)} activeOpacity={0.5}> @@ -27,7 +52,6 @@ const useStyles = () => { const styles = StyleSheet.create({ address: { ...atoms.flex_row, - ...atoms.align_center, ...atoms.flex_row, ...atoms.justify_between, }, @@ -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 = { diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/CollapsibleSection.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/CollapsibleSection.tsx index 0bb8691140..30ed657866 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/CollapsibleSection.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/CollapsibleSection.tsx @@ -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 ( <> {label} - setIsOpen((isOpen) => !isOpen)}> + - {isOpen && children} + + {children} + ) } @@ -34,6 +58,9 @@ const useStyles = () => { ...atoms.body_1_lg_medium, color: color.gray_900, }, + childrenContainer: { + overflow: 'hidden', + }, }) const colors = { diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx index 9770e71a55..5773e15efb 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx @@ -57,12 +57,7 @@ export const useFormattedInputs = ( ) => { const query = useQuery( ['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, }, diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx index 0513fdd25f..0fc40e2f04 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx @@ -1,4 +1,4 @@ -import {useIntl} from 'react-intl' +import {defineMessages, useIntl} from 'react-intl' import {txLabels} from '../../../../kernel/i18n/global-messages' @@ -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', + }, +}) diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx index 42b46ba0d5..b07a3c5fc3 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx @@ -1,3 +1,5 @@ +// 🚧 TODO: grouping by staking address 🚧 + import {Blockies} from '@yoroi/identicon' import {useTheme} from '@yoroi/theme' import * as React from 'react' @@ -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]) @@ -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) @@ -45,7 +50,7 @@ const WalletInfoSection = ({tx}: {tx: FormattedTx}) => { return ( <> - Wallet + {strings.walletLabel} @@ -65,10 +70,11 @@ const WalletInfoSection = ({tx}: {tx: FormattedTx}) => { const FeeInfoItem = ({fee}: {fee: string}) => { const {styles} = useStyles() + const strings = useStrings() return ( - Fee + {strings.feeLabel} {fee} @@ -84,10 +90,11 @@ const SenderSection = ({ notOwnedOutputs: FormattedOutputs ownedOutputs: FormattedOutputs }) => { + const strings = useStrings() const address = ownedOutputs[0]?.rewardAddress ?? ownedOutputs[0]?.address return ( - +
@@ -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( @@ -142,6 +151,7 @@ const SenderTokens = ({tx, notOwnedOutputs}: {tx: FormattedTx; notOwnedOutputs: const SenderSectionLabel = () => { const {styles, colors} = useStyles() + const strings = useStrings() return ( @@ -149,7 +159,7 @@ const SenderSectionLabel = () => { - Send + {strings.sendLabel} ) } @@ -157,6 +167,7 @@ const SenderSectionLabel = () => { 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' @@ -165,7 +176,7 @@ const ReceiverSection = ({notOwnedOutputs}: {notOwnedOutputs: FormattedOutputs}) - {isScriptAddress ? 'To script' : `To`}: + {isScriptAddress ? strings.receiveToScriptLabel : strings.receiveToLabel}:
@@ -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() @@ -269,7 +280,7 @@ const CreatedByInfoItem = () => { ) } -// TODO: WIP +// 🚧 TODO: WIP 🚧 // eslint-disable-next-line @typescript-eslint/no-unused-vars const ReceiverTokensSectionMultiReceiver = () => { const {styles} = useStyles() @@ -328,7 +339,7 @@ const ReceiverTokensSectionMultiReceiver = () => { ) } -// TODO: WIP +// 🚧 TODO: WIP 🚧 const ReceiverSectionLabel = () => { const {styles, colors} = useStyles() diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx index 2d831995ee..1b14061d9f 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx @@ -11,27 +11,30 @@ import {ReviewTxRoutes, useUnsafeParams} from '../../../../kernel/navigation' import {Divider} from '../../common/Divider' import {useFormattedTx} from '../../common/hooks/useFormattedTx' import {useOnConfirm} from '../../common/hooks/useOnConfirm' +import {useStrings} from '../../common/hooks/useStrings' import {useTxBody} from '../../common/hooks/useTxBody' import {OverviewTab} from './Overview/OverviewTab' +import {UTxOsTab} from './UTxOs/UTxOsTab' type Tabs = 'overview' | 'utxos' export const ReviewTxScreen = () => { const {styles} = useStyles() + const strings = useStrings() const [activeTab, setActiveTab] = React.useState('overview') + // TODO: move this to a context const params = useUnsafeParams() - - // TODO: add cbor arguments - const txBody = useTxBody({unsignedTx: params.unsignedTx}) - const formatedTx = useFormattedTx(txBody) - const {onConfirm} = useOnConfirm({ unsignedTx: params.unsignedTx, onSuccess: params.onSuccess, onError: params.onError, }) + // TODO: add cbor arguments + const txBody = useTxBody({unsignedTx: params.unsignedTx}) + const formatedTx = useFormattedTx(txBody) + const renderTabs = React.useMemo(() => { return ( @@ -39,13 +42,21 @@ export const ReviewTxScreen = () => { style={styles.tab} active={activeTab === 'overview'} onPress={() => setActiveTab('overview')} - label="Overview" + label={strings.overviewTab} /> - setActiveTab('utxos')} label="UTxOs" /> + setActiveTab('utxos')} + label={strings.utxosTab} + /> ) - }, [activeTab, setActiveTab, styles.tab, styles.tabs]) + }, [activeTab, strings.overviewTab, strings.utxosTab, styles.tab, styles.tabs]) + + const OverviewTabMemo = React.memo(() => ) + const UtxosTabMemo = React.memo(() => ) return ( @@ -55,11 +66,13 @@ export const ReviewTxScreen = () => { - {activeTab === 'overview' && } + {activeTab === 'overview' && } + + {activeTab === 'utxos' && } -