send tip modal

This commit is contained in:
Sean Yesmunt 2018-01-31 13:26:06 -08:00
parent 2d80c35ead
commit b07c332c0f
9 changed files with 138 additions and 40 deletions

View file

@ -26,11 +26,12 @@ type FormFieldProps = {
prefix?: string,
postfix?: string,
error?: string | boolean,
helper?: string | React.Node,
};
export class FormField extends React.PureComponent<FormFieldProps> {
render() {
const { render, label, prefix, postfix, error } = this.props;
const { render, label, prefix, postfix, error, helper } = this.props;
/* eslint-disable jsx-a11y/label-has-for */
// Will come back to this on the settings page
// Need htmlFor on the label
@ -47,6 +48,7 @@ export class FormField extends React.PureComponent<FormFieldProps> {
{typeof error === 'string' ? error : __('There was an error')}
</div>
)}
{helper && <div className="form-field__help">{helper}</div>}
</div>
);
/* eslint-enable jsx-a11y/label-has-for */

View file

@ -1,66 +1,92 @@
// I'll come back to this
/* eslint-disable */
// @flow
import React from 'react';
import Link from 'component/link';
import { FormRow } from 'component/common/form';
import Button from 'component/link';
import { FormField } from 'component/common/form';
import UriIndicator from 'component/uriIndicator';
class WalletSendTip extends React.PureComponent {
constructor(props) {
type Props = {
claim_id: string,
uri: string,
title: string,
errorMessage: string,
isPending: boolean,
sendSupport: (number, string, string) => void,
onCancel: () => void,
sendTipCallback?: () => void,
};
type State = {
amount: number,
};
class WalletSendTip extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
amount: 0.0,
amount: 0,
};
(this: any).handleSendButtonClicked = this.handleSendButtonClicked.bind(this);
}
handleSendButtonClicked() {
const { claim_id, uri } = this.props;
const amount = this.state.amount;
this.props.sendSupport(amount, claim_id, uri);
const { claim_id: claimId, uri, sendSupport, sendTipCallback } = this.props;
const { amount } = this.state;
sendSupport(amount, claimId, uri);
// ex: close modal
if (sendTipCallback) {
sendTipCallback();
}
}
handleSupportPriceChange(event) {
handleSupportPriceChange(event: SyntheticInputEvent<*>) {
this.setState({
amount: Number(event.target.value),
});
}
render() {
const { errorMessage, isPending, title, uri } = this.props;
const { errorMessage, isPending, title, uri, onCancel } = this.props;
return (
<div>
<div className="card__title-primary">
<h1>
{__('Send a tip')} <UriIndicator uri={uri} />
{__('Send a tip to')} <UriIndicator uri={uri} />
</h1>
</div>
<div className="card__content">
<FormRow
<FormField
label={__('Amount')}
postfix={__('LBC')}
min="0"
step="any"
type="number"
errorMessage={errorMessage}
error={errorMessage}
helper={
<span>
{`${__('This will appear as a tip for "%s" located at %s.', title, uri)} `}
<Link label={__('Learn more')} href="https://lbry.io/faq/tipping" />
{__(`This will appear as a tip for ${title} located at ${uri}.`)}
{" "}
<Button label={__('Learn more')} fakeLink href="https://lbry.io/faq/tipping" />
</span>
}
placeholder="1.00"
onChange={event => this.handleSupportPriceChange(event)}
render={() => (
<input
min="0"
step="any"
type="number"
placeholder="1.00"
onChange={event => this.handleSupportPriceChange(event)}
/>
)}
/>
<div className="form-row-submit">
<Link
<div className="card__actions">
<Button
label={__('Send')}
button="primary"
disabled={isPending}
onClick={this.handleSendButtonClicked.bind(this)}
onClick={this.handleSendButtonClicked}
/>
<Link label={__('Cancel')} button="alt" navigate="/show" navigateParams={{ uri }} />
<Button alt label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
</div>
</div>
</div>
@ -69,4 +95,3 @@ class WalletSendTip extends React.PureComponent {
}
export default WalletSendTip;
/* eslint-enable */

View file

@ -14,3 +14,4 @@ export const TRANSACTION_FAILED = 'transaction_failed';
export const REWARD_APPROVAL_REQUIRED = 'reward_approval_required';
export const AFFIRM_PURCHASE = 'affirm_purchase';
export const CONFIRM_CLAIM_REVOKE = 'confirmClaimRevoke';
export const SEND_TIP = 'sendTip';

View file

@ -14,6 +14,7 @@ import ModalAffirmPurchase from 'modal/modalAffirmPurchase';
import ModalRevokeClaim from 'modal/modalRevokeClaim';
import ModalEmailCollection from '../modalEmailCollection';
import ModalPhoneCollection from '../modalPhoneCollection';
import ModalSendTip from '../modalSendTip';
import * as modals from 'constants/modal_types';
class ModalRouter extends React.PureComponent {
@ -129,6 +130,8 @@ class ModalRouter extends React.PureComponent {
return <ModalPhoneCollection {...modalProps} />;
case modals.EMAIL_COLLECTION:
return <ModalEmailCollection {...modalProps} />;
case modals.SEND_TIP:
return <ModalSendTip {...modalProps} />;
default:
return null;
}

View file

@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import { doCloseModal } from 'redux/actions/app';
import ModalSendTip from './view';
const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()),
});
export default connect(null, perform)(ModalSendTip);

View file

@ -0,0 +1,23 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import SendTip from 'component/walletSendTip';
type Props = {
closeModal: () => void,
uri: string,
};
class ModalSendTip extends React.PureComponent<Props> {
render() {
const { closeModal, uri } = this.props;
return (
<Modal isOpen type="custom">
<SendTip uri={uri} onCancel={closeModal} sendTipCallback={closeModal} />
</Modal>
);
}
}
export default ModalSendTip;

View file

@ -12,6 +12,7 @@ import {
import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info';
import { selectShowNsfw } from 'redux/selectors/settings';
import { selectMediaPaused } from 'redux/selectors/media';
import { doOpenModal } from 'redux/actions/app';
import FilePage from './view';
const select = (state, props) => ({
@ -30,6 +31,7 @@ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
});
export default connect(select, perform)(FilePage);

View file

@ -1,4 +1,4 @@
/* eslint-disable */
// @flow
import React from 'react';
import lbry from 'lbry';
import { buildURI, normalizeURI } from 'lbryURI';
@ -12,29 +12,58 @@ import Icon from 'component/common/icon';
import WalletSendTip from 'component/walletSendTip';
import DateTime from 'component/dateTime';
import * as icons from 'constants/icons';
import Link from 'component/link';
import Button from 'component/link';
import SubscribeButton from 'component/subscribeButton';
import Page from 'component/page';
import classnames from 'classnames';
import player from 'render-media';
import * as modals from 'constants/modal_types';
class FilePage extends React.PureComponent {
type Props = {
claim: {
claim_id: string,
height: number,
channel_name: string,
value: {
publisherSignature: ?{
certificateId: ?string
}
}
},
fileInfo: {},
metadata: {
title: string,
thumbnail: string,
nsfw: boolean
},
contentType: string,
uri: string,
rewardedContentClaimIds: Array<string>,
obscureNsfw: boolean,
playingUri: ?string,
isPaused: boolean,
openModal: (string, any) => void,
fetchFileInfo: (string) => void,
fetchCostInfo: (string) => void,
}
class FilePage extends React.Component<Props> {
componentDidMount() {
this.fetchFileInfo(this.props);
this.fetchCostInfo(this.props);
}
componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps: Props) {
this.fetchFileInfo(nextProps);
}
fetchFileInfo(props) {
fetchFileInfo(props: Props) {
if (props.fileInfo === undefined) {
props.fetchFileInfo(props.uri);
}
}
fetchCostInfo(props) {
fetchCostInfo(props: Props) {
if (props.costInfo === undefined) {
props.fetchCostInfo(props.uri);
}
@ -51,6 +80,7 @@ class FilePage extends React.PureComponent {
obscureNsfw,
playingUri,
isPaused,
openModal,
} = this.props;
// This should be included below in the page
@ -65,9 +95,9 @@ class FilePage extends React.PureComponent {
const shouldObscureThumbnail = obscureNsfw && metadata.nsfw;
const thumbnail = metadata.thumbnail;
const { height, channel_name: channelName, value } = claim;
const mediaType = lbry.getMediaType(contentType);
const isPlayable =
Object.values(player.mime).indexOf(contentType) !== -1 || mediaType === 'audio';
const mediaType = lbry.getMediaType(contentType);
const channelClaimId =
value && value.publisherSignature && value.publisherSignature.certificateId;
let subscriptionUri;
@ -76,7 +106,6 @@ class FilePage extends React.PureComponent {
}
const isPlaying = playingUri === uri && !isPaused;
console.log('isPlaying?', isPlaying);
return (
<Page>
@ -112,7 +141,12 @@ class FilePage extends React.PureComponent {
<div className="card__channel-info">
<UriIndicator uri={uri} link />
<div className="card__actions card__actions--no-margin">
<Link alt iconRight="Send" label={__('Enjoy this? Send a tip')} />
<Button
alt
iconRight="Send"
label={__('Enjoy this? Send a tip')}
onClick={() => openModal(modals.SEND_TIP, { uri })}
/>
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
</div>
</div>
@ -128,4 +162,3 @@ class FilePage extends React.PureComponent {
}
export default FilePage;
/* eslint-enable */

View file

@ -121,7 +121,7 @@
color: var(--color-grey-dark);
font-size: calc(var(--font-size-subtext-multiple) * 1em);
padding-top: $spacing-vertical * 1/3;
word-break: break-all;
word-break: break-word;
font-weight: 300;
}