fix frontend bug

show superchats in order properly

scroll properly when switching tabs

calculate fiat tips properly

sum up lbc amounts

refactor code a bit remove why isnt this working bit

bugfix cant tip fiat if no lbc balance

add toast when someone does a tip for a comment

add error toast for card page

show error on account connection page

automatically truncate to two decimals

close to working perfectly

show decimals value better

increase size of input value

one bug left but almost working perfectly

reverse so newest transactions come first

fixing bug caused by floating point precision

eslint fixes

remove unused conditional

get stuff ready for merge

bugfix and cleanup

requested changes

fixing flow errors

fix last flow error and touchups

fiat and lbc tabs coming along

support setting currency as the default tab via query param

add wallet fiat balance

fixing naming

add fiat transactions

using es6 to populate data

should be fine but keeps crashing

transaction listing working

add no transactions thing

about to add a third tab

add third tab

add card last 4 to transaction history

some renaming

show payments successfully

show filler for subscriptions

display if no transactions or subs

working but in the wrong component

approaching something thats working

showing total tipped amount

about to add last couple features

cleanup

More touchups

adding last features

calculate the total amount of unique creators tipped

couple touchups

remove transaction listings from settings

add view transactions buttons

small optimization

add subscriptions section

fix lot of linting errors and make command more userful
This commit is contained in:
Anthony 2021-07-22 22:37:49 +02:00 committed by zeppi
parent ff9ca662f2
commit 6532efdfad
12 changed files with 919 additions and 155 deletions

View file

@ -38,7 +38,7 @@
"build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null",
"crossenv": "./node_modules/cross-env/dist/bin/cross-env",
"lint": "eslint 'ui/**/*.{js,jsx}' && eslint 'web/**/*.{js,jsx}' && eslint 'electron/**/*.js' && flow",
"lint-fix": "eslint --fix 'ui/**/*.{js,jsx}' && eslint --fix 'web/**/*.{js,jsx}' && eslint --fix 'electron/**/*.js' && flow",
"lint-fix": "eslint --fix --quiet 'ui/**/*.{js,jsx}' && eslint --fix --quiet 'web/**/*.{js,jsx}' && eslint --fix --quiet 'electron/**/*.js'",
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write",
"flow-defs": "flow-typed install",
"precommit": "lint-staged",

View file

@ -0,0 +1,40 @@
import { connect } from 'react-redux';
import {
selectBalance,
selectClaimsBalance,
selectSupportsBalance,
selectTipsBalance,
selectIsFetchingUtxoCounts,
selectUtxoCounts,
doFetchUtxoCounts,
doUtxoConsolidate,
selectIsConsolidatingUtxos,
selectIsMassClaimingTips,
selectPendingConsolidateTxid,
selectPendingMassClaimTxid,
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectSyncHash } from 'redux/selectors/sync';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import WalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
claimsBalance: selectClaimsBalance(state) || 0,
supportsBalance: selectSupportsBalance(state) || 0,
tipsBalance: selectTipsBalance(state) || 0,
rewards: selectClaimedRewards(state),
hasSynced: Boolean(selectSyncHash(state)),
fetchingUtxoCounts: selectIsFetchingUtxoCounts(state),
consolidatingUtxos: selectIsConsolidatingUtxos(state),
massClaimingTips: selectIsMassClaimingTips(state),
utxoCounts: selectUtxoCounts(state),
consolidateIsPending: selectPendingConsolidateTxid(state),
massClaimIsPending: selectPendingMassClaimTxid(state),
});
export default connect(select, {
doOpenModal,
doFetchUtxoCounts,
doUtxoConsolidate,
})(WalletBalance);

View file

