confirmation cleanup

This commit is contained in:
Sean Yesmunt 2020-06-15 10:04:44 -04:00
parent 01e0a2a5db
commit deb4107dd0
8 changed files with 146 additions and 167 deletions

View file

@ -135,7 +135,7 @@
"imagesloaded": "^4.1.4",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#70c2ffc0bd8b69e44fc867b98c4763f387494c4d",
"lbry-redux": "lbryio/lbry-redux#f8ac5359d9d05fba2c3a536003a9d4c64b86c9f0",
"lbryinc": "lbryio/lbryinc#3ceb09549cb5ec22927ce3bea44ae8dbe2e4a006",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",

View file

@ -8,6 +8,7 @@ import {
SETTINGS,
selectMyChannelClaims,
makeSelectClaimIsMine,
selectFetchingMyChannels,
} from 'lbry-redux';
import WalletSendTip from './view';
import { doOpenModal, doHideModal } from 'redux/actions/app';
@ -23,12 +24,13 @@ const select = (state, props) => ({
instantTipMax: makeSelectClientSetting(SETTINGS.INSTANT_PURCHASE_MAX)(state),
channels: selectMyChannelClaims(state),
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
fetchingChannels: selectFetchingMyChannels(state),
});
const perform = dispatch => ({
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
closeModal: () => dispatch(doHideModal()),
sendSupport: (amount, claimId, isSupport) => dispatch(doSendTip(amount, claimId, isSupport)),
sendSupport: (params, isSupport) => dispatch(doSendTip(params, isSupport)),
});
export default withRouter(connect(select, perform)(WalletSendTip));

View file

