2021-07-06 22:28:29 +02:00
|
|
|
// @flow
|
|
|
|
import * as ICONS from 'constants/icons';
|
2021-08-13 19:59:43 +02:00
|
|
|
import * as PAGES from 'constants/pages';
|
2021-07-06 22:28:29 +02:00
|
|
|
import React from 'react';
|
|
|
|
import Button from 'component/button';
|
|
|
|
import Card from 'component/common/card';
|
|
|
|
import Page from 'component/page';
|
2021-08-13 19:59:43 +02:00
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
import { Lbryio } from 'lbryinc';
|
2021-08-18 00:34:16 +02:00
|
|
|
import { URL, WEBPACK_WEB_PORT } from 'config';
|
|
|
|
import { getStripeEnvironment } from 'util/stripe';
|
2021-07-06 22:28:29 +02:00
|
|
|
|
|
|
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
|
|
|
2021-08-18 00:34:16 +02:00
|
|
|
let stripeEnvironment = getStripeEnvironment();
|
2021-07-06 22:28:29 +02:00
|
|
|
let successStripeRedirectUrl, failureStripeRedirectUrl;
|
|
|
|
let successEndpoint = '/$/settings/tip_account';
|
|
|
|
let failureEndpoint = '/$/settings/tip_account';
|
|
|
|
if (isDev) {
|
|
|
|
successStripeRedirectUrl = 'http://localhost:' + WEBPACK_WEB_PORT + successEndpoint;
|
|
|
|
failureStripeRedirectUrl = 'http://localhost:' + WEBPACK_WEB_PORT + failureEndpoint;
|
|
|
|
} else {
|
|
|
|
successStripeRedirectUrl = URL + successEndpoint;
|
|
|
|
failureStripeRedirectUrl = URL + failureEndpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
source: string,
|
2021-08-11 22:58:55 +02:00
|
|
|
doOpenModal: (string, {}) => void,
|
|
|
|
doToast: ({ message: string }) => void,
|
2021-07-06 22:28:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
type State = {
|
|
|
|
error: boolean,
|
|
|
|
loading: boolean,
|
|
|
|
content: ?string,
|
|
|
|
stripeConnectionUrl: string,
|
|
|
|
accountConfirmed: boolean,
|
|
|
|
accountPendingConfirmation: boolean,
|
|
|
|
accountNotConfirmedButReceivedTips: boolean,
|
|
|
|
unpaidBalance: number,
|
|
|
|
pageTitle: string,
|
2021-08-13 19:59:43 +02:00
|
|
|
stillRequiringVerification: boolean,
|
2021-08-18 00:34:16 +02:00
|
|
|
accountTransactions: any,
|
2021-07-06 22:28:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class StripeAccountConnection extends React.Component<Props, State> {
|
|
|
|
constructor(props: Props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
error: false,
|
|
|
|
content: null,
|
|
|
|
loading: true,
|
|
|
|
accountConfirmed: false,
|
|
|
|
accountPendingConfirmation: false,
|
|
|
|
accountNotConfirmedButReceivedTips: false,
|
|
|
|
unpaidBalance: 0,
|
|
|
|
stripeConnectionUrl: '',
|
|
|
|
pageTitle: 'Add Payout Method',
|
2021-08-13 20:22:33 +02:00
|
|
|
stillRequiringVerification: false,
|
2021-07-06 22:28:29 +02:00
|
|
|
accountTransactions: [],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
2021-08-11 22:58:55 +02:00
|
|
|
let doToast = this.props.doToast;
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
var that = this;
|
|
|
|
|
|
|
|
function getAndSetAccountLink(stillNeedToConfirmAccount) {
|
|
|
|
Lbryio.call(
|
|
|
|
'account',
|
|
|
|
'link',
|
|
|
|
{
|
|
|
|
return_url: successStripeRedirectUrl,
|
|
|
|
refresh_url: failureStripeRedirectUrl,
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
).then((accountLinkResponse) => {
|
|
|
|
// stripe link for user to navigate to and confirm account
|
|
|
|
const stripeConnectionUrl = accountLinkResponse.url;
|
|
|
|
|
|
|
|
// set connection url on frontend
|
|
|
|
that.setState({
|
|
|
|
stripeConnectionUrl,
|
|
|
|
});
|
|
|
|
|
|
|
|
// show the account confirmation link if not created already
|
|
|
|
if (stillNeedToConfirmAccount) {
|
|
|
|
that.setState({
|
|
|
|
accountPendingConfirmation: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// call the account status endpoint
|
|
|
|
Lbryio.call(
|
|
|
|
'account',
|
|
|
|
'status',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
)
|
|
|
|
.then((accountStatusResponse) => {
|
|
|
|
const yetToBeCashedOutBalance = accountStatusResponse.total_received_unpaid;
|
|
|
|
if (yetToBeCashedOutBalance) {
|
|
|
|
that.setState({
|
|
|
|
unpaidBalance: yetToBeCashedOutBalance,
|
|
|
|
});
|
|
|
|
|
|
|
|
Lbryio.call(
|
|
|
|
'account',
|
|
|
|
'list',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
2021-07-17 18:08:53 +02:00
|
|
|
).then((accountListResponse: any) => {
|
|
|
|
// TODO type this
|
|
|
|
that.setState({
|
2021-08-11 22:58:55 +02:00
|
|
|
accountTransactions: accountListResponse.reverse(),
|
2021-07-06 22:28:29 +02:00
|
|
|
});
|
2021-07-17 18:08:53 +02:00
|
|
|
});
|
2021-07-06 22:28:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// if charges already enabled, no need to generate an account link
|
|
|
|
if (accountStatusResponse.charges_enabled) {
|
|
|
|
// account has already been confirmed
|
|
|
|
|
2021-08-13 19:59:43 +02:00
|
|
|
const eventuallyDueInformation = accountStatusResponse.account_info.requirements.eventually_due;
|
|
|
|
|
|
|
|
const currentlyDueInformation = accountStatusResponse.account_info.requirements.currently_due;
|
|
|
|
|
|
|
|
let objectToUpdateState = {
|
2021-07-06 22:28:29 +02:00
|
|
|
accountConfirmed: true,
|
2021-08-13 19:59:43 +02:00
|
|
|
stillRequiringVerification: false,
|
|
|
|
};
|
|
|
|
|
2021-08-18 00:34:16 +02:00
|
|
|
if (
|
|
|
|
(eventuallyDueInformation && eventuallyDueInformation.length) ||
|
|
|
|
(currentlyDueInformation && currentlyDueInformation.length)
|
|
|
|
) {
|
2021-08-13 19:59:43 +02:00
|
|
|
objectToUpdateState.stillRequiringVerification = true;
|
|
|
|
getAndSetAccountLink(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
that.setState(objectToUpdateState);
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
// user has not confirmed an account but have received payments
|
|
|
|
} else if (accountStatusResponse.total_received_unpaid > 0) {
|
|
|
|
that.setState({
|
|
|
|
accountNotConfirmedButReceivedTips: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
getAndSetAccountLink();
|
|
|
|
|
|
|
|
// user has not received any amount or confirmed an account
|
|
|
|
} else {
|
|
|
|
// get stripe link and set it on the frontend
|
|
|
|
// pass true so it updates the frontend
|
|
|
|
getAndSetAccountLink(true);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function (error) {
|
|
|
|
// errorString passed from the API (with a 403 error)
|
|
|
|
const errorString = 'account not linked to user, please link first';
|
|
|
|
|
|
|
|
// if it's beamer's error indicating the account is not linked yet
|
|
|
|
if (error.message.indexOf(errorString) > -1) {
|
|
|
|
// get stripe link and set it on the frontend
|
2021-07-22 22:03:42 +02:00
|
|
|
getAndSetAccountLink(true);
|
2021-07-06 22:28:29 +02:00
|
|
|
} else {
|
2021-08-11 22:58:55 +02:00
|
|
|
// probably an error from stripe
|
|
|
|
const displayString = __('There was an error getting your account setup, please try again later');
|
|
|
|
doToast({ message: displayString, isError: true });
|
2021-07-06 22:28:29 +02:00
|
|
|
// not an error from Beamer, throw it
|
|
|
|
throw new Error(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const {
|
|
|
|
stripeConnectionUrl,
|
|
|
|
accountConfirmed,
|
|
|
|
accountPendingConfirmation,
|
|
|
|
unpaidBalance,
|
|
|
|
accountNotConfirmedButReceivedTips,
|
|
|
|
pageTitle,
|
2021-08-13 19:59:43 +02:00
|
|
|
stillRequiringVerification,
|
2021-07-06 22:28:29 +02:00
|
|
|
} = this.state;
|
|
|
|
|
2021-08-13 19:59:43 +02:00
|
|
|
return (
|
2021-08-19 07:58:40 +02:00
|
|
|
<Page
|
|
|
|
noFooter
|
|
|
|
noSideNavigation
|
|
|
|
settingsPage
|
|
|
|
className="card-stack"
|
|
|
|
backout={{ title: pageTitle, backLabel: __('Back') }}
|
|
|
|
>
|
2021-08-13 19:59:43 +02:00
|
|
|
<Card
|
|
|
|
title={<div className="table__header-text">{__('Connect a bank account')}</div>}
|
|
|
|
isBodyList
|
|
|
|
body={
|
|
|
|
<div>
|
|
|
|
{/* show while waiting for account status */}
|
|
|
|
{!accountConfirmed && !accountPendingConfirmation && !accountNotConfirmedButReceivedTips && (
|
|
|
|
<div className="card__body-actions">
|
|
|
|
<div>
|
2021-07-06 22:28:29 +02:00
|
|
|
<div>
|
2021-08-13 19:59:43 +02:00
|
|
|
<h3>{__('Getting your bank account connection status...')}</h3>
|
2021-07-06 22:28:29 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-08-13 19:59:43 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{/* user has yet to complete their integration */}
|
|
|
|
{!accountConfirmed && accountPendingConfirmation && (
|
|
|
|
<div className="card__body-actions">
|
|
|
|
<div>
|
2021-07-06 22:28:29 +02:00
|
|
|
<div>
|
2021-08-13 19:59:43 +02:00
|
|
|
<h3>{__('Connect your bank account to Odysee to receive donations directly from users')}</h3>
|
|
|
|
</div>
|
|
|
|
<div className="section__actions">
|
|
|
|
<a href={stripeConnectionUrl}>
|
|
|
|
<Button button="secondary" label={__('Connect your bank account')} icon={ICONS.FINANCE} />
|
|
|
|
</a>
|
2021-07-06 22:28:29 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-08-13 19:59:43 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{/* user has completed their integration */}
|
|
|
|
{accountConfirmed && (
|
|
|
|
<div className="card__body-actions">
|
|
|
|
<div>
|
2021-07-06 22:28:29 +02:00
|
|
|
<div>
|
2021-08-13 19:59:43 +02:00
|
|
|
<h3>{__('Congratulations! Your account has been connected with Odysee.')}</h3>
|
2021-08-18 00:34:16 +02:00
|
|
|
{stillRequiringVerification && (
|
|
|
|
<>
|
|
|
|
<h3 style={{ marginTop: '10px' }}>
|
|
|
|
Although your account is connected it still requires verification to begin receiving tips.
|
|
|
|
</h3>
|
|
|
|
<h3 style={{ marginTop: '10px' }}>
|
|
|
|
Please use the button below to complete your verification process and enable tipping for
|
|
|
|
your account.
|
|
|
|
</h3>
|
|
|
|
</>
|
|
|
|
)}
|
2021-07-06 22:28:29 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-08-13 19:59:43 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{/* TODO: hopefully we won't be using this anymore and can remove it */}
|
|
|
|
{accountNotConfirmedButReceivedTips && (
|
|
|
|
<div className="card__body-actions">
|
|
|
|
<div>
|
2021-07-06 22:28:29 +02:00
|
|
|
<div>
|
2021-08-13 19:59:43 +02:00
|
|
|
<h3>{__('Congratulations, you have already begun receiving tips on Odysee!')}</h3>
|
2021-07-06 22:28:29 +02:00
|
|
|
<div>
|
|
|
|
<br />
|
2021-08-13 19:59:43 +02:00
|
|
|
<h3>
|
|
|
|
{__('Your pending account balance is $%balance% USD.', { balance: unpaidBalance / 100 })}
|
|
|
|
</h3>
|
|
|
|
</div>
|
|
|
|
<br />
|
|
|
|
<div>
|
|
|
|
<h3>
|
2021-08-18 00:34:16 +02:00
|
|
|
{__('Connect your bank account to be able to cash your pending balance out to your account.')}
|
2021-08-13 19:59:43 +02:00
|
|
|
</h3>
|
|
|
|
</div>
|
|
|
|
<div className="section__actions">
|
|
|
|
<a href={stripeConnectionUrl}>
|
|
|
|
<Button button="secondary" label={__('Connect your bank account')} icon={ICONS.FINANCE} />
|
|
|
|
</a>
|
2021-07-06 22:28:29 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-08-13 19:59:43 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
}
|
2021-08-23 19:52:56 +02:00
|
|
|
// only show additional buttons if its for additional verification or to show transaction page
|
|
|
|
actions={(stillRequiringVerification || accountConfirmed) &&
|
2021-08-18 00:34:16 +02:00
|
|
|
<>
|
|
|
|
{stillRequiringVerification && (
|
|
|
|
<Button
|
|
|
|
button="primary"
|
|
|
|
label={__('Complete Verification')}
|
|
|
|
icon={ICONS.SETTINGS}
|
|
|
|
navigate={stripeConnectionUrl}
|
|
|
|
className="stripe__complete-verification-button"
|
|
|
|
/>
|
|
|
|
)}
|
2021-08-23 19:52:56 +02:00
|
|
|
{accountConfirmed && (
|
|
|
|
<Button
|
|
|
|
button="secondary"
|
|
|
|
label={__('View Transactions')}
|
|
|
|
icon={ICONS.SETTINGS}
|
|
|
|
navigate={`/$/${PAGES.WALLET}?fiatType=incoming&tab=fiat-payment-history¤cy=fiat`}
|
|
|
|
/>
|
|
|
|
)}
|
2021-08-18 00:34:16 +02:00
|
|
|
</>
|
2021-08-13 19:59:43 +02:00
|
|
|
}
|
|
|
|
/>
|
|
|
|
<br />
|
|
|
|
</Page>
|
|
|
|
);
|
2021-07-06 22:28:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default StripeAccountConnection;
|