@ -0,0 +1,166 @@
// @flow
import React from 'react';
import Button from 'component/button';
import Card from 'component/common/card';
import { Lbryio } from 'lbryinc';
import moment from 'moment';
type Props = {
accountDetails: any,
transactions: any,
};
const WalletBalance = (props: Props) => {
// receive transactions from parent component
let accountTransactions = props.transactions;
// reverse so most recent payments come first
if (accountTransactions) {
accountTransactions = accountTransactions.reverse();
}
if (accountTransactions && accountTransactions.length > 10) {
accountTransactions.length = 10;
}
// const [detailsExpanded, setDetailsExpanded] = React.useState(false);
const [accountStatusResponse, setAccountStatusResponse] = React.useState();
const [subscriptions, setSubscriptions] = React.useState([]);
var environment = 'test';
function getAccountStatus() {
return Lbryio.call(
'account',
'status',
{
environment,
},
'post'
);
}
React.useEffect(() => {
(async function() {
const response = await getAccountStatus();
setAccountStatusResponse(response);
console.log(response);
})();
}, []);
return (
<><Card
title={'Tip History'}
body={(
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Processing Fee')}</th>
<th>{__('Odysee Fee')}</th>
<th>{__('Received Amount')}</th>
</tr>
</thead>
<tbody>
{accountTransactions &&
accountTransactions.map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>${transaction.transaction_fee / 100}</td>
<td>${transaction.application_fee / 100}</td>
<td>${transaction.received_amount / 100}</td>
</tr>
))}
</tbody>
</table>
{!accountTransactions && <p style={{textAlign: 'center', marginTop: '20px', fontSize: '13px', color: 'rgb(171, 171, 171)'}}>No Transactions</p>}
</div>
</>
)}
/>
<Card
title={__('Subscriptions')}
body={
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Card Last 4')}</th>
<th>{__('Anonymous')}</th>
</tr>
</thead>
<tbody>
{subscriptions &&
subscriptions.reverse().map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>{lastFour}</td>
<td>{transaction.private_tip ? 'Yes' : 'No'}</td>
</tr>
))}
</tbody>
</table>
{(!subscriptions || subscriptions.length === 0) && <p style={{textAlign: 'center', marginTop: '22px', fontSize: '13px', color: 'rgb(171, 171, 171)'}}>No Subscriptions</p>}
</div>
</>
}
/></>
);
};
export default WalletBalance;

View file

@ -0,0 +1,40 @@
import { connect } from 'react-redux';
import {
selectBalance,
selectClaimsBalance,
selectSupportsBalance,
selectTipsBalance,
selectIsFetchingUtxoCounts,
selectUtxoCounts,
doFetchUtxoCounts,
doUtxoConsolidate,
selectIsConsolidatingUtxos,
selectIsMassClaimingTips,
selectPendingConsolidateTxid,
selectPendingMassClaimTxid,
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectSyncHash } from 'redux/selectors/sync';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import WalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
claimsBalance: selectClaimsBalance(state) || 0,
supportsBalance: selectSupportsBalance(state) || 0,
tipsBalance: selectTipsBalance(state) || 0,
rewards: selectClaimedRewards(state),
hasSynced: Boolean(selectSyncHash(state)),
fetchingUtxoCounts: selectIsFetchingUtxoCounts(state),
consolidatingUtxos: selectIsConsolidatingUtxos(state),
massClaimingTips: selectIsMassClaimingTips(state),
utxoCounts: selectUtxoCounts(state),
consolidateIsPending: selectPendingConsolidateTxid(state),
massClaimIsPending: selectPendingMassClaimTxid(state),
});
export default connect(select, {
doOpenModal,
doFetchUtxoCounts,
doUtxoConsolidate,
})(WalletBalance);

View file

