diff --git a/android/app/build.gradle b/android/app/build.gradle index e2d4d7e4..36acb3d4 100755 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,7 +5,7 @@ import com.android.build.OutputFile def versionMajor = 1 def versionMinor = 0 -def versionRevision = 21 +def versionRevision = 22 def versionBuild = 0 def keystorePropertiesFile = rootProject.file("keystore.properties"); diff --git a/env/main.android.json b/env/main.android.json index 0cb5c6d6..2540c6c6 100644 --- a/env/main.android.json +++ b/env/main.android.json @@ -1,5 +1,5 @@ { - "APP_VERSION": "1.0.21", + "APP_VERSION": "1.0.22", "ELECTRUM_PROTOCOL_CHANGE": 1.4, "KEY_DERIVATION_VERSION": 1, diff --git a/env/main.ios.json b/env/main.ios.json index 062f8e08..4c9e72e1 100644 --- a/env/main.ios.json +++ b/env/main.ios.json @@ -1,5 +1,5 @@ { - "APP_VERSION": "1.0.21", + "APP_VERSION": "1.0.22", "ELECTRUM_PROTOCOL_CHANGE": 1.4, "KEY_DERIVATION_VERSION": 1, diff --git a/ios/assets/env/main.json b/ios/assets/env/main.json index 062f8e08..4c9e72e1 100644 --- a/ios/assets/env/main.json +++ b/ios/assets/env/main.json @@ -1,5 +1,5 @@ { - "APP_VERSION": "1.0.21", + "APP_VERSION": "1.0.22", "ELECTRUM_PROTOCOL_CHANGE": 1.4, "KEY_DERIVATION_VERSION": 1, diff --git a/ios/verusMobile.xcodeproj/project.pbxproj b/ios/verusMobile.xcodeproj/project.pbxproj index 9bd969c4..eb32e3be 100644 --- a/ios/verusMobile.xcodeproj/project.pbxproj +++ b/ios/verusMobile.xcodeproj/project.pbxproj @@ -745,7 +745,7 @@ "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/rn-fetch-blob\"", ); - MARKETING_VERSION = 1.0.21; + MARKETING_VERSION = 1.0.22; PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.verusmobile; PRODUCT_NAME = verusmobile; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -817,7 +817,7 @@ "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/rn-fetch-blob\"", ); - MARKETING_VERSION = 1.0.21; + MARKETING_VERSION = 1.0.22; PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.verusmobile; PRODUCT_NAME = verusmobile; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/package.json b/package.json index 8571fce7..2a0057c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "verusmobile", - "version": "1.0.21", + "version": "1.0.22", "private": true, "scripts": { "postinstall": "./node_modules/.bin/rn-nodeify --hack --install --yarn && npx jetify", diff --git a/src/components/LoadingModal/LoadingModal.js b/src/components/LoadingModal/LoadingModal.js index b3807473..b1714d04 100644 --- a/src/components/LoadingModal/LoadingModal.js +++ b/src/components/LoadingModal/LoadingModal.js @@ -6,9 +6,10 @@ import Colors from '../../globals/colors'; import styles from '../../styles'; import AnimatedActivityIndicator from '../AnimatedActivityIndicator'; import SemiModal from '../SemiModal'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; export default function LoadingModal(props) { - const {visible, message, height} = useSelector(state => state.loadingModal); + const {visible, message, height} = useObjectSelector(state => state.loadingModal); return ( diff --git a/src/components/SendModal/AddErc20Token/AddErc20TokenConfirm/AddErc20TokenConfirm.js b/src/components/SendModal/AddErc20Token/AddErc20TokenConfirm/AddErc20TokenConfirm.js index 9b2b4b4b..6d3cc6c7 100644 --- a/src/components/SendModal/AddErc20Token/AddErc20TokenConfirm/AddErc20TokenConfirm.js +++ b/src/components/SendModal/AddErc20Token/AddErc20TokenConfirm/AddErc20TokenConfirm.js @@ -13,17 +13,19 @@ import {AddErc20TokenConfirmRender} from './AddErc20TokenConfirm.render'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; import { coinsList } from '../../../../utils/CoinData/CoinsList'; import { ERC20 } from '../../../../utils/constants/intervalConstants'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AddErc20TokenConfirm = props => { const [contract, setCurrency] = useState(props.route.params.contract); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector( + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); - const activeCoinsForUser = useSelector(state => state.coins.activeCoinsForUser); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); + const activeCoinsForUser = useObjectSelector(state => state.coins.activeCoinsForUser); + const testAccount = useSelector(state => (Object.keys(state.authentication.activeAccount.testnetOverrides).length > 0)) const goBack = useCallback(() => { diff --git a/src/components/SendModal/AddErc20Token/AddErc20TokenForm/AddErc20TokenForm.js b/src/components/SendModal/AddErc20Token/AddErc20TokenForm/AddErc20TokenForm.js index e4fdfd0b..2ce6a5a8 100644 --- a/src/components/SendModal/AddErc20Token/AddErc20TokenForm/AddErc20TokenForm.js +++ b/src/components/SendModal/AddErc20Token/AddErc20TokenForm/AddErc20TokenForm.js @@ -1,5 +1,5 @@ import {useCallback, useState} from 'react'; -import {useSelector, useDispatch} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {Alert} from 'react-native'; import {createAlert} from '../../../../actions/actions/alert/dispatchers/alert'; import { @@ -10,10 +10,11 @@ import {getWeb3ProviderForNetwork} from '../../../../utils/web3/provider'; import {AddErc20TokenFormRender} from './AddErc20TokenForm.render'; import { getCurrency } from '../../../../utils/api/channels/verusid/callCreators'; import { getCurrenciesMappedToEth } from '../../../../utils/api/channels/vrpc/requests/getCurrenciesMappedToEth'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AddErc20TokenForm = props => { const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const [useMappedCurrency, setUseMappedCurrency] = useState(false); diff --git a/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyConfirm/AddPbaasCurrencyConfirm.js b/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyConfirm/AddPbaasCurrencyConfirm.js index 1cd553f2..591406cd 100644 --- a/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyConfirm/AddPbaasCurrencyConfirm.js +++ b/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyConfirm/AddPbaasCurrencyConfirm.js @@ -1,5 +1,5 @@ import React, {useState, useCallback} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {Alert} from 'react-native'; import {addCoin, addKeypairs, setUserCoins} from '../../../../actions/actionCreators'; import { @@ -11,6 +11,7 @@ import { } from '../../../../utils/constants/sendModal'; import {AddPbaasCurrencyConfirmRender} from './AddPbaasCurrencyConfirm.render'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AddPbaasCurrencyConfirm = props => { const [currency, setCurrency] = useState(props.route.params.currency); @@ -22,11 +23,11 @@ const AddPbaasCurrencyConfirm = props => { ); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector( + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); const goBack = useCallback(() => { props.setModalHeight(); diff --git a/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyForm/AddPbaasCurrencyForm.js b/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyForm/AddPbaasCurrencyForm.js index 410d1de3..d004d288 100644 --- a/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyForm/AddPbaasCurrencyForm.js +++ b/src/components/SendModal/AddPbaasCurrency/AddPbaasCurrencyForm/AddPbaasCurrencyForm.js @@ -1,5 +1,5 @@ import {useCallback, useEffect} from 'react'; -import {useSelector, useDispatch} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {fromBase58Check} from '@bitgo/utxo-lib/dist/src/address'; import {Alert, Dimensions} from 'react-native'; import {createAlert} from '../../../../actions/actions/alert/dispatchers/alert'; @@ -15,12 +15,13 @@ import { } from '../../../../utils/constants/sendModal'; import {deriveKeyPair} from '../../../../utils/keys'; import {AddPbaasCurrencyFormRender} from './AddPbaasCurrencyForm.render'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AddPbaasCurrencyForm = (props) => { const { height } = Dimensions.get("window"); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeCoinsForUser = useSelector(state => state.coins.activeCoinsForUser); + const sendModal = useObjectSelector(state => state.sendModal); + const activeCoinsForUser = useObjectSelector(state => state.coins.activeCoinsForUser); const formHasError = useCallback(() => { const {data} = sendModal; diff --git a/src/components/SendModal/AuthenticateUser/AuthenticateUserForm/AuthenticateUserForm.js b/src/components/SendModal/AuthenticateUser/AuthenticateUserForm/AuthenticateUserForm.js index 582f82ba..d07074a3 100644 --- a/src/components/SendModal/AuthenticateUser/AuthenticateUserForm/AuthenticateUserForm.js +++ b/src/components/SendModal/AuthenticateUser/AuthenticateUserForm/AuthenticateUserForm.js @@ -2,13 +2,13 @@ import React from 'react'; import { useEffect, useState } from "react" import { FlatList, TouchableOpacity } from "react-native"; import { List } from "react-native-paper"; -import { useSelector } from 'react-redux' import styles from "../../../../styles"; import { SEND_MODAL_FORM_STEP_CONFIRM, SEND_MODAL_USER_ALLOWLIST } from "../../../../utils/constants/sendModal"; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AuthenticateUserForm = props => { - const accounts = useSelector(state => state.authentication.accounts) - const data = useSelector(state => state.sendModal.data) + const accounts = useObjectSelector(state => state.authentication.accounts) + const data = useObjectSelector(state => state.sendModal.data) const [accountList, setAccountList] = useState([]) const selectAccount = (account) => { diff --git a/src/components/SendModal/AuthenticateUser/AuthenticateUserPassword/AuthenticateUserPassword.js b/src/components/SendModal/AuthenticateUser/AuthenticateUserPassword/AuthenticateUserPassword.js index fe33b38e..3a6dd557 100644 --- a/src/components/SendModal/AuthenticateUser/AuthenticateUserPassword/AuthenticateUserPassword.js +++ b/src/components/SendModal/AuthenticateUser/AuthenticateUserPassword/AuthenticateUserPassword.js @@ -9,15 +9,18 @@ import Colors from '../../../../globals/colors'; import styles from "../../../../styles"; import { SEND_MODAL_FORM_STEP_FORM, SEND_MODAL_FORM_STEP_RESULT, SEND_MODAL_USER_TO_AUTHENTICATE } from "../../../../utils/constants/sendModal"; import { getBiometricPassword, getSupportedBiometryType } from '../../../../utils/keychain/keychain'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const AuthenticateUserPassword = props => { const [password, setPassword] = useState("") const defaultAccount = useSelector( state => state.settings.generalWalletSettings.defaultAccount, ); - const accounts = useSelector(state => state.authentication.accounts) - const activeAccount = useSelector(state => state.authentication.activeAccount) - const data = useSelector(state => state.sendModal.data) + + const accounts = useObjectSelector(state => state.authentication.accounts) + const activeAccount = useObjectSelector(state => state.authentication.activeAccount) + const data = useObjectSelector(state => state.sendModal.data) + const account = props.route.params == null || props.route.params.account == null ? accounts.find( diff --git a/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.js b/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.js index f9063c05..078b972c 100644 --- a/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.js +++ b/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.js @@ -1,3 +1,5 @@ +// DEPRECATED + import BigNumber from "bignumber.js"; import { Component } from "react" import { Alert } from "react-native"; diff --git a/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.render.js b/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.render.js index 3e964a16..755bb86a 100644 --- a/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.render.js +++ b/src/components/SendModal/ConversionSend/ConversionSendConfirm/ConversionSendConfirm.render.js @@ -1,3 +1,5 @@ +// DEPRECATED + import React from "react"; import { ScrollView, View, TouchableOpacity } from "react-native"; import { Button, List, Divider, Text } from "react-native-paper"; diff --git a/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.js b/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.js index 8d931537..10a49a05 100644 --- a/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.js +++ b/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.js @@ -1,3 +1,5 @@ +// DEPRECATED + import BigNumber from "bignumber.js"; import { Component } from "react" import { Alert, Dimensions } from "react-native"; diff --git a/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.render.js b/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.render.js index 1df7fdbf..a04d31b5 100644 --- a/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.render.js +++ b/src/components/SendModal/ConversionSend/ConversionSendForm/ConversionSendForm.render.js @@ -1,3 +1,5 @@ +// DEPRECATED + import React from "react"; import { ScrollView, diff --git a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendConfirm/ConvertOrCrossChainSendConfirm.js b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendConfirm/ConvertOrCrossChainSendConfirm.js index 43090c4d..414a4fab 100644 --- a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendConfirm/ConvertOrCrossChainSendConfirm.js +++ b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendConfirm/ConvertOrCrossChainSendConfirm.js @@ -1,7 +1,7 @@ import React, {useEffect, useRef, useState} from 'react'; import {ScrollView, View, TouchableOpacity, Alert} from 'react-native'; import {Button, List, Divider, Text} from 'react-native-paper'; -import {useDispatch, useSelector} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {expireCoinData} from '../../../../actions/actionCreators'; import {copyToClipboard} from '../../../../utils/clipboard/clipboard'; import { @@ -29,6 +29,7 @@ import {TransferDestination} from 'verus-typescript-primitives'; import {sendCurrencyTransfer} from '../../../../utils/api/channels/vrpc/callCreators'; import {CoinDirectory} from '../../../../utils/CoinData/CoinDirectory'; import { sendConvertOrCrossChain } from '../../../../utils/api/routers/sendConvertOrCrossChain'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; function ConvertOrCrossChainSendConfirm({ navigation, @@ -37,9 +38,9 @@ function ConvertOrCrossChainSendConfirm({ setModalHeight, setPreventExit, }) { - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector(state => state.authentication.activeAccount); - const networkName = useSelector(state => { + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector(state => state.authentication.activeAccount); + const networkName = useObjectSelector(state => { try { const subwallet = state.sendModal.subWallet; diff --git a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendForm/ConvertOrCrossChainSendForm.js b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendForm/ConvertOrCrossChainSendForm.js index e09d4483..de4b6ac9 100644 --- a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendForm/ConvertOrCrossChainSendForm.js +++ b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendForm/ConvertOrCrossChainSendForm.js @@ -3,7 +3,6 @@ import BigNumber from "bignumber.js"; import { Alert, View, TouchableWithoutFeedback, Keyboard, FlatList, Animated, TouchableOpacity, Dimensions } from "react-native"; import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; import { TextInput, Button, Divider, Checkbox, List, Text, IconButton } from "react-native-paper"; -import { useSelector } from 'react-redux'; import { createAlert } from "../../../../actions/actions/alert/dispatchers/alert"; import { API_SEND, DLIGHT_PRIVATE, ERC20, ETH } from "../../../../utils/constants/intervalConstants"; import { @@ -53,15 +52,16 @@ import { addressIsBlocked } from "../../../../utils/addressBlocklist"; import { selectAddressBlocklist } from "../../../../selectors/settings"; import { I_ADDRESS_VERSION, R_ADDRESS_VERSION } from "../../../../utils/constants/constants"; import { getWeb3ProviderForNetwork } from "../../../../utils/web3/provider"; +import { useObjectSelector } from "../../../../hooks/useObjectSelector"; const ConvertOrCrossChainSendForm = ({ setLoading, setModalHeight, updateSendFormData, navigation }) => { const { height } = Dimensions.get('window'); - const sendModal = useSelector(state => state.sendModal); - const activeUser = useSelector(state => state.authentication.activeAccount); - const addresses = useSelector(state => selectAddresses(state)); - const activeAccount = useSelector(state => state.authentication.activeAccount); - const addressBlocklist = useSelector(selectAddressBlocklist); - const networkName = useSelector(state => { + const sendModal = useObjectSelector(state => state.sendModal); + const activeUser = useObjectSelector(state => state.authentication.activeAccount); + const addresses = useObjectSelector(state => selectAddresses(state)); + const activeAccount = useObjectSelector(state => state.authentication.activeAccount); + const addressBlocklist = useObjectSelector(selectAddressBlocklist); + const networkName = useObjectSelector(state => { try { const subwallet = state.sendModal.subWallet; diff --git a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendResult/ConvertOrCrossChainSendResult.js b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendResult/ConvertOrCrossChainSendResult.js index 1a16adac..75b089c6 100644 --- a/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendResult/ConvertOrCrossChainSendResult.js +++ b/src/components/SendModal/ConvertOrCrossChainSend/ConvertOrCrossChainSendResult/ConvertOrCrossChainSendResult.js @@ -8,11 +8,11 @@ import Colors from "../../../../globals/colors"; import Styles from "../../../../styles"; import { copyToClipboard } from "../../../../utils/clipboard/clipboard"; import AnimatedSuccessCheckmark from "../../../AnimatedSuccessCheckmark"; -import { useSelector } from "react-redux"; import { SEND_MODAL_SEND_COMPLETED } from "../../../../utils/constants/sendModal"; +import { useObjectSelector } from "../../../../hooks/useObjectSelector"; const ConvertOrCrossChainSendResult = (props) => { - const coinObj = useSelector(state => state.sendModal.coinObj); + const coinObj = useObjectSelector(state => state.sendModal.coinObj); const [params, setParams] = useState(props.route.params == null ? {} : props.route.params); const { updateSendFormData } = props; diff --git a/src/components/SendModal/DepositSend/DepositSendForm/DepositSendForm.js b/src/components/SendModal/DepositSend/DepositSendForm/DepositSendForm.js index 2468af20..9f0b163c 100644 --- a/src/components/SendModal/DepositSend/DepositSendForm/DepositSendForm.js +++ b/src/components/SendModal/DepositSend/DepositSendForm/DepositSendForm.js @@ -1,3 +1,5 @@ +// DEPRECATED + import BigNumber from "bignumber.js"; import { Component } from "react" import { Alert, Dimensions } from "react-native"; diff --git a/src/components/SendModal/LinkIdentity/LinkIdentityConfirm/LinkIdentityConfirm.js b/src/components/SendModal/LinkIdentity/LinkIdentityConfirm/LinkIdentityConfirm.js index e84a8a66..394eace9 100644 --- a/src/components/SendModal/LinkIdentity/LinkIdentityConfirm/LinkIdentityConfirm.js +++ b/src/components/SendModal/LinkIdentity/LinkIdentityConfirm/LinkIdentityConfirm.js @@ -1,5 +1,5 @@ import React, {useState, useCallback} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {Alert} from 'react-native'; import {setUserCoins} from '../../../../actions/actionCreators'; import {updateVerusIdWallet} from '../../../../actions/actions/channels/verusid/dispatchers/VerusidWalletReduxManager'; @@ -14,6 +14,7 @@ import { } from '../../../../utils/constants/sendModal'; import {convertFqnToDisplayFormat} from '../../../../utils/fullyqualifiedname'; import {LinkIdentityConfirmRender} from './LinkIdentityConfirm.render'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const LinkIdentityConfirm = props => { const [verusId, setVerusId] = useState(props.route.params.verusId); @@ -22,11 +23,11 @@ const LinkIdentityConfirm = props => { ); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector( + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); const goBack = useCallback(() => { props.setModalHeight(); diff --git a/src/components/SendModal/LinkIdentity/LinkIdentityForm/LinkIdentityForm.js b/src/components/SendModal/LinkIdentity/LinkIdentityForm/LinkIdentityForm.js index 7a1fdb1c..ff540752 100644 --- a/src/components/SendModal/LinkIdentity/LinkIdentityForm/LinkIdentityForm.js +++ b/src/components/SendModal/LinkIdentity/LinkIdentityForm/LinkIdentityForm.js @@ -1,5 +1,5 @@ import {useCallback} from 'react'; -import {useSelector, useDispatch} from 'react-redux'; +import {useDispatch} from 'react-redux'; import {fromBase58Check} from '@bitgo/utxo-lib/dist/src/address'; import {Alert, Dimensions} from 'react-native'; import {createAlert} from '../../../../actions/actions/alert/dispatchers/alert'; @@ -15,11 +15,12 @@ import { } from '../../../../utils/constants/sendModal'; import {deriveKeyPair} from '../../../../utils/keys'; import {LinkIdentityFormRender} from './LinkIdentityForm.render'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const LinkIdentityForm = (props) => { const { height } = Dimensions.get("window"); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const formHasError = useCallback(() => { const {data} = sendModal; diff --git a/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.js b/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.js index b6bd791b..5d1894fd 100644 --- a/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.js +++ b/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.js @@ -1,12 +1,12 @@ import {useEffect, useState} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; import {closeSendModal} from '../../../../actions/actions/sendModal/dispatchers/sendModal'; import {LinkIdentityResultRender} from './LinkIdentityResult.render'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const LinkIdentityResult = (props) => { const [verusId, setVerusId] = useState(props.route.params == null ? {} : props.route.params.verusId); const [friendlyNames, setFriendlyNames] = useState(props.route.params == null ? {} : props.route.params.friendlyNames); - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const {data} = sendModal; const finishSend = async () => { diff --git a/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.render.js b/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.render.js index 31ba56f9..71dc94c4 100644 --- a/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.render.js +++ b/src/components/SendModal/LinkIdentity/LinkIdentityResult/LinkIdentityResult.render.js @@ -5,11 +5,11 @@ import Colors from '../../../../globals/colors'; import Styles from '../../../../styles'; import {copyToClipboard} from '../../../../utils/clipboard/clipboard'; import AnimatedSuccessCheckmark from '../../../AnimatedSuccessCheckmark'; -import { useSelector } from 'react-redux'; import { convertFqnToDisplayFormat } from '../../../../utils/fullyqualifiedname'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; export const LinkIdentityResultRender = ({verusId, finishSend}) => { - const coinObj = useSelector(state => state.sendModal.coinObj); + const coinObj = useObjectSelector(state => state.sendModal.coinObj); const formattedFriendlyName = convertFqnToDisplayFormat(verusId.fullyqualifiedname); return ( diff --git a/src/components/SendModal/ProvisionIdentity/ProvisionIdentityForm/ProvisionIdentityForm.js b/src/components/SendModal/ProvisionIdentity/ProvisionIdentityForm/ProvisionIdentityForm.js index a18f645f..c73295aa 100644 --- a/src/components/SendModal/ProvisionIdentity/ProvisionIdentityForm/ProvisionIdentityForm.js +++ b/src/components/SendModal/ProvisionIdentity/ProvisionIdentityForm/ProvisionIdentityForm.js @@ -1,6 +1,5 @@ import { fromBase58Check } from "@bitgo/utxo-lib/dist/src/address"; import React, { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; import { primitives } from "verusid-ts-client"; import { createAlert } from "../../../../actions/actions/alert/dispatchers/alert"; import { getIdentity } from "../../../../utils/api/channels/verusid/callCreators"; @@ -18,12 +17,13 @@ import { } from "react-native"; import { TextInput, Button, Paragraph } from "react-native-paper"; import Styles from "../../../../styles"; +import { useObjectSelector } from "../../../../hooks/useObjectSelector"; const ProvisionIdentityForm = (props) => { const { height } = Dimensions.get("window"); - const sendModal = useSelector((state) => state.sendModal); + const sendModal = useObjectSelector((state) => state.sendModal); const chainTicker = sendModal.coinObj.id; - const addresses = useSelector(state => + const addresses = useObjectSelector(state => state.authentication.activeAccount.keys[chainTicker] ? state.authentication.activeAccount.keys[chainTicker].vrpc.addresses : [], diff --git a/src/components/SendModal/RecoverIdentity/RecoverIdentityConfirm/RecoverIdentityConfirm.js b/src/components/SendModal/RecoverIdentity/RecoverIdentityConfirm/RecoverIdentityConfirm.js index 2e1d0273..18cf718b 100644 --- a/src/components/SendModal/RecoverIdentity/RecoverIdentityConfirm/RecoverIdentityConfirm.js +++ b/src/components/SendModal/RecoverIdentity/RecoverIdentityConfirm/RecoverIdentityConfirm.js @@ -13,12 +13,11 @@ import { decryptkey } from '../../../../utils/seedCrypt'; import { deriveKeyPair } from '../../../../utils/keys'; import { ELECTRUM } from '../../../../utils/constants/intervalConstants'; import { coinsList } from '../../../../utils/CoinData/CoinsList'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RecoverIdentityConfirm = props => { const [targetId, setTargetId] = useState(props.route.params.targetId); const [recoveryId, setRecoveryId] = useState(props.route.params.recoveryId); - const [ownedAddress, setOwnedAddress] = useState(props.route.params.ownedAddress); - const [recoverableByUser, setRecoverableByUser] = useState(props.route.params.recoverableByUser); const [recoveryResult, setRecoveryResult] = useState(props.route.params.recoveryResult); const [revocationAddr, setRevocationAddr] = useState(props.route.params.revocationAddr); const [recoveryAddr, setRecoveryAddr] = useState(props.route.params.recoveryAddr); @@ -31,11 +30,12 @@ const RecoverIdentityConfirm = props => { const instanceKey = useSelector(state => state.authentication.instanceKey); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector( + + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); const goBack = useCallback(() => { props.setModalHeight(); diff --git a/src/components/SendModal/RecoverIdentity/RecoverIdentityForm/RecoverIdentityForm.js b/src/components/SendModal/RecoverIdentity/RecoverIdentityForm/RecoverIdentityForm.js index 4ffa7a02..7162d9c1 100644 --- a/src/components/SendModal/RecoverIdentity/RecoverIdentityForm/RecoverIdentityForm.js +++ b/src/components/SendModal/RecoverIdentity/RecoverIdentityForm/RecoverIdentityForm.js @@ -26,12 +26,16 @@ import { createRecoverIdentityTx, createRevokeIdentityTx } from '../../../../uti import { coinsList } from '../../../../utils/CoinData/CoinsList'; import { decryptkey } from '../../../../utils/seedCrypt'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RecoverIdentityForm = (props) => { const { height } = Dimensions.get("window"); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); + + const sendModal = useObjectSelector(state => state.sendModal); + const instanceKey = useSelector(state => state.authentication.instanceKey); + const [networkName, setNetworkName] = useState(sendModal.data[SEND_MODAL_SYSTEM_ID]); const [scannerOpen, setScannerOpen] = useState(false); diff --git a/src/components/SendModal/RecoverIdentity/RecoverIdentityResult/RecoverIdentityResult.js b/src/components/SendModal/RecoverIdentity/RecoverIdentityResult/RecoverIdentityResult.js index f521e22d..8fbe1a4d 100644 --- a/src/components/SendModal/RecoverIdentity/RecoverIdentityResult/RecoverIdentityResult.js +++ b/src/components/SendModal/RecoverIdentity/RecoverIdentityResult/RecoverIdentityResult.js @@ -1,14 +1,14 @@ import {useEffect, useState} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; import {closeSendModal} from '../../../../actions/actions/sendModal/dispatchers/sendModal'; import { RecoverIdentityResultRender } from './RecoverIdentityResult.render'; import { SEND_MODAL_REVOKE_RECOVER_COMPLETE, SEND_MODAL_SYSTEM_ID } from '../../../../utils/constants/sendModal'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; import { explorers } from '../../../../utils/CoinData/CoinData'; import { openUrl } from '../../../../utils/linking'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RecoverIdentityResult = (props) => { - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const {data} = sendModal; const [targetId, setTargetId] = useState(props.route.params == null ? {} : props.route.params.targetId); const [txid, setTxid] = useState(props.route.params.txid); diff --git a/src/components/SendModal/RevokeIdentity/RevokeIdentityConfirm/RevokeIdentityConfirm.js b/src/components/SendModal/RevokeIdentity/RevokeIdentityConfirm/RevokeIdentityConfirm.js index cceaf96e..67037539 100644 --- a/src/components/SendModal/RevokeIdentity/RevokeIdentityConfirm/RevokeIdentityConfirm.js +++ b/src/components/SendModal/RevokeIdentity/RevokeIdentityConfirm/RevokeIdentityConfirm.js @@ -13,6 +13,7 @@ import { decryptkey } from '../../../../utils/seedCrypt'; import { deriveKeyPair } from '../../../../utils/keys'; import { ELECTRUM } from '../../../../utils/constants/intervalConstants'; import { coinsList } from '../../../../utils/CoinData/CoinsList'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RevokeIdentityConfirm = props => { const [targetId, setTargetId] = useState(props.route.params.targetId); @@ -26,11 +27,12 @@ const RevokeIdentityConfirm = props => { const instanceKey = useSelector(state => state.authentication.instanceKey); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); - const activeAccount = useSelector( + + const sendModal = useObjectSelector(state => state.sendModal); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); const goBack = useCallback(() => { props.setModalHeight(); diff --git a/src/components/SendModal/RevokeIdentity/RevokeIdentityForm/RevokeIdentityForm.js b/src/components/SendModal/RevokeIdentity/RevokeIdentityForm/RevokeIdentityForm.js index be2ecdb6..6751daf2 100644 --- a/src/components/SendModal/RevokeIdentity/RevokeIdentityForm/RevokeIdentityForm.js +++ b/src/components/SendModal/RevokeIdentity/RevokeIdentityForm/RevokeIdentityForm.js @@ -20,11 +20,14 @@ import { createRevokeIdentityTx } from '../../../../utils/api/channels/verusid/r import { coinsList } from '../../../../utils/CoinData/CoinsList'; import { decryptkey } from '../../../../utils/seedCrypt'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RevokeIdentityForm = (props) => { const { height } = Dimensions.get("window"); const dispatch = useDispatch(); - const sendModal = useSelector(state => state.sendModal); + + const sendModal = useObjectSelector(state => state.sendModal); + const instanceKey = useSelector(state => state.authentication.instanceKey); const [networkName, setNetworkName] = useState(sendModal.data[SEND_MODAL_SYSTEM_ID]); diff --git a/src/components/SendModal/RevokeIdentity/RevokeIdentityResult/RevokeIdentityResult.js b/src/components/SendModal/RevokeIdentity/RevokeIdentityResult/RevokeIdentityResult.js index 5fdd1600..eb10b495 100644 --- a/src/components/SendModal/RevokeIdentity/RevokeIdentityResult/RevokeIdentityResult.js +++ b/src/components/SendModal/RevokeIdentity/RevokeIdentityResult/RevokeIdentityResult.js @@ -1,14 +1,14 @@ import {useEffect, useState} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; import {closeSendModal} from '../../../../actions/actions/sendModal/dispatchers/sendModal'; import { RevokeIdentityResultRender } from './RevokeIdentityResult.render'; import { SEND_MODAL_REVOKE_RECOVER_COMPLETE, SEND_MODAL_SYSTEM_ID } from '../../../../utils/constants/sendModal'; import { CoinDirectory } from '../../../../utils/CoinData/CoinDirectory'; import { explorers } from '../../../../utils/CoinData/CoinData'; import { openUrl } from '../../../../utils/linking'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const RevokeIdentityResult = (props) => { - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const {data} = sendModal; const [targetId, setTargetId] = useState(props.route.params == null ? {} : props.route.params.targetId); const [txid, setTxid] = useState(props.route.params.txid); diff --git a/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendConfirm/TraditionalCryptoSendConfirm.js b/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendConfirm/TraditionalCryptoSendConfirm.js index 5faa0816..c9a21f5c 100644 --- a/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendConfirm/TraditionalCryptoSendConfirm.js +++ b/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendConfirm/TraditionalCryptoSendConfirm.js @@ -12,24 +12,25 @@ import { truncateDecimal } from "../../../../utils/math"; import Colors from "../../../../globals/colors"; import Styles from "../../../../styles"; import BigNumber from "bignumber.js"; +import { useObjectSelector } from "../../../../hooks/useObjectSelector"; function TraditionalCryptoSendConfirm({ navigation, route, setLoading, setModalHeight, setPreventExit }) { const [params, setParams] = useState(route.params.txConfirmation); const [confirmationFields, setConfirmationFields] = useState([]); const dispatch = useDispatch(); - const balance_channel = useSelector(state => state.sendModal.subWallet.api_channels[API_GET_BALANCES]); - const rates_channel = useSelector(state => state.sendModal.subWallet.api_channels[API_GET_FIATPRICE]); + const balance_channel = useObjectSelector(state => state.sendModal.subWallet.api_channels[API_GET_BALANCES]); + const rates_channel = useObjectSelector(state => state.sendModal.subWallet.api_channels[API_GET_FIATPRICE]); const chainTicker = params.coinObj.id const balances = { - results: useSelector(state => state.ledger.balances[balance_channel] + results: useObjectSelector(state => state.ledger.balances[balance_channel] ? state.ledger.balances[balance_channel][chainTicker] : null), - errors: useSelector(state => state.errors[API_GET_BALANCES][balance_channel][chainTicker]), + errors: useObjectSelector(state => state.errors[API_GET_BALANCES][balance_channel][chainTicker]), }; - const rates = useSelector(state => state.ledger.rates[rates_channel]); + const rates = useObjectSelector(state => state.ledger.rates[rates_channel]); const displayCurrency = useSelector(state => state.settings.generalWalletSettings.displayCurrency || USD); diff --git a/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendForm/TraditionalCryptoSendForm.js b/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendForm/TraditionalCryptoSendForm.js index d932d655..8eb9c75a 100644 --- a/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendForm/TraditionalCryptoSendForm.js +++ b/src/components/SendModal/TraditionalCryptoSend/TraditionalCryptoSendForm/TraditionalCryptoSendForm.js @@ -16,13 +16,14 @@ import { useEffect } from "react"; import { CoinDirectory } from "../../../../utils/CoinData/CoinDirectory"; import { selectAddressBlocklist } from "../../../../selectors/settings"; import { addressIsBlocked } from "../../../../utils/addressBlocklist"; +import { useObjectSelector } from "../../../../hooks/useObjectSelector"; const TraditionalCryptoSendForm = ({ setLoading, setModalHeight, updateSendFormData, navigation }) => { const { height } = Dimensions.get("window"); const [amountFiat, setAmountFiat] = useState(false); - const sendModal = useSelector(state => state.sendModal); - const addressBlocklist = useSelector(selectAddressBlocklist); - const balances = useSelector(state => { + const sendModal = useObjectSelector(state => state.sendModal); + const addressBlocklist = useObjectSelector(selectAddressBlocklist); + const balances = useObjectSelector(state => { const chainTicker = state.sendModal.coinObj.id; const balance_channel = state.sendModal.subWallet.api_channels[API_GET_BALANCES]; return { @@ -32,10 +33,10 @@ const TraditionalCryptoSendForm = ({ setLoading, setModalHeight, updateSendFormD errors: state.errors[API_GET_BALANCES][balance_channel][chainTicker], }; }); - const rates = useSelector(state => state.ledger.rates[state.sendModal.subWallet.api_channels[API_GET_FIATPRICE]]); + const rates = useObjectSelector(state => state.ledger.rates[state.sendModal.subWallet.api_channels[API_GET_FIATPRICE]]); const displayCurrency = useSelector(state => state.settings.generalWalletSettings.displayCurrency || USD); const [price, setPrice] = useState(0); - const networkName = useSelector(state => { + const networkName = useObjectSelector(state => { try { const subwallet = state.sendModal.subWallet; diff --git a/src/components/SendModal/WithdrawSend/WithdrawSendForm/WithdrawSendForm.js b/src/components/SendModal/WithdrawSend/WithdrawSendForm/WithdrawSendForm.js index ee1382a0..8d6c8772 100644 --- a/src/components/SendModal/WithdrawSend/WithdrawSendForm/WithdrawSendForm.js +++ b/src/components/SendModal/WithdrawSend/WithdrawSendForm/WithdrawSendForm.js @@ -1,3 +1,5 @@ +// DEPRECATED + import BigNumber from "bignumber.js"; import { Component } from "react" import { Alert, Dimensions } from "react-native"; diff --git a/src/containers/AddCoin/AddCoin.js b/src/containers/AddCoin/AddCoin.js index 5c9d8673..e455aacf 100644 --- a/src/containers/AddCoin/AddCoin.js +++ b/src/containers/AddCoin/AddCoin.js @@ -14,6 +14,7 @@ import {RenderSquareCoinLogo} from '../../utils/CoinData/Graphics'; import CoinDetailsModal from '../../components/CoinDetailsModal/CoinDetailsModal'; import {WYRE_SERVICE} from '../../utils/constants/intervalConstants'; import {CoinDirectory} from '../../utils/CoinData/CoinDirectory'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; const AddCoin = props => { const [loading, setLoading] = useState(true); @@ -27,13 +28,14 @@ const AddCoin = props => { Object.keys(state.authentication.activeAccount.testnetOverrides).length > 0, ); - const activeAccount = useSelector( + + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); - const activeCoinsForUser = useSelector( + const activeCoinsForUser = useObjectSelector( state => state.coins.activeCoinsForUser, ); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); useEffect(() => { setCoinList(getCoinList()); diff --git a/src/containers/Coin/ConvertCoin/ConvertCoin.js b/src/containers/Coin/ConvertCoin/ConvertCoin.js index 3ce8389a..07704eed 100644 --- a/src/containers/Coin/ConvertCoin/ConvertCoin.js +++ b/src/containers/Coin/ConvertCoin/ConvertCoin.js @@ -1,3 +1,5 @@ +// DEPRECATED + /* This component is responsible for allowing a user to create conversion transactions/transfers (if the card they are using allows it) diff --git a/src/containers/Coin/DynamicHeader.js b/src/containers/Coin/DynamicHeader.js index 0ee081a8..cf757ccf 100644 --- a/src/containers/Coin/DynamicHeader.js +++ b/src/containers/Coin/DynamicHeader.js @@ -3,11 +3,10 @@ with it by swiping or pressing will allow you to change your active sub-wallet. */ -import React, {Component} from 'react'; -import {connect} from 'react-redux'; -import {View, Animated, TouchableOpacity} from 'react-native'; -import {DEVICE_WINDOW_WIDTH} from '../../utils/constants/constants'; -import {setCoinSubWallet} from '../../actions/actionCreators'; +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; +import { View, Animated, TouchableOpacity } from 'react-native'; +import { DEVICE_WINDOW_WIDTH } from '../../utils/constants/constants'; +import { setCoinSubWallet } from '../../actions/actionCreators'; import { API_GET_BALANCES, API_GET_FIATPRICE, @@ -15,16 +14,16 @@ import { ERC20, } from '../../utils/constants/intervalConstants'; import Colors from '../../globals/colors'; -import {Card, Paragraph, Text, IconButton, Button} from 'react-native-paper'; +import { Card, Paragraph, Text, IconButton, Button } from 'react-native-paper'; import BigNumber from 'bignumber.js'; import { extractErrorData, extractLedgerData, } from '../../utils/ledger/extractLedgerData'; -import {CONNECTION_ERROR} from '../../utils/api/errors/errorMessages'; -import {truncateDecimal} from '../../utils/math'; -import {USD} from '../../utils/constants/currencies'; -import {CoinDirectory} from '../../utils/CoinData/CoinDirectory'; +import { CONNECTION_ERROR } from '../../utils/api/errors/errorMessages'; +import { truncateDecimal } from '../../utils/math'; +import { USD } from '../../utils/constants/currencies'; +import { CoinDirectory } from '../../utils/CoinData/CoinDirectory'; import { VERUS_BRIDGE_DELEGATOR_GOERLI_CONTRACT, VERUS_BRIDGE_DELEGATOR_MAINNET_CONTRACT, @@ -33,171 +32,182 @@ import { createAlert, resolveAlert, } from '../../actions/actions/alert/dispatchers/alert'; -import {openUrl} from '../../utils/linking'; +import { openUrl } from '../../utils/linking'; import { formatCurrency } from 'react-native-format-currency'; import { GestureDetector, Gesture, Directions } from 'react-native-gesture-handler'; +import { useSelector, useDispatch } from 'react-redux'; +import Styles from '../../styles'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; + +const DynamicHeader = ({ switchTab }) => { + const dispatch = useDispatch(); + + const chainTicker = useSelector((state) => state.coins.activeCoin.id); + const showBalance = useSelector((state) => state.coins.showBalance); + const displayTicker = useSelector((state) => state.coins.activeCoin.display_ticker); + const displayCurrency = useSelector( + (state) => state.settings.generalWalletSettings.displayCurrency || USD, + ); + + const activeCoin = useObjectSelector((state) => state.coins.activeCoin); + const selectedSubWallet = useObjectSelector( + (state) => state.coinMenus.activeSubWallets[chainTicker], + ); + const allSubWallets = useObjectSelector( + (state) => state.coinMenus.allSubWallets[chainTicker], + ); + const balances = useObjectSelector((state) => + extractLedgerData(state, 'balances', API_GET_BALANCES, chainTicker), + ); + const info = useObjectSelector((state) => + extractLedgerData(state, 'info', API_GET_INFO, chainTicker), + ); + const balanceErrors = useObjectSelector((state) => + extractErrorData(state, API_GET_BALANCES, chainTicker), + ); + const rates = useObjectSelector((state) => state.ledger.rates); -class DynamicHeader extends Component { - constructor(props) { - super(props); - this.state = { - carouselItems: [], - loadingCarouselItems: true, - mappedCoinObj: null - }; - this.fadeAnimation = new Animated.Value(0); - this.carousel = null; - } - - componentDidMount() { - this.fadeIn(); - let mappedCoinObj; - - if (this.props.activeCoin.mapped_to != null) { - try { - mappedCoinObj = CoinDirectory.getBasicCoinObj( - this.props.activeCoin.mapped_to, - ); - } catch (e) { - console.warn(e); + const [carouselItems, setCarouselItems] = useState([]); + const [loadingCarouselItems, setLoadingCarouselItems] = useState(true); + const [mappedCoinObj, setMappedCoinObj] = useState(null); + const fadeAnimation = useRef(new Animated.Value(0)).current; + + const pendingBalance = useMemo(() => { + return Object.values(balances).reduce((a, b) => { + if (a == null) { + return b == null ? 0 : b; + } + if (b == null) { + return a == null ? 0 : a; } - } - this.setState( - { - loadingCarouselItems: true, - mappedCoinObj, - }, - () => { - this.setState( - { - carouselItems: this.prepareCarouselItems( - this.props.allSubWallets, - this.props.selectedSubWallet, - ), - }, - () => { - this.setState({ - loadingCarouselItems: false, - }); - }, - ); - }, - ); - } + const aPending = BigNumber.isBigNumber(a) ? a : BigNumber(a.pending); + const bPending = BigNumber.isBigNumber(b) ? b : BigNumber(b.pending); - openTokenAddressExplorer = (address, testnet) => { - const baseUrl = testnet - ? 'https://goerli.etherscan.io/token/' - : 'https://etherscan.io/token/'; + return aPending.plus(bPending); + }, BigNumber(0)); + }, [balances]); - return createAlert( - 'Go to explorer?', - `Would you like to go to ${baseUrl} to see more information about ${address}?`, - [ - { - text: 'No', - onPress: async () => { - resolveAlert(false); - }, - }, - { - text: 'Yes', - onPress: () => { - openUrl(baseUrl + '/' + address); - resolveAlert(false); - }, - }, - ], - ); - }; + const confirmedBalance = useMemo(() => { + return Object.values(balances).reduce((a, b) => { + if (a == null) { + return b == null ? 0 : b; + } + if (b == null) { + return a == null ? 0 : a; + } - openReceiveTab = () => { - this.props.switchTab(2); - } + const aConfirmed = BigNumber.isBigNumber(a) ? a : BigNumber(a.confirmed); + const bConfirmed = BigNumber.isBigNumber(b) ? b : BigNumber(b.confirmed); - fadeIn = () => { - Animated.timing(this.fadeAnimation, { + return aConfirmed.plus(bConfirmed); + }, BigNumber(0)); + }, [balances]); + + const fadeIn = useCallback(() => { + Animated.timing(fadeAnimation, { toValue: 1, duration: 1000, useNativeDriver: true, - }).start(() => { - if (this.carousel != null) { - this.carousel.triggerRenderingHack(0); - } - }); - }; + }).start(); + }, [fadeAnimation]); - prepareCarouselItems(allSubWallets, selectedSubWallet) { - let wallets = []; + const prepareCarouselItems = useCallback( + (allSubWallets, selectedSubWallet) => { + let wallets = []; - if (selectedSubWallet == null) { - wallets = allSubWallets; - } else { - let newSubWallets = [...allSubWallets]; + if (selectedSubWallet == null) { + wallets = allSubWallets; + } else { + let newSubWallets = [...allSubWallets]; + + while (newSubWallets[0].id !== selectedSubWallet.id) { + newSubWallets.push(newSubWallets.shift()); + } - while (newSubWallets[0].id !== selectedSubWallet.id) { - newSubWallets.push(newSubWallets.shift()); + wallets = newSubWallets; } - wallets = newSubWallets; - } + if (wallets.length === 1) { + return [{ ...wallets[0], index: 0 }]; + } else { + return wallets.map((x, index) => { + return { ...x, index }; + }); + } + }, + [], + ); - if (wallets.length === 1) { - return [{...wallets[0], index: 0}]; - } else { - return wallets.map((x, index) => { - return {...x, index}; - }); + useEffect(() => { + fadeIn(); + + let mappedCoin = null; + + if (activeCoin.mapped_to != null) { + try { + mappedCoin = CoinDirectory.getBasicCoinObj(activeCoin.mapped_to); + } catch (e) { + console.warn(e); + } } - } - setSubWallet = wallet => { - this.props.dispatch(setCoinSubWallet(this.props.chainTicker, wallet)); + setMappedCoinObj(mappedCoin); + }, [activeCoin, fadeIn]); - this.setState({ - carouselItems: this.prepareCarouselItems( - this.props.allSubWallets, - wallet, - ), - }); - }; + useEffect(() => { + setLoadingCarouselItems(true); + const items = prepareCarouselItems(allSubWallets, selectedSubWallet); + setCarouselItems(items); + setLoadingCarouselItems(false); + }, [allSubWallets, selectedSubWallet, prepareCarouselItems]); + + const setSubWallet = (wallet) => { + dispatch(setCoinSubWallet(chainTicker, wallet)); - calculateSyncProgress = subWallet => { - const syncInfo = this.props.info; + const items = prepareCarouselItems(allSubWallets, wallet); + setCarouselItems(items); + }; - if (syncInfo == null || syncInfo[subWallet.id] == null) { + const calculateSyncProgress = (subWallet) => { + if (info == null || info[subWallet.id] == null) { return 100; } else { - return syncInfo[subWallet.id].percent; + return info[subWallet.id].percent; } }; - _handleItemPress = (index) => { - if (this.props.selectedSubWallet != null && index !== 0) { - this.setSubWallet(this.state.carouselItems[index]); + const handleItemPress = (index) => { + if (selectedSubWallet != null && index !== 0) { + setSubWallet(carouselItems[index]); } }; - handleLeftSwipe = () => { - if (this.props.selectedSubWallet != null && this.state.carouselItems.length > 1) { - const currentIndex = this.state.carouselItems.findIndex(x => x.id === this.props.selectedSubWallet.id); - const index = currentIndex === this.state.carouselItems.length - 1 ? 0 : currentIndex + 1; + const handleLeftSwipe = () => { + if (selectedSubWallet != null && carouselItems.length > 1) { + const currentIndex = carouselItems.findIndex( + (x) => x.id === selectedSubWallet.id, + ); + const index = + currentIndex === carouselItems.length - 1 ? 0 : currentIndex + 1; - this.setSubWallet(this.state.carouselItems[index]); + setSubWallet(carouselItems[index]); } - } + }; - handleRightSwipe = () => { - if (this.props.selectedSubWallet != null && this.state.carouselItems.length > 1) { - const currentIndex = this.state.carouselItems.findIndex(x => x.id === this.props.selectedSubWallet.id); - const index = currentIndex === 0 ? this.state.carouselItems.length - 1 : currentIndex - 1; + const handleRightSwipe = () => { + if (selectedSubWallet != null && carouselItems.length > 1) { + const currentIndex = carouselItems.findIndex( + (x) => x.id === selectedSubWallet.id, + ); + const index = + currentIndex === 0 ? carouselItems.length - 1 : currentIndex - 1; - this.setSubWallet(this.state.carouselItems[index]); + setSubWallet(carouselItems[index]); } - } + }; - getNetworkName(item) { + const getNetworkName = (item) => { try { return item.network ? CoinDirectory.getBasicCoinObj(item.network).display_ticker @@ -205,59 +215,85 @@ class DynamicHeader extends Component { } catch (e) { return null; } - } + }; + + const openReceiveTab = () => { + switchTab(2); + }; + + const openTokenAddressExplorer = (address, testnet) => { + const baseUrl = testnet + ? 'https://goerli.etherscan.io/token/' + : 'https://etherscan.io/token/'; + + return createAlert( + 'Go to explorer?', + `Would you like to go to ${baseUrl} to see more information about ${address}?`, + [ + { + text: 'No', + onPress: async () => { + resolveAlert(false); + }, + }, + { + text: 'Yes', + onPress: () => { + openUrl(baseUrl + '/' + address); + resolveAlert(false); + }, + }, + ], + ); + }; - _renderCarouselItem({item, index, alone}) { + const renderCarouselItem = ({ item, index, alone }) => { const displayBalance = - this.props.balances[item.id] != null - ? this.props.balances[item.id].confirmed - : null; + balances[item.id] != null ? balances[item.id].confirmed : null; const pendingBalance = - this.props.balances[item.id] != null - ? this.props.balances[item.id].pending - : null; + balances[item.id] != null ? balances[item.id].pending : null; let fiatBalance = null; - const rates = - this.props.rates[item.api_channels[API_GET_FIATPRICE]] != null - ? this.props.rates[item.api_channels[API_GET_FIATPRICE]][ - this.props.chainTicker - ] + const ratesForChannel = + rates[item.api_channels[API_GET_FIATPRICE]] != null + ? rates[item.api_channels[API_GET_FIATPRICE]][chainTicker] : null; if ( displayBalance != null && - rates != null && - rates[this.props.displayCurrency] != null + ratesForChannel != null && + ratesForChannel[displayCurrency] != null ) { - const price = BigNumber(rates[this.props.displayCurrency]); + const price = BigNumber(ratesForChannel[displayCurrency]); fiatBalance = BigNumber(displayBalance).multipliedBy(price).toFixed(2); } - const syncProgress = this.calculateSyncProgress(item); + const syncProgress = calculateSyncProgress(item); return ( + flexDirection: 'column', + alignItems: 'flex-start', + }} + > {index == 0 && !alone && ( ) - } + + )} this._handleItemPress(index)} + onPress={() => handleItemPress(index)} > - - + + + flex: 1, + }} + > + style={{ + fontSize: 16, + fontWeight: 'bold', + color: Colors.quaternaryColor, + }} + > {item.name} @@ -297,38 +345,58 @@ class DynamicHeader extends Component { icon="arrow-down" iconColor={Colors.secondaryColor} style={{ - marginRight: 0 + marginRight: 0, }} /> - {!this.props.showBalance ? ( + {!showBalance ? ( + style={{ + fontSize: 18, + marginBottom: 24, + color: Colors.secondaryColor, + }} + numberOfLines={2} + > ********* ) : ( - - - {this.props.balanceErrors[item.id] + + + {balanceErrors[item.id] ? CONNECTION_ERROR - : `${displayBalance == null - ? '-' - : truncateDecimal(displayBalance, 8) - }${pendingBalance != null && - !BigNumber(pendingBalance).isEqualTo(0) - ? ` (${BigNumber(pendingBalance).isGreaterThan(0) - ? '+' - : '' - }${truncateDecimal(pendingBalance, 4)})` - : '' - }`} + : `${ + displayBalance == null + ? '-' + : truncateDecimal(displayBalance, 8) + }${ + pendingBalance != null && + !BigNumber(pendingBalance).isEqualTo(0) + ? ` (${ + BigNumber(pendingBalance).isGreaterThan(0) + ? '+' + : '' + }${truncateDecimal(pendingBalance, 4)})` + : '' + }`} - - {this.props.balanceErrors[item.id] - ? "" - : ` ${this.props.displayTicker}`} + + {balanceErrors[item.id] ? '' : ` ${displayTicker}`} + marginTop: 0, + }} + > {syncProgress != 100 && syncProgress != -1 ? `Syncing - ${syncProgress.toFixed(2)}%` - : `${fiatBalance == null ? '-' : formatCurrency({ - amount: fiatBalance, - code: this.props.displayCurrency, - })[0]}`} + : `${ + fiatBalance == null + ? '-' + : formatCurrency({ + amount: fiatBalance, + code: displayCurrency, + })[0] + }`} )} {item.network && ( - + }} + > + {`${this.getNetworkName(item)}`} + fontWeight: 'bold', + }} + >{`${getNetworkName(item)}`} {` Network`} + alignSelf: 'center', + }} + >{` Network`} )} @@ -384,229 +462,179 @@ class DynamicHeader extends Component { ); - } - - render() { - const mappedToEth = - this.props.activeCoin.mapped_to != null && - this.state.mappedCoinObj != null && - (this.state.mappedCoinObj.currency_id.toLowerCase() === - VERUS_BRIDGE_DELEGATOR_GOERLI_CONTRACT.toLowerCase() || - this.state.mappedCoinObj.currency_id.toLowerCase() === - VERUS_BRIDGE_DELEGATOR_MAINNET_CONTRACT.toLowerCase()); + }; - return ( - - + const mappedToEth = + activeCoin.mapped_to != null && + mappedCoinObj != null && + (mappedCoinObj.currency_id.toLowerCase() === + VERUS_BRIDGE_DELEGATOR_GOERLI_CONTRACT.toLowerCase() || + mappedCoinObj.currency_id.toLowerCase() === + VERUS_BRIDGE_DELEGATOR_MAINNET_CONTRACT.toLowerCase()); + + return ( + + + - - {this.props.showBalance ? ( - - {"Total: "} - {`${truncateDecimal(this.props.confirmedBalance, 8)} ${this.props.displayTicker - }`} - - ) : ( + justifyContent: 'center', + padding: 16, + }} + > + {showBalance ? ( + + {'Total: '} + {`${truncateDecimal( + confirmedBalance, + 8, + )} ${displayTicker}`} + + ) : ( + ****** + )} + {!pendingBalance.isEqualTo(0) && ( + + + {pendingBalance.isGreaterThan(0) ? '+' : ''} + - ****** + style={{ fontWeight: '500', color: Colors.quaternaryColor }} + > + {truncateDecimal(pendingBalance, 8)} + + {' change pending'} + + + )} + {pendingBalance.isEqualTo(0) && + activeCoin.mapped_to != null && + mappedCoinObj != null && ( + + openTokenAddressExplorer( + mappedCoinObj.currency_id, + mappedCoinObj.testnet, + ) + } + > + + + {`mapped to ${ + mappedToEth + ? 'Ethereum' + : mappedCoinObj.display_ticker.length > 15 + ? mappedCoinObj.display_ticker.substring(0, 15) + '...' + : mappedCoinObj.display_ticker + }${ + !mappedToEth && mappedCoinObj.proto === ERC20 + ? ` (ERC20 ${mappedCoinObj.currency_id.substring( + 0, + 5, + ) + + '...' + + mappedCoinObj.currency_id.substring( + mappedCoinObj.currency_id.length - 3, + )})` + : '' + }`} + + + )} - {!this.props.pendingBalance.isEqualTo(0) && ( + {pendingBalance.isEqualTo(0) && activeCoin.proto === ERC20 && ( + + openTokenAddressExplorer( + activeCoin.currency_id, + activeCoin.testnet, + ) + } + > - - {this.props.pendingBalance.isGreaterThan(0) ? '+' : ''} - - - {truncateDecimal(this.props.pendingBalance, 8)} - + }} + > - {' change pending'} + {`${ + activeCoin.unlisted ? 'unlisted ' : '' + }ERC20 token (${activeCoin.currency_id.substring( + 0, + 5, + ) + + '...' + + activeCoin.currency_id.substring( + activeCoin.currency_id.length - 4, + )})`} - )} - {this.props.pendingBalance.isEqualTo(0) && - this.props.activeCoin.mapped_to != null && - this.state.mappedCoinObj != null && ( - - this.openTokenAddressExplorer( - this.state.mappedCoinObj.currency_id, - this.state.mappedCoinObj.testnet, - ) - }> - - - {`mapped to ${mappedToEth - ? 'Ethereum' - : this.state.mappedCoinObj.display_ticker.length > 15 - ? this.state.mappedCoinObj.display_ticker.substring( - 0, - 15, - ) + '...' - : this.state.mappedCoinObj.display_ticker - }${!mappedToEth && this.state.mappedCoinObj.proto === ERC20 - ? ` (ERC20 ${this.state.mappedCoinObj.currency_id.substring( - 0, - 5, - ) + - '...' + - this.state.mappedCoinObj.currency_id.substring( - this.state.mappedCoinObj.currency_id.length - 3, - ) - })` - : '' - }`} - - - - )} - {this.props.pendingBalance.isEqualTo(0) && - this.props.activeCoin.proto === ERC20 && ( - - this.openTokenAddressExplorer( - this.props.activeCoin.currency_id, - this.props.activeCoin.testnet, - ) - }> - - - {`${this.props.activeCoin.unlisted ? 'unlisted ' : '' - }ERC20 token (${this.props.activeCoin.currency_id.substring(0, 5) + - '...' + - this.props.activeCoin.currency_id.substring( - this.props.activeCoin.currency_id.length - 4, - ) - })`} - - - - )} - - - {this.state.loadingCarouselItems ? null : this.state.carouselItems.slice(0, 2).map((x, index) => { - return this._renderCarouselItem({ - item: this.state.carouselItems[index], - index, - alone: this.state.carouselItems.length === 1, - }) - })} - + + )} + + + {loadingCarouselItems + ? null + : carouselItems.slice(0, 2).map((x, index) => { + return renderCarouselItem({ + item: carouselItems[index], + index, + alone: carouselItems.length === 1, + }); + })} - + - ); - } -} - -const mapStateToProps = state => { - const chainTicker = state.coins.activeCoin.id; - const showBalance = state.coins.showBalance; - const balances = extractLedgerData( - state, - 'balances', - API_GET_BALANCES, - chainTicker, + ); - - return { - chainTicker, - showBalance, - displayTicker: state.coins.activeCoin.display_ticker, - activeCoin: state.coins.activeCoin, - selectedSubWallet: state.coinMenus.activeSubWallets[chainTicker], - allSubWallets: state.coinMenus.allSubWallets[chainTicker], - balances: extractLedgerData( - state, - 'balances', - API_GET_BALANCES, - chainTicker, - ), - info: extractLedgerData(state, 'info', API_GET_INFO, chainTicker), - balanceErrors: extractErrorData(state, API_GET_BALANCES, chainTicker), - pendingBalance: Object.values(balances).reduce((a, b) => { - if (a == null) { - return b == null ? 0 : b; - } - if (b == null) { - return a == null ? 0 : a; - } - - const aPending = BigNumber.isBigNumber(a) ? a : BigNumber(a.pending); - const bPending = BigNumber.isBigNumber(b) ? b : BigNumber(b.pending); - - return aPending.plus(bPending); - }, BigNumber(0)), - confirmedBalance: Object.values(balances).reduce((a, b) => { - if (a == null) { - return b == null ? 0 : b; - } - if (b == null) { - return a == null ? 0 : a; - } - - const aConfirmed = BigNumber.isBigNumber(a) ? a : BigNumber(a.confirmed); - const bConfirmed = BigNumber.isBigNumber(b) ? b : BigNumber(b.confirmed); - - return aConfirmed.plus(bConfirmed); - }, BigNumber(0)), - displayCurrency: - state.settings.generalWalletSettings.displayCurrency || USD, - rates: state.ledger.rates, - }; }; -export default connect(mapStateToProps)(DynamicHeader); +export default DynamicHeader; \ No newline at end of file diff --git a/src/containers/Coin/ManageCoin/DepositCoin/DepositCoin.js b/src/containers/Coin/ManageCoin/DepositCoin/DepositCoin.js index bee716c4..41e5eb32 100644 --- a/src/containers/Coin/ManageCoin/DepositCoin/DepositCoin.js +++ b/src/containers/Coin/ManageCoin/DepositCoin/DepositCoin.js @@ -1,3 +1,5 @@ +// DEPRECATED + import React, { Component } from "react" import { Alert } from "react-native"; import { connect } from 'react-redux' diff --git a/src/containers/Coin/ManageCoin/ManageCoin.js b/src/containers/Coin/ManageCoin/ManageCoin.js index 64ae6350..9c6545b0 100644 --- a/src/containers/Coin/ManageCoin/ManageCoin.js +++ b/src/containers/Coin/ManageCoin/ManageCoin.js @@ -17,11 +17,13 @@ import { import store from "../../../store"; import { useSelector } from "react-redux"; import { expireCoinData } from "../../../actions/actionCreators"; +import { useObjectSelector } from "../../../hooks/useObjectSelector"; export default function ManageCoin(props) { const layout = useWindowDimensions(); const chainTicker = useSelector(state => state.coins.activeCoin.id) - const updateIntervals = useSelector( + + const updateIntervals = useObjectSelector( state => state.updates.coinUpdateTracker[chainTicker], ); diff --git a/src/containers/Coin/ManageCoin/WithdrawCoin/WithdrawCoin.js b/src/containers/Coin/ManageCoin/WithdrawCoin/WithdrawCoin.js index 580b633c..19a75d34 100644 --- a/src/containers/Coin/ManageCoin/WithdrawCoin/WithdrawCoin.js +++ b/src/containers/Coin/ManageCoin/WithdrawCoin/WithdrawCoin.js @@ -1,3 +1,5 @@ +// DEPRECATED + import React, { Component } from "react" import { connect } from 'react-redux' import { API_GET_WITHDRAW_DESTINATIONS } from "../../../../utils/constants/intervalConstants"; diff --git a/src/containers/Coin/SendCoin/SendCoin.js b/src/containers/Coin/SendCoin/SendCoin.js index 667b88bd..ab7e923a 100644 --- a/src/containers/Coin/SendCoin/SendCoin.js +++ b/src/containers/Coin/SendCoin/SendCoin.js @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { View } from "react-native"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; import Styles from "../../../styles/index"; import { Button, Portal } from "react-native-paper"; import VerusPay from "../../VerusPay/VerusPay"; @@ -32,14 +32,15 @@ import { createAlert, resolveAlert } from "../../../actions/actions/alert/dispat import { CONVERSION_DISABLED } from '../../../../env/index'; +import { useObjectSelector } from "../../../hooks/useObjectSelector"; const SendCoin = ({ navigation }) => { - const activeCoin = useSelector(state => state.coins.activeCoin); - const subWallet = useSelector(state => { + const activeCoin = useObjectSelector(state => state.coins.activeCoin); + const subWallet = useObjectSelector(state => { const chainTicker = state.coins.activeCoin.id; return state.coinMenus.activeSubWallets[chainTicker]; }); - const generalWalletSettings = useSelector( + const generalWalletSettings = useObjectSelector( state => state.settings.generalWalletSettings, ); const dispatch = useDispatch() diff --git a/src/containers/CoinDetails/CoinDetails.js b/src/containers/CoinDetails/CoinDetails.js index 616dba41..63140f8e 100644 --- a/src/containers/CoinDetails/CoinDetails.js +++ b/src/containers/CoinDetails/CoinDetails.js @@ -1,3 +1,5 @@ +// DEPRECATED + /* This screen is passed a coinID, which it finds more data for in the activeCoinsForUser section of the store upon being mounted. It's purpose diff --git a/src/containers/Convert/Convert.js b/src/containers/Convert/Convert.js new file mode 100644 index 00000000..3f79f9d6 --- /dev/null +++ b/src/containers/Convert/Convert.js @@ -0,0 +1,46 @@ +import React, { useEffect, useState } from "react"; +import { ScrollView, View } from "react-native"; +import Styles from "../../styles"; +import { Button } from "react-native-paper"; +import Colors from "../../globals/colors"; +import ConvertCard from "./ConvertCard/ConvertCard"; + +const Convert = (props) => { + useEffect(() => { + + }, []) + + return ( + + + + + + + + + ); +} + +export default Convert; \ No newline at end of file diff --git a/src/containers/Convert/ConvertCard/ConvertCard.js b/src/containers/Convert/ConvertCard/ConvertCard.js new file mode 100644 index 00000000..338969ed --- /dev/null +++ b/src/containers/Convert/ConvertCard/ConvertCard.js @@ -0,0 +1,165 @@ +import React, { useEffect, useState } from "react"; +import { ScrollView, View } from "react-native"; +import Styles from "../../../styles"; +import { Button, Card, Text, TextInput } from "react-native-paper"; +import Colors from "../../../globals/colors"; +import { RenderCircleCoinLogo, RenderPlainCoinLogo } from "../../../utils/CoinData/Graphics"; + +const ConvertCard = ({ + coinObj, + networkObj, + address, + amount, + setAmount, + balance, + onMaxPressed, + onSelectPressed, + selectDisabled +}) => { + const [cardActive, setCardActive] = useState(false); + + useEffect(() => { + if (coinObj != null && networkObj != null && address != null) { + setCardActive(true); + } else setCardActive(false); + }, [coinObj, networkObj, address]) + + return ( + + + + setAmount(x)} + mode="outlined" + keyboardType="numeric" + /> + {!cardActive ? + + : + + {RenderCircleCoinLogo(coinObj.id)} + + + {coinObj.display_ticker} + + + {coinObj.display_name} + + + + } + + + + {!cardActive ? '' : `${balance == null ? balance : '-'} ${coinObj.display_ticker}`} + + + + + + {"From: "} + {cardActive && {`${networkObj.display_ticker} `}} + {cardActive && RenderPlainCoinLogo(networkObj.id, {}, 20, 20)} + + {cardActive && {address}} + + + + ); +} + +export default ConvertCard; \ No newline at end of file diff --git a/src/containers/CreateWallet/Forms/CreateSeed/Forms/SeedWords.js b/src/containers/CreateWallet/Forms/CreateSeed/Forms/SeedWords.js index b350d1da..9e3f04f1 100644 --- a/src/containers/CreateWallet/Forms/CreateSeed/Forms/SeedWords.js +++ b/src/containers/CreateWallet/Forms/CreateSeed/Forms/SeedWords.js @@ -8,7 +8,6 @@ import { Alert, } from 'react-native'; import {Text, Button, TextInput} from 'react-native-paper'; -import {useSelector} from 'react-redux'; import TallButton from '../../../../../components/LargerButton'; import Colors from '../../../../../globals/colors'; import {DEFAULT_SEED_PHRASE_LENGTH} from '../../../../../utils/constants/constants'; diff --git a/src/containers/CreateWallet/Forms/ImportWallet/Forms/ImportText.js b/src/containers/CreateWallet/Forms/ImportWallet/Forms/ImportText.js index 7a0102c9..822f801d 100644 --- a/src/containers/CreateWallet/Forms/ImportWallet/Forms/ImportText.js +++ b/src/containers/CreateWallet/Forms/ImportWallet/Forms/ImportText.js @@ -8,7 +8,6 @@ import { Keyboard, } from 'react-native'; import {Text, Button, Paragraph, TextInput} from 'react-native-paper'; -import { useSelector } from 'react-redux'; import { createAlert } from '../../../../../actions/actions/alert/dispatchers/alert'; import TallButton from '../../../../../components/LargerButton'; import ScanSeed from '../../../../../components/ScanSeed'; diff --git a/src/containers/DeepLink/DeepLink.js b/src/containers/DeepLink/DeepLink.js index d6f310c1..aeea660b 100644 --- a/src/containers/DeepLink/DeepLink.js +++ b/src/containers/DeepLink/DeepLink.js @@ -26,10 +26,11 @@ import { CoinDirectory } from '../../utils/CoinData/CoinDirectory'; import BigNumber from 'bignumber.js'; import { blocksToTime, satsToCoins } from '../../utils/math'; import InvoiceInfo from './InvoiceInfo/InvoiceInfo'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; const DeepLink = (props) => { const deeplinkId = useSelector((state) => state.deeplink.id) - const deeplinkData = useSelector((state) => state.deeplink.data) + const deeplinkData = useObjectSelector((state) => state.deeplink.data) const signedIn = useSelector((state) => state.authentication.signedIn) const [displayKey, setDisplayKey] = useState(null) diff --git a/src/containers/DeepLink/InvoiceInfo/InvoiceInfo.js b/src/containers/DeepLink/InvoiceInfo/InvoiceInfo.js index 096455cc..e7768624 100644 --- a/src/containers/DeepLink/InvoiceInfo/InvoiceInfo.js +++ b/src/containers/DeepLink/InvoiceInfo/InvoiceInfo.js @@ -18,6 +18,7 @@ import { CoinDirectory } from '../../../utils/CoinData/CoinDirectory'; import ListSelectionModal from '../../../components/ListSelectionModal/ListSelectionModal'; import { copyToClipboard } from '../../../utils/clipboard/clipboard'; import BigNumber from 'bignumber.js'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const InvoiceInfo = props => { const { @@ -106,7 +107,8 @@ const InvoiceInfo = props => { const [sigDateString, setSigDateString] = useState(unixToDate(sigtime)); const [waitingForSignin, setWaitingForSignin] = useState(false); - const accounts = useSelector(state => state.authentication.accounts); + const accounts = useObjectSelector(state => state.authentication.accounts); + const signedIn = useSelector(state => state.authentication.signedIn); const sendModalType = useSelector(state => state.sendModal.type); const isWrongInvoiceType = useSelector(state => { diff --git a/src/containers/DeepLink/InvoicePaymentConfiguration/InvoicePaymentConfiguration.js b/src/containers/DeepLink/InvoicePaymentConfiguration/InvoicePaymentConfiguration.js index 37b16ce6..5d226d02 100644 --- a/src/containers/DeepLink/InvoicePaymentConfiguration/InvoicePaymentConfiguration.js +++ b/src/containers/DeepLink/InvoicePaymentConfiguration/InvoicePaymentConfiguration.js @@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react'; import { View, SafeAreaView, Alert } from 'react-native'; import Styles from '../../../styles/index'; import { primitives } from "verusid-ts-client"; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { openConvertOrCrossChainSendModal } from '../../../actions/actions/sendModal/dispatchers/sendModal'; import AnimatedActivityIndicatorBox from '../../../components/AnimatedActivityIndicatorBox'; import BigNumber from 'bignumber.js'; @@ -31,6 +31,7 @@ import FundSourceSelectList from '../../FundSourceSelect/FundSourceSelectList'; import { usePrevious } from '../../../hooks/usePrevious'; import { conditionallyUpdateWallet } from '../../../actions/actionDispatchers'; import store from '../../../store'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const InvoicePaymentConfiguration = props => { const { @@ -51,12 +52,12 @@ const InvoicePaymentConfiguration = props => { const [loading, setLoading] = useState(false); const inv = primitives.VerusPayInvoice.fromJson(deeplinkData); - const activeCoinsForUser = useSelector(state => state.coins.activeCoinsForUser); + const activeCoinsForUser = useObjectSelector(state => state.coins.activeCoinsForUser); - const sendModal = useSelector(state => state.sendModal); + const sendModal = useObjectSelector(state => state.sendModal); const prevSendModal = usePrevious(sendModal); - const allSubWallets = useSelector(state => state.coinMenus.allSubWallets) + const allSubWallets = useObjectSelector(state => state.coinMenus.allSubWallets) const dispatch = useDispatch() diff --git a/src/containers/DeepLink/LoginRequestIdentity/LoginRequestIdentity.js b/src/containers/DeepLink/LoginRequestIdentity/LoginRequestIdentity.js index 1ba32c0a..a4531e8c 100644 --- a/src/containers/DeepLink/LoginRequestIdentity/LoginRequestIdentity.js +++ b/src/containers/DeepLink/LoginRequestIdentity/LoginRequestIdentity.js @@ -19,6 +19,7 @@ import { ELECTRUM } from '../../../utils/constants/intervalConstants'; import { coinsList } from '../../../utils/CoinData/CoinsList'; import { requestSeeds } from '../../../utils/auth/authBox'; import { deriveKeyPair } from '../../../utils/keys'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const LoginRequestIdentity = props => { const { deeplinkData } = props.route.params @@ -28,8 +29,9 @@ const LoginRequestIdentity = props => { const [idProvisionSuccess, setIdProvisionSuccess] = useState(false) const [canProvision, setCanProvision] = useState(false) const req = new primitives.LoginConsentRequest(deeplinkData) - const encryptedIds = useSelector(state => state.services.stored[VERUSID_SERVICE_ID]) - const sendModal = useSelector((state) => state.sendModal); + const encryptedIds = useObjectSelector(state => state.services.stored[VERUSID_SERVICE_ID]) + const sendModal = useObjectSelector((state) => state.sendModal); + const fromService = useSelector((state) => state.deeplink.fromService); const passthrough = useSelector((state) => state.deeplink.passthrough); @@ -54,8 +56,8 @@ const LoginRequestIdentity = props => { setCanProvision(canProvision) }, [linkedIds]) - const activeCoinsForUser = useSelector(state => state.coins.activeCoinsForUser) - const testnetOverrides = useSelector(state => state.authentication.activeAccount.testnetOverrides) + const activeCoinsForUser = useObjectSelector(state => state.coins.activeCoinsForUser) + const testnetOverrides = useObjectSelector(state => state.authentication.activeAccount.testnetOverrides) const identityNetwork = testnetOverrides[VERUSID_NETWORK_DEFAULT] ? testnetOverrides[VERUSID_NETWORK_DEFAULT] : VERUSID_NETWORK_DEFAULT; diff --git a/src/containers/DeepLink/LoginRequestInfo/LoginRequestInfo.js b/src/containers/DeepLink/LoginRequestInfo/LoginRequestInfo.js index 252320a7..4e1a7f09 100644 --- a/src/containers/DeepLink/LoginRequestInfo/LoginRequestInfo.js +++ b/src/containers/DeepLink/LoginRequestInfo/LoginRequestInfo.js @@ -18,6 +18,7 @@ import { CoinDirectory } from '../../../utils/CoinData/CoinDirectory'; import { addCoin, addKeypairs, setUserCoins } from '../../../actions/actionCreators'; import { refreshActiveChainLifecycles } from '../../../actions/actions/intervals/dispatchers/lifecycleManager'; import { SMALL_DEVICE_HEGHT } from '../../../utils/constants/constants'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const LoginRequestInfo = props => { const { deeplinkData, sigtime, cancel, signerFqn } = props @@ -26,7 +27,7 @@ const LoginRequestInfo = props => { const [verusIdDetailsModalProps, setVerusIdDetailsModalProps] = useState(null) const [sigDateString, setSigDateString] = useState(unixToDate(sigtime)) const [waitingForSignin, setWaitingForSignin] = useState(false) - const accounts = useSelector(state => state.authentication.accounts) + const accounts = useObjectSelector(state => state.authentication.accounts) const signedIn = useSelector(state => state.authentication.signedIn) const passthrough = useSelector((state) => state.deeplink.passthrough); const sendModalType = useSelector(state => state.sendModal.type) @@ -44,12 +45,12 @@ const LoginRequestInfo = props => { ); const [prevRootSystemAdded, setPrevRootSystemAdded] = useState(rootSystemAdded) - const activeAccount = useSelector( + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); const isTestnet = activeAccount ? Object.keys(activeAccount.testnetOverrides).length > 0 : false; - const activeCoinList = useSelector(state => state.coins.activeCoinList); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); let mainLoginMessage = ''; diff --git a/src/containers/FundSourceSelect/FundSourceSelectList.js b/src/containers/FundSourceSelect/FundSourceSelectList.js index 71633e49..3afdbf64 100644 --- a/src/containers/FundSourceSelect/FundSourceSelectList.js +++ b/src/containers/FundSourceSelect/FundSourceSelectList.js @@ -1,5 +1,4 @@ import React, { useEffect, useState } from "react"; -import { useSelector } from 'react-redux'; import { ScrollView, View @@ -15,11 +14,12 @@ import { VerusPayInvoice } from "verus-typescript-primitives"; import { coinsList } from "../../utils/CoinData/CoinsList"; import MissingInfoRedirect from "../../components/MissingInfoRedirect/MissingInfoRedirect"; import AnimatedActivityIndicatorBox from "../../components/AnimatedActivityIndicatorBox"; +import { useObjectSelector } from "../../hooks/useObjectSelector"; const FundSourceSelectList = (props) => { const { coinObjs, allSubWallets, sourceOptions: rawSourceOptions, invoice } = props; - const allBalances = useSelector(state => state.ledger.balances); + const allBalances = useObjectSelector(state => state.ledger.balances); const [cryptoBalances, setCryptoBalances] = useState({}); const [sourceOptions, setSourceOptions] = useState({}); diff --git a/src/containers/Home/Home.js b/src/containers/Home/Home.js index 54cf1633..5f28b454 100644 --- a/src/containers/Home/Home.js +++ b/src/containers/Home/Home.js @@ -1,14 +1,14 @@ /* The purpose of this component is to be the first screen a user is - met with after login. This screen should have all necesarry or + met with after login. This screen should have all necessary or essential wallet components available at the press of one button. This includes VerusPay, adding coins, and coin menus. Keeping this - screen clean is also essential, as users will spend alot of time with + screen clean is also essential, as users will spend a lot of time with it in their faces. It updates the balances and the rates upon loading if they are flagged to be updated in the redux store. */ -import React, {Component} from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { setActiveCoin, setActiveApp, @@ -18,9 +18,7 @@ import { expireServiceData, saveGeneralSettings, } from '../../actions/actionCreators'; -import {connect} from 'react-redux'; -import {Animated} from 'react-native'; -import {CommonActions} from '@react-navigation/native'; +import { CommonActions, useNavigation, useFocusEffect } from '@react-navigation/native'; import { API_GET_FIATPRICE, API_GET_BALANCES, @@ -30,9 +28,9 @@ import { API_GET_SERVICE_ACCOUNT, API_GET_SERVICE_PAYMENT_METHODS, API_GET_SERVICE_RATES, - API_GET_SERVICE_NOTIFICATIONS + API_GET_SERVICE_NOTIFICATIONS, } from '../../utils/constants/intervalConstants'; -import {USD} from '../../utils/constants/currencies'; +import { USD } from '../../utils/constants/currencies'; import { conditionallyUpdateService, conditionallyUpdateWallet, @@ -41,171 +39,155 @@ import { import BigNumber from 'bignumber.js'; import { extractLedgerData, - extractErrorData, } from '../../utils/ledger/extractLedgerData'; -import {HomeRender} from './Home.render'; -import {extractDisplaySubWallets} from '../../utils/subwallet/extractSubWallets'; +import { HomeRender, HomeRenderCoinsList, HomeRenderWidget } from './Home.render'; +import { extractDisplaySubWallets } from '../../utils/subwallet/extractSubWallets'; import { CURRENCY_WIDGET_TYPE, TOTAL_UNI_BALANCE_WIDGET_TYPE, VERUSID_WIDGET_TYPE, } from '../../utils/constants/widgets'; -import {createAlert} from '../../actions/actions/alert/dispatchers/alert'; -import {VERUSID_SERVICE_ID} from '../../utils/constants/services'; -import {dragDetectionEnabled} from '../../utils/dragDetection'; -import {CoinDirectory} from '../../utils/CoinData/CoinDirectory'; +import { createAlert } from '../../actions/actions/alert/dispatchers/alert'; +import { VERUSID_SERVICE_ID } from '../../utils/constants/services'; +import { dragDetectionEnabled } from '../../utils/dragDetection'; +import { CoinDirectory } from '../../utils/CoinData/CoinDirectory'; import { openAddErc20TokenModal, openAddPbaasCurrencyModal, } from '../../actions/actions/sendModal/dispatchers/sendModal'; - -class Home extends Component { - constructor(props) { - super(props); - this.state = { - totalFiatBalance: 0, - totalCryptoBalances: {}, - loading: false, - listItemHeights: {}, - widgets: [], - displayCurrencyModalOpen: false, - editingCards: false, - //TODO: MOVE TO REDUX - expandedListItems: {}, - }; - - this._unsubscribeFocus = null; - this.LIST_ITEM_INITIAL_HEIGHT = 58; - this.LIST_ITEM_MARGIN = 8; - this.LIST_ITEM_ANIMATION_DURATION = 250; - } - - async componentDidMount() { - this._unsubscribeFocus = this.props.navigation.addListener('focus', () => { - this.refresh(false); - }); - - await this.getWidgets(); - } - - dragDetectionEnabled() { - const {homeCardDragDetection} = this.props; - +import { useSelector, useDispatch } from 'react-redux'; +import store from '../../store'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; + +const Home = () => { + const dispatch = useDispatch(); + const navigation = useNavigation(); + + const activeCoinsForUser = useObjectSelector((state) => state.coins.activeCoinsForUser); + + const activeAccount = useObjectSelector((state) => state.authentication.activeAccount); + const testnetOverrides = useObjectSelector( + (state) => state.authentication.activeAccount.testnetOverrides, + ); + const balances = useObjectSelector((state) => + extractLedgerData(state, 'balances', API_GET_BALANCES), + ); + const rates = useObjectSelector((state) => state.ledger.rates); + const allSubWallets = useObjectSelector((state) => extractDisplaySubWallets(state)); + const activeSubWallets = useObjectSelector((state) => state.coinMenus.activeSubWallets); + const widgetOrder = useObjectSelector((state) => state.widgets.order); + + const homeCardDragDetection = useSelector( + (state) => state.settings.generalWalletSettings.homeCardDragDetection, + ); + const displayCurrency = useSelector( + (state) => state.settings.generalWalletSettings.displayCurrency || USD, + ); + + const [totalFiatBalance, setTotalFiatBalance] = useState(0); + const [totalCryptoBalances, setTotalCryptoBalances] = useState({}); + const [loading, setLoading] = useState(false); + const [listItemHeights, setListItemHeights] = useState({}); + const [widgets, setWidgets] = useState([]); + const [displayCurrencyModalOpen, setDisplayCurrencyModalOpen] = useState(false); + const [editingCards, setEditingCards] = useState(false); + const [expandedListItems, setExpandedListItems] = useState({}); + + const LIST_ITEM_INITIAL_HEIGHT = 58; + const LIST_ITEM_MARGIN = 8; + const LIST_ITEM_ANIMATION_DURATION = 250; + + const isDragDetectionEnabled = () => { return dragDetectionEnabled(homeCardDragDetection); - } + }; - setEditingCards(editing) { - this.setState({ - editingCards: editing, - }); - } + const handleSetEditingCards = (editing) => { + setEditingCards(editing); + }; - sortWidgets() { - const widgets = this.state.widgets.sort((a, b) => { - return this.props.widgetOrder[a] <= this.props.widgetOrder[b] ? -1 : 1; + const sortWidgets = useCallback(() => { + setWidgets((prevWidgets) => { + const sortedWidgets = [...prevWidgets].sort((a, b) => { + return widgetOrder[a] <= widgetOrder[b] ? -1 : 1; + }); + return sortedWidgets; }); + }, [widgetOrder]); - this.setState({ - widgets, + const getWidgets = useCallback(async () => { + setWidgets([]); + let widgetsList = [...Object.keys(widgetOrder)].sort((a, b) => { + return widgetOrder[a] <= widgetOrder[b] ? -1 : 1; }); - } - - async getWidgets() { - this.setState( - { - widgets: [], - }, - () => { - const widgets = [...Object.keys(this.props.widgetOrder)].sort( - (a, b) => { - return this.props.widgetOrder[a] <= this.props.widgetOrder[b] - ? -1 - : 1; - }, - ); - const activeAccount = this.props.activeAccount; - const widgetsToRemove = []; + const widgetsToRemove = []; - // Remove currency widgets for coins that arent active - for (let i = 0; i < widgets.length; i++) { - const widgetId = widgets[i]; - const widgetSplit = widgetId.split(':'); - const widgetType = widgetSplit[0]; + // Remove currency widgets for coins that aren't active + for (let i = 0; i < widgetsList.length; i++) { + const widgetId = widgetsList[i]; + const widgetSplit = widgetId.split(':'); + const widgetType = widgetSplit[0]; - if ( - widgetType === CURRENCY_WIDGET_TYPE && - !this.props.activeCoinsForUser.some(x => x.id === widgetSplit[1]) - ) { - widgetsToRemove.unshift(i); - } - } + if ( + widgetType === CURRENCY_WIDGET_TYPE && + !activeCoinsForUser.some((x) => x.id === widgetSplit[1]) + ) { + widgetsToRemove.unshift(i); + } + } - for (const widgetIndex of widgetsToRemove) { - widgets.splice(widgetIndex, 1); - } + for (const widgetIndex of widgetsToRemove) { + widgetsList.splice(widgetIndex, 1); + } - // Add the balance widget if not present - if (!widgets.includes(TOTAL_UNI_BALANCE_WIDGET_TYPE)) { - widgets.push(TOTAL_UNI_BALANCE_WIDGET_TYPE); - dispatchAddWidget( - TOTAL_UNI_BALANCE_WIDGET_TYPE, - activeAccount.accountHash, - ); - } + // Add the balance widget if not present + if (!widgetsList.includes(TOTAL_UNI_BALANCE_WIDGET_TYPE)) { + widgetsList.push(TOTAL_UNI_BALANCE_WIDGET_TYPE); + dispatchAddWidget(TOTAL_UNI_BALANCE_WIDGET_TYPE, activeAccount.accountHash); + } - // Add currency widgets for active coins - for (const coinObj of this.props.activeCoinsForUser) { - const currencyWidgetId = `${CURRENCY_WIDGET_TYPE}:${coinObj.id}`; + // Add currency widgets for active coins + for (const coinObj of activeCoinsForUser) { + const currencyWidgetId = `${CURRENCY_WIDGET_TYPE}:${coinObj.id}`; - if (!widgets.includes(currencyWidgetId)) { - widgets.push(currencyWidgetId); - dispatchAddWidget(currencyWidgetId, activeAccount.accountHash); - } - } + if (!widgetsList.includes(currencyWidgetId)) { + widgetsList.push(currencyWidgetId); + dispatchAddWidget(currencyWidgetId, activeAccount.accountHash); + } + } - // Add the balance widget if not present - if (!widgets.includes(VERUSID_WIDGET_TYPE)) { - widgets.push(VERUSID_WIDGET_TYPE); - dispatchAddWidget(VERUSID_WIDGET_TYPE, activeAccount.accountHash); - } + // Add the VerusID widget if not present + if (!widgetsList.includes(VERUSID_WIDGET_TYPE)) { + widgetsList.push(VERUSID_WIDGET_TYPE); + dispatchAddWidget(VERUSID_WIDGET_TYPE, activeAccount.accountHash); + } - this.setState({ - widgets, - }); - }, - ); - } + setWidgets(widgetsList); + }, [activeAccount.accountHash, activeCoinsForUser, widgetOrder]); - handleWidgetPress(widgetId) { + const handleWidgetPress = (widgetId) => { const widgetSplit = widgetId.split(':'); const widgetType = widgetSplit[0]; const widgetOnPress = { [CURRENCY_WIDGET_TYPE]: () => { const coinId = widgetSplit[1]; - const coinObj = this.props.activeCoinsForUser.find( - x => x.id === coinId, - ); + const coinObj = activeCoinsForUser.find((x) => x.id === coinId); if (coinObj) { - const subWallets = this.props.allSubWallets[coinId]; + const subWallets = allSubWallets[coinId]; - this.openCoin( + openCoin( coinObj, - this.props.activeSubWallets[coinId] - ? this.props.activeSubWallets[coinId] - : subWallets[0], + activeSubWallets[coinId] ? activeSubWallets[coinId] : subWallets[0], ); } }, [TOTAL_UNI_BALANCE_WIDGET_TYPE]: () => { - this.setState({ - displayCurrencyModalOpen: true, - }); + setDisplayCurrencyModalOpen(true); }, [VERUSID_WIDGET_TYPE]: () => { - this.props.navigation.navigate('Service', { + navigation.navigate('Service', { service: VERUSID_SERVICE_ID, }); }, @@ -214,94 +196,45 @@ class Home extends Component { if (widgetOnPress[widgetType]) { widgetOnPress[widgetType](); } - } + }; - async setDisplayCurrency(displayCurrency) { + const setDisplayCurrencyFunc = async (currency) => { try { - this.props.dispatch(await saveGeneralSettings({displayCurrency})); + dispatch(await saveGeneralSettings({ displayCurrency: currency })); } catch (e) { createAlert('Error setting display currency', e.message); } - } - - animateHeightChange(anim, toValue, cb = () => {}) { - Animated.timing(anim, { - toValue, - duration: this.LIST_ITEM_ANIMATION_DURATION, - useNativeDriver: false, - }).start(cb); - } - - toggleListItem(id, numCards) { - const _toggleListItem = () => { - const newExpanded = !this.state.expandedListItems[id]; - const changeExpandState = (cb = () => {}) => { - this.setState( - { - expandedListItems: { - ...this.state.expandedListItems, - [id]: newExpanded, - }, - }, - cb, - ); - }; - - if (newExpanded) { - changeExpandState( - this.animateHeightChange( - this.state.listItemHeights[id], - this.LIST_ITEM_INITIAL_HEIGHT * (numCards + 1) + - numCards * this.LIST_ITEM_MARGIN, - ), - ); - } else { - this.animateHeightChange( - this.state.listItemHeights[id], - this.LIST_ITEM_INITIAL_HEIGHT, - () => changeExpandState(), - ); - } - }; + }; - if (this.state.listItemHeights[id] == null) { - this.setState( - { - listItemHeights: { - ...this.state.listItemHeights, - [id]: new Animated.Value(this.LIST_ITEM_INITIAL_HEIGHT), - }, - }, - () => _toggleListItem(), - ); - } else { - _toggleListItem(); - } - } + useFocusEffect( + useCallback(() => { + refresh(false); + return () => {}; + }, []), + ); - componentWillUnmount() { - this._unsubscribeFocus(); - } + useEffect(() => { + getWidgets(); + }, [getWidgets]); - componentDidUpdate(lastProps) { - if (this.props.balances !== lastProps.balances) { - const totalBalances = this.getTotalBalances(this.props); + useEffect(() => { + const totalBalances = getTotalBalances(); + setTotalFiatBalance(totalBalances.fiat); + setTotalCryptoBalances(totalBalances.crypto); + }, [balances]); - this.setState({ - totalFiatBalance: totalBalances.fiat, - totalCryptoBalances: totalBalances.crypto, - }); - } + useEffect(() => { + getWidgets(); + }, [activeCoinsForUser, getWidgets]); - if (this.props.activeCoinsForUser !== lastProps.activeCoinsForUser) { - this.getWidgets(); - } else if (this.props.widgetOrder !== lastProps.widgetOrder) { - this.sortWidgets(); - } - } + useEffect(() => { + sortWidgets(); + }, [widgetOrder, sortWidgets]); + + const refresh = useCallback( + async (showLoading = true) => { + setLoading(showLoading); - refresh = (showLoading = true) => { - this.setState({loading: showLoading}, async () => { const serviceUpdates = [ API_GET_SERVICE_ACCOUNT, API_GET_SERVICE_PAYMENT_METHODS, @@ -315,13 +248,13 @@ class Home extends Component { { keys: serviceUpdates, update: conditionallyUpdateService, - params: [[this.props.dispatch]], + params: [[dispatch]], }, { keys: coinUpdates, update: conditionallyUpdateWallet, - params: this.props.activeCoinsForUser.map(coinObj => { - return [this.props.dispatch, coinObj.id]; + params: activeCoinsForUser.map((coinObj) => { + return [dispatch, coinObj.id]; }), }, ]; @@ -339,97 +272,60 @@ class Home extends Component { } } - this.setState({loading: false}); - }); - }; + setLoading(false); + }, + [activeCoinsForUser, dispatch], + ); - resetToScreen = (route, title, data) => { + const resetToScreen = (route, title, data) => { const resetAction = CommonActions.reset({ - index: 1, // <-- currect active route from actions array + index: 1, routes: [ - {name: 'Home'}, - {name: route, params: {title: title, data: data}}, + { name: 'Home' }, + { name: route, params: { title: title, data: data } }, ], }); - this.props.navigation.closeDrawer(); - this.props.navigation.dispatch(resetAction); + navigation.closeDrawer(); + navigation.dispatch(resetAction); }; - forceUpdate = () => { - this.props.activeCoinsForUser.map(coinObj => { - this.props.dispatch(expireCoinData(coinObj.id, API_GET_FIATPRICE)); - this.props.dispatch(expireCoinData(coinObj.id, API_GET_BALANCES)); - this.props.dispatch(expireCoinData(coinObj.id, API_GET_INFO)); + const forceUpdate = () => { + activeCoinsForUser.forEach((coinObj) => { + dispatch(expireCoinData(coinObj.id, API_GET_FIATPRICE)); + dispatch(expireCoinData(coinObj.id, API_GET_BALANCES)); + dispatch(expireCoinData(coinObj.id, API_GET_INFO)); }); - this.props.dispatch(expireServiceData(API_GET_SERVICE_ACCOUNT)); - this.props.dispatch(expireServiceData(API_GET_SERVICE_PAYMENT_METHODS)); - this.props.dispatch(expireServiceData(API_GET_SERVICE_RATES)); - this.props.dispatch(expireServiceData(API_GET_SERVICE_NOTIFICATIONS)); - this.refresh(); - }; + dispatch(expireServiceData(API_GET_SERVICE_ACCOUNT)); + dispatch(expireServiceData(API_GET_SERVICE_PAYMENT_METHODS)); + dispatch(expireServiceData(API_GET_SERVICE_RATES)); + dispatch(expireServiceData(API_GET_SERVICE_NOTIFICATIONS)); - updateProps = promiseArray => { - return new Promise((resolve, reject) => { - Promise.all(promiseArray) - .then(updatesArray => { - if (updatesArray.length > 0) { - for (let i = 0; i < updatesArray.length; i++) { - if (updatesArray[i]) { - this.props.dispatch(updatesArray[i]); - } - } - if (this.state.loading) { - this.setState({loading: false}); - } - return true; - } else { - return false; - } - }) - .then(res => { - if (res) { - const totalBalances = this.getTotalBalances(this.props); - - this.setState({ - totalFiatBalance: totalBalances.fiat, - totalCryptoBalances: totalBalances.crypto, - }); - resolve(true); - } else { - resolve(false); - } - }); - }); + refresh(); }; - getTotalBalances = props => { + const getTotalBalances = () => { let _totalFiatBalance = BigNumber(0); let coinBalances = {}; - const balances = props.balances; - const {displayCurrency, activeCoinsForUser, allSubWallets} = props; - activeCoinsForUser.map(coinObj => { + activeCoinsForUser.forEach((coinObj) => { const key = coinObj.id; - coinBalances[coinObj.id] = BigNumber('0'); + coinBalances[coinObj.id] = BigNumber(0); - allSubWallets[coinObj.id].map(wallet => { - if ( - balances[coinObj.id] != null && - balances[coinObj.id][wallet.id] != null - ) { + allSubWallets[coinObj.id].forEach((wallet) => { + if (balances[coinObj.id] != null && balances[coinObj.id][wallet.id] != null) { coinBalances[coinObj.id] = coinBalances[coinObj.id].plus( balances[key] && balances[key][wallet.id] && balances[key][wallet.id].total != null ? BigNumber(balances[key][wallet.id].total) - : BigNumber('0'), + : BigNumber(0), ); } }); - const rate = this.getRate(key, displayCurrency); + const rate = getRate(key, displayCurrency); if (rate != null) { const price = BigNumber(rate); @@ -446,108 +342,87 @@ class Home extends Component { }; }; - getRate = (coinId, displayCurrency) => { - return this.props.rates[WYRE_SERVICE] && - this.props.rates[WYRE_SERVICE][coinId] && - this.props.rates[WYRE_SERVICE][coinId][displayCurrency] - ? this.props.rates[WYRE_SERVICE][coinId][displayCurrency] - : this.props.rates[GENERAL] && - this.props.rates[GENERAL][coinId] && - this.props.rates[GENERAL][coinId][displayCurrency] - ? this.props.rates[GENERAL][coinId][displayCurrency] + const getRate = (coinId, currency) => { + return rates[WYRE_SERVICE] && + rates[WYRE_SERVICE][coinId] && + rates[WYRE_SERVICE][coinId][currency] + ? rates[WYRE_SERVICE][coinId][currency] + : rates[GENERAL] && + rates[GENERAL][coinId] && + rates[GENERAL][coinId][currency] + ? rates[GENERAL][coinId][currency] : null; }; - _verusPay = () => { - let navigation = this.props.navigation; - + const _verusPay = () => { navigation.navigate('VerusPay'); }; - openCoin = (coinObj, subWallet) => { + const openCoin = (coinObj, subWallet) => { if (subWallet != null) { - this.props.dispatch(setCoinSubWallet(coinObj.id, subWallet)); - } - this.props.dispatch(setActiveCoin(coinObj)); - this.props.dispatch(setActiveApp(coinObj.default_app)); - this.props.dispatch( - setActiveSection(coinObj.apps[coinObj.default_app].data[0]), - ); - - this.resetToScreen('CoinMenus', 'Overview'); - }; - - _handleIdentity = () => { - let navigation = this.props.navigation; - navigation.navigate('Identity', {selectedScreen: 'Identity'}); - }; - - calculateSyncProgress = (coinObj, subWallet) => { - const syncInfo = this.props.info; - - if ( - syncInfo[coinObj.id] == null || - syncInfo[coinObj.id][subWallet.id] == null - ) { - return 100; - } else { - return syncInfo[coinObj.id][subWallet.id].percent; + dispatch(setCoinSubWallet(coinObj.id, subWallet)); } - }; + dispatch(setActiveCoin(coinObj)); + dispatch(setActiveApp(coinObj.default_app)); + dispatch(setActiveSection(coinObj.apps[coinObj.default_app].data[0])); - _addCoin = () => { - let navigation = this.props.navigation; - navigation.navigate('AddCoin', {refresh: this.refresh}); + resetToScreen('CoinMenus', 'Overview'); }; - handleScanToVerify = () => { - this.props.navigation.navigate('ScanBadge'); + const _addCoin = () => { + navigation.navigate('AddCoin', { refresh: refresh }); }; - _addPbaasCurrency = async () => { + const _addPbaasCurrency = async () => { openAddPbaasCurrencyModal( - CoinDirectory.findCoinObj( - this.props.testnetOverrides.VRSC - ? this.props.testnetOverrides.VRSC - : 'VRSC', - ), + CoinDirectory.findCoinObj(testnetOverrides.VRSC ? testnetOverrides.VRSC : 'VRSC'), ); }; - _addErc20Token = () => { + const _addErc20Token = () => { openAddErc20TokenModal( - CoinDirectory.findCoinObj( - this.props.testnetOverrides.ETH - ? this.props.testnetOverrides.ETH - : 'ETH', - ), + CoinDirectory.findCoinObj(testnetOverrides.ETH ? testnetOverrides.ETH : 'ETH'), ); }; - render() { - return HomeRender.call(this); - } -} - -const mapStateToProps = state => { - return { - activeCoinsForUser: state.coins.activeCoinsForUser, - activeCoinList: state.coins.activeCoinList, - - activeAccount: state.authentication.activeAccount, - testnetOverrides: state.authentication.activeAccount.testnetOverrides, - balances: extractLedgerData(state, 'balances', API_GET_BALANCES), - balanceErrors: extractErrorData(state, API_GET_BALANCES), - info: extractLedgerData(state, 'info', API_GET_INFO), - rates: state.ledger.rates, - displayCurrency: - state.settings.generalWalletSettings.displayCurrency || USD, - allSubWallets: extractDisplaySubWallets(state), - activeSubWallets: state.coinMenus.activeSubWallets, - widgetOrder: state.widgets.order, - homeCardDragDetection: - state.settings.generalWalletSettings.homeCardDragDetection, - }; + return ( + + HomeRenderCoinsList({ + widgets, + dragDetectionEnabled: isDragDetectionEnabled, + editingCards, + loading, + forceUpdate, + handleWidgetPress, + dispatch, + navigation, + activeAccount, + totalCryptoBalances, + totalFiatBalance, + HomeRenderWidget: (widgetId) => + HomeRenderWidget({ + widgetId, + totalCryptoBalances, + totalFiatBalance, + }), + }) + } + /> + ); }; -export default connect(mapStateToProps)(Home); +export default Home; \ No newline at end of file diff --git a/src/containers/Home/Home.render.js b/src/containers/Home/Home.render.js index e63a8e7f..834eba9f 100644 --- a/src/containers/Home/Home.render.js +++ b/src/containers/Home/Home.render.js @@ -1,9 +1,10 @@ +// Home.render.js + import React from 'react'; -import {View, RefreshControl} from 'react-native'; -import {Text, Provider, Portal, Banner} from 'react-native-paper'; -import {truncateDecimal} from '../../utils/math'; -import BigNumber from 'bignumber.js'; -import {HomeListItemThemeDark, HomeListItemThemeLight} from './Home.themes'; +import { View, RefreshControl } from 'react-native'; +import { Provider, Portal, Banner } from 'react-native-paper'; +import { truncateDecimal } from '../../utils/math'; +import { HomeListItemThemeDark, HomeListItemThemeLight } from './Home.themes'; import HomeFAB from './HomeFAB/HomeFAB'; import CurrencyWidget from './HomeWidgets/CurrencyWidget'; import { @@ -16,7 +17,7 @@ import { TOTAL_UNI_BALANCE_WIDGET_TYPE, VERUSID_WIDGET_TYPE, } from '../../utils/constants/widgets'; -import {setAndSaveAccountWidgets} from '../../actions/actionCreators'; +import { setAndSaveAccountWidgets } from '../../actions/actionCreators'; import TotalUniBalanceWidget from './HomeWidgets/TotalUniBalanceWidget'; import ListSelectionModal from '../../components/ListSelectionModal/ListSelectionModal'; import { @@ -27,95 +28,82 @@ import VerusIdWidget from './HomeWidgets/VerusIdWidget'; import { CoinDirectory } from '../../utils/CoinData/CoinDirectory'; import NotificationWidget from './HomeWidgets/NotificationWidget'; -export const HomeRender = function () { - const dragDetection = this.dragDetectionEnabled(); +export const HomeRender = ({ + dragDetectionEnabled, + displayCurrencyModalOpen, + displayCurrency, + setDisplayCurrency, + setDisplayCurrencyModalOpen, + editingCards, + setEditingCards, + _addCoin, + _verusPay, + _addPbaasCurrency, + _addErc20Token, + forceUpdate, + loading, + HomeRenderCoinsList, +}) => { + const dragDetection = dragDetectionEnabled(); return ( - {this.state.displayCurrencyModalOpen && ( + {displayCurrencyModalOpen && ( this.setDisplayCurrency(item.key)} - data={SUPPORTED_UNIVERSAL_DISPLAY_CURRENCIES.map(key => { + selectedKey={displayCurrency} + visible={displayCurrencyModalOpen} + onSelect={(item) => setDisplayCurrency(item.key)} + data={SUPPORTED_UNIVERSAL_DISPLAY_CURRENCIES.map((key) => { return { key, title: key, description: CURRENCY_NAMES[key], }; })} - cancel={() => this.setState({displayCurrencyModalOpen: false})} + cancel={() => setDisplayCurrencyModalOpen(false)} /> )} this._addCoin()} - handleVerusPay={() => this._verusPay()} - handleEditCards={() => this.setEditingCards(!this.state.editingCards)} - handleAddPbaasCurrency={() => this._addPbaasCurrency()} - handleAddErc20Token={() => this._addErc20Token()} + handleAddCoin={_addCoin} + handleVerusPay={_verusPay} + handleEditCards={() => setEditingCards(!editingCards)} + handleAddPbaasCurrency={_addPbaasCurrency} + handleAddErc20Token={_addErc20Token} showConfigureHomeCards={!dragDetection} /> this.setEditingCards(false), + onPress: () => setEditingCards(false), }, - ]}> + ]} + > {'Drag your cards into your desired configuration, then press done.'} - {HomeRenderCoinsList.call(this)} + {HomeRenderCoinsList()} ); }; -export const HomeRenderWidget = function (widgetId) { - const widgetSplit = widgetId.split(':'); - const widgetType = widgetSplit[0]; - - const renderers = { - [CURRENCY_WIDGET_TYPE]: () => { - const coinId = widgetSplit[1]; - const coinObj = CoinDirectory.findCoinObj(coinId); - - const balance = - this.state.totalCryptoBalances[coinObj.id] == null - ? null - : truncateDecimal(this.state.totalCryptoBalances[coinObj.id], 8); - - return ( - - - - ); - }, - [TOTAL_UNI_BALANCE_WIDGET_TYPE]: () => { - return ( - - - - ); - }, - [VERUSID_WIDGET_TYPE]: () => { - return ( - - - - ); - }, - }; - - return renderers[widgetType] ? renderers[widgetType]() : ; -}; - -export const HomeRenderCoinsList = function () { - const {widgets} = this.state; - const dragDetection = this.dragDetectionEnabled(); +export const HomeRenderCoinsList = ({ + widgets, + dragDetectionEnabled, + editingCards, + loading, + forceUpdate, + handleWidgetPress, + dispatch, + navigation, + activeAccount, + HomeRenderWidget, +}) => { + const dragDetection = dragDetectionEnabled(); return widgets.length == 0 ? ( @@ -126,32 +114,25 @@ export const HomeRenderCoinsList = function () { backgroundColor: 'white', width: '100%', overflow: 'visible', - }}> - + }} + > + - } - onPressDetected={ - !this.state.editingCards - ? id => this.handleWidgetPress(id) - : () => {} + } + onPressDetected={!editingCards ? (id) => handleWidgetPress(id) : () => {}} editing={true} - onDragEnd={positions => - this.props.dispatch( - setAndSaveAccountWidgets( - positions, - this.props.activeAccount.accountHash, - ), - ) - }> + onDragEnd={(positions) => + dispatch(setAndSaveAccountWidgets(positions, activeAccount.accountHash)) + } + > {widgets.map((widgetId, index) => ( - {HomeRenderWidget.call(this, widgetId)} + }} + > + {HomeRenderWidget(widgetId)} ))} @@ -170,49 +152,45 @@ export const HomeRenderCoinsList = function () { ); }; -export const renderFiatBalance = function (balance, ticker) { - const {displayCurrency} = this.props; - const rate = this.getRate(ticker, displayCurrency); +export const HomeRenderWidget = ({ + widgetId, + totalCryptoBalances, + totalFiatBalance, +}) => { + const widgetSplit = widgetId.split(':'); + const widgetType = widgetSplit[0]; - return ( - - {(balance == null || rate == null - ? '-' - : truncateDecimal( - BigNumber(rate).multipliedBy(BigNumber(balance)), - 2, - )) + - ' ' + - displayCurrency} - - ); -}; + const renderers = { + [CURRENCY_WIDGET_TYPE]: () => { + const coinId = widgetSplit[1]; + const coinObj = CoinDirectory.findCoinObj(coinId); -/** - * Render a list item for a cryptocurrency in your wallet - * @param {Object} coinObj The coin object - * @param {Boolean} isParent Whether or not the list item is a parent - * @param {Object} subWallet The subwallet (child only) - */ -export const HomeListItemRender = function ( - coinObj, - isParent, - subWallet, - index = 0, - length, -) { - const balance = isParent - ? this.state.totalCryptoBalances[coinObj.id] == null - ? null - : truncateDecimal(this.state.totalCryptoBalances[coinObj.id], 8) - : this.props.balances[coinObj.id] && - this.props.balances[coinObj.id][subWallet.id] != null - ? truncateDecimal(this.props.balances[coinObj.id][subWallet.id].total, 8) - : null; + const balance = + totalCryptoBalances[coinObj.id] == null + ? null + : truncateDecimal(totalCryptoBalances[coinObj.id], 8); - return ( - - - - ); -}; + return ( + + + + ); + }, + [TOTAL_UNI_BALANCE_WIDGET_TYPE]: () => { + return ( + + + + ); + }, + [VERUSID_WIDGET_TYPE]: () => { + return ( + + + + ); + }, + }; + + return renderers[widgetType] ? renderers[widgetType]() : ; +}; \ No newline at end of file diff --git a/src/containers/Home/HomeWidgets/CurrencyWidget.js b/src/containers/Home/HomeWidgets/CurrencyWidget.js index f53529bc..54e17282 100644 --- a/src/containers/Home/HomeWidgets/CurrencyWidget.js +++ b/src/containers/Home/HomeWidgets/CurrencyWidget.js @@ -12,6 +12,7 @@ import {extractDisplaySubWallets} from '../../../utils/subwallet/extractSubWalle import {normalizeNum} from '../../../utils/normalizeNum'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import Colors from '../../../globals/colors'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const CurrencyWidget = props => { const {currencyBalance, coinObj} = props; @@ -21,13 +22,13 @@ const CurrencyWidget = props => { const themeColor = coinObj.theme_color ? coinObj.theme_color : '#1C1C1C'; const showBalance = useSelector(state => state.coins.showBalance); - const allSubwallets = useSelector(state => extractDisplaySubWallets(state)); + const allSubwallets = useObjectSelector(state => extractDisplaySubWallets(state)); + const displayCurrency = useSelector(state => state.settings.generalWalletSettings.displayCurrency ? state.settings.generalWalletSettings.displayCurrency : USD, ); - const uniRate = useSelector(state => state.ledger.rates[GENERAL] && state.ledger.rates[GENERAL][coinObj.id] ? state.ledger.rates[GENERAL][coinObj.id][displayCurrency] diff --git a/src/containers/Home/HomeWidgets/NotificationWidget.js b/src/containers/Home/HomeWidgets/NotificationWidget.js index 45def536..1158e910 100644 --- a/src/containers/Home/HomeWidgets/NotificationWidget.js +++ b/src/containers/Home/HomeWidgets/NotificationWidget.js @@ -16,6 +16,7 @@ import { VerusIdAtIcon, ReceivedIcon, VerusIdErrorIcon } from "../../../images/c import { DeeplinkNotification, BasicNotification, LoadingNotification, VerusIdProvisioningNotification } from '../../../utils/notification'; import { processVerusId } from '../../../containers/Services/ServiceComponents/VerusIdService/VerusIdLogin'; import { dispatchRemoveNotification, dispatchClearNotifications } from '../../../actions/actions/notifications/dispatchers/notifications'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; // has the state changed hook const useCompare = (val) => { const prevVal = usePrevious(val) @@ -32,7 +33,6 @@ const usePrevious = (value) => { } const createNotificationText = (text, icon, index) => { - return ( { } const getIcon = (type, index) => { - switch (type) { case NOTIFICATION_ICON_VERUSID: return ( { } const getNotifications = (notifications, acchash) => { - const { directory } = notifications; let tempNotificaions = []; const keys = Object.keys(directory || {}); @@ -124,11 +122,11 @@ const getNotifications = (notifications, acchash) => { return tempNotificaions; } -const NotificationWidget = ({ props } = props) => { +const NotificationWidget = (props) => { const { width } = Dimensions.get('window'); const [collapsed, setCollapsed] = useState(false); const [traynotifications, setTrayNotifications] = useState([]); - const notifications = useSelector(state => + const notifications = useObjectSelector(state => state.notifications ); const acchash = useSelector(state => diff --git a/src/containers/Login/Login.js b/src/containers/Login/Login.js index c12c8d8f..21d1b067 100644 --- a/src/containers/Login/Login.js +++ b/src/containers/Login/Login.js @@ -23,6 +23,7 @@ import { import {useSelector} from 'react-redux'; import TallButton from '../../components/LargerButton'; import SignedOutDropdown from '../SignedOutDropdown/SignedOutDropdown'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; const {height} = Dimensions.get('window'); @@ -36,7 +37,8 @@ const Login = props => { const modalVisible = useSelector( state => state.sendModal.visible, ); - const accounts = useSelector(state => state.authentication.accounts); + + const accounts = useObjectSelector(state => state.authentication.accounts); openAuthModal = ignoreDefault => { if (ignoreDefault) { diff --git a/src/containers/Onboard/CreateProfile/CreateProfile.js b/src/containers/Onboard/CreateProfile/CreateProfile.js index 98b7f882..383f5cdc 100644 --- a/src/containers/Onboard/CreateProfile/CreateProfile.js +++ b/src/containers/Onboard/CreateProfile/CreateProfile.js @@ -12,7 +12,7 @@ import CreatePassword from './Forms/CreatePassword'; import UseBiometrics from './Forms/UseBiometrics'; import {KEY_DERIVATION_VERSION, SERVICES_DISABLED_DEFAULT} from '../../../../env/index'; import {START_COINS, TEST_PROFILE_OVERRIDES} from '../../../utils/constants/constants'; -import {useDispatch, useSelector} from 'react-redux'; +import {useDispatch} from 'react-redux'; import { closeLoadingModal, initializeAccountData, @@ -20,6 +20,7 @@ import { } from '../../../actions/actionDispatchers'; import { deriveKeyPair } from '../../../utils/keys'; import { CoinDirectory } from '../../../utils/CoinData/CoinDirectory'; +import { useObjectSelector } from '../../../hooks/useObjectSelector'; const CreateProfileStack = createStackNavigator(); @@ -28,8 +29,9 @@ export default function CreateProfileStackScreens(props) { const [password, setPassword] = useState(''); const [useBiometrics, setUseBiometrics] = useState(false); const dispatch = useDispatch(); - const accounts = useSelector(state => state.authentication.accounts); - const activeCoinList = useSelector(state => state.coins.activeCoinList); + + const accounts = useObjectSelector(state => state.authentication.accounts); + const activeCoinList = useObjectSelector(state => state.coins.activeCoinList); const addStartingCoins = async (accountId, testnetOverrides = {}) => { const testAccount = Object.keys(testnetOverrides).length > 0; diff --git a/src/containers/Onboard/CreateProfile/Forms/ChooseName.js b/src/containers/Onboard/CreateProfile/Forms/ChooseName.js index 0241fab6..c4ca5222 100644 --- a/src/containers/Onboard/CreateProfile/Forms/ChooseName.js +++ b/src/containers/Onboard/CreateProfile/Forms/ChooseName.js @@ -1,15 +1,15 @@ import React from 'react'; import {View, Dimensions, TouchableWithoutFeedback, Keyboard} from 'react-native'; import {Text, Paragraph, TextInput} from 'react-native-paper'; -import { useSelector } from 'react-redux'; import { createAlert } from '../../../../actions/actions/alert/dispatchers/alert'; import TallButton from '../../../../components/LargerButton'; import Colors from '../../../../globals/colors'; import { SMALL_DEVICE_HEGHT } from '../../../../utils/constants/constants'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; export default function ChooseName({ profileName, setProfileName, navigation }) { const {height} = Dimensions.get('window'); - const accounts = useSelector(state => state.authentication.accounts) + const accounts = useObjectSelector(state => state.authentication.accounts) const isDuplicateAccount = (accountID) => { let index = 0; diff --git a/src/containers/Onboard/CreateProfile/Forms/CreatePassword.js b/src/containers/Onboard/CreateProfile/Forms/CreatePassword.js index b0f71d5b..a73a1f90 100644 --- a/src/containers/Onboard/CreateProfile/Forms/CreatePassword.js +++ b/src/containers/Onboard/CreateProfile/Forms/CreatePassword.js @@ -6,7 +6,6 @@ import { Keyboard, } from 'react-native'; import {Text, Paragraph, Button, TextInput} from 'react-native-paper'; -import {useSelector} from 'react-redux'; import {createAlert} from '../../../../actions/actions/alert/dispatchers/alert'; import TallButton from '../../../../components/LargerButton'; import Colors from '../../../../globals/colors'; diff --git a/src/containers/RecoverSeeds/RecoverSeedsSelectAccount.js b/src/containers/RecoverSeeds/RecoverSeedsSelectAccount.js index 40929045..d7adbf5c 100644 --- a/src/containers/RecoverSeeds/RecoverSeedsSelectAccount.js +++ b/src/containers/RecoverSeeds/RecoverSeedsSelectAccount.js @@ -1,6 +1,5 @@ import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, SafeAreaView } from 'react-native'; -import { useSelector } from 'react-redux'; import { Card, Button, List, IconButton } from 'react-native-paper'; import styles from '../../styles'; import Colors from '../../globals/colors'; @@ -10,9 +9,10 @@ import { createAlert } from '../../actions/actions/alert/dispatchers/alert'; import { checkPinForUser } from '../../utils/asyncStore/authDataStorage'; import { canShowSeed } from '../../actions/actions/channels/dlight/dispatchers/AlertManager'; import { CommonActions } from '@react-navigation/native'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; const RecoverSeedsSelectAccount = ({ navigation }) => { - const accounts = useSelector(state => state.authentication.accounts); + const accounts = useObjectSelector(state => state.authentication.accounts); const [numSeeds, setNumSeeds] = useState({}); const [passwordDialogOpen, setPasswordDialogOpen] = useState(false); const [passwordDialogTitle, setPasswordDialogTitle] = useState(''); diff --git a/src/containers/RootStack/ConvertStackScreens/ConvertStackScreens.js b/src/containers/RootStack/ConvertStackScreens/ConvertStackScreens.js new file mode 100644 index 00000000..a9e161f7 --- /dev/null +++ b/src/containers/RootStack/ConvertStackScreens/ConvertStackScreens.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { createStackNavigator } from "@react-navigation/stack"; +import { defaultHeaderOptions } from '../../../utils/navigation/header'; +import Convert from '../../Convert/Convert'; + +const ConvertStack = createStackNavigator(); + +const ConvertStackScreens = props => { + return ( + + + + ); +}; + +export default ConvertStackScreens \ No newline at end of file diff --git a/src/containers/RootStack/HomeTabScreens/HomeTabScreens.js b/src/containers/RootStack/HomeTabScreens/HomeTabScreens.js index 60a6338d..34b03114 100644 --- a/src/containers/RootStack/HomeTabScreens/HomeTabScreens.js +++ b/src/containers/RootStack/HomeTabScreens/HomeTabScreens.js @@ -6,6 +6,7 @@ import WalletStackScreens from '../WalletStackScreens/WalletStackScreens'; import ProfileStackScreens from '../ProfileStackScreens/ProfileStackScreens'; import ServicesStackScreens from '../ServicesStackScreens/ServicesStackScreens'; import VerusPay from '../../VerusPay/VerusPay'; +import ConvertStackScreens from '../ConvertStackScreens/ConvertStackScreens'; const HomeTabs = createMaterialBottomTabNavigator() @@ -53,6 +54,20 @@ const HomeTabScreens = props => { ), }} /> + {/* ( + + ), + }} + /> */} { const [currenciesInPreconvert, setCurrenciesInPreconvert] = useState(null); const loading = useSelector(state => state.services.loading[PBAAS_PRECONVERT_SERVICE_ID]); - const activeAccount = useSelector(state => state.authentication.activeAccount); + const activeAccount = useObjectSelector(state => state.authentication.activeAccount); const dispatch = useDispatch(); props.navigation.setOptions({ title: 'Preconvert' }); diff --git a/src/containers/Settings/WalletSettings/GeneralWalletSettings/GeneralWalletSettings.js b/src/containers/Settings/WalletSettings/GeneralWalletSettings/GeneralWalletSettings.js index 530e060b..ef562ce5 100644 --- a/src/containers/Settings/WalletSettings/GeneralWalletSettings/GeneralWalletSettings.js +++ b/src/containers/Settings/WalletSettings/GeneralWalletSettings/GeneralWalletSettings.js @@ -13,7 +13,7 @@ import { TouchableOpacity, Platform, } from 'react-native'; -import {useSelector, useDispatch} from 'react-redux'; +import {useDispatch} from 'react-redux'; import Styles from '../../../../styles/index'; import Colors from '../../../../globals/colors'; import { @@ -27,16 +27,17 @@ import {saveGeneralSettings} from '../../../../actions/actionCreators'; import {createAlert} from '../../../../actions/actions/alert/dispatchers/alert'; import {NavigationActions} from '@react-navigation/compat'; import { ADDRESS_BLOCKLIST_FROM_WEBSERVER } from '../../../../utils/constants/constants'; +import { useObjectSelector } from '../../../../hooks/useObjectSelector'; const NO_DEFAULT = 'None'; const WalletSettings = props => { const isMounted = useRef(false); - const generalWalletSettings = useSelector( + const generalWalletSettings = useObjectSelector( state => state.settings.generalWalletSettings, ); - const accounts = useSelector(state => state.authentication.accounts); - const activeAccount = useSelector( + const accounts = useObjectSelector(state => state.authentication.accounts); + const activeAccount = useObjectSelector( state => state.authentication.activeAccount, ); const dispatch = useDispatch(); diff --git a/src/containers/SignUp/SignUp.js b/src/containers/SignUp/SignUp.js index e23c15f6..d19c30e6 100644 --- a/src/containers/SignUp/SignUp.js +++ b/src/containers/SignUp/SignUp.js @@ -1,3 +1,5 @@ +// DEPRECATED + /* This component represents the screen that the user is met with if there is no account present in AsyncStorage. It allows them diff --git a/src/containers/SignUp/SignUp.render.js b/src/containers/SignUp/SignUp.render.js index c150e811..d041493e 100644 --- a/src/containers/SignUp/SignUp.render.js +++ b/src/containers/SignUp/SignUp.render.js @@ -1,3 +1,5 @@ +// DEPRECATED + import React from "react"; import { View, diff --git a/src/containers/SubWalletSelect/SubWalletSelectorModal.js b/src/containers/SubWalletSelect/SubWalletSelectorModal.js index bce1d377..bcabc0fc 100644 --- a/src/containers/SubWalletSelect/SubWalletSelectorModal.js +++ b/src/containers/SubWalletSelect/SubWalletSelectorModal.js @@ -15,11 +15,12 @@ import { USD } from "../../utils/constants/currencies"; import BigNumber from "bignumber.js"; import Colors from "../../globals/colors"; import { CoinDirectory } from "../../utils/CoinData/CoinDirectory"; +import { useObjectSelector } from "../../hooks/useObjectSelector"; const SubWalletSelectorModal = (props) => { const dispatch = useDispatch(); - const allBalances = useSelector(state => state.ledger.balances); - const rates = useSelector(state => state.ledger.rates); + const allBalances = useObjectSelector(state => state.ledger.balances); + const rates = useObjectSelector(state => state.ledger.rates); const displayCurrency = useSelector(state => state.settings.generalWalletSettings.displayCurrency || USD); const [cryptoBalances, setCryptoBalances] = useState({}); diff --git a/src/containers/VerusPay/VerusPay.js b/src/containers/VerusPay/VerusPay.js index f3d37b55..4a3b38a5 100644 --- a/src/containers/VerusPay/VerusPay.js +++ b/src/containers/VerusPay/VerusPay.js @@ -6,82 +6,108 @@ user side of things. */ -import React, { Component } from "react"; -import { - View, - Alert -} from "react-native"; -import { arrayToObject } from '../../utils/objectManip' -import { connect } from 'react-redux'; +import React, { useState, useEffect, useCallback } from 'react'; +import { View, Alert } from 'react-native'; +import { useSelector, useDispatch } from 'react-redux'; import base64url from 'base64url'; import { URL } from 'react-native-url-polyfill'; -import { primitives } from 'verusid-ts-client' +import { primitives } from 'verusid-ts-client'; import { CALLBACK_HOST, INCOMPATIBLE_APP, ONLY_ADDRESS, SUPPORTED_DLS, -} from '../../utils/constants/constants' -import { API_GET_BALANCES, API_GET_FIATPRICE, API_GET_INFO, API_SEND, IS_PBAAS } from "../../utils/constants/intervalConstants"; -import { conditionallyUpdateWallet } from "../../actions/actionDispatchers"; -import store from "../../store"; -import { Button, Portal } from "react-native-paper"; -import SubWalletSelectorModal from "../SubWalletSelect/SubWalletSelectorModal"; -import { createAlert, resolveAlert } from "../../actions/actions/alert/dispatchers/alert"; -import QrScanner from "../../utils/QrScanner/QrScanner"; -import styles from "../../styles"; -import BarcodeReader from "../../components/BarcodeReader/BarcodeReader"; -import AnimatedActivityIndicator from "../../components/AnimatedActivityIndicator"; -import { openSubwalletSendModal } from "../../actions/actions/sendModal/dispatchers/sendModal"; -import { SEND_MODAL_AMOUNT_FIELD, SEND_MODAL_MEMO_FIELD, SEND_MODAL_TO_ADDRESS_FIELD } from "../../utils/constants/sendModal"; -import { SET_DEEPLINK_DATA } from "../../utils/constants/storeType"; -import { getCurrency } from "../../utils/api/channels/verusid/callCreators"; -import { CommonActions } from "@react-navigation/routers"; - -class VerusPay extends Component { - constructor(props) { - super(props); - this.state = { - loading: false, - coinObj: null, - activeUser: null, - address: null, - amount: null, - note: null, - subWalletSelectorOpen: false, - subWalletSelectorCoin: null, - subWalletSelectorDisplayTicker: null +} from '../../utils/constants/constants'; +import { + API_GET_BALANCES, + API_GET_FIATPRICE, + API_GET_INFO, + IS_PBAAS, +} from '../../utils/constants/intervalConstants'; +import { conditionallyUpdateWallet } from '../../actions/actionDispatchers'; +import store from '../../store'; +import { Portal } from 'react-native-paper'; +import SubWalletSelectorModal from '../SubWalletSelect/SubWalletSelectorModal'; +import { + createAlert, + resolveAlert, +} from '../../actions/actions/alert/dispatchers/alert'; +import QrScanner from '../../utils/QrScanner/QrScanner'; +import styles from '../../styles'; +import BarcodeReader from '../../components/BarcodeReader/BarcodeReader'; +import AnimatedActivityIndicator from '../../components/AnimatedActivityIndicator'; +import { openSubwalletSendModal } from '../../actions/actions/sendModal/dispatchers/sendModal'; +import { + SEND_MODAL_AMOUNT_FIELD, + SEND_MODAL_MEMO_FIELD, + SEND_MODAL_TO_ADDRESS_FIELD, +} from '../../utils/constants/sendModal'; +import { SET_DEEPLINK_DATA } from '../../utils/constants/storeType'; +import { getCurrency } from '../../utils/api/channels/verusid/callCreators'; +import { CommonActions } from '@react-navigation/routers'; +import { useNavigation } from '@react-navigation/native'; +import { useObjectSelector } from '../../hooks/useObjectSelector'; + +const VerusPay = (props) => { + const navigation = useNavigation(); + const dispatch = useDispatch(); + + const [loading, setLoading] = useState(false); + const [coinObj, setCoinObj] = useState(null); + const [activeUser, setActiveUser] = useState(null); + const [address, setAddress] = useState(null); + const [amount, setAmount] = useState(null); + const [note, setNote] = useState(null); + const [subWalletSelectorOpen, setSubWalletSelectorOpen] = useState(false); + const [subWalletSelectorCoin, setSubWalletSelectorCoin] = useState(null); + const [subWalletSelectorDisplayTicker, setSubWalletSelectorDisplayTicker] = + useState(null); + + const activeCoinsForUser = useSelector( + (state) => state.coins.activeCoinsForUser, + ); + const activeCoin = useSelector((state) => state.coins.activeCoin); + const activeAccount = useSelector( + (state) => state.authentication.activeAccount, + ); + const allSubWallets = useObjectSelector( + (state) => state.coinMenus.allSubWallets, + ); + const activeAlert = useObjectSelector((state) => state.alert.active); + const sendModal = useObjectSelector((state) => state.sendModal); + + const { containerStyle, acceptAddressOnly, channel, coinObj: propCoinObj, button, maskProps } = props; + + useEffect(() => { + return () => { + refresh(); }; - } - - componentWillUnmount() { - this.refresh(); - } + }, []); - refresh() { - this.props.activeCoinsForUser.map(async coinObj => { + const refresh = useCallback(() => { + activeCoinsForUser.forEach(async (coinObj) => { await conditionallyUpdateWallet( store.getState(), - this.props.dispatch, + dispatch, coinObj.id, API_GET_FIATPRICE, ); await conditionallyUpdateWallet( store.getState(), - this.props.dispatch, + dispatch, coinObj.id, API_GET_BALANCES, ); await conditionallyUpdateWallet( store.getState(), - this.props.dispatch, + dispatch, coinObj.id, API_GET_INFO, ); }); - } + }, [activeCoinsForUser, dispatch]); - tryProcessDeeplink(urlstring) { + const tryProcessDeeplink = (urlstring) => { const url = new URL(urlstring); if (url.host !== CALLBACK_HOST) @@ -92,7 +118,6 @@ class VerusPay extends Component { if (!SUPPORTED_DLS.includes(id)) { throw new Error('Unsupported deeplink url path.'); } - let dl; @@ -107,120 +132,127 @@ class VerusPay extends Component { dl = primitives.VerusPayInvoice.fromWalletDeeplinkUri(urlstring); } - this.props.dispatch({ + dispatch({ type: SET_DEEPLINK_DATA, payload: { id, data: dl.toJson(), }, }); - this.props.navigation.dispatch(CommonActions.reset({ - index: 0, - routes: [{name: 'DeepLink'}], - })); - } + navigation.dispatch( + CommonActions.reset({ + index: 0, + routes: [{ name: 'DeepLink' }], + }), + ); + }; - onSuccess(codes) { + const onSuccess = (codes) => { try { let result = codes[0].value; try { - this.tryProcessDeeplink(result) - return - } catch(dlError) { + tryProcessDeeplink(result); + return; + } catch (dlError) { console.log( `Could not find deeplink uri in QR scan, falling back to payment request, error: ${dlError.message}`, ); } const paymentRequest = QrScanner.processGenericPaymentRequest(result); - const {coinObj, address, note, amount, system} = paymentRequest; - - if (coinObj == null) { - this.addressOnly(address); - } else if ( - !this.props.acceptAddressOnly || - this.props.activeCoin.id === coinObj.id - ) { - if (amount === null) { - this.handleMissingAmount(coinObj, address, note, system); + const { + coinObj: scannedCoinObj, + address: scannedAddress, + note: scannedNote, + amount: scannedAmount, + system, + } = paymentRequest; + + if (scannedCoinObj == null) { + addressOnly(scannedAddress); + } else if (!acceptAddressOnly || activeCoin.id === scannedCoinObj.id) { + if (scannedAmount === null) { + handleMissingAmount( + scannedCoinObj, + scannedAddress, + scannedNote, + system, + ); } else { - this.preConfirm( - coinObj, - this.props.activeAccount, - address, - amount, - note, + preConfirm( + scannedCoinObj, + activeAccount, + scannedAddress, + scannedAmount, + scannedNote, false, - system + system, ); } } else { - this.canExitWallet(this.props.activeCoin.display_ticker, coinObj.display_ticker).then(res => { + canExitWallet( + activeCoin.display_ticker, + scannedCoinObj.display_ticker, + ).then((res) => { if (res) { - if (amount === null) { - this.handleMissingAmount(coinObj, address, note, system); + if (scannedAmount === null) { + handleMissingAmount( + scannedCoinObj, + scannedAddress, + scannedNote, + system, + ); } else { - this.preConfirm( - coinObj, - this.props.activeAccount, - address, - amount, - note, + preConfirm( + scannedCoinObj, + activeAccount, + scannedAddress, + scannedAmount, + scannedNote, true, - system + system, ); } } else { - this.cancelHandler(); + cancelHandler(); } }); } } catch (e) { console.warn(e); - this.errorHandler(e.message); + errorHandler(e.message); } - } + }; - errorHandler = error => { + const errorHandler = (error) => { createAlert('Error', error); - this.cancelHandler(); + cancelHandler(); }; - cancelHandler = () => { - this.setState({ - loading: false, - }); + const cancelHandler = () => { + setLoading(false); }; - handleMissingAmount = (coinObj, address, note, system) => { + const handleMissingAmount = (coinObj, address, note, system) => { if (coinObj.apps.hasOwnProperty('wallet')) { - this.preConfirm( - coinObj, - this.props.activeAccount, - address, - '', - note, - false, - system - ); + preConfirm(coinObj, activeAccount, address, '', note, false, system); } else { - this.errorHandler(INCOMPATIBLE_APP); + errorHandler(INCOMPATIBLE_APP); } }; - preConfirm = async ( + const preConfirm = async ( coinObj, activeUser, address, amount, note, sourceSwitch = false, - system + system, ) => { - const subWallet = - this.props.channel && !sourceSwitch ? this.props.channel : null; + const subWallet = channel && !sourceSwitch ? channel : null; if (coinObj.tags.includes(IS_PBAAS) && system != null) { const getCurrencyRes = await getCurrency(coinObj.system_id, system); @@ -238,246 +270,129 @@ class VerusPay extends Component { } } - this.setState( - { - coinObj: coinObj, - activeUser: activeUser, - address: address, - amount: amount, - note: note, - }, - () => { - this.handleUpdates().then(() => { - this.openSendModal(subWallet); - }); - }, - ); - }; + setCoinObj(coinObj); + setActiveUser(activeUser); + setAddress(address); + setAmount(amount); + setNote(note); - canExitWallet = (fromTicker, toTicker) => { - return createAlert( - 'Leaving Wallet', - 'This invoice is requesting funds in ' + - toTicker + - ', but you are currently ' + - 'in the ' + - fromTicker + - ' wallet. Would you like to proceed?', - [ - { - text: 'No, take me back', - onPress: () => resolveAlert(false), - style: 'cancel', - }, - {text: 'Yes', onPress: () => resolveAlert(true)}, - ], - ); - }; + await handleUpdates(); - canFillAmount = (currency, note, address) => { - return createAlert( - 'Missing Amount', - 'This invoice does not specify an amount, in order to proceed you ' + - 'will need to fill in the amount yourself, would you like to continue?' + - (currency ? '\n\n Currency: ' + currency : null) + - '\n\n To: ' + - address + - (note ? '\n\n Memo: ' + note : ''), - [ - { - text: 'No, take me back', - onPress: () => resolveAlert(false), - style: 'cancel', - }, - {text: 'Yes', onPress: () => resolveAlert(true)}, - ], - ); + openSendModal(subWallet); }; - canAddCoin = coinTicker => { + const canExitWallet = (fromTicker, toTicker) => { return createAlert( - 'Coin Inactive', - 'This invoice is requesting funds in ' + - coinTicker + - ', but you have not ' + - 'activated that coin yet, would you like to activate ' + - coinTicker + - ' and proceed?', + 'Leaving Wallet', + `This invoice is requesting funds in ${toTicker}, but you are currently in the ${fromTicker} wallet. Would you like to proceed?`, [ { text: 'No, take me back', onPress: () => resolveAlert(false), style: 'cancel', }, - {text: 'Yes', onPress: () => resolveAlert(true)}, + { text: 'Yes', onPress: () => resolveAlert(true) }, ], - { - cancelable: false, - }, ); }; - openSendModal = subWallet => { + const openSendModal = (subWallet) => { if (subWallet != null) { - this.setState( - { - subWalletSelectorOpen: false, - subWalletSelectorCoin: null, - }, - () => { - openSubwalletSendModal(this.state.coinObj, subWallet, { - [SEND_MODAL_TO_ADDRESS_FIELD]: this.state.address, - [SEND_MODAL_AMOUNT_FIELD]: this.state.amount.toString(), - [SEND_MODAL_MEMO_FIELD]: '', - }); - }, - ); + setSubWalletSelectorOpen(false); + setSubWalletSelectorCoin(null); + openSubwalletSendModal(coinObj, subWallet, { + [SEND_MODAL_TO_ADDRESS_FIELD]: address, + [SEND_MODAL_AMOUNT_FIELD]: amount.toString(), + [SEND_MODAL_MEMO_FIELD]: '', + }); } else { - this.setState( - { - subWalletSelectorCoin: this.state.coinObj.id, - subWalletSelectorDisplayTicker: this.state.coinObj.display_ticker - }, - () => { - const subWallets = - this.props.allSubWallets[this.state.subWalletSelectorCoin]; + setSubWalletSelectorCoin(coinObj.id); + setSubWalletSelectorDisplayTicker(coinObj.display_ticker); - if (subWallets.length == 1) { - this.openSendModal(subWallets[0]); - } else { - this.setState({ - subWalletSelectorOpen: true, - }); - } - }, - ); + const subWallets = allSubWallets[coinObj.id]; + + if (subWallets.length === 1) { + openSendModal(subWallets[0]); + } else { + setSubWalletSelectorOpen(true); + } } }; - handleUpdates = async () => { - return new Promise((resolve, reject) => { - this.setState( - { - loading: true, - }, - async () => { - const updates = [API_GET_BALANCES, API_GET_INFO]; - - for (const update of updates) { - await conditionallyUpdateWallet( - store.getState(), - this.props.dispatch, - this.state.coinObj.id, - update, - ); - } + const handleUpdates = async () => { + setLoading(true); - this.setState({loading: false}); - resolve(); - }, + const updates = [API_GET_BALANCES, API_GET_INFO]; + + for (const update of updates) { + await conditionallyUpdateWallet( + store.getState(), + dispatch, + coinObj.id, + update, ); - }); + } + + setLoading(false); }; - addressOnly = address => { - if (this.props.acceptAddressOnly) { - this.preConfirm( - this.props.coinObj, - this.props.activeAccount, - address, - '', - '', - false, - ); + const addressOnly = (address) => { + if (acceptAddressOnly) { + preConfirm(propCoinObj, activeAccount, address, '', '', false); } else { - this.errorHandler(ONLY_ADDRESS); + errorHandler(ONLY_ADDRESS); } }; - render() { - const containerStyle = - this.props.containerStyle == null ? {} : this.props.containerStyle; - const loading = - this.state.loading || - this.state.addingCoin || - this.props.activeAlert != null || - this.props.sendModal.visible || - this.props.showSpinner; - - return ( - - - {this.state.subWalletSelectorOpen && ( - - this.setState({ - subWalletSelectorOpen: false, - subWalletSelectorCoin: null, - }) - } - animationType="slide" - subWallets={ - this.state.subWalletSelectorCoin == null - ? [] - : this.props.allSubWallets[this.state.subWalletSelectorCoin] - } - onSelect={wallet => this.openSendModal(wallet)} - displayTicker={this.state.subWalletSelectorDisplayTicker} - /> - )} - - {loading ? ( - - - - ) : ( - - this.onSuccess(codes)} - button={this.props.button} - maskProps={this.props.maskProps} - /> - + const loadingState = + loading || activeAlert != null || sendModal.visible || props.showSpinner; + + return ( + + + {subWalletSelectorOpen && ( + { + setSubWalletSelectorOpen(false); + setSubWalletSelectorCoin(null); + }} + animationType="slide" + subWallets={ + subWalletSelectorCoin == null + ? [] + : allSubWallets[subWalletSelectorCoin] + } + onSelect={(wallet) => openSendModal(wallet)} + displayTicker={subWalletSelectorDisplayTicker} + /> )} - - ); - } -} - -const mapStateToProps = (state) => { - return { - activeCoinsForUser: state.coins.activeCoinsForUser, - activeCoin: state.coins.activeCoin, - activeAccount: state.authentication.activeAccount, - balances: { - results: arrayToObject( - Object.keys(state.ledger.balances), - (curr, key) => state.ledger.balances[key], - true - ), - errors: arrayToObject( - Object.keys(state.errors[API_GET_BALANCES]), - (curr, key) => state.errors[API_GET_BALANCES][key], - true - ), - }, - coinSettings: state.settings.coinSettings, - activeCoinList: state.coins.activeCoinList, - allSubWallets: state.coinMenus.allSubWallets, - activeAlert: state.alert.active, - sendModal: state.sendModal - }; + + {loadingState ? ( + + + + ) : ( + + onSuccess(codes)} + button={button} + maskProps={maskProps} + /> + + )} + + ); }; -export default connect(mapStateToProps)(VerusPay); +export default VerusPay; \ No newline at end of file diff --git a/src/hooks/useObjectSelector.js b/src/hooks/useObjectSelector.js new file mode 100644 index 00000000..81e3cb27 --- /dev/null +++ b/src/hooks/useObjectSelector.js @@ -0,0 +1,6 @@ +import { isEqual } from "lodash"; +import { useSelector } from "react-redux"; + +export const useObjectSelector = (extractor) => { + return useSelector(extractor, isEqual); +} \ No newline at end of file diff --git a/src/utils/CoinData/Graphics.js b/src/utils/CoinData/Graphics.js index 85da4ee3..7efcdcfb 100644 --- a/src/utils/CoinData/Graphics.js +++ b/src/utils/CoinData/Graphics.js @@ -25,6 +25,28 @@ export const RenderSquareLogo = (LogoComponent, color, width = 40, height = 40) ); }; +export const RenderCircleLogo = (LogoComponent, color, width = 40, height = 40) => { + return ( + + + {LogoComponent} + + + ); +}; + export const RenderSquareCoinLogo = (chainTicker, style = {}, width = 40, height = 40) => { const coinObj = CoinDirectory.findCoinObj(chainTicker) @@ -44,3 +66,38 @@ export const RenderSquareCoinLogo = (chainTicker, style = {}, width = 40, height height ); }; + +export const RenderCircleCoinLogo = (chainTicker, style = {}, width = 40, height = 40) => { + const coinObj = CoinDirectory.findCoinObj(chainTicker) + + const Logo = getCoinLogo(chainTicker, coinObj.proto); + + return RenderCircleLogo( + , + coinObj.theme_color, + width, + height + ); +}; + +export const RenderPlainCoinLogo = (chainTicker, style = {}, width = 40, height = 40) => { + const coinObj = CoinDirectory.findCoinObj(chainTicker) + + const Logo = getCoinLogo(chainTicker, coinObj.proto, 'dark'); + + return +}; \ No newline at end of file diff --git a/src/utils/notification.js b/src/utils/notification.js index 0c97de6f..c0a78886 100644 --- a/src/utils/notification.js +++ b/src/utils/notification.js @@ -85,7 +85,7 @@ export class DeeplinkNotification extends Notification { static fromJson(json, reopen) { const {body, title, uid, uri, fromService} = json; - return new DeeplinkNotification(body, title, reopen, uid, uri, null , fromService); + return new DeeplinkNotification(body, title, reopen, uid, uri, null, fromService); } onAction(props = null) { @@ -109,7 +109,6 @@ export class VerusIdProvisioningNotification extends DeeplinkNotification { super(body, title, reopen, uid, uri, acchash, fromService) this.type = NOTIFICATION_TYPE_VERUS_ID_PROVISIONING this.fqn = fqn - } static fromJson(json, reopen) { @@ -130,7 +129,6 @@ export class VerusIdProvisioningNotification extends DeeplinkNotification { uri: this.uri, fqn: this.fqn, fromService: this.fromService - }; } } \ No newline at end of file