diff --git a/cashtab/src/components/Airdrop/__tests__/__snapshots__/Airdrop.test.js.snap b/cashtab/src/components/Airdrop/__tests__/__snapshots__/Airdrop.test.js.snap --- a/cashtab/src/components/Airdrop/__tests__/__snapshots__/Airdrop.test.js.snap +++ b/cashtab/src/components/Airdrop/__tests__/__snapshots__/Airdrop.test.js.snap @@ -1,15 +1,15 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances 1`] = ` Array [

MigrationTestAlpha

@@ -51,7 +51,7 @@
You currently have 0 XEC @@ -61,7 +61,7 @@
,
,
XEC Airdrop Calculator
@@ -143,13 +143,13 @@ exports[`Wallet with BCH balances and tokens 1`] = ` Array [

MigrationTestAlpha

@@ -191,7 +191,7 @@
You currently have 0 XEC @@ -201,7 +201,7 @@
,
,
XEC Airdrop Calculator
@@ -283,13 +283,13 @@ exports[`Wallet with BCH balances and tokens and state field 1`] = ` Array [

MigrationTestAlpha

@@ -331,10 +331,10 @@
0.06 @@ -346,7 +346,7 @@
,
,
XEC Airdrop Calculator
@@ -428,13 +428,13 @@ exports[`Wallet without BCH balance 1`] = ` Array [

MigrationTestAlpha

@@ -476,7 +476,7 @@
You currently have 0 XEC @@ -486,7 +486,7 @@
,
,
XEC Airdrop Calculator
@@ -568,10 +568,10 @@ exports[`Without wallet defined 1`] = ` Array [
You currently have 0 XEC @@ -621,7 +621,7 @@
,
,
XEC Airdrop Calculator
diff --git a/cashtab/src/components/Alias/Alias.js b/cashtab/src/components/Alias/Alias.js --- a/cashtab/src/components/Alias/Alias.js +++ b/cashtab/src/components/Alias/Alias.js @@ -8,8 +8,12 @@ SidePaddingCtn, WalletInfoCtn, } from 'components/Common/Atoms'; -import { DestinationAddressSingle } from 'components/Common/EnhancedInputs'; -import { AntdFormWrapper } from 'components/Common/EnhancedInputs'; +import { + AntdFormWrapper, + AliasInput, + AliasAddressInput, + CashtabCheckbox, +} from 'components/Common/EnhancedInputs'; import { Form, Modal } from 'antd'; import { SmartButton } from 'components/Common/PrimaryButton'; import BalanceHeader from 'components/Common/BalanceHeader'; @@ -32,6 +36,12 @@ } from 'components/Common/Notifications'; import { isAliasFormat, isValidAliasString } from 'utils/validation'; import { getPendingAliases } from 'utils/aliasUtils'; +import cashaddr from 'ecashaddrjs'; + +export const CheckboxContainer = styled.div` + text-align: left; + margin-bottom: 12px; +`; export const NamespaceCtn = styled.div` width: 100%; @@ -73,8 +83,13 @@ aliasName: '', aliasAddress: '', }); + const [useThisAddressChecked, setUseThisAddressChecked] = useState(false); const [isValidAliasInput, setIsValidAliasInput] = useState(false); // tracks whether to activate the registration button + const [isValidAliasAddressInput, setIsValidAliasAddressInput] = + useState(false); // tracks whether to activate the registration button const [aliasValidationError, setAliasValidationError] = useState(false); + const [aliasAddressValidationError, setAliasAddressValidationError] = + useState(false); const [activeWalletAliases, setActiveWalletAliases] = useState([]); // stores the list of aliases registered to this active wallet const [aliasLength, setAliasLength] = useState(false); // real time tracking of alias char length const [aliasFee, setAliasFee] = useState(false); // real time tracking of alias registration fee @@ -98,12 +113,10 @@ } passLoadingStatus(true); - // Set address of active wallet to default alias registration address - // Use formdata approach as we will later add a form field for aliasAddress - setFormData(formData => ({ - ...formData, - aliasAddress: wallet.Path1899.cashAddress, - })); + // Default to registering the user's active wallet + // Must be called in this useEffect to ensure that wallet is loaded + // Call with this function to ensure that checkbox state and checkbox are updated + handleDefaultAddressCheckboxChange({ target: { checked: true } }); // check whether the address is attached to an onchain alias on page load const walletHasAlias = isAddressRegistered( @@ -287,6 +300,82 @@ })); }; + const handleDefaultAddressCheckboxChange = e => { + /* handleDefaultAddressCheckboxChange + * + * Function to handle user action of checking or unchecking the + * checkbox on this page labeled 'Register active wallet address' + * + * May be called programmatically by mocking the usual js event + * of a user checking the box + * + * If the box is checked, set formData for aliasAddress to the active wallet's address + * If the box is unchecked, clear formData for aliasAddress + */ + const checked = e.target.checked; + setUseThisAddressChecked(checked); + if (checked) { + // Set address of active wallet to default alias registration address + handleAliasAddressInput({ + target: { + name: 'aliasAddress', + value: wallet.Path1899.cashAddress, + }, + }); + } else { + // Clear the form if the user unchecks + handleAliasAddressInput({ + target: { + name: 'aliasAddress', + value: '', + }, + }); + } + }; + + const handleAliasAddressInput = e => { + /* handleAliasAddressInput + * + * Function called to handle any changes to the aliasAddress input form + * + * May be called programmatically by mocking the usual js event + * of a user updating the addressName input field + */ + let { name, value } = e.target; + + // remove any whitespaces + value = value.trim(); + + // Validate + let decoded; + let isValidAddress = false; + try { + decoded = cashaddr.decode(value, true); + const { hash } = decoded; + // We only support 20-byte payloads + isValidAddress = hash.length === 40; + } catch (err) { + // Invalid cashaddress + // Log to console for user support + console.log(`Invalid address`, err); + } + + if (isValidAddress) { + setIsValidAliasAddressInput(true); + setAliasAddressValidationError(false); + } else { + setAliasAddressValidationError( + 'Invalid alias registration address.', + ); + setIsValidAliasAddressInput(false); + } + + setFormData(p => ({ + ...p, + [name]: value, + })); + }; + function handleAliasRegistrationError(errorObj) { // Set loading to false here as well, as balance may not change depending on where error occured in try loop passLoadingStatus(false); @@ -363,7 +452,7 @@ }} > - + + + Register active wallet address + + + {!useThisAddressChecked && ( + + handleAliasAddressInput( + e, + ), + required: true, + }} + /> + )} {aliasLength && aliasFee && `Registration fee for this ${aliasLength} byte Alias is ${fromSatoshisToXec( @@ -390,7 +516,10 @@ setIsModalVisible(true) } diff --git a/cashtab/src/components/Alias/__tests__/__snapshots__/Alias.test.js.snap b/cashtab/src/components/Alias/__tests__/__snapshots__/Alias.test.js.snap --- a/cashtab/src/components/Alias/__tests__/__snapshots__/Alias.test.js.snap +++ b/cashtab/src/components/Alias/__tests__/__snapshots__/Alias.test.js.snap @@ -1,15 +1,15 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with XEC balances 1`] = ` Array [

MigrationTestAlpha

@@ -51,7 +51,7 @@
You currently have 0 XEC @@ -60,7 +60,7 @@
,

eCash Namespace Alias

- - - + user.svg +
+
+ +
@@ -218,7 +235,7 @@ className="ant-form-item-control-input-content" >

@@ -273,13 +290,13 @@ exports[`Wallet with XEC balances and tokens 1`] = ` Array [

MigrationTestAlpha

@@ -321,7 +338,7 @@
You currently have 0 XEC @@ -330,7 +347,7 @@

,

eCash Namespace Alias

- - - + user.svg +
+
+ +
+
+
+
+
+
+
+ + + + + + + + +
+
+
+
+
+
@@ -488,7 +591,7 @@ className="ant-form-item-control-input-content" >

@@ -543,13 +646,13 @@ exports[`Wallet with XEC balances and tokens and state field 1`] = ` Array [

MigrationTestAlpha

@@ -591,10 +694,10 @@
0.06 @@ -605,7 +708,7 @@

,

eCash Namespace Alias

- - - + user.svg +
+
+ +
@@ -763,7 +883,7 @@ className="ant-form-item-control-input-content" >

@@ -818,13 +938,13 @@ exports[`Wallet without XEC balance 1`] = ` Array [

MigrationTestAlpha

@@ -866,7 +986,7 @@
You currently have 0 XEC @@ -875,7 +995,7 @@

,

eCash Namespace Alias

- - - + user.svg +
+
+ +
+
+
+
+
+
+
+ + + + + + + + +
+
+
+
+
+
@@ -1033,7 +1239,7 @@ className="ant-form-item-control-input-content" >

@@ -1088,10 +1294,10 @@ exports[`Without wallet defined 1`] = ` Array [

,

eCash Namespace Alias

- - - + user.svg +
+
+ +
+
+
+
+
+
+
+ + + + + + + + +
+
+
+
+
+
@@ -1298,7 +1590,7 @@ className="ant-form-item-control-input-content" >

diff --git a/cashtab/src/components/Common/CustomIcons.js b/cashtab/src/components/Common/CustomIcons.js --- a/cashtab/src/components/Common/CustomIcons.js +++ b/cashtab/src/components/Common/CustomIcons.js @@ -165,6 +165,11 @@ height: 33px; width: 30px; `; +export const ThemedAliasOutlined = styled(User)` + fill: ${props => props.theme.icons.outlined} !important; + height: 12px; + width: 12px; +`; export const LoadingBlock = styled.div` width: 100%; diff --git a/cashtab/src/components/Common/EnhancedInputs.js b/cashtab/src/components/Common/EnhancedInputs.js --- a/cashtab/src/components/Common/EnhancedInputs.js +++ b/cashtab/src/components/Common/EnhancedInputs.js @@ -1,9 +1,10 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { Form, Input, Select } from 'antd'; +import { Form, Input, Select, Checkbox } from 'antd'; import { ThemedDollarOutlined, ThemedWalletOutlined, + ThemedAliasOutlined, } from 'components/Common/CustomIcons'; import styled, { css } from 'styled-components'; import ScanQRCode from './ScanQRCode'; @@ -151,6 +152,16 @@ : `cursor: pointer;`} `; +export const CashtabCheckbox = styled(Checkbox)` + .ant-checkbox-checked .ant-checkbox-inner { + background-color: ${props => props.theme.eCashBlue} !important; + border-color: ${props => props.theme.eCashBlue} !important; + } + .ant-checkbox + span { + color: ${props => props.theme.forms.text} !important; + } +`; + export const SendBchInput = ({ onMax, inputProps, @@ -349,6 +360,42 @@ inputProps: PropTypes.object, }; +export const AliasInput = ({ inputProps, ...otherProps }) => { + return ( + + + } + autoComplete="off" + {...inputProps} + /> + + + ); +}; + +AliasInput.propTypes = { + inputProps: PropTypes.object, +}; + +export const AliasAddressInput = ({ inputProps, ...otherProps }) => { + return ( + + + } + autoComplete="off" + {...inputProps} + /> + + + ); +}; + +AliasAddressInput.propTypes = { + inputProps: PropTypes.object, +}; + export const DestinationAddressMulti = ({ inputProps, ...otherProps }) => { return ( diff --git a/cashtab/src/components/Configure/__tests__/__snapshots__/Configure.test.js.snap b/cashtab/src/components/Configure/__tests__/__snapshots__/Configure.test.js.snap --- a/cashtab/src/components/Configure/__tests__/__snapshots__/Configure.test.js.snap +++ b/cashtab/src/components/Configure/__tests__/__snapshots__/Configure.test.js.snap @@ -1,11 +1,11 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances and tokens 1`] = `

,
,
@@ -386,13 +386,13 @@ onClick={[Function]} >

TBS @@ -412,13 +412,13 @@ exports[`Wallet without BCH balance 1`] = ` Array [

MigrationTestAlpha

@@ -460,10 +460,10 @@
0 @@ -474,26 +474,26 @@

,
@@ -541,18 +541,18 @@ exports[`Without wallet defined 1`] = `
ecash: qzagy47m vh6qxkvcn3acjnz73rkhkc6y7c cxkrr6zd @@ -165,16 +165,16 @@ exports[`Wallet with BCH balances and tokens 1`] = `

MigrationTestAlpha

@@ -216,7 +216,7 @@
You currently have 0 XEC @@ -225,7 +225,7 @@
ecash: qzagy47m vh6qxkvcn3acjnz73rkhkc6y7c cxkrr6zd @@ -328,16 +328,16 @@ exports[`Wallet with BCH balances and tokens and state field 1`] = `

MigrationTestAlpha

@@ -379,10 +379,10 @@
0.06 @@ -393,7 +393,7 @@
ecash: qzagy47m vh6qxkvcn3acjnz73rkhkc6y7c cxkrr6zd @@ -496,16 +496,16 @@ exports[`Wallet without BCH balance 1`] = `

MigrationTestAlpha

@@ -547,7 +547,7 @@
You currently have 0 XEC @@ -556,7 +556,7 @@
ecash: qzagy47m vh6qxkvcn3acjnz73rkhkc6y7c cxkrr6zd @@ -659,18 +659,18 @@ exports[`Without wallet defined 1`] = `

Welcome to Cashtab!

Cashtab is an

You currently have 0 XEC @@ -60,7 +60,7 @@
,
Multiple Recipients:  

0 XEC

= @@ -507,16 +507,16 @@ } >

MigrationTestAlpha

@@ -641,7 +641,7 @@
You currently have 0 XEC @@ -650,7 +650,7 @@
,
Multiple Recipients:  

0 XEC

= @@ -1097,16 +1097,16 @@ } >

MigrationTestAlpha

@@ -1231,10 +1231,10 @@
0.06 @@ -1245,7 +1245,7 @@
,
Multiple Recipients:  

0 XEC

= @@ -1692,17 +1692,17 @@ } >

MigrationTestAlpha

@@ -1827,7 +1827,7 @@
You currently have 0 XEC @@ -1836,7 +1836,7 @@
,
Multiple Recipients:  

0 XEC

= @@ -2283,16 +2283,16 @@ } >
,
Multiple Recipients:  

0 XEC

= @@ -2868,16 +2868,16 @@ } >
6.001000000 @@ -33,7 +33,7 @@ } >

@@ -239,7 +239,7 @@ } >
0 @@ -65,17 +65,17 @@
,

Create a Token

You need at least @@ -96,13 +96,13 @@ exports[`Wallet with BCH balances and tokens 1`] = ` Array [

MigrationTestAlpha

@@ -144,10 +144,10 @@
0 @@ -158,17 +158,17 @@
,

Create a Token

You need at least @@ -189,13 +189,13 @@ exports[`Wallet with BCH balances and tokens and state field 1`] = ` Array [

MigrationTestAlpha

@@ -237,10 +237,10 @@
0.06 @@ -251,16 +251,16 @@
,

Create a Token

@@ -311,7 +311,7 @@
@@ -349,7 +349,7 @@
@@ -387,7 +387,7 @@
@@ -425,7 +425,7 @@
@@ -463,7 +463,7 @@
@@ -569,7 +569,7 @@
0 @@ -672,17 +672,17 @@
,