@ -0,0 +1,99 @@
// @flow
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import React from 'react';
import CreditAmount from 'component/common/credit-amount';
import Button from 'component/button';
import Card from 'component/common/card';
import Icon from 'component/common/icon';
import I18nMessage from 'component/i18nMessage';
type Props = {
accountDetails: any,
};
const WalletBalance = (props: Props) => {
const {
accountDetails,
} = props;
console.log('account details');
console.log(accountDetails);
const [detailsExpanded, setDetailsExpanded] = React.useState(false);
return (
<>{<Card
title={<><Icon size="18" icon={ICONS.FINANCE} />{(accountDetails && (accountDetails.total_received_unpaid / 100)) || 0} USD</>}
subtitle={
<I18nMessage>
This is your remaining balance that can still be withdrawn to your bank account
</I18nMessage>
}
actions={
<>
<h2 className="section__title--small">
${(accountDetails && (accountDetails.total_tipped / 100)) || 0} Total Received Tips
</h2>
<h2 className="section__title--small">
${(accountDetails && (accountDetails.total_paid_out / 100)) || 0} Withdrawn
<Button
button="link"
label={detailsExpanded ? __('View less') : __('View more')}
iconRight={detailsExpanded ? ICONS.UP : ICONS.DOWN}
onClick={() => setDetailsExpanded(!detailsExpanded)}
/>
</h2>
{/* view more section */}
{detailsExpanded && (
<div className="section__subtitle">
<dl>
<dt>
<span className="dt__text">{__('Earned from uploads')}</span>
{/* <span className="help--dt">({__('Earned from channel page')})</span> */}
</dt>
<dd>
<span className="dd__text">
{Boolean(1) && (
<Button
button="link"
className="dd__button"
icon={ICONS.UNLOCK}
/>
)}
<CreditAmount amount={1} precision={4} />
</span>
</dd>
<dt>
<span className="dt__text">{__('Earned from channel page')}</span>
{/* <span className="help--dt">({__('Delete or edit past content to spend')})</span> */}
</dt>
<dd>
<CreditAmount amount={1} precision={4} />
</dd>
{/* <dt> */}
{/* <span className="dt__text">{__('...supporting content')}</span> */}
{/* <span className="help--dt">({__('Delete supports to spend')})</span> */}
{/* </dt> */}
{/* <dd> */}
{/* <CreditAmount amount={1} precision={4} /> */}
{/* </dd> */}
</dl>
</div>
)}
<div className="section__actions">
<Button button="primary" label={__('Receive Payout')} icon={ICONS.SEND} />
<Button button="secondary" label={__('Account Configuration')} icon={ICONS.SETTINGS} navigate={`/$/${PAGES.SETTINGS_STRIPE_ACCOUNT}`} />
</div>
</>
}
/>}</>
);
};
export default WalletBalance;

View file

@ -0,0 +1,40 @@
import { connect } from 'react-redux';
import {
selectBalance,
selectClaimsBalance,
selectSupportsBalance,
selectTipsBalance,
selectIsFetchingUtxoCounts,
selectUtxoCounts,
doFetchUtxoCounts,
doUtxoConsolidate,
selectIsConsolidatingUtxos,
selectIsMassClaimingTips,
selectPendingConsolidateTxid,
selectPendingMassClaimTxid,
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectSyncHash } from 'redux/selectors/sync';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import WalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
claimsBalance: selectClaimsBalance(state) || 0,
supportsBalance: selectSupportsBalance(state) || 0,
tipsBalance: selectTipsBalance(state) || 0,
rewards: selectClaimedRewards(state),
hasSynced: Boolean(selectSyncHash(state)),
fetchingUtxoCounts: selectIsFetchingUtxoCounts(state),
consolidatingUtxos: selectIsConsolidatingUtxos(state),
massClaimingTips: selectIsMassClaimingTips(state),
utxoCounts: selectUtxoCounts(state),
consolidateIsPending: selectPendingConsolidateTxid(state),
massClaimIsPending: selectPendingMassClaimTxid(state),
});
export default connect(select, {
doOpenModal,
doFetchUtxoCounts,
doUtxoConsolidate,
})(WalletBalance);

View file

@ -0,0 +1,68 @@
// @flow
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import React from 'react';
import Button from 'component/button';
import Card from 'component/common/card';
import Icon from 'component/common/icon';
import I18nMessage from 'component/i18nMessage';
type Props = {
totalTippedAmount: number,
accountDetails: any,
transactions: any,
};
const WalletBalance = (props: Props) => {
const {
// accountDetails,
totalTippedAmount,
transactions,
} = props;
// const [detailsExpanded, setDetailsExpanded] = React.useState(false);
const [totalCreatorsSupported, setTotalCreatorsSupported] = React.useState(false);
// calculate how many unique users tipped
React.useEffect(() => {
if (transactions) {
let channelNames = [];
for (const transaction of transactions) {
channelNames.push(transaction.channel_name);
console.log(transaction.channel_name);
}
let unique = [...new Set(channelNames)];
setTotalCreatorsSupported(unique.length);
}
}, [transactions]);
return (
<>{<Card
title={<><Icon size="18" icon={ICONS.FINANCE} />{totalTippedAmount} USD</>}
subtitle={
<I18nMessage>
The total amount you have tipped to different creators
</I18nMessage>
}
actions={
<>
<h2 className="section__title--small">
{transactions && transactions.length} Total Tips
</h2>
<h2 className="section__title--small">
{totalCreatorsSupported || 0} Creators Supported
</h2>
<div className="section__actions">
<Button button="secondary" label={__('Manage Cards')} icon={ICONS.SETTINGS} navigate={`/$/${PAGES.SETTINGS_STRIPE_CARD}`} />
</div>
</>
}
/>}</>
);
};
export default WalletBalance;

