allow sending directly to a channel or content address (#5990)
* allow sending directly to a channel or content address
This commit is contained in:
parent
200dc66763
commit
2852138c3a
6 changed files with 340 additions and 90 deletions
|
@ -1,16 +1,19 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectBalance, selectMyChannelClaims } from 'lbry-redux';
|
import { selectBalance, selectMyChannelClaims, makeSelectClaimForUri } from 'lbry-redux';
|
||||||
import { doOpenModal } from 'redux/actions/app';
|
import { doOpenModal } from 'redux/actions/app';
|
||||||
import WalletSend from './view';
|
import WalletSend from './view';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
|
import { selectToast } from 'redux/selectors/notifications';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const select = state => ({
|
const select = (state, props) => ({
|
||||||
balance: selectBalance(state),
|
balance: selectBalance(state),
|
||||||
channels: selectMyChannelClaims(state),
|
channels: selectMyChannelClaims(state),
|
||||||
|
contentClaim: makeSelectClaimForUri(props.contentUri)(state),
|
||||||
|
snack: selectToast(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default withRouter(connect(select, perform)(WalletSend));
|
export default withRouter(connect(select, perform)(WalletSend));
|
||||||
|
|
|
@ -4,20 +4,36 @@ import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { Form, FormField } from 'component/common/form';
|
import { Form, FormField } from 'component/common/form';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import { validateSendTx } from 'util/form-validation';
|
import validateSendTx from 'util/form-validation';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
import LbcSymbol from 'component/common/lbc-symbol';
|
import LbcSymbol from 'component/common/lbc-symbol';
|
||||||
import WalletSpendableBalanceHelp from 'component/walletSpendableBalanceHelp';
|
import WalletSpendableBalanceHelp from 'component/walletSpendableBalanceHelp';
|
||||||
|
import classnames from 'classnames';
|
||||||
type DraftTransaction = {
|
import ChannelSelector from 'component/channelSelector';
|
||||||
address: string,
|
import ClaimPreview from 'component/claimPreview';
|
||||||
amount: ?number, // So we can use a placeholder in the input
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
openModal: (id: string, { address: string, amount: number }) => void,
|
openModal: (id: string, { destination: string, amount: string, isAddress: boolean }) => void,
|
||||||
|
draftTransaction: { address: string, amount: string },
|
||||||
|
setDraftTransaction: ({ address: string, amount: string }) => void,
|
||||||
balance: number,
|
balance: number,
|
||||||
|
isAddress: boolean,
|
||||||
|
setIsAddress: (boolean) => void,
|
||||||
|
contentUri: string,
|
||||||
|
contentError: string,
|
||||||
|
contentClaim?: StreamClaim,
|
||||||
|
setEnteredContentUri: (string) => void,
|
||||||
|
confirmed: boolean,
|
||||||
|
setConfirmed: (boolean) => void,
|
||||||
|
sendLabel: string,
|
||||||
|
setSendLabel: (string) => void,
|
||||||
|
snack: ?{
|
||||||
|
linkTarget: ?string,
|
||||||
|
linkText: ?string,
|
||||||
|
message: string,
|
||||||
|
isError: boolean,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class WalletSend extends React.PureComponent<Props> {
|
class WalletSend extends React.PureComponent<Props> {
|
||||||
|
@ -25,19 +41,49 @@ class WalletSend extends React.PureComponent<Props> {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
(this: any).handleClear = this.handleClear.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(values: DraftTransaction) {
|
handleSubmit() {
|
||||||
const { openModal } = this.props;
|
const { draftTransaction, openModal, isAddress, contentUri, setConfirmed } = this.props;
|
||||||
const { address, amount } = values;
|
const destination = isAddress ? draftTransaction.address : contentUri;
|
||||||
if (amount && address) {
|
const amount = draftTransaction.amount;
|
||||||
const modalProps = { address, amount };
|
|
||||||
openModal(MODALS.CONFIRM_TRANSACTION, modalProps);
|
const modalProps = { destination, amount, isAddress, setConfirmed };
|
||||||
}
|
|
||||||
|
openModal(MODALS.CONFIRM_TRANSACTION, modalProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClear() {
|
||||||
|
const { setDraftTransaction, setConfirmed } = this.props;
|
||||||
|
setDraftTransaction({
|
||||||
|
address: '',
|
||||||
|
amount: '',
|
||||||
|
});
|
||||||
|
setConfirmed(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { balance } = this.props;
|
const {
|
||||||
|
draftTransaction,
|
||||||
|
setDraftTransaction,
|
||||||
|
balance,
|
||||||
|
isAddress,
|
||||||
|
setIsAddress,
|
||||||
|
contentUri,
|
||||||
|
contentClaim,
|
||||||
|
setEnteredContentUri,
|
||||||
|
contentError,
|
||||||
|
confirmed,
|
||||||
|
sendLabel,
|
||||||
|
setSendLabel,
|
||||||
|
snack,
|
||||||
|
} = this.props;
|
||||||
|
if (confirmed) {
|
||||||
|
this.handleClear();
|
||||||
|
setSendLabel('Sending...');
|
||||||
|
}
|
||||||
|
if (snack) setSendLabel('Send');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
@ -54,60 +100,112 @@ class WalletSend extends React.PureComponent<Props> {
|
||||||
amount: '',
|
amount: '',
|
||||||
}}
|
}}
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
validate={validateSendTx}
|
render={({ values, errors, touched, handleBlur, handleSubmit }) => (
|
||||||
render={({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
|
<div>
|
||||||
<Form onSubmit={handleSubmit}>
|
<div className="section">
|
||||||
<fieldset-group class="fieldset-group--smushed">
|
|
||||||
<FormField
|
|
||||||
autoFocus
|
|
||||||
type="number"
|
|
||||||
name="amount"
|
|
||||||
label={__('Amount')}
|
|
||||||
className="form-field--price-amount"
|
|
||||||
affixClass="form-field--fix-no-height"
|
|
||||||
min="0"
|
|
||||||
step="any"
|
|
||||||
placeholder="12.34"
|
|
||||||
onChange={handleChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={values.amount}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
type="text"
|
|
||||||
name="address"
|
|
||||||
placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs"
|
|
||||||
className="form-field--address"
|
|
||||||
label={__('Recipient address')}
|
|
||||||
onChange={handleChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={values.address}
|
|
||||||
/>
|
|
||||||
</fieldset-group>
|
|
||||||
<div className="card__actions">
|
|
||||||
<Button
|
<Button
|
||||||
button="primary"
|
key="Address"
|
||||||
type="submit"
|
label={__('Address')}
|
||||||
label={__('Send')}
|
button="alt"
|
||||||
disabled={
|
onClick={() => setIsAddress(true)}
|
||||||
!values.address ||
|
className={classnames('button-toggle', { 'button-toggle--active': isAddress })}
|
||||||
!!Object.keys(errors).length ||
|
/>
|
||||||
!(parseFloat(values.amount) > 0.0) ||
|
<Button
|
||||||
parseFloat(values.amount) === balance
|
key="Search"
|
||||||
}
|
label={__('Search')}
|
||||||
|
button="alt"
|
||||||
|
onClick={() => setIsAddress(false)}
|
||||||
|
className={classnames('button-toggle', { 'button-toggle--active': !isAddress })}
|
||||||
/>
|
/>
|
||||||
{!!Object.keys(errors).length || (
|
|
||||||
<span className="error__text">
|
|
||||||
{(!!values.address && touched.address && errors.address) ||
|
|
||||||
(!!values.amount && touched.amount && errors.amount) ||
|
|
||||||
(parseFloat(values.amount) === balance &&
|
|
||||||
__('Decrease amount to account for transaction fee')) ||
|
|
||||||
(parseFloat(values.amount) > balance && __('Not enough Credits'))}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<WalletSpendableBalanceHelp />
|
|
||||||
</Form>
|
<div className="section">
|
||||||
|
{!isAddress && <ChannelSelector />}
|
||||||
|
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
{!isAddress && (
|
||||||
|
<FormField
|
||||||
|
type="text"
|
||||||
|
name="search"
|
||||||
|
error={contentError}
|
||||||
|
placeholder={__('Enter a name, @username or URL')}
|
||||||
|
className="form-field--address"
|
||||||
|
label={__('Recipient search')}
|
||||||
|
onChange={(event) => setEnteredContentUri(event.target.value)}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
value={values.search}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isAddress && (
|
||||||
|
<fieldset-section>
|
||||||
|
<ClaimPreview
|
||||||
|
key={contentUri}
|
||||||
|
uri={contentUri}
|
||||||
|
actions={''}
|
||||||
|
type={'small'}
|
||||||
|
showNullPlaceholder
|
||||||
|
hideMenu
|
||||||
|
hideRepostLabel
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<fieldset-group class="fieldset-group--smushed">
|
||||||
|
<FormField
|
||||||
|
autoFocus
|
||||||
|
type="number"
|
||||||
|
name="amount"
|
||||||
|
label={__('Amount')}
|
||||||
|
className="form-field--price-amount"
|
||||||
|
affixClass="form-field--fix-no-height"
|
||||||
|
min="0"
|
||||||
|
step="any"
|
||||||
|
placeholder="12.34"
|
||||||
|
onChange={(event) => setDraftTransaction({ address: draftTransaction.address, amount: event.target.value })}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
value={draftTransaction.amount}
|
||||||
|
/>
|
||||||
|
{isAddress && (
|
||||||
|
<FormField
|
||||||
|
type="text"
|
||||||
|
name="address"
|
||||||
|
placeholder={'bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs'}
|
||||||
|
className="form-field--address"
|
||||||
|
label={__('Recipient Address')}
|
||||||
|
onChange={(event) => setDraftTransaction({ address: event.target.value, amount: draftTransaction.amount })}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
value={draftTransaction.address}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</fieldset-group>
|
||||||
|
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
type="submit"
|
||||||
|
label={__(sendLabel)}
|
||||||
|
disabled={
|
||||||
|
!(parseFloat(draftTransaction.amount) > 0.0) ||
|
||||||
|
parseFloat(draftTransaction.amount) >= balance ||
|
||||||
|
sendLabel === 'Sending...' ||
|
||||||
|
(isAddress ? !draftTransaction.address || validateSendTx(draftTransaction.address).address !== '' : !contentClaim)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{!!Object.keys(errors).length || (
|
||||||
|
<span className="error__text">
|
||||||
|
{(!!draftTransaction.address && touched.address && errors.address) ||
|
||||||
|
(!!draftTransaction.amount && touched.amount && errors.amount) ||
|
||||||
|
(parseFloat(draftTransaction.amount) === balance &&
|
||||||
|
__('Decrease amount to account for transaction fee')) ||
|
||||||
|
(parseFloat(draftTransaction.amount) > balance && __('Not enough Credits'))}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<WalletSpendableBalanceHelp />
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doSendDraftTransaction } from 'lbry-redux';
|
import { doSendDraftTransaction, makeSelectClaimForUri, doSendTip } from 'lbry-redux';
|
||||||
import { doHideModal } from 'redux/actions/app';
|
import { doHideModal } from 'redux/actions/app';
|
||||||
import ModalConfirmTransaction from './view';
|
import ModalConfirmTransaction from './view';
|
||||||
|
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const select = (state, props) => ({
|
||||||
closeModal: () => dispatch(doHideModal()),
|
claim: makeSelectClaimForUri(props.destination)(state),
|
||||||
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
activeChannelClaim: selectActiveChannelClaim(state),
|
||||||
|
incognito: selectIncognito(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
const perform = (dispatch) => ({
|
||||||
null,
|
closeModal: () => dispatch(doHideModal()),
|
||||||
perform
|
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
||||||
)(ModalConfirmTransaction);
|
sendTip: (params, isSupport) => dispatch(doSendTip(params, isSupport)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(ModalConfirmTransaction);
|
||||||
|
|
|
@ -5,23 +5,40 @@ import { Form } from 'component/common/form';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import LbcSymbol from 'component/common/lbc-symbol';
|
import LbcSymbol from 'component/common/lbc-symbol';
|
||||||
|
import ClaimPreview from 'component/claimPreview';
|
||||||
|
|
||||||
|
type TipParams = { amount: number, claim_id: string, channel_id?: string };
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
address: string,
|
destination: string,
|
||||||
amount: number,
|
amount: number,
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
sendToAddress: (string, number) => void,
|
sendToAddress: (string, number) => void,
|
||||||
|
sendTip: (TipParams, boolean) => void,
|
||||||
|
isAddress: boolean,
|
||||||
|
claim: StreamClaim,
|
||||||
|
activeChannelClaim: ?ChannelClaim,
|
||||||
|
incognito: boolean,
|
||||||
|
setConfirmed: (boolean) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModalConfirmTransaction extends React.PureComponent<Props> {
|
class ModalConfirmTransaction extends React.PureComponent<Props> {
|
||||||
onConfirmed() {
|
onConfirmed() {
|
||||||
const { closeModal, sendToAddress, amount, address } = this.props;
|
const { closeModal, sendToAddress, sendTip, amount, destination, isAddress, claim, setConfirmed } = this.props;
|
||||||
sendToAddress(address, amount);
|
if (!isAddress) {
|
||||||
|
const claimId = claim && claim.claim_id;
|
||||||
|
const tipParams: TipParams = { amount: amount, claim_id: claimId };
|
||||||
|
sendTip(tipParams, false);
|
||||||
|
} else {
|
||||||
|
sendToAddress(destination, amount);
|
||||||
|
}
|
||||||
|
setConfirmed(true);
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { amount, address, closeModal } = this.props;
|
const { amount, destination, closeModal, isAddress, incognito, activeChannelClaim } = this.props;
|
||||||
|
const activeChannelUrl = activeChannelClaim && activeChannelClaim.canonical_url;
|
||||||
const title = __('Confirm Transaction');
|
const title = __('Confirm Transaction');
|
||||||
return (
|
return (
|
||||||
<Modal isOpen contentLabel={title} type="card" onAborted={closeModal}>
|
<Modal isOpen contentLabel={title} type="card" onAborted={closeModal}>
|
||||||
|
@ -33,8 +50,26 @@ class ModalConfirmTransaction extends React.PureComponent<Props> {
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<div className="confirm__label">{__('Sending')}</div>
|
<div className="confirm__label">{__('Sending')}</div>
|
||||||
<div className="confirm__value">{<LbcSymbol postfix={amount} size={22} />}</div>
|
<div className="confirm__value">{<LbcSymbol postfix={amount} size={22} />}</div>
|
||||||
|
|
||||||
|
{!isAddress && <div className="confirm__label">{__('From')}</div>}
|
||||||
|
{!isAddress && (
|
||||||
|
<div className="confirm__value">
|
||||||
|
{incognito ? (
|
||||||
|
'Anonymous'
|
||||||
|
) : (
|
||||||
|
<ClaimPreview key={activeChannelUrl} uri={activeChannelUrl} actions={''} type={'small'} hideMenu hideRepostLabel />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="confirm__label">{__('To')}</div>
|
<div className="confirm__label">{__('To')}</div>
|
||||||
<div className="confirm__value">{address}</div>
|
<div className="confirm__value">
|
||||||
|
{!isAddress ? (
|
||||||
|
<ClaimPreview key={destination} uri={destination} actions={''} type={'small'} hideMenu hideRepostLabel />
|
||||||
|
) : (
|
||||||
|
destination
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,111 @@ import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import LbcSymbol from 'component/common/lbc-symbol';
|
import LbcSymbol from 'component/common/lbc-symbol';
|
||||||
import WalletSend from 'component/walletSend';
|
import WalletSend from 'component/walletSend';
|
||||||
|
import { URL as SITE_URL, URL_LOCAL, URL_DEV } from 'config';
|
||||||
|
import { parseURI, isNameValid, isURIValid, normalizeURI } from 'lbry-redux';
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
export default function SendPage(props: Props) {
|
export default function SendPage(props: Props) {
|
||||||
|
const [isAddress, setIsAddress] = React.useState(true);
|
||||||
|
const [contentUri, setContentUri] = React.useState('');
|
||||||
|
const [draftTransaction, setDraftTransaction] = React.useState({ address: '', amount: '' });
|
||||||
|
const [enteredContent, setEnteredContentUri] = React.useState(undefined);
|
||||||
|
const contentFirstRender = React.useRef(true);
|
||||||
|
const [contentError, setContentError] = React.useState('');
|
||||||
|
const [confirmed, setConfirmed] = React.useState(false);
|
||||||
|
const [sendLabel, setSendLabel] = React.useState('Send');
|
||||||
|
|
||||||
|
function getSearchUri(value) {
|
||||||
|
const WEB_DEV_PREFIX = `${URL_DEV}/`;
|
||||||
|
const WEB_LOCAL_PREFIX = `${URL_LOCAL}/`;
|
||||||
|
const WEB_PROD_PREFIX = `${SITE_URL}/`;
|
||||||
|
const ODYSEE_PREFIX = `https://odysee.com/`;
|
||||||
|
const includesLbryTvProd = value.includes(WEB_PROD_PREFIX);
|
||||||
|
const includesOdysee = value.includes(ODYSEE_PREFIX);
|
||||||
|
const includesLbryTvLocal = value.includes(WEB_LOCAL_PREFIX);
|
||||||
|
const includesLbryTvDev = value.includes(WEB_DEV_PREFIX);
|
||||||
|
const wasCopiedFromWeb = includesLbryTvDev || includesLbryTvLocal || includesLbryTvProd || includesOdysee;
|
||||||
|
const isLbryUrl = value.startsWith('lbry://') && value !== 'lbry://';
|
||||||
|
const error = '';
|
||||||
|
|
||||||
|
const addLbryIfNot = term => {
|
||||||
|
return term.startsWith('lbry://') ? term : `lbry://${term}`;
|
||||||
|
};
|
||||||
|
if (wasCopiedFromWeb) {
|
||||||
|
let prefix = WEB_PROD_PREFIX;
|
||||||
|
if (includesLbryTvLocal) prefix = WEB_LOCAL_PREFIX;
|
||||||
|
if (includesLbryTvDev) prefix = WEB_DEV_PREFIX;
|
||||||
|
if (includesOdysee) prefix = ODYSEE_PREFIX;
|
||||||
|
|
||||||
|
let query = (value && value.slice(prefix.length).replace(/:/g, '#')) || '';
|
||||||
|
try {
|
||||||
|
const lbryUrl = `lbry://${query}`;
|
||||||
|
parseURI(lbryUrl);
|
||||||
|
return [lbryUrl, null];
|
||||||
|
} catch (e) {
|
||||||
|
return [query, 'error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLbryUrl) {
|
||||||
|
if (value.startsWith('@')) {
|
||||||
|
if (isNameValid(value.slice(1))) {
|
||||||
|
return [value, null];
|
||||||
|
} else {
|
||||||
|
return [value, error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [addLbryIfNot(value), null];
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const isValid = isURIValid(value);
|
||||||
|
if (isValid) {
|
||||||
|
let uri;
|
||||||
|
try {
|
||||||
|
uri = normalizeURI(value);
|
||||||
|
} catch (e) {
|
||||||
|
return [value, null];
|
||||||
|
}
|
||||||
|
return [uri, null];
|
||||||
|
} else {
|
||||||
|
return [value, null];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return [value, 'error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setContentUri given enteredUri
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!enteredContent && !contentFirstRender.current) {
|
||||||
|
setContentError(__('A name is required'));
|
||||||
|
}
|
||||||
|
if (enteredContent) {
|
||||||
|
contentFirstRender.current = false;
|
||||||
|
const [searchContent, error] = getSearchUri(enteredContent);
|
||||||
|
if (error) {
|
||||||
|
setContentError(__('Something not quite right..'));
|
||||||
|
} else {
|
||||||
|
setContentError('');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { streamName, channelName, isChannel } = parseURI(searchContent);
|
||||||
|
if (!isChannel && streamName && isNameValid(streamName)) {
|
||||||
|
// contentNameValid = true;
|
||||||
|
setContentUri(searchContent);
|
||||||
|
} else if (isChannel && channelName && isNameValid(channelName)) {
|
||||||
|
// contentNameValid = true;
|
||||||
|
setContentUri(searchContent);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (enteredContent !== '@') setContentError('');
|
||||||
|
setContentUri(``);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [enteredContent, setContentUri, setContentError, parseURI, isNameValid]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page
|
||||||
noSideNavigation
|
noSideNavigation
|
||||||
|
@ -20,7 +121,19 @@ export default function SendPage(props: Props) {
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<WalletSend />
|
<WalletSend
|
||||||
|
isAddress={isAddress}
|
||||||
|
setIsAddress={setIsAddress}
|
||||||
|
contentUri={contentUri}
|
||||||
|
contentError={contentError}
|
||||||
|
setEnteredContentUri={setEnteredContentUri}
|
||||||
|
confirmed={confirmed}
|
||||||
|
setConfirmed={setConfirmed}
|
||||||
|
draftTransaction={draftTransaction}
|
||||||
|
setDraftTransaction={setDraftTransaction}
|
||||||
|
sendLabel={sendLabel}
|
||||||
|
setSendLabel={setSendLabel}
|
||||||
|
/>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { regexAddress } from 'lbry-redux';
|
import { regexAddress } from 'lbry-redux';
|
||||||
|
|
||||||
type DraftTxValues = {
|
export default function validateSendTx(address: string) {
|
||||||
address: string,
|
const errors = {
|
||||||
// amount: number
|
address: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateSendTx = (formValues: DraftTxValues) => {
|
|
||||||
const { address } = formValues;
|
|
||||||
const errors = {};
|
|
||||||
|
|
||||||
// All we need to check is if the address is valid
|
// All we need to check is if the address is valid
|
||||||
// If values are missing, users wont' be able to submit the form
|
// If values are missing, users wont' be able to submit the form
|
||||||
|
|
Loading…
Reference in a new issue