diff --git a/app/components/UI/ApproveTransactionReview/EditPermission/index.js b/app/components/UI/ApproveTransactionReview/EditPermission/index.tsx similarity index 83% rename from app/components/UI/ApproveTransactionReview/EditPermission/index.js rename to app/components/UI/ApproveTransactionReview/EditPermission/index.tsx index 72464018a73..c15c136e95a 100644 --- a/app/components/UI/ApproveTransactionReview/EditPermission/index.js +++ b/app/components/UI/ApproveTransactionReview/EditPermission/index.tsx @@ -1,18 +1,22 @@ -import React, { useCallback, useMemo, useState } from 'react'; -import PropTypes from 'prop-types'; -import { View, StyleSheet, TouchableOpacity, TextInput } from 'react-native'; +import React, { useCallback, useEffect, useState } from 'react'; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + TextInput, +} from 'react-native'; import { fontStyles } from '../../../../styles/common'; -import Text from '../../../Base/Text'; import StyledButton from '../../StyledButton'; import { strings } from '../../../../../locales/i18n'; +import { isNumber } from '../../../../util/number'; import ConnectHeader from '../../ConnectHeader'; import Device from '../../../../util/device'; import ErrorMessage from '../../../Views/SendFlow/ErrorMessage'; import { useAppThemeFromContext, mockTheme } from '../../../../util/theme'; import formatNumber from '../../../../util/formatNumber'; -import { INTEGER_OR_FLOAT_REGEX } from '../../../../util/number'; -const createStyles = (colors) => +const createStyles = (colors: any) => StyleSheet.create({ wrapper: { paddingHorizontal: 24, @@ -99,6 +103,20 @@ const createStyles = (colors) => }, }); +interface IEditPermissionProps { + host: string; + minimumSpendLimit: string; + spendLimitUnlimitedSelected: boolean; + tokenSymbol: string; + spendLimitCustomValue: string; + originalApproveAmount: string; + onSetApprovalAmount: () => void; + onSpendLimitCustomValueChange: (approvalCustomValue: string) => void; + onPressSpendLimitUnlimitedSelected: () => void; + onPressSpendLimitCustomSelected: () => void; + toggleEditPermission: () => void; +} + function EditPermission({ host, minimumSpendLimit, @@ -111,21 +129,25 @@ function EditPermission({ onPressSpendLimitUnlimitedSelected, onPressSpendLimitCustomSelected, toggleEditPermission, -}) { +}: IEditPermissionProps) { const [initialState] = useState({ spendLimitUnlimitedSelected, spendLimitCustomValue, }); + const [disableBtn, setDisableBtn] = useState(false); + const [displayErrorMsg, setDisplayErrorMsg] = useState(false); const { colors, themeAppearance } = useAppThemeFromContext() || mockTheme; const styles = createStyles(colors); - const displayErrorMessage = useMemo( - () => - (!spendLimitUnlimitedSelected && - !INTEGER_OR_FLOAT_REGEX.test(spendLimitCustomValue)) || - Number(minimumSpendLimit) > spendLimitCustomValue, - [spendLimitUnlimitedSelected, spendLimitCustomValue, minimumSpendLimit], - ); + useEffect(() => { + setDisplayErrorMsg( + Number(minimumSpendLimit) > Number(spendLimitCustomValue), + ); + }, [minimumSpendLimit, spendLimitCustomValue, spendLimitUnlimitedSelected]); + + useEffect(() => { + setDisableBtn(!isNumber(spendLimitCustomValue) || displayErrorMsg); + }, [spendLimitCustomValue, displayErrorMsg]); const onSetApprovalAmount = useCallback(() => { if (!spendLimitUnlimitedSelected && !spendLimitCustomValue) { @@ -141,13 +163,12 @@ function EditPermission({ ]); const onBackPress = useCallback(() => { - const { spendLimitUnlimitedSelected, spendLimitCustomValue } = initialState; - if (spendLimitUnlimitedSelected) { + if (initialState.spendLimitUnlimitedSelected) { onPressSpendLimitUnlimitedSelected(); } else { onPressSpendLimitCustomSelected(); } - onSpendLimitCustomValueChange(spendLimitCustomValue); + onSpendLimitCustomValueChange(initialState.spendLimitCustomValue); toggleEditPermission(); }, [ initialState, @@ -249,7 +270,7 @@ function EditPermission({ returnKeyType={'done'} keyboardAppearance={themeAppearance} /> - {displayErrorMessage && ( + {displayErrorMsg && ( @@ -275,18 +296,4 @@ function EditPermission({ ); } -EditPermission.propTypes = { - host: PropTypes.string.isRequired, - minimumSpendLimit: PropTypes.string, - spendLimitUnlimitedSelected: PropTypes.bool.isRequired, - tokenSymbol: PropTypes.string.isRequired, - spendLimitCustomValue: PropTypes.string.isRequired, - originalApproveAmount: PropTypes.string.isRequired, - onPressSpendLimitUnlimitedSelected: PropTypes.func.isRequired, - onPressSpendLimitCustomSelected: PropTypes.func.isRequired, - onSpendLimitCustomValueChange: PropTypes.func.isRequired, - onSetApprovalAmount: PropTypes.func.isRequired, - toggleEditPermission: PropTypes.func.isRequired, -}; - export default EditPermission; diff --git a/app/components/UI/Swaps/components/ApprovalTransactionEditionModal.js b/app/components/UI/Swaps/components/ApprovalTransactionEditionModal.js index a15c984ce90..0012a58a54e 100644 --- a/app/components/UI/Swaps/components/ApprovalTransactionEditionModal.js +++ b/app/components/UI/Swaps/components/ApprovalTransactionEditionModal.js @@ -37,6 +37,8 @@ function ApprovalTransactionEditionModal({ chainId, }) { /* Approval transaction if any */ + const [customApprovalTransaction, setCustomApprovalTransaction] = + useState(approvalTransaction); const [approvalTransactionAmount, setApprovalTransactionAmount] = useState(''); const [approvalCustomValue, setApprovalCustomValue] = @@ -49,10 +51,12 @@ function ApprovalTransactionEditionModal({ (approvalCustomValue) => setApprovalCustomValue(approvalCustomValue), [], ); + const onPressSpendLimitUnlimitedSelected = useCallback( () => setSpendLimitUnlimitedSelected(true), [], ); + const onPressSpendLimitCustomSelected = useCallback( () => setSpendLimitUnlimitedSelected(false), [], @@ -66,8 +70,9 @@ function ApprovalTransactionEditionModal({ : approvalCustomValue, sourceToken.decimals, swapsUtils.getSwapsContractAddress(chainId), - approvalTransaction, + customApprovalTransaction, ); + setCustomApprovalTransaction(newApprovalTransaction); setApprovalTransaction(newApprovalTransaction); onCancelEditQuoteTransactions(); } catch (err) { @@ -78,27 +83,32 @@ function ApprovalTransactionEditionModal({ spendLimitUnlimitedSelected, approvalTransactionAmount, approvalCustomValue, - approvalTransaction, + customApprovalTransaction, sourceToken, chainId, onCancelEditQuoteTransactions, ]); useEffect(() => { - setApprovalTransaction(originalApprovalTransaction); - if (originalApprovalTransaction) { + const newApprovalTx = spendLimitUnlimitedSelected + ? originalApprovalTransaction + : customApprovalTransaction; + setApprovalTransaction(newApprovalTx); + if (newApprovalTx) { const approvalTransactionAmount = decodeApproveData( - originalApprovalTransaction.data, + newApprovalTx.data, ).encodedAmount; const amountDec = hexToBN(approvalTransactionAmount).toString(10); setApprovalTransactionAmount( fromTokenMinimalUnitString(amountDec, sourceToken.decimals), ); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ originalApprovalTransaction, - sourceToken.decimals, setApprovalTransaction, + spendLimitUnlimitedSelected, + customApprovalTransaction, ]); return ( @@ -120,7 +130,7 @@ function ApprovalTransactionEditionModal({ - {Boolean(approvalTransaction) && ( + {Boolean(customApprovalTransaction) && ( { @@ -489,3 +490,28 @@ describe('Number utils :: fastSplit', () => { expect(fastSplit('test string', ' ')).toEqual('test'); }); }); + +describe('Number utils :: isNumber', () => { + it('should be a valid number ', () => { + expect(isNumber('1650.7')).toBe(true); + expect(isNumber('1000')).toBe(true); + expect(isNumber('0.0001')).toBe(true); + expect(isNumber('0001')).toBe(true); + expect(isNumber('1')).toBe(true); + }); + + it('should not be a valid number ', () => { + expect(isNumber('..7')).toBe(false); + expect(isNumber('1..1')).toBe(false); + expect(isNumber('0..')).toBe(false); + expect(isNumber('a.0001')).toBe(false); + expect(isNumber('00a01')).toBe(false); + expect(isNumber('1,.')).toBe(false); + expect(isNumber('1,')).toBe(false); + expect(isNumber('.')).toBe(false); + expect(isNumber('a¡1')).toBe(false); + expect(isNumber('.01')).toBe(false); + expect(isNumber(undefined)).toBe(false); + expect(isNumber(null)).toBe(false); + }); +});