View file

@ -0,0 +1,40 @@
import { connect } from 'react-redux';
import {
selectBalance,
selectClaimsBalance,
selectSupportsBalance,
selectTipsBalance,
selectIsFetchingUtxoCounts,
selectUtxoCounts,
doFetchUtxoCounts,
doUtxoConsolidate,
selectIsConsolidatingUtxos,
selectIsMassClaimingTips,
selectPendingConsolidateTxid,
selectPendingMassClaimTxid,
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectSyncHash } from 'redux/selectors/sync';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import WalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
claimsBalance: selectClaimsBalance(state) || 0,
supportsBalance: selectSupportsBalance(state) || 0,
tipsBalance: selectTipsBalance(state) || 0,
rewards: selectClaimedRewards(state),
hasSynced: Boolean(selectSyncHash(state)),
fetchingUtxoCounts: selectIsFetchingUtxoCounts(state),
consolidatingUtxos: selectIsConsolidatingUtxos(state),
massClaimingTips: selectIsMassClaimingTips(state),
utxoCounts: selectUtxoCounts(state),
consolidateIsPending: selectPendingConsolidateTxid(state),
massClaimIsPending: selectPendingMassClaimTxid(state),
});
export default connect(select, {
doOpenModal,
doFetchUtxoCounts,
doUtxoConsolidate,
})(WalletBalance);

View file

@ -0,0 +1,203 @@
// @flow
import React from 'react';
import Button from 'component/button';
import Card from 'component/common/card';
import { Lbryio } from 'lbryinc';
import moment from 'moment';
type Props = {
accountDetails: any,
transactions: any,
totalTippedAmount: number,
};
const WalletBalance = (props: Props) => {
// receive transactions from parent component
let accountTransactions = props.transactions;
console.log('heres transactions');
console.log(accountTransactions);
// let totalTippedAmount = props.totalTippedAmount;
// totalTippedAmount = 0;
// reverse so most recent payments come first
if (accountTransactions) {
accountTransactions = accountTransactions.reverse();
}
// const [detailsExpanded, setDetailsExpanded] = React.useState(false);
// const [accountStatusResponse, setAccountStatusResponse] = React.useState();
// const [totalTippedAmount, setTotalTippedAmount] = React.useState(0);
const [paymentHistoryTransactions, setPaymentHistoryTransactions] = React.useState();
const [subscriptions, setSubscriptions] = React.useState();
const [lastFour, setLastFour] = React.useState();
var environment = 'test';
// function getPaymentHistory() {
// return Lbryio.call(
// 'customer',
// 'list',
// {
// environment,
// },
// 'post'
// ); };
function getCustomerStatus() {
return Lbryio.call(
'customer',
'status',
{
environment,
},
'post'
);
}
React.useEffect(() => {
(async function() {
let response = accountTransactions;
console.log('payment transactions');
console.log(response);
const customerStatusResponse = await getCustomerStatus();
setLastFour(customerStatusResponse.PaymentMethods[0].card.last4);
if (response && response.length > 10) response.length = 10;
setPaymentHistoryTransactions(response);
const subscriptions = [...response];
if (subscriptions && subscriptions.length > 2) {
subscriptions.length = 2;
setSubscriptions([]);
} else {
setSubscriptions([]);
}
console.log(response);
})();
}, [accountTransactions]);
return (
<>
<Card
title={__('Payment History')}
body={
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Card Last 4')}</th>
<th>{__('Anonymous')}</th>
</tr>
</thead>
<tbody>
{accountTransactions &&
accountTransactions.map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>{lastFour}</td>
<td>{transaction.private_tip ? 'Yes' : 'No'}</td>
</tr>
))}
</tbody>
</table>
{(!accountTransactions || accountTransactions.length === 0) && <p style={{textAlign: 'center', marginTop: '20px', fontSize: '13px', color: 'rgb(171, 171, 171)'}}>No Transactions</p>}
</div>
</>
}
/>
<Card
title={__('Subscriptions')}
body={
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Card Last 4')}</th>
<th>{__('Anonymous')}</th>
</tr>
</thead>
<tbody>
{subscriptions &&
subscriptions.reverse().map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>{lastFour}</td>
<td>{transaction.private_tip ? 'Yes' : 'No'}</td>
</tr>
))}
</tbody>
</table>
{(!subscriptions || subscriptions.length === 0) && <p style={{textAlign: 'center', marginTop: '22px', fontSize: '13px', color: 'rgb(171, 171, 171)'}}>No Subscriptions</p>}
</div>
</>
}
/>
</>
);
};
export default WalletBalance;