@ -1,11 +1,10 @@
// @flow
import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import React from 'react';
import Button from 'component/button';
import { FormField, Form } from 'component/common/form';
import { MINIMUM_PUBLISH_BID } from 'constants/claim';
import { MINIMUM_PUBLISH_BID, CHANNEL_ANONYMOUS } from 'constants/claim';
import useIsMobile from 'effects/use-is-mobile';
import CreditAmount from 'component/common/credit-amount';
import I18nMessage from 'component/i18nMessage';
@ -18,17 +17,19 @@ import usePersistedState from 'effects/use-persisted-state';
const DEFAULT_TIP_AMOUNTS = [5, 25, 100, 1000];
type SupportParams = { amount: number, claim_id: string, channel_id?: string };
type Props = {
uri: string,
claimIsMine: boolean,
title: string,
claim: StreamClaim,
isPending: boolean,
sendSupport: (number, string, boolean) => void,
sendSupport: (SupportParams, boolean) => void,
closeModal: () => void,
balance: number,
isSupport: boolean,
openModal: (id: string, { tipAmount: number, claimId: string, isSupport: boolean }) => void,
fetchingChannels: boolean,
instantTipEnabled: boolean,
instantTipMax: { amount: number, currency: string },
channels: ?Array<ChannelClaim>,
@ -44,19 +45,21 @@ function WalletSendTip(props: Props) {
claim = {},
instantTipEnabled,
instantTipMax,
openModal,
sendSupport,
closeModal,
channels,
fetchingChannels,
} = props;
const [tipAmount, setTipAmount] = React.useState(DEFAULT_TIP_AMOUNTS[0]);
const [tipError, setTipError] = React.useState();
const [isSupport, setIsSupport] = React.useState(claimIsMine);
const [showMore, setShowMore] = React.useState(false);
const [isConfirming, setIsConfirming] = React.useState(false);
const isMobile = useIsMobile();
const [selectedChannel, setSelectedChannel] = usePersistedState('comment-support:channel');
const { claim_id: claimId } = claim;
const { channelName } = parseURI(uri);
const channelStrings = channels && channels.map(channel => channel.permanent_url).join(',');
React.useEffect(() => {
if (!selectedChannel && channelStrings) {
@ -89,11 +92,27 @@ function WalletSendTip(props: Props) {
}, [tipAmount, balance, setTipError]);
function sendSupportOrConfirm(instantTipMaxAmount = null) {
if (!isSupport && (!instantTipMaxAmount || !instantTipEnabled || tipAmount > instantTipMaxAmount)) {
const modalProps = { uri, tipAmount, claimId, title, isSupport };
openModal(MODALS.CONFIRM_SEND_TIP, modalProps);
let selectedChannelId;
if (selectedChannel !== CHANNEL_ANONYMOUS) {
const selectedChannelClaim = channels && channels.find(channelClaim => channelClaim.name === selectedChannel);
if (selectedChannelClaim) {
selectedChannelId = selectedChannelClaim.claim_id;
}
}
if (
!isSupport &&
!isConfirming &&
(!instantTipMaxAmount || !instantTipEnabled || tipAmount > instantTipMaxAmount)
) {
setIsConfirming(true);
} else {
sendSupport(tipAmount, claimId, isSupport);
const supportParams: SupportParams = { amount: tipAmount, claim_id: claimId };
if (selectedChannelId) {
supportParams.channel_id = selectedChannelId;
}
sendSupport(supportParams, isSupport);
closeModal();
}
}
@ -147,94 +166,114 @@ function WalletSendTip(props: Props) {
</React.Fragment>
}
actions={
<>
<div className="section">
<SelectChannel
label="Channel to show support as"
channel={selectedChannel}
onChannelChange={newChannel => setSelectedChannel(newChannel)}
/>
</div>
isConfirming ? (
<>
<div className="section section--padded card--inline confirm__wrapper">
<div className="section">
<div className="confirm__label">{__('To')}</div>
<div className="confirm__value">{channelName || title}</div>
<div className="confirm__label">{__('From')}</div>
<div className="confirm__value">{selectedChannel}</div>
<div className="confirm__label">{__(isSupport ? 'Supporting' : 'Tipping')}</div>
<div className="confirm__value">{tipAmount} LBC</div>
</div>
</div>
<div className="section__actions">
<Button autoFocus button="primary" disabled={isPending} label={__('Confirm')} />
<Button button="link" label={__('Cancel')} onClick={() => setIsConfirming(false)} />
</div>
</>
) : (
<>
<div className="section">
<SelectChannel
label="Channel to show support as"
channel={selectedChannel}
onChannelChange={newChannel => setSelectedChannel(newChannel)}
/>
</div>
<div className="section">
{DEFAULT_TIP_AMOUNTS.map(amount => (
<div className="section">
{DEFAULT_TIP_AMOUNTS.map(amount => (
<Button
key={amount}
disabled={amount > balance}
button="alt"
className={classnames('button-toggle', {
'button-toggle--active': tipAmount === amount,
'button-toggle--disabled': amount > balance,
})}
label={`${amount} LBC`}
onClick={() => setTipAmount(amount)}
/>
))}
<Button
key={amount}
disabled={amount > balance}
button="alt"
className={classnames('button-toggle', {
'button-toggle--active': tipAmount === amount,
'button-toggle--disabled': amount > balance,
'button-toggle--active': !DEFAULT_TIP_AMOUNTS.includes(tipAmount),
})}
label={`${amount} LBC`}
onClick={() => setTipAmount(amount)}
/>
))}
<Button
button="alt"
className={classnames('button-toggle', {
'button-toggle--active': !DEFAULT_TIP_AMOUNTS.includes(tipAmount),
})}
label={__('Custom')}
onClick={() => setShowMore(true)}
/>
</div>
{showMore && (
<div className="section">
<FormField
autoFocus
name="tip-input"
label={
<React.Fragment>
{'Custom support amount'}{' '}
{isMobile && (
<I18nMessage tokens={{ lbc_balance: <CreditAmount badge={false} amount={balance} /> }}>
(%lbc_balance% available)
</I18nMessage>
)}
</React.Fragment>
}
className="form-field--price-amount"
error={tipError}
min="0"
step="any"
type="number"
placeholder="1.23"
onChange={event => handleSupportPriceChange(event)}
label={__('Custom')}
onClick={() => setShowMore(true)}
/>
</div>
)}
<div className="section__actions">
<Button
autoFocus
icon={isSupport ? undefined : ICONS.SUPPORT}
button="primary"
type="submit"
disabled={isPending || tipError || !tipAmount}
label={
isSupport
? __('Send Revokable Support')
: __('Send a %amount% Tip', { amount: tipAmount ? `${tipAmount} LBC` : '' })
}
/>
{!claimIsMine && (
<FormField
name="toggle-is-support"
type="checkbox"
label={__('Make this support permanent')}
checked={!isSupport}
onChange={() => setIsSupport(!isSupport)}
/>
{showMore && (
<div className="section">
<FormField
autoFocus
name="tip-input"
label={
<React.Fragment>
{'Custom support amount'}{' '}
{isMobile && (
<I18nMessage tokens={{ lbc_balance: <CreditAmount badge={false} amount={balance} /> }}>
(%lbc_balance% available)
</I18nMessage>
)}
</React.Fragment>
}
className="form-field--price-amount"
error={tipError}
min="0"
step="any"
type="number"
placeholder="1.23"
onChange={event => handleSupportPriceChange(event)}
/>
</div>
)}
</div>
{DEFAULT_TIP_AMOUNTS.some(val => val > balance) && (
<div className="section">
<Button button="link" label={__('Buy More LBC')} />
<div className="section__actions">
<Button
autoFocus
icon={isSupport ? undefined : ICONS.SUPPORT}
button="primary"
type="submit"
disabled={fetchingChannels || isPending || tipError || !tipAmount}
label={
isSupport
? __('Send Revokable Support')
: __('Send a %amount% Tip', { amount: tipAmount ? `${tipAmount} LBC` : '' })
}
/>
{fetchingChannels && <span className="help">{__('Loading your channels...')}</span>}
{!claimIsMine && !fetchingChannels && (
<FormField
name="toggle-is-support"
type="checkbox"
label={__('Make this support permanent')}
checked={!isSupport}
onChange={() => setIsSupport(!isSupport)}
/>
)}
</div>
)}
</>
{DEFAULT_TIP_AMOUNTS.some(val => val > balance) && (
<div className="section">
<Button button="link" label={__('Buy More LBC')} />
</div>
)}
</>
)
}
/>
)}

View file

@ -1,11 +0,0 @@
import { connect } from 'react-redux';
import { doSendTip } from 'lbry-redux';
import { doHideModal } from 'redux/actions/app';
import ModalConfirmSendTip from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()),
sendSupport: (tipAmount, claimId, isSupport) => dispatch(doSendTip(tipAmount, claimId, isSupport)),
});
export default connect(null, perform)(ModalConfirmSendTip);

View file

@ -1,61 +0,0 @@
// @flow
import React from 'react';
import { parseURI } from 'lbry-redux';
import Button from 'component/button';
import { Form } from 'component/common/form';
import { Modal } from 'modal/modal';
import Card from 'component/common/card';
type Props = {
uri: string,
claimId: string,
title: string,
tipAmount: number,
isSupport: boolean,
closeModal: () => void,
sendSupport: (number, string, boolean) => void,
};
class ModalConfirmSendTip extends React.PureComponent<Props> {
onConfirmed() {
const { closeModal, sendSupport, tipAmount, claimId, isSupport } = this.props;
sendSupport(tipAmount, claimId, isSupport);
closeModal();
}
render() {
const { tipAmount, title, isSupport, closeModal, uri } = this.props;
const cardTitle = __(isSupport ? 'Confirm Support' : 'Confirm Tip');
const { channelName } = parseURI(uri);
return (
<Modal isOpen type="card" onAborted={closeModal} contentLabel={cardTitle}>
<Form onSubmit={() => this.onConfirmed()}>
<Card
title={cardTitle}
body={
<>
<div className="section">
<label>{__(isSupport ? 'Supporting: ' : 'Tipping: ')}</label>
<blockquote>{tipAmount} LBC</blockquote>
</div>
<div className="section">
<label>{__('To: ')}</label>
<blockquote>{title || channelName}</blockquote>
</div>
</>
}
actions={
<div className="section__actions">
<Button autoFocus button="primary" type="submit" label={__('Send')} />
<Button button="link" label={__('Cancel')} onClick={closeModal} />
</div>
}
/>
</Form>
</Modal>
);
}
}
export default ModalConfirmSendTip;

View file

@ -19,7 +19,6 @@ import ModalFirstSubscription from 'modal/modalFirstSubscription';
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
import ModalSocialShare from 'modal/modalSocialShare';
import ModalSendTip from 'modal/modalSendTip';
import ModalConfirmSendTip from 'modal/modalConfirmSendTip';
import ModalPublish from 'modal/modalPublish';
import ModalOpenExternalResource from 'modal/modalOpenExternalResource';
import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload';
@ -97,8 +96,6 @@ function ModalRouter(props: Props) {
return <ModalFirstSubscription {...modalProps} />;
case MODALS.SEND_TIP:
return <ModalSendTip {...modalProps} />;
case MODALS.CONFIRM_SEND_TIP:
return <ModalConfirmSendTip {...modalProps} />;
case MODALS.SOCIAL_SHARE:
return <ModalSocialShare {...modalProps} />;
case MODALS.PUBLISH:

View file

@ -288,3 +288,16 @@ textarea {
.privacy-img {
height: 10rem;
}
.confirm__label {
@extend label;
}
.confirm__value {
margin-bottom: var(--spacing-m);
font-size: var(--font-large);
&:last-child {
margin-bottom: 0;
}
}

View file

@ -6207,9 +6207,9 @@ lazy-val@^1.0.4:
yargs "^13.2.2"
zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#70c2ffc0bd8b69e44fc867b98c4763f387494c4d:
lbry-redux@lbryio/lbry-redux#f8ac5359d9d05fba2c3a536003a9d4c64b86c9f0:
version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/70c2ffc0bd8b69e44fc867b98c4763f387494c4d"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/f8ac5359d9d05fba2c3a536003a9d4c64b86c9f0"
dependencies:
proxy-polyfill "0.1.6"
reselect "^3.0.0"