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

US-2160 User would like to add a contact from the Transaction Summary screen so they can send to them later #905

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions src/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ const resources = {
transaction_summary_plus_fees_capitalcase: '+ Fees',
transaction_summary_insufficient_funds: 'Insufficient funds',
transaction_summary_address_text: 'Address',
transaction_summary_add_non_existent_contact_title: 'Do you wish to add',
transaction_summary_add_non_existent_contact_title_2: 'as your contact?',
transaction_summary_add_non_existent_contact_action: 'Yes, sure',
profile_screen_title: 'Profile',
profile_contact_details_subtitle: 'Contact Details',
profile_phone_label: 'Phone Number',
Expand Down
2 changes: 1 addition & 1 deletion src/navigation/contactsNavigator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const ContactsNavigation = ({
<Stack.Screen
name={contactsStackRouteNames.ContactsList}
component={ContactsScreen}
options={{ header: props => <AppHeader {...props} /> }}
options={{ header: AppHeader }}
/>
<Stack.Screen
name={contactsStackRouteNames.ContactForm}
Expand Down
15 changes: 10 additions & 5 deletions src/navigation/rootNavigator/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import {
BottomTabBarProps,
createBottomTabNavigator,
} from '@react-navigation/bottom-tabs'
import JailMonkey from 'jail-monkey'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useTranslation } from 'react-i18next'
Expand Down Expand Up @@ -39,6 +42,9 @@ import {

const RootTabs = createBottomTabNavigator<RootTabsParamsList>()

const TabBar = (isShown: boolean) => (props: BottomTabBarProps) =>
!isShown ? null : <AppFooterMenu {...props} />

export const RootNavigationComponent = () => {
const { t } = useTranslation()
const { top } = useSafeAreaInsets()
Expand All @@ -48,16 +54,15 @@ export const RootNavigationComponent = () => {
const fullscreen = useAppSelector(selectFullscreen)
const settingsLoading = useAppSelector(selectSettingsIsLoading)

const isShown = unlocked && !fullscreen
const isShown = useMemo(() => unlocked && !fullscreen, [unlocked, fullscreen])

useEffect(() => {
BootSplash.hide()
}, [])

return (
<View style={sharedStyles.flex}>
<RootTabs.Navigator
tabBar={props => (!isShown ? null : <AppFooterMenu {...props} />)}>
<RootTabs.Navigator tabBar={TabBar(isShown)}>
{!unlocked ? (
<RootTabs.Screen
name={rootTabsRouteNames.CreateKeysUX}
Expand Down
27 changes: 15 additions & 12 deletions src/screens/contacts/ContactDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ import { WalletContext } from 'src/shared/wallet'

const copyButtonConfig = { name: 'copy', size: 18, color: sharedColors.white }

const HeaderRight = (onDeleteContact: () => void) => () =>
(
<AppTouchable
width={24}
onPress={onDeleteContact}
style={sharedStyles.marginRight24}>
<FontAwesome5Icon
name={'trash-alt'}
size={20}
color={sharedColors.white}
/>
</AppTouchable>
)

export const ContactDetails = ({
navigation,
route: {
Expand Down Expand Up @@ -123,18 +137,7 @@ export const ContactDetails = ({

useEffect(() => {
navigation.setOptions({
headerRight: _ => (
<AppTouchable
width={24}
onPress={onDeleteContact}
style={sharedStyles.marginRight24}>
<FontAwesome5Icon
name={'trash-alt'}
size={20}
color={sharedColors.white}
/>
</AppTouchable>
),
headerRight: HeaderRight(onDeleteContact),
headerStyle: {
backgroundColor: sharedColors.inputActive,
},
Expand Down
5 changes: 5 additions & 0 deletions src/screens/contacts/ContactFormScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export const checkIfContactExists = (
name: string,
searchArray: Contact[],
) => {
if (!address || !name) {
return false
}

const index = searchArray.findIndex(c => {
return (
c.displayAddress === address.toLowerCase() ||
Expand Down Expand Up @@ -166,6 +170,7 @@ export const ContactFormScreen = ({
address: lAddress,
displayAddress,
}

const contactExists = checkIfContactExists(
displayAddress && lAddress,
trimmedName,
Expand Down
15 changes: 8 additions & 7 deletions src/screens/send/SendScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import {
selectBalances,
selectTotalUsdValue,
} from 'store/slices/balancesSlice/selectors'
import { sharedColors, sharedStyles } from 'shared/constants'
import { TokenBalanceObject } from 'store/slices/balancesSlice/types'
import { selectChainId } from 'store/slices/settingsSlice'
import { TransactionStatus } from 'store/shared/types'
import { selectRecentRskTransactions } from 'store/slices/transactionsSlice'
import { getContactsAsArrayAndSelected } from 'store/slices/contactsSlice'
import { FullScreenSpinner } from 'components/fullScreenSpinner'
import { SuccessIcon } from 'components/icons/SuccessIcon'
import { FeedbackModal } from 'components/feedbackModal'
import { getContactsAsArrayAndSelected } from 'store/slices/contactsSlice'
import { selectRecentRskTransactions } from 'store/slices/transactionsSlice'
import { sharedColors, sharedStyles } from 'shared/constants'
import { useWalletState } from 'shared/wallet'

import { TransactionForm } from './TransactionForm'
Expand Down Expand Up @@ -177,15 +178,15 @@ export const SendScreen = ({
status = error.toString()
} else if (
currentTransaction?.status &&
currentTransaction.status === 'USER_CONFIRM'
currentTransaction.status === TransactionStatus.USER_CONFIRM
) {
status = t('send_screen_sending_transaction')
}

useEffect(() => {
if (
currentTransaction?.status === 'SUCCESS' ||
currentTransaction?.status === 'FAILED'
currentTransaction?.status === TransactionStatus.SUCCESS ||
currentTransaction?.status === TransactionStatus.FAILED
) {
navigation.navigate(rootTabsRouteNames.Home, {
screen: homeStackRouteNames.Main,
Expand Down Expand Up @@ -239,7 +240,7 @@ export const SendScreen = ({
status={status}
bitcoinBalance={bitcoinBalance}
/>
{currentTransaction?.status === 'USER_CONFIRM' && (
{currentTransaction?.status === TransactionStatus.USER_CONFIRM && (
<FullScreenSpinner message={{ text: status }} />
)}
</KeyboardAvoidingView>
Expand Down
19 changes: 5 additions & 14 deletions src/screens/transactionSummary/TransactionSummaryComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ import {
import { castStyle, formatTokenValues } from 'shared/utils'
import { AppButton, AppTouchable, Typography } from 'components/index'
import { useAppSelector } from 'store/storeUtils'
import { isMyAddress } from 'components/address/lib'
import { DollarIcon } from 'components/icons/DollarIcon'
import { FullScreenSpinner } from 'components/fullScreenSpinner'
import { getContactByAddress } from 'store/slices/contactsSlice'
import { getWalletSetting } from 'core/config'
import { SETTINGS } from 'core/types'
import { selectChainId } from 'store/slices/settingsSlice'
Expand All @@ -44,13 +42,13 @@ type TransactionSummaryComponentProps = Omit<
Props

export const TransactionSummaryComponent = ({
address,
transaction,
buttons,
functionName,
goBack,
isLoaded,
FeeComponent,
contact,
}: TransactionSummaryComponentProps) => {
const [confirmed, setConfirmed] = useState(false)
const chainId = useAppSelector(selectChainId)
Expand All @@ -64,21 +62,14 @@ export const TransactionSummaryComponent = ({
time,
hashId,
to,
from,
totalToken,
totalUsd,
amIReceiver,
} = transaction

const iconObject = transactionStatusToIconPropsMap.get(status)
const transactionStatusText = transactionStatusDisplayText.get(status)

const amIReceiver = transaction.amIReceiver ?? isMyAddress(address, to)
const contactAddress = amIReceiver ? from || '' : to
const contact = useAppSelector(
getContactByAddress(contactAddress.toLowerCase()),
)
const contactToUse = contact || { address: contactAddress }

const title = useMemo(() => {
if (amIReceiver) {
if (status === TransactionStatus.SUCCESS) {
Expand Down Expand Up @@ -121,7 +112,7 @@ export const TransactionSummaryComponent = ({
<TokenBalance
firstValue={tokenValue}
secondValue={usdValue}
contact={contactToUse}
contact={contact}
amIReceiver={amIReceiver}
/>
{functionName && (
Expand Down Expand Up @@ -247,7 +238,7 @@ export const TransactionSummaryComponent = ({
{/* separator */}
<View style={styles.separator} />
{/* address value */}
{contactToUse?.name && (
{contact?.name && (
<View style={[styles.summaryAlignment]}>
<Typography
type={'body2'}
Expand All @@ -259,7 +250,7 @@ export const TransactionSummaryComponent = ({
style={[sharedStyles.textRight, styles.fullAddress]}
numberOfLines={1}
ellipsizeMode={'middle'}>
{contactToUse.address}
{contact.address}
</Typography>
</View>
)}
Expand Down
55 changes: 53 additions & 2 deletions src/screens/transactionSummary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { useFocusEffect, useIsFocused } from '@react-navigation/native'
import { ReactNode, useCallback, useEffect, useMemo } from 'react'
import { BackHandler } from 'react-native'
import { showMessage } from 'react-native-flash-message'
import { useTranslation } from 'react-i18next'

import { shortAddress } from 'lib/utils'

import { AppButtonProps } from 'components/button'
import { CurrencyValue } from 'components/token'
import { sharedHeaderLeftOptions } from 'navigation/index'
import { contactsStackRouteNames } from 'navigation/contactsNavigator'
import {
RootTabsScreenProps,
rootTabsRouteNames,
} from 'navigation/rootNavigator'
import { isMyAddress } from 'components/index'
import { TransactionSummaryComponent } from 'screens/transactionSummary/TransactionSummaryComponent'
import { setFullscreen } from 'store/slices/settingsSlice'
import { TokenFeeValueObject } from 'store/slices/transactionsSlice'
import { useAppDispatch } from 'store/storeUtils'
import { useAppDispatch, useAppSelector } from 'store/storeUtils'
import { useWallet } from 'shared/wallet'
import { getPopupMessage } from 'shared/popupMessage'
import { ContactWithAddressRequired } from 'shared/types'
import { TransactionStatus } from 'store/shared/types'
import { getContactByAddress } from 'store/slices/contactsSlice'

export interface TransactionSummaryScreenProps {
transaction: {
Expand All @@ -30,6 +39,7 @@ export interface TransactionSummaryScreenProps {
amIReceiver?: boolean
from?: string
}
contact: ContactWithAddressRequired
buttons?: [AppButtonProps, AppButtonProps]
functionName?: string
backScreen?: rootTabsRouteNames
Expand All @@ -41,10 +51,19 @@ export const TransactionSummaryScreen = ({
route,
navigation,
}: RootTabsScreenProps<rootTabsRouteNames.TransactionSummary>) => {
const { t } = useTranslation()
const { transaction, backScreen } = route.params
const { to, from } = transaction

const { address } = useWallet()
const dispatch = useAppDispatch()
const isFocused = useIsFocused()
const { backScreen } = route.params
const amIReceiver = transaction.amIReceiver ?? isMyAddress(address, to)
const contactAddress = amIReceiver ? from || '' : to
const contact = useAppSelector(
getContactByAddress(contactAddress.toLowerCase()),
)
const contactToUse = contact || { address: contactAddress }

const goBack = useMemo(() => {
if (backScreen) {
Expand Down Expand Up @@ -77,9 +96,41 @@ export const TransactionSummaryScreen = ({
})
}, [goBack, navigation])

const moveToCreateContact = useCallback(() => {
navigation.navigate(rootTabsRouteNames.Contacts, {
screen: contactsStackRouteNames.ContactForm,
params: {
initialValue: {
address: contactAddress,
name: '',
displayAddress: '',
},
proposed: true,
},
})
}, [navigation, contactAddress])

useEffect(() => {
if (!contact) {
showMessage(
getPopupMessage(
`${t(
'transaction_summary_add_non_existent_contact_title',
)} ${shortAddress(contactAddress)} ${t(
'transaction_summary_add_non_existent_contact_title_2',
)}`,
t('transaction_summary_add_non_existent_contact_action'),
moveToCreateContact,
),
)
}
}, [contact, contactAddress, moveToCreateContact, t])

return (
<TransactionSummaryComponent
{...route.params}
transaction={{ ...route.params.transaction, amIReceiver }}
contact={contactToUse}
goBack={goBack}
address={address}
/>
Expand Down
8 changes: 7 additions & 1 deletion src/ux/requestsModal/ReviewBitcoinTransactionContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import { TransactionSummaryComponent } from 'screens/transactionSummary/Transact
import { TokenSymbol } from 'screens/home/TokenImage'
import { selectUsdPrices } from 'store/slices/usdPricesSlice'
import { useAppSelector } from 'store/storeUtils'
import { sharedColors } from 'shared/constants'
import { getContactByAddress } from 'store/slices/contactsSlice'
import { AppButtonBackgroundVarietyEnum, Input } from 'components/index'
import { TransactionSummaryScreenProps } from 'screens/transactionSummary'
import { formatTokenValues } from 'shared/utils'
import { sharedColors } from 'shared/constants'

import {
BitcoinMiningFeeContainer,
Expand All @@ -44,6 +45,8 @@ export const ReviewBitcoinTransactionContainer = ({
payload: { addressToPay, payment, ...payload },
} = request

const contact = useAppSelector(getContactByAddress(addressToPay))

const [miningFeeState, setMiningFeeState] = useState(payload.miningFee)

const onMiningFeeChange = useCallback(
Expand Down Expand Up @@ -85,6 +88,7 @@ export const ReviewBitcoinTransactionContainer = ({
const feeUsd = convertToUSD(miningFee)
const isAmountSmall = !Number(amountToPayUsd) && !!Number(amountToPay)
const totalSent = Number(amountToPay) + Number(miningFee)
const contactToUse = contact || { address: addressToPay }

return {
transaction: {
Expand Down Expand Up @@ -114,6 +118,7 @@ export const ReviewBitcoinTransactionContainer = ({
),
to: addressToPay,
},
contact: contactToUse,
buttons: [
{
title: t('transaction_summary_title_confirm_button_title'),
Expand Down Expand Up @@ -146,6 +151,7 @@ export const ReviewBitcoinTransactionContainer = ({
tokenPrices,
payload.miningFee,
onMiningFeeChange,
contact,
])
return (
<View style={[styles.container, { paddingTop: insets.top }]}>
Expand Down
Loading
Loading