View file

@ -1,12 +1,12 @@
// @flow
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import React from 'react';
import Button from 'component/button';
import Card from 'component/common/card';
import Page from 'component/page';
import { Lbryio } from 'lbryinc';
import { URL, WEBPACK_WEB_PORT, STRIPE_PUBLIC_KEY } from 'config';
import moment from 'moment';
const isDev = process.env.NODE_ENV !== 'production';
@ -184,7 +184,7 @@ class StripeAccountConnection extends React.Component<Props, State> {
unpaidBalance,
accountNotConfirmedButReceivedTips,
pageTitle,
accountTransactions,
// accountTransactions,
} = this.state;
const { user } = this.props;
@ -228,25 +228,11 @@ class StripeAccountConnection extends React.Component<Props, State> {
<div>
<div>
<h3>{__('Congratulations! Your account has been connected with Odysee.')}</h3>
{unpaidBalance > 0 ? (
<div>
<br />
<h3>
{__('Your pending account balance is $%balance% USD.', { balance: unpaidBalance / 100 })}
</h3>
</div>
) : (
<div>
<br />
<h3>
{__('Your account balance is $0 USD. When you receive a tip you will see it here.')}
</h3>
</div>
)}
</div>
</div>
</div>
)}
{/* TODO: hopefully we won't be using this anymore and can remove it */}
{accountNotConfirmedButReceivedTips && (
<div className="card__body-actions">
<div>
@ -277,66 +263,16 @@ class StripeAccountConnection extends React.Component<Props, State> {
)}
</div>
}
actions={
<Button
button="primary"
label={__('View Transactions')}
icon={ICONS.SETTINGS}
navigate={`/$/${PAGES.WALLET}?tab=account-history`}
/>
}
/>
<br />
{/* customer already has transactions */}
{accountTransactions && accountTransactions.length > 0 && (
<Card
title={__('Tip History')}
body={
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Processing Fee')}</th>
<th>{__('Odysee Fee')}</th>
<th>{__('Received Amount')}</th>
</tr>
</thead>
<tbody>
{accountTransactions &&
accountTransactions.map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>${transaction.transaction_fee / 100}</td>
<td>${transaction.application_fee / 100}</td>
<td>${transaction.received_amount / 100}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
}
/>
)}
</Page>
);
} else {

View file

@ -11,6 +11,7 @@ import Plastic from 'react-plastic';
import Button from 'component/button';
import * as ICONS from 'constants/icons';
import * as MODALS from 'constants/modal_types';
import * as PAGES from 'constants/pages';
let stripeEnvironment = 'test';
// if the key contains pk_live it's a live key
@ -418,72 +419,18 @@ class SettingsStripeCard extends React.Component<Props, State> {
/>
</>
}
actions={
<Button
button="primary"
label={__('View Transactions')}
icon={ICONS.SETTINGS}
navigate={`/$/${PAGES.WALLET}?tab=payment-history`}
/>
}
/>
<br />
{/* if a user has no transactions yet */}
{(!customerTransactions || customerTransactions.length === 0) && (
<Card
title={__('Tip History')}
subtitle={__('You have not sent any tips yet. When you do they will appear here. ')}
/>
)}
</div>
)}
{/* customer already has transactions */}
{customerTransactions && customerTransactions.length > 0 && (
<Card
title={__('Tip History')}
body={
<>
<div className="table__wrapper">
<table className="table table--transactions">
<thead>
<tr>
<th className="date-header">{__('Date')}</th>
<th>{<>{__('Receiving Channel Name')}</>}</th>
<th>{__('Tip Location')}</th>
<th>{__('Amount (USD)')} </th>
<th>{__('Anonymous')}</th>
</tr>
</thead>
<tbody>
{customerTransactions &&
customerTransactions.reverse().map((transaction) => (
<tr key={transaction.name + transaction.created_at}>
<td>{moment(transaction.created_at).format('LLL')}</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.channel_claim_id}
label={transaction.channel_name}
button="link"
/>
</td>
<td>
<Button
className="stripe__card-link-text"
navigate={'/' + transaction.channel_name + ':' + transaction.source_claim_id}
label={
transaction.channel_claim_id === transaction.source_claim_id
? 'Channel Page'
: 'File Page'
}
button="link"
/>
</td>
<td>${transaction.tipped_amount / 100}</td>
<td>{transaction.private_tip ? 'Yes' : 'No'}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
}
/>
)}
</Page>
);
}

