Compare commits

...

4 commits

2 changed files with 63 additions and 21 deletions

View file

@ -22,6 +22,8 @@ const DEFAULT_TIP_AMOUNTS = [1, 5, 25, 100];
const MINIMUM_FIAT_TIP = 1; const MINIMUM_FIAT_TIP = 1;
const MAXIMUM_FIAT_TIP = 1000; const MAXIMUM_FIAT_TIP = 1000;
const DEFAULT_TIP_ERROR = __('Sorry, there was an error in processing your payment!');
const TAB_BOOST = 'TabBoost'; const TAB_BOOST = 'TabBoost';
const TAB_FIAT = 'TabFiat'; const TAB_FIAT = 'TabFiat';
const TAB_LBC = 'TabLBC'; const TAB_LBC = 'TabLBC';
@ -64,20 +66,48 @@ function WalletSendTip(props: Props) {
doToast, doToast,
isAuthenticated, isAuthenticated,
} = props; } = props;
/** REACT STATE **/
const [presetTipAmount, setPresetTipAmount] = usePersistedState('comment-support:presetTip', DEFAULT_TIP_AMOUNTS[0]); const [presetTipAmount, setPresetTipAmount] = usePersistedState('comment-support:presetTip', DEFAULT_TIP_AMOUNTS[0]);
const [customTipAmount, setCustomTipAmount] = usePersistedState('comment-support:customTip', 1.0); const [customTipAmount, setCustomTipAmount] = usePersistedState('comment-support:customTip', 1.0);
const [useCustomTip, setUseCustomTip] = usePersistedState('comment-support:useCustomTip', false); const [useCustomTip, setUseCustomTip] = usePersistedState('comment-support:useCustomTip', false);
const [tipError, setTipError] = React.useState();
const [isConfirming, setIsConfirming] = React.useState(false); const [isConfirming, setIsConfirming] = React.useState(false);
// only allow certain creators to receive tips
const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(); // dont persist because it needs to be calc'd per creator
// show things conditionally based on if a user has a card already
const [hasCardSaved, setHasSavedCard] = usePersistedState('comment-support:hasCardSaved', false);
// show the tip error on the frontend
const [tipError, setTipError] = React.useState();
// denote which tab to show on the frontend
const [activeTab, setActiveTab] = usePersistedState(TAB_LBC);
// handle default active tab
React.useEffect(() => {
// force to boost tab if it's someone's own upload
if (claimIsMine) {
setActiveTab(TAB_BOOST);
} else {
// or set LBC tip as the default if none is set yet
if (!activeTab || activeTab === 'undefined') {
setActiveTab(TAB_LBC);
}
}
}, []);
// alphanumeric claim id
const { claim_id: claimId } = claim; const { claim_id: claimId } = claim;
// channel name used in url
const { channelName } = parseURI(uri); const { channelName } = parseURI(uri);
const activeChannelName = activeChannelClaim && activeChannelClaim.name; const activeChannelName = activeChannelClaim && activeChannelClaim.name;
const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id;
const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(); // dont persist because it needs to be calc'd per creator // setup variables for backend tip API
const [hasCardSaved, setHasSavedCard] = usePersistedState('comment-support:hasCardSaved', false);
// setup variables for tip API
let channelClaimId, tipChannelName; let channelClaimId, tipChannelName;
// if there is a signing channel it's on a file // if there is a signing channel it's on a file
if (claim.signing_channel) { if (claim.signing_channel) {
@ -114,7 +144,7 @@ function WalletSendTip(props: Props) {
} }
}, [channelClaimId, isAuthenticated, stripeEnvironment]); }, [channelClaimId, isAuthenticated, stripeEnvironment]);
// check if creator has an account saved // focus tip element if it exists
React.useEffect(() => { React.useEffect(() => {
const tipInputElement = document.getElementById('tip-input'); const tipInputElement = document.getElementById('tip-input');
if (tipInputElement) { if (tipInputElement) {
@ -122,6 +152,7 @@ function WalletSendTip(props: Props) {
} }
}, []); }, []);
// check if user can receive tips
React.useEffect(() => { React.useEffect(() => {
if (channelClaimId && stripeEnvironment) { if (channelClaimId && stripeEnvironment) {
Lbryio.call( Lbryio.call(
@ -147,11 +178,13 @@ function WalletSendTip(props: Props) {
} }
}, [channelClaimId, stripeEnvironment]); }, [channelClaimId, stripeEnvironment]);
// if user has no balance, used to show conditional frontend
const noBalance = balance === 0; const noBalance = balance === 0;
// the tip amount, based on if a preset or custom tip amount is being used
const tipAmount = useCustomTip ? customTipAmount : presetTipAmount; const tipAmount = useCustomTip ? customTipAmount : presetTipAmount;
const [activeTab, setActiveTab] = React.useState(TAB_BOOST); // get type of claim (stream/channel/repost/collection) for display on frontend
function getClaimTypeText() { function getClaimTypeText() {
if (claim.value_type === 'stream') { if (claim.value_type === 'stream') {
return __('Content'); return __('Content');
@ -167,6 +200,7 @@ function WalletSendTip(props: Props) {
} }
const claimTypeText = getClaimTypeText(); const claimTypeText = getClaimTypeText();
// icon to use or explainer text to show per tab
let iconToUse; let iconToUse;
let explainerText = ''; let explainerText = '';
if (activeTab === TAB_BOOST) { if (activeTab === TAB_BOOST) {
@ -231,7 +265,7 @@ function WalletSendTip(props: Props) {
setTipError(tipError); setTipError(tipError);
}, [tipAmount, balance, setTipError, activeTab]); }, [tipAmount, balance, setTipError, activeTab]);
// // make call to the backend to send lbc or fiat
function sendSupportOrConfirm(instantTipMaxAmount = null) { function sendSupportOrConfirm(instantTipMaxAmount = null) {
// send a tip // send a tip
if (!isConfirming && (!instantTipMaxAmount || !instantTipEnabled || tipAmount > instantTipMaxAmount)) { if (!isConfirming && (!instantTipMaxAmount || !instantTipEnabled || tipAmount > instantTipMaxAmount)) {
@ -271,6 +305,7 @@ function WalletSendTip(props: Props) {
} else if (isConfirming) { } else if (isConfirming) {
let sendAnonymously = !activeChannelClaim || incognito; let sendAnonymously = !activeChannelClaim || incognito;
// hit backend to send tip
Lbryio.call( Lbryio.call(
'customer', 'customer',
'tip', 'tip',
@ -297,10 +332,12 @@ function WalletSendTip(props: Props) {
}); });
}) })
.catch(function (error) { .catch(function (error) {
let displayError = 'Sorry, there was an error in processing your payment!'; // show error message from Stripe if one exists (being passed from backend by Beamer's API currently)
let displayError;
if (error.message !== 'payment intent failed to confirm') { if (error.message) {
displayError = error.message; displayError = error.message;
} else {
displayError = DEFAULT_TIP_ERROR;
} }
doToast({ message: displayError, isError: true }); doToast({ message: displayError, isError: true });
@ -385,6 +422,7 @@ function WalletSendTip(props: Props) {
// if it's a valid number display it, otherwise do an empty string // if it's a valid number display it, otherwise do an empty string
const displayAmount = !isNan(tipAmount) ? amountToShow : ''; const displayAmount = !isNan(tipAmount) ? amountToShow : '';
// build button text based on tab
if (activeTab === TAB_BOOST) { if (activeTab === TAB_BOOST) {
return claimIsMine return claimIsMine
? __('Boost Your %claimTypeText%', { claimTypeText }) ? __('Boost Your %claimTypeText%', { claimTypeText })
@ -396,12 +434,14 @@ function WalletSendTip(props: Props) {
} }
} }
// dont allow user to click send button
function shouldDisableAmountSelector(amount) { function shouldDisableAmountSelector(amount) {
return ( return (
(amount > balance && activeTab !== TAB_FIAT) || (activeTab === TAB_FIAT && (!hasCardSaved || !canReceiveFiatTip)) (amount > balance && activeTab !== TAB_FIAT) || (activeTab === TAB_FIAT && (!hasCardSaved || !canReceiveFiatTip))
); );
} }
// showed on confirm page above amount
function setConfirmLabel() { function setConfirmLabel() {
if (activeTab === TAB_LBC) { if (activeTab === TAB_LBC) {
return __('Tipping Credit'); return __('Tipping Credit');
@ -530,6 +570,7 @@ function WalletSendTip(props: Props) {
<ChannelSelector /> <ChannelSelector />
</div> </div>
{/* prompt to save a card */}
{activeTab === TAB_FIAT && !hasCardSaved && ( {activeTab === TAB_FIAT && !hasCardSaved && (
<h3 className="add-card-prompt"> <h3 className="add-card-prompt">
<Button navigate={`/$/${PAGES.SETTINGS_STRIPE_CARD}`} label={__('Add a Card')} button="link" />{' '} <Button navigate={`/$/${PAGES.SETTINGS_STRIPE_CARD}`} label={__('Add a Card')} button="link" />{' '}

View file

@ -361,12 +361,14 @@ class SettingsStripeCard extends React.Component<Props, State> {
className="card-stack" className="card-stack"
backout={{ title: __(pageTitle), backLabel: __('Back') }} backout={{ title: __(pageTitle), backLabel: __('Back') }}
> >
{/* if Stripe javascript didn't load */}
<div> <div>
{scriptFailedToLoad && ( {scriptFailedToLoad && (
<div className="error__text">{__('There was an error connecting to Stripe. Please try again later.')}</div> <div className="error__text">{__('There was an error connecting to Stripe. Please try again later.')}</div>
)} )}
</div> </div>
{/* initial markup to show while getting information */}
{currentFlowStage === 'loading' && ( {currentFlowStage === 'loading' && (
<div className="headerCard toConfirmCard"> <div className="headerCard toConfirmCard">
<Card title={__('Connect your card with Odysee')} subtitle={__('Getting your card connection status...')} /> <Card title={__('Connect your card with Odysee')} subtitle={__('Getting your card connection status...')} />
@ -407,7 +409,7 @@ class SettingsStripeCard extends React.Component<Props, State> {
/> />
<br /> <br />
<Button <Button
button="secondary" button="primary"
label={__('Remove Card')} label={__('Remove Card')}
icon={ICONS.DELETE} icon={ICONS.DELETE}
onClick={(e) => { onClick={(e) => {
@ -419,15 +421,14 @@ class SettingsStripeCard extends React.Component<Props, State> {
}); });
}} }}
/> />
</>
}
actions={
<Button <Button
button="primary" button="secondary"
label={__('View Transactions')} label={__('View Transactions')}
icon={ICONS.SETTINGS} icon={ICONS.SETTINGS}
navigate={`/$/${PAGES.WALLET}?fiatType=outgoing&tab=fiat-payment-history&currency=fiat`} navigate={`/$/${PAGES.WALLET}?fiatType=outgoing&tab=fiat-payment-history&currency=fiat`}
style={{marginLeft: '10px'}}
/> />
</>
} }
/> />
<br /> <br />