diff --git a/cashtab/package-lock.json b/cashtab/package-lock.json
--- a/cashtab/package-lock.json
+++ b/cashtab/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cashtab",
- "version": "2.34.1",
+ "version": "2.34.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cashtab",
- "version": "2.34.1",
+ "version": "2.34.2",
"dependencies": {
"@bitgo/utxo-lib": "^9.33.0",
"@zxing/browser": "^0.1.4",
diff --git a/cashtab/package.json b/cashtab/package.json
--- a/cashtab/package.json
+++ b/cashtab/package.json
@@ -1,6 +1,6 @@
{
"name": "cashtab",
- "version": "2.34.1",
+ "version": "2.34.2",
"private": true,
"scripts": {
"start": "node scripts/start.js",
diff --git a/cashtab/src/components/Airdrop/Airdrop.js b/cashtab/src/components/Airdrop/Airdrop.js
--- a/cashtab/src/components/Airdrop/Airdrop.js
+++ b/cashtab/src/components/Airdrop/Airdrop.js
@@ -4,7 +4,6 @@
import React, { useState, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
-import PropTypes from 'prop-types';
import { BN } from 'slp-mdm';
import styled from 'styled-components';
import { WalletContext } from 'wallet/context';
@@ -24,6 +23,7 @@
import { CopyPasteIcon } from 'components/Common/CustomIcons';
import { getTokenGenesisInfo } from 'chronik';
import cashaddr from 'ecashaddrjs';
+import Spinner from 'components/Common/Spinner';
const AirdropForm = styled.div`
margin-top: 24px;
@@ -54,13 +54,14 @@
justify-content: center;
`;
-const Airdrop = ({ passLoadingStatus }) => {
+const Airdrop = () => {
const ContextValue = React.useContext(WalletContext);
const { chronik, cashtabState, updateCashtabState } = ContextValue;
const { wallets, cashtabCache } = cashtabState;
const wallet = wallets.length > 0 ? wallets[0] : false;
const location = useLocation();
+ const [calculatingAirdrop, setCalculatingAirdrop] = useState(false);
const [formData, setFormData] = useState({
tokenId: '',
totalAirdrop: '',
@@ -230,7 +231,7 @@
const calculateXecAirdrop = async () => {
// Airdrop txs are instant for most tokens, but can take some time for
// tokens with a large amount of holders
- passLoadingStatus(true);
+ setCalculatingAirdrop(true);
// hide any previous airdrop outputs
setShowAirdropOutputs(false);
@@ -242,7 +243,7 @@
toast.error('Error retrieving airdrop recipients');
// Clear result field from earlier calc, if present, on any error
setAirdropRecipients('');
- return passLoadingStatus(false);
+ return setCalculatingAirdrop(false);
}
const excludedAddresses = [];
@@ -257,7 +258,7 @@
);
// Clear result field from earlier calc, if present, on any error
setAirdropRecipients('');
- return passLoadingStatus(false);
+ return setCalculatingAirdrop(false);
}
excludedAddresses.push(mintAddress);
}
@@ -278,7 +279,7 @@
);
// Clear result field from earlier calc, if present, on any error
setAirdropRecipients('');
- return passLoadingStatus(false);
+ return setCalculatingAirdrop(false);
}
undecimalizedMinTokenAmount = new BN(ignoreMinEtokenBalanceAmount)
.times(10 ** tokenInfo.genesisInfo.decimals)
@@ -310,7 +311,7 @@
setAirdropRecipients('');
toast.error(`${err}`);
}
- return passLoadingStatus(false);
+ return setCalculatingAirdrop(false);
};
const handleIgnoreMinEtokenBalanceAmt = e => {
@@ -381,201 +382,187 @@
}
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- setEqualDistributionRatio(prev => !prev);
- }}
- />
-
- {equalDistributionRatio
- ? ` Airdrop
+ <>
+ {calculatingAirdrop && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setEqualDistributionRatio(prev => !prev);
+ }}
+ />
+
+ {equalDistributionRatio
+ ? ` Airdrop
the same for everyone`
- : ` Airdrop
+ : ` Airdrop
scaled to token balance`}
-
-
-
-
-
-
- handleIgnoreOwnAddress(prev => !prev)
- }
- />
- Ignore my own address
-
-
-
-
-
- handleIgnoreMintAddress(prev => !prev)
- }
- />
- Ignore eToken minter address
-
-
-
-
-
- handleIgnoreMinEtokenBalanceAmt(prev => !prev)
- }
- />
- Minimum eToken holder balance
-
- {ignoreMinEtokenBalance && (
-
- )}
-
-
-
-
- handleIgnoreCustomAddresses(prev => !prev)
- }
- />
- Ignore custom addresses
-
- {ignoreCustomAddresses && (
-
- )}
-
-
- calculateXecAirdrop()}
- disabled={
- !airdropCalcInputIsValid ||
- !tokenIdIsValid ||
- (ignoreMintAddress &&
- typeof mintAddress === 'undefined') ||
- (ignoreMinEtokenBalance &&
- typeof tokenInfo === 'undefined')
- }
- >
- Calculate Airdrop
-
-
- {showAirdropOutputs && (
- <>
-
-
- One to Many Airdrop Payment Outputs
-
-
-
-
+
+
+
+
+
+
+ handleIgnoreOwnAddress(prev => !prev)
+ }
+ />
+ Ignore my own address
+
+
+
+
+
+ handleIgnoreMintAddress(prev => !prev)
+ }
+ />
+ Ignore eToken minter address
+
+
+
+
+
+ handleIgnoreMinEtokenBalanceAmt(prev => !prev)
+ }
+ />
+ Minimum eToken holder balance
+
+ {ignoreMinEtokenBalance && (
+
+ )}
+
+
+
+
+ handleIgnoreCustomAddresses(prev => !prev)
+ }
+ />
+ Ignore custom addresses
+
+ {ignoreCustomAddresses && (
-
-
-
- Copy to Send screen
-
-
- >
- )}
-
+ )}
+
+
+ calculateXecAirdrop()}
+ disabled={
+ !airdropCalcInputIsValid ||
+ !tokenIdIsValid ||
+ (ignoreMintAddress &&
+ typeof mintAddress === 'undefined') ||
+ (ignoreMinEtokenBalance &&
+ typeof tokenInfo === 'undefined')
+ }
+ >
+ Calculate Airdrop
+
+
+ {showAirdropOutputs && (
+ <>
+
+
+ One to Many Airdrop Payment Outputs
+
+
+
+
+
+
+
+
+ Copy to Send screen
+
+
+ >
+ )}
+
+ >
);
};
-/*
-passLoadingStatus must receive a default prop that is a function
-in order to pass the rendering unit test in Airdrop.test.js
-
-status => {console.info(status)} is an arbitrary stub function
-*/
-
-Airdrop.defaultProps = {
- passLoadingStatus: status => {
- console.info(status);
- },
-};
-
-Airdrop.propTypes = {
- passLoadingStatus: PropTypes.func,
-};
-
export default Airdrop;
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
@@ -5,7 +5,6 @@
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { WalletContext } from 'wallet/context';
-import PropTypes from 'prop-types';
import { AlertMsg } from 'components/Common/Atoms';
import PrimaryButton from 'components/Common/Buttons';
import { getWalletState } from 'utils/cashMethods';
@@ -24,6 +23,7 @@
import { AliasInput, Input } from 'components/Common/Inputs';
import Switch from 'components/Common/Switch';
import Modal from 'components/Common/Modal';
+import Spinner from 'components/Common/Spinner';
const AliasWrapper = styled.div`
color: ${props => props.theme.contrast};
@@ -113,7 +113,7 @@
white-space: pre-wrap;
`;
-const Alias = ({ passLoadingStatus }) => {
+const Alias = () => {
const ContextValue = React.useContext(WalletContext);
const {
chronik,
@@ -135,6 +135,7 @@
aliasName: '',
aliasAddress: defaultAddress,
});
+ const [waitingForServer, setWaitingForServer] = useState(false);
const [registerActiveWallet, setRegisterActiveWallet] = useState(true);
const [isValidAliasInput, setIsValidAliasInput] = useState(false); // tracks whether to activate the registration button
const [isValidAliasAddressInput, setIsValidAliasAddressInput] =
@@ -149,7 +150,7 @@
const [isModalVisible, setIsModalVisible] = useState(false);
useEffect(() => {
- passLoadingStatus(false);
+ setWaitingForServer(false);
}, [balanceSats]);
useEffect(() => {
@@ -185,7 +186,7 @@
setAliasValidationError(
`Failed to fetch alias price information from server. Alias registration disabled. Refresh page to try again.`,
);
- passLoadingStatus(false);
+ setWaitingForServer(false);
}
}
@@ -214,13 +215,13 @@
setAliasValidationError(
`Failed to check alias availability from server. Alias registration disabled. Refresh page to try again.`,
);
- passLoadingStatus(false);
+ setWaitingForServer(false);
}
}
}, aliasSettings.aliasKeyUpTimeoutMs);
});
- passLoadingStatus(false);
+ setWaitingForServer(false);
};
useEffect(() => {
@@ -228,9 +229,9 @@
if (wallet === false || typeof wallet === 'undefined') {
return;
}
- passLoadingStatus(true);
+ setWaitingForServer(true);
- // passLoadingStatus(false) will be called after awaiting expected methods
+ // setWaitingForServer(false) will be called after awaiting expected methods
handleAliasWalletChange();
}, [wallet.name]);
@@ -244,7 +245,7 @@
};
const preparePreviewModal = async () => {
- passLoadingStatus(true);
+ setWaitingForServer(true);
// Retrieve alias details
let aliasDetailsResp;
@@ -277,7 +278,7 @@
console.error(`preparePreviewModal(): ${errorMsg}`, err);
// Using a pop up notification since this is a modal block
toast.error(`${errorMsg}`);
- passLoadingStatus(false);
+ setWaitingForServer(false);
return;
}
@@ -302,7 +303,7 @@
);
setAliasDetails(false);
}
- passLoadingStatus(false);
+ setWaitingForServer(false);
};
const handleOk = () => {
@@ -315,7 +316,7 @@
};
const registerAlias = async () => {
- passLoadingStatus(true);
+ setWaitingForServer(true);
// note: input already validated via handleAliasNameInput()
const aliasInput = formData.aliasName;
@@ -388,7 +389,7 @@
`Alias "${aliasInput}" has already been taken, please try another alias.`,
);
}
- passLoadingStatus(false);
+ setWaitingForServer(false);
};
const handleAliasNameInput = e => {
@@ -454,6 +455,7 @@
return (
<>
+ {waitingForServer && }
{isModalVisible && (
{console.info(status)} is an arbitrary stub function
-*/
-
-Alias.defaultProps = {
- passLoadingStatus: status => {
- console.info(status);
- },
-};
-
-Alias.propTypes = {
- passLoadingStatus: PropTypes.func,
-};
-
export default Alias;
diff --git a/cashtab/src/components/App/App.js b/cashtab/src/components/App/App.js
--- a/cashtab/src/components/App/App.js
+++ b/cashtab/src/components/App/App.js
@@ -94,7 +94,6 @@
const wallet = wallets.length > 0 ? wallets[0] : false;
const walletState = getWalletState(wallet);
const { balanceSats } = walletState;
- const [spinner, setSpinner] = useState(false);
const [navMenuClicked, setNavMenuClicked] = useState(false);
const [scrollYPosition, setScrollYPosition] = React.useState(0);
const handleNavMenuClick = () => setNavMenuClicked(!navMenuClicked);
@@ -139,7 +138,6 @@
1,
)
: false;
-
return (
@@ -155,9 +153,7 @@
>
)}
- {loading ||
- spinner ||
- (wallet !== false && !validWallet && )}
+ {loading || (wallet !== false && !validWallet && )}
- }
+ element={}
/>
- }
+ element={}
/>
)}