View file

@ -2,10 +2,15 @@
import React from 'react';
import { withRouter } from 'react-router';
import WalletBalance from 'component/walletBalance';
import WalletFiatBalance from 'component/walletFiatBalance';
import WalletFiatPaymentBalance from 'component/walletFiatPaymentBalance';
import WalletFiatAccountHistory from 'component/walletFiatAccountHistory';
import WalletFiatPaymentHistory from 'component/walletFiatPaymentHistory';
import TxoList from 'component/txoList';
import Page from 'component/page';
import Spinner from 'component/spinner';
import YrblWalletEmpty from 'component/yrblWalletEmpty';
import { Lbryio } from 'lbryinc';
type Props = {
history: { action: string, push: (string) => void, replace: (string) => void },
@ -14,6 +19,143 @@ type Props = {
};
const WalletPage = (props: Props) => {
console.log(props);
const stripeEnvironment = 'test';
const tab = new URLSearchParams(props.location.search).get('tab');
const [accountStatusResponse, setAccountStatusResponse] = React.useState();
const [accountTransactionResponse, setAccountTransactionResponse] = React.useState();
const [customerTransactions, setCustomerTransactions] = React.useState();
const [totalTippedAmount, setTotalTippedAmount] = React.useState(0);
function getPaymentHistory() {
return Lbryio.call(
'customer',
'list',
{
environment: stripeEnvironment,
},
'post'
); };
// function getCustomerStatus() {
// return Lbryio.call(
// 'customer',
// 'status',
// {
// environment: stripeEnvironment,
// },
// 'post'
// );
// }
function getAccountStatus() {
return Lbryio.call(
'account',
'status',
{
environment: stripeEnvironment,
},
'post'
);
}
function getAccountTransactionsa() {
return Lbryio.call(
'account',
'list',
{
environment: stripeEnvironment,
},
'post'
);
}
// calculate account transactions section
React.useEffect(() => {
(async function() {
try {
const response = await getAccountStatus();
setAccountStatusResponse(response);
// TODO: some weird naming clash hence getAccountTransactionsa
const getAccountTransactions = await getAccountTransactionsa();
setAccountTransactionResponse(getAccountTransactions);
} catch (err) {
console.log(err);
}
})();
}, []);
// populate customer payment data
React.useEffect(() => {
(async function() {
try {
// get card payments customer has made
const customerTransactionResponse = await getPaymentHistory();
let totalTippedAmount = 0;
for (const transaction of customerTransactionResponse) {
totalTippedAmount = totalTippedAmount + transaction.tipped_amount;
}
setTotalTippedAmount(totalTippedAmount / 100);
setCustomerTransactions(customerTransactionResponse);
} catch (err) {
console.log(err);
}
})();
}, []);
function focusLBCTab() {
document.getElementsByClassName('lbc-transactions')[0].style.display = 'inline';
document.getElementsByClassName('fiat-transactions')[0].style.display = 'none';
document.getElementsByClassName('payment-history-tab')[0].style.display = 'none';
document.getElementsByClassName('lbc-tab-switcher')[0].style.textDecoration = 'underline';
document.getElementsByClassName('fiat-tab-switcher')[0].style.textDecoration = 'none';
document.getElementsByClassName('fiat-payment-history-switcher')[0].style.textDecoration = 'none';
}
function focusAccountHistoryTab() {
document.getElementsByClassName('lbc-transactions')[0].style.display = 'none';
document.getElementsByClassName('payment-history-tab')[0].style.display = 'none';
document.getElementsByClassName('fiat-transactions')[0].style.display = 'inline';
document.getElementsByClassName('lbc-tab-switcher')[0].style.textDecoration = 'none';
document.getElementsByClassName('fiat-tab-switcher')[0].style.textDecoration = 'underline';
document.getElementsByClassName('fiat-payment-history-switcher')[0].style.textDecoration = 'none';
}
function focusPaymentHistoryTab() {
document.getElementsByClassName('lbc-transactions')[0].style.display = 'none';
document.getElementsByClassName('fiat-transactions')[0].style.display = 'none';
document.getElementsByClassName('payment-history-tab')[0].style.display = 'inline';
document.getElementsByClassName('lbc-tab-switcher')[0].style.textDecoration = 'none';
document.getElementsByClassName('fiat-tab-switcher')[0].style.textDecoration = 'none';
document.getElementsByClassName('fiat-payment-history-switcher')[0].style.textDecoration = 'underline';
}
// select the first tab
React.useEffect(() => {
if (tab === 'account-history') {
// if (1 === 2) {
focusAccountHistoryTab();
} else if (tab === 'payment-history') {
// } else if (1 === 2){
focusPaymentHistoryTab();
} else {
focusLBCTab();
}
}, []);
const { location, totalBalance } = props;
const { search } = location;
const showIntro = totalBalance === 0;
@ -21,23 +163,66 @@ const WalletPage = (props: Props) => {
return (
<Page>
{loading && (
<div className="main--empty">
<Spinner delayed />
</div>
)}
{!loading && (
<>
{showIntro ? (
<YrblWalletEmpty includeWalletLink />
) : (
<div className="card-stack">
<WalletBalance />
<TxoList search={search} />
</div>
)}
</>
)}
{/* tabs to switch between fiat and lbc */}
{/* lbc button */}
<h2 className="lbc-tab-switcher"
style={{display: 'inline-block', paddingBottom: '16px', marginRight: '14px', textUnderlineOffset: '4px', fontSize: '18px', marginLeft: '3px'}}
onClick={() => {
focusLBCTab();
}}
>LBC Wallet</h2>
{/* account history button */}
<h2 className="fiat-tab-switcher"
style={{display: 'inline-block', textUnderlineOffset: '4px', fontSize: '18px', marginRight: '14px'}}
onClick={() => {
focusAccountHistoryTab();
}}
>Account History</h2>
{/* payment history button */}
<h2 className="fiat-payment-history-switcher"
style={{display: 'inline-block', textUnderlineOffset: '4px', fontSize: '18px'}}
onClick={() => {
focusPaymentHistoryTab();
}}
>Payment History</h2>
{/* lbc wallet section */}
<div className="lbc-transactions">
{/* if the transactions are loading */}
{ loading && (
<div className="main--empty">
<Spinner delayed />
</div>
)}
{/* when the transactions are finished loading */}
{ !loading && (
<>
{showIntro ? (
<YrblWalletEmpty includeWalletLink />
) : (
<div className="card-stack">
<WalletBalance />
<TxoList search={search} />
</div>
)}
</>
)}
</div>
{/* account received transactions section */}
<div className="fiat-transactions" style={{display: 'none'}}>
<WalletFiatBalance accountDetails={accountStatusResponse} />
<div style={{paddingTop: '25px'}} />
<WalletFiatAccountHistory transactions={accountTransactionResponse} />
</div>
{/* fiat payment history for tips made by user */}
<div className="payment-history-tab" style={{display: 'none'}}>
<WalletFiatPaymentBalance transactions={customerTransactions} totalTippedAmount={totalTippedAmount} accountDetails={accountStatusResponse} />
<div style={{paddingTop: '25px'}} />
<WalletFiatPaymentHistory transactions={customerTransactions} />
</div>
</Page>
);
};