transaction refactor / cleanup / improvement
This commit is contained in:
parent
f68136bd79
commit
65f65f1aea
16 changed files with 257 additions and 259 deletions
|
@ -8,15 +8,15 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
* Added a tipping button to send LBRY Credits to the publisher
|
* Added a tipping button to send LBRY Credits to a creator.
|
||||||
* Added edit button on published content / improved UX for editing claims.
|
* Added an edit button on published content. Significantly improved UX for editing claims.
|
||||||
|
* Significantly more detail is shown about past transactions and new filtering options for transactions.
|
||||||
* File pages now show the time of a publish.
|
* File pages now show the time of a publish.
|
||||||
* The "auth token" displayable on Help offers security warning
|
* The "auth token" displayable on Help offers security warning
|
||||||
* Added a new component for rendering dates and times. This component can render the date and time of a block height, as well.
|
* Added a new component for rendering dates and times. This component can render the date and time of a block height, as well.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
*
|
*
|
||||||
*
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* URLs on cards no longer wrap and show an ellipsis if longer than one line
|
* URLs on cards no longer wrap and show an ellipsis if longer than one line
|
||||||
|
|
|
@ -70,7 +70,7 @@ export class CreditAmount extends React.PureComponent {
|
||||||
showFree: React.PropTypes.bool,
|
showFree: React.PropTypes.bool,
|
||||||
showFullPrice: React.PropTypes.bool,
|
showFullPrice: React.PropTypes.bool,
|
||||||
showPlus: React.PropTypes.bool,
|
showPlus: React.PropTypes.bool,
|
||||||
look: React.PropTypes.oneOf(["indicator", "plain"]),
|
look: React.PropTypes.oneOf(["indicator", "plain", "fee"]),
|
||||||
fee: React.PropTypes.bool,
|
fee: React.PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +79,6 @@ export class CreditAmount extends React.PureComponent {
|
||||||
label: true,
|
label: true,
|
||||||
showFree: false,
|
showFree: false,
|
||||||
look: "indicator",
|
look: "indicator",
|
||||||
showFree: false,
|
|
||||||
showFullPrice: false,
|
showFullPrice: false,
|
||||||
showPlus: false,
|
showPlus: false,
|
||||||
fee: false,
|
fee: false,
|
||||||
|
@ -119,10 +118,7 @@ export class CreditAmount extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={`credit-amount credit-amount--${this.props.look} ${this.props
|
className={`credit-amount credit-amount--${this.props.look}`}
|
||||||
.fee
|
|
||||||
? " meta"
|
|
||||||
: ""}`}
|
|
||||||
title={fullPrice}
|
title={fullPrice}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
class DateTime extends React.PureComponent {
|
class DateTime extends React.PureComponent {
|
||||||
|
static SHOW_DATE = "date";
|
||||||
|
static SHOW_TIME = "time";
|
||||||
|
static SHOW_BOTH = "both";
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.refreshDate(this.props);
|
this.refreshDate(this.props);
|
||||||
}
|
}
|
||||||
|
@ -17,9 +21,20 @@ class DateTime extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { date } = this.props;
|
const { date, formatOptions } = this.props;
|
||||||
|
const show = this.props.show || DateTime.SHOW_BOTH;
|
||||||
|
|
||||||
return <span>{date && date.toLocaleString()}</span>;
|
return (
|
||||||
|
<span>
|
||||||
|
{date &&
|
||||||
|
(show == DateTime.SHOW_BOTH || show === DateTime.SHOW_DATE) &&
|
||||||
|
date.toLocaleDateString()}
|
||||||
|
{show == DateTime.SHOW_BOTH && " "}
|
||||||
|
{date &&
|
||||||
|
(show == DateTime.SHOW_BOTH || show === DateTime.SHOW_TIME) &&
|
||||||
|
date.toLocaleTimeString()}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import Link from "./view";
|
import LinkTransaction from "./view";
|
||||||
|
|
||||||
export default connect(null, null)(Link);
|
export default connect(null, null)(LinkTransaction);
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { doNavigate } from "actions/navigation";
|
import { doNavigate } from "actions/navigation";
|
||||||
|
import { selectClaimedRewardsByTransactionId } from "selectors/rewards";
|
||||||
import TransactionList from "./view";
|
import TransactionList from "./view";
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
rewards: selectClaimedRewardsByTransactionId(state),
|
||||||
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import LinkTransaction from "component/linkTransaction";
|
|
||||||
import { CreditAmount } from "component/common";
|
|
||||||
|
|
||||||
class TransactionTableBody extends React.PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
getClaimLink(claim_name, claim_id) {
|
|
||||||
let uri = `lbry://${claim_name}#${claim_id}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a className="button-text" onClick={() => this.props.navigate(uri)}>
|
|
||||||
{claim_name}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
filterList(transaction) {
|
|
||||||
if (this.props.filter == "claim") {
|
|
||||||
return transaction.claim_info.length > 0;
|
|
||||||
} else if (this.props.filter == "support") {
|
|
||||||
return transaction.support_info.length > 0;
|
|
||||||
} else if (this.props.filter == "update") {
|
|
||||||
return transaction.update_info.length > 0;
|
|
||||||
} else {
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderBody(transaction) {
|
|
||||||
const txid = transaction.id;
|
|
||||||
const date = transaction.date;
|
|
||||||
const fee = transaction.fee;
|
|
||||||
const filter = this.props.filter;
|
|
||||||
const options = {
|
|
||||||
weekday: "short",
|
|
||||||
year: "2-digit",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (filter == "tipSupport")
|
|
||||||
transaction["tipSupport_info"] = transaction["support_info"].filter(
|
|
||||||
tx => tx.is_tip
|
|
||||||
);
|
|
||||||
|
|
||||||
return filter != "unfiltered"
|
|
||||||
? transaction[`${filter}_info`].map(item => {
|
|
||||||
return (
|
|
||||||
<tr key={`${txid}:${item.nout}`}>
|
|
||||||
<td>
|
|
||||||
{date
|
|
||||||
? date.toLocaleDateString("en-US", options)
|
|
||||||
: <span className="empty">
|
|
||||||
{__("(Transaction pending)")}
|
|
||||||
</span>}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<CreditAmount
|
|
||||||
amount={item.amount}
|
|
||||||
look="plain"
|
|
||||||
label={false}
|
|
||||||
showPlus={true}
|
|
||||||
precision={8}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<CreditAmount
|
|
||||||
amount={fee}
|
|
||||||
look="plain"
|
|
||||||
fee={true}
|
|
||||||
label={false}
|
|
||||||
precision={8}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{this.getClaimLink(item.claim_name, item.claim_id)}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<LinkTransaction id={txid} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: <tr key={txid}>
|
|
||||||
<td>
|
|
||||||
{date
|
|
||||||
? date.toLocaleDateString("en-US", options)
|
|
||||||
: <span className="empty">
|
|
||||||
{__("(Transaction pending)")}
|
|
||||||
</span>}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<CreditAmount
|
|
||||||
amount={transaction.amount}
|
|
||||||
look="plain"
|
|
||||||
label={false}
|
|
||||||
showPlus={true}
|
|
||||||
precision={8}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<CreditAmount
|
|
||||||
amount={fee}
|
|
||||||
look="plain"
|
|
||||||
fee={true}
|
|
||||||
label={false}
|
|
||||||
precision={8}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<LinkTransaction id={txid} />
|
|
||||||
</td>
|
|
||||||
</tr>;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFeeTx(transaction) {
|
|
||||||
if (this.props.filter == "unfiltered")
|
|
||||||
return Math.abs(transaction.amount) != Math.abs(transaction.fee);
|
|
||||||
else return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { transactions, filter } = this.props;
|
|
||||||
let transactionList = transactions
|
|
||||||
.filter(this.filterList, this)
|
|
||||||
.filter(this.removeFeeTx, this)
|
|
||||||
.map(this.renderBody, this);
|
|
||||||
|
|
||||||
if (transactionList.length == 0) {
|
|
||||||
return (
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td className="empty" colSpan="3">
|
|
||||||
{__("There are no transactions of this type.")}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tbody>
|
|
||||||
{transactionList}
|
|
||||||
</tbody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TransactionTableBody;
|
|
|
@ -1,19 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
class TransactionTableHeader extends React.PureComponent {
|
|
||||||
render() {
|
|
||||||
const { filter } = this.props;
|
|
||||||
return (
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{__("Date")}</th>
|
|
||||||
<th>{__("Amount(Fee)")}</th>
|
|
||||||
{filter != "unfiltered" && <th> {__("Claim Name")} </th>}
|
|
||||||
<th>{__("Transaction")}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TransactionTableHeader;
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import React from "react";
|
||||||
|
import LinkTransaction from "component/linkTransaction";
|
||||||
|
import { CreditAmount } from "component/common";
|
||||||
|
import DateTime from "component/dateTime";
|
||||||
|
import Link from "component/link";
|
||||||
|
import lbryuri from "lbryuri";
|
||||||
|
|
||||||
|
class TransactionListItem extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
const { reward, transaction } = this.props;
|
||||||
|
const {
|
||||||
|
amount,
|
||||||
|
claim_id: claimId,
|
||||||
|
claim_name: name,
|
||||||
|
date,
|
||||||
|
fee,
|
||||||
|
txid,
|
||||||
|
type,
|
||||||
|
} = transaction;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{date
|
||||||
|
? <div>
|
||||||
|
<DateTime date={date} show={DateTime.SHOW_DATE} />
|
||||||
|
<div className="meta">
|
||||||
|
<DateTime date={date} show={DateTime.SHOW_TIME} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: <span className="empty">
|
||||||
|
{__("(Transaction pending)")}
|
||||||
|
</span>}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<CreditAmount
|
||||||
|
amount={amount}
|
||||||
|
look="plain"
|
||||||
|
label={false}
|
||||||
|
showPlus={true}
|
||||||
|
precision={8}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
{fee != 0 &&
|
||||||
|
<CreditAmount
|
||||||
|
amount={fee}
|
||||||
|
look="fee"
|
||||||
|
label={false}
|
||||||
|
precision={8}
|
||||||
|
/>}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{type}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{reward &&
|
||||||
|
<Link navigate="/rewards">
|
||||||
|
{__("Reward: %s", reward.reward_title)}
|
||||||
|
</Link>}
|
||||||
|
{name &&
|
||||||
|
claimId &&
|
||||||
|
<Link
|
||||||
|
className="button-text"
|
||||||
|
navigate="/show"
|
||||||
|
navigateParams={{ uri: lbryuri.build({ name, claimId }) }}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</Link>}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<LinkTransaction id={txid} />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TransactionListItem;
|
|
@ -1,6 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import TransactionTableHeader from "./internal/TransactionListHeader";
|
import TransactionListItem from "./internal/TransactionListItem";
|
||||||
import TransactionTableBody from "./internal/TransactionListBody";
|
|
||||||
import FormField from "component/formField";
|
import FormField from "component/formField";
|
||||||
|
|
||||||
class TransactionList extends React.PureComponent {
|
class TransactionList extends React.PureComponent {
|
||||||
|
@ -8,7 +7,7 @@ class TransactionList extends React.PureComponent {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
filter: "unfiltered",
|
filter: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,45 +17,63 @@ class TransactionList extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClaimNameClicked(uri) {
|
filterTransaction(transaction) {
|
||||||
this.props.navigate("/show", { uri });
|
const { filter } = this.state;
|
||||||
|
|
||||||
|
return !filter || filter == transaction.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { emptyMessage, transactions } = this.props;
|
const { emptyMessage, rewards, transactions } = this.props;
|
||||||
const { filter } = this.state;
|
|
||||||
|
|
||||||
if (!transactions || !transactions.length) {
|
let transactionList = transactions.filter(
|
||||||
return (
|
this.filterTransaction.bind(this)
|
||||||
<div className="empty">
|
);
|
||||||
{emptyMessage || __("No transactions to list.")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="sort-section">
|
{(transactionList.length || this.state.filter) &&
|
||||||
{__("Filter")} {" "}
|
<span className="sort-section">
|
||||||
<FormField
|
{__("Filter")} {" "}
|
||||||
type="select"
|
<FormField
|
||||||
onChange={this.handleFilterChanged.bind(this)}
|
type="select"
|
||||||
>
|
onChange={this.handleFilterChanged.bind(this)}
|
||||||
<option value="unfiltered">{__("All")}</option>
|
>
|
||||||
<option value="claim">{__("Publishes")}</option>
|
<option value="">{__("All")}</option>
|
||||||
<option value="support">{__("Supports")}</option>
|
<option value="spend">{__("Spends")}</option>
|
||||||
<option value="tipSupport">{__("Tips")}</option>
|
<option value="receive">{__("Receives")}</option>
|
||||||
<option value="update">{__("Updates")}</option>
|
<option value="publish">{__("Publishes")}</option>
|
||||||
</FormField>
|
<option value="channel">{__("Channels")}</option>
|
||||||
</span>
|
<option value="tip">{__("Tips")}</option>
|
||||||
<table className="table-standard table-stretch">
|
<option value="support">{__("Supports")}</option>
|
||||||
<TransactionTableHeader filter={filter} />
|
<option value="update">{__("Updates")}</option>
|
||||||
<TransactionTableBody
|
</FormField>
|
||||||
transactions={transactions}
|
</span>}
|
||||||
filter={filter}
|
{!transactionList.length &&
|
||||||
navigate={this.handleClaimNameClicked.bind(this)}
|
<div className="empty">
|
||||||
/>
|
{emptyMessage || __("No transactions to list.")}
|
||||||
</table>
|
</div>}
|
||||||
|
{Boolean(transactionList.length) &&
|
||||||
|
<table className="table-standard table-transactions table-stretch">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{__("Date")}</th>
|
||||||
|
<th>{__("Amount (Fee)")}</th>
|
||||||
|
<th>{__("Type")} </th>
|
||||||
|
<th>{__("Details")} </th>
|
||||||
|
<th>{__("Transaction")}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{transactionList.map(t =>
|
||||||
|
<TransactionListItem
|
||||||
|
key={`${t.txid}:${t.nout}`}
|
||||||
|
transaction={t}
|
||||||
|
reward={rewards && rewards[t.txid]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,11 +215,7 @@ class DiscoverPage extends React.PureComponent {
|
||||||
failedToLoad = !fetchingFeaturedUris && !hasContent;
|
failedToLoad = !fetchingFeaturedUris && !hasContent;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main
|
<main className={hasContent && fetchingFeaturedUris ? "reloading" : null}>
|
||||||
className={
|
|
||||||
hasContent && fetchingFeaturedUris ? "main--refreshing" : null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{!hasContent &&
|
{!hasContent &&
|
||||||
fetchingFeaturedUris &&
|
fetchingFeaturedUris &&
|
||||||
<BusyMessage message={__("Fetching content")} />}
|
<BusyMessage message={__("Fetching content")} />}
|
||||||
|
|
|
@ -10,18 +10,26 @@ class TransactionHistoryPage extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fetchingTransactions, transactions } = this.props;
|
const { fetchingTransactions, transactions } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<main className="main--single-column">
|
||||||
<SubHeader />
|
<SubHeader />
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card__title-primary">
|
<div
|
||||||
|
className={
|
||||||
|
"card__title-primary " +
|
||||||
|
(fetchingTransactions && transactions.length ? "reloading" : "")
|
||||||
|
}
|
||||||
|
>
|
||||||
<h3>{__("Transaction History")}</h3>
|
<h3>{__("Transaction History")}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
{fetchingTransactions &&
|
{fetchingTransactions && !transactions.length
|
||||||
<BusyMessage message={__("Loading transactions")} />}
|
? <BusyMessage message={__("Loading transactions")} />
|
||||||
{!fetchingTransactions &&
|
: ""}
|
||||||
<TransactionList transactions={transactions} />}
|
{transactions && transactions.length
|
||||||
|
? <TransactionList transactions={transactions} />
|
||||||
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -10,7 +10,7 @@ const buildDraftTransaction = () => ({
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
balance: undefined,
|
balance: undefined,
|
||||||
blocks: {},
|
blocks: {},
|
||||||
transactions: [],
|
transactions: {},
|
||||||
fetchingTransactions: false,
|
fetchingTransactions: false,
|
||||||
receiveAddress: address,
|
receiveAddress: address,
|
||||||
gettingNewAddress: false,
|
gettingNewAddress: false,
|
||||||
|
@ -25,20 +25,16 @@ reducers[types.FETCH_TRANSACTIONS_STARTED] = function(state, action) {
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[types.FETCH_TRANSACTIONS_COMPLETED] = function(state, action) {
|
reducers[types.FETCH_TRANSACTIONS_COMPLETED] = function(state, action) {
|
||||||
const oldTransactions = Object.assign({}, state.transactions);
|
let byId = Object.assign({}, state.transactions);
|
||||||
const byId = Object.assign({}, oldTransactions.byId);
|
|
||||||
const { transactions } = action.data;
|
const { transactions } = action.data;
|
||||||
|
|
||||||
transactions.forEach(transaction => {
|
transactions.forEach(transaction => {
|
||||||
byId[transaction.txid] = transaction;
|
byId[transaction.txid] = transaction;
|
||||||
});
|
});
|
||||||
|
|
||||||
const newTransactions = Object.assign({}, oldTransactions, {
|
|
||||||
byId: byId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
transactions: newTransactions,
|
transactions: byId,
|
||||||
fetchingTransactions: false,
|
fetchingTransactions: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,15 @@ export const selectClaimedRewards = createSelector(
|
||||||
byId => Object.values(byId) || []
|
byId => Object.values(byId) || []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectClaimedRewardsByTransactionId = createSelector(
|
||||||
|
selectClaimedRewards,
|
||||||
|
rewards =>
|
||||||
|
rewards.reduce((map, reward) => {
|
||||||
|
map[reward.transaction_id] = reward;
|
||||||
|
return map;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
export const selectUnclaimedRewards = createSelector(
|
export const selectUnclaimedRewards = createSelector(
|
||||||
selectUnclaimedRewardsByType,
|
selectUnclaimedRewardsByType,
|
||||||
byType =>
|
byType =>
|
||||||
|
|
|
@ -7,34 +7,70 @@ export const selectBalance = createSelector(
|
||||||
state => state.balance
|
state => state.balance
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectTransactions = createSelector(
|
|
||||||
_selectState,
|
|
||||||
state => state.transactions || {}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectTransactionsById = createSelector(
|
export const selectTransactionsById = createSelector(
|
||||||
selectTransactions,
|
_selectState,
|
||||||
transactions => transactions.byId || {}
|
state => state.transactions
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectTransactionItems = createSelector(
|
export const selectTransactionItems = createSelector(
|
||||||
selectTransactionsById,
|
selectTransactionsById,
|
||||||
byId => {
|
byId => {
|
||||||
const transactionItems = [];
|
const items = [];
|
||||||
const txids = Object.keys(byId);
|
|
||||||
txids.forEach(txid => {
|
Object.keys(byId).forEach(txid => {
|
||||||
const tx = byId[txid];
|
const tx = byId[txid];
|
||||||
transactionItems.push({
|
|
||||||
id: txid,
|
//ignore dust/fees
|
||||||
date: tx.timestamp ? new Date(parseInt(tx.timestamp) * 1000) : null,
|
if (Math.abs(tx.amount) === Math.abs(tx.fee)) {
|
||||||
amount: parseFloat(tx.value),
|
return;
|
||||||
claim_info: tx.claim_info,
|
}
|
||||||
support_info: tx.support_info,
|
|
||||||
update_info: tx.update_info,
|
let append = [];
|
||||||
fee: tx.fee,
|
|
||||||
});
|
append.push(
|
||||||
|
...tx.claim_info.map(item =>
|
||||||
|
Object.assign({}, item, {
|
||||||
|
type: item.claim_name[0] === "@" ? "channel" : "publish",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
append.push(
|
||||||
|
...tx.support_info.map(item =>
|
||||||
|
Object.assign({}, item, { type: !item.is_tip ? "support" : "tip" })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
append.push(
|
||||||
|
...tx.update_info.map(item =>
|
||||||
|
Object.assign({}, item, { type: "update" })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!append.length) {
|
||||||
|
append.push(
|
||||||
|
Object.assign({}, tx, {
|
||||||
|
type: tx.value < 0 ? "spend" : "receive",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(
|
||||||
|
...append.map(item => {
|
||||||
|
const amount = parseFloat(item.value || -1 * item.amount); //it's value on a transaction, amount on an outpoint (which has the sign the opposite way)
|
||||||
|
|
||||||
|
return {
|
||||||
|
txid: txid,
|
||||||
|
date: tx.timestamp ? new Date(parseInt(tx.timestamp) * 1000) : null,
|
||||||
|
amount: amount,
|
||||||
|
fee: amount < 0 ? -1 * tx.fee / append.length : 0,
|
||||||
|
claim_id: item.claim_id,
|
||||||
|
claim_name: item.claim_name,
|
||||||
|
type: item.type || "send",
|
||||||
|
nout: item.nout,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return transactionItems.reverse();
|
return items.reverse();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,11 @@ body
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--color-money);
|
color: var(--color-money);
|
||||||
}
|
}
|
||||||
|
.credit-amount--fee
|
||||||
|
{
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--color-meta-light);
|
||||||
|
}
|
||||||
|
|
||||||
#main-content
|
#main-content
|
||||||
{
|
{
|
||||||
|
@ -44,7 +49,8 @@ body
|
||||||
width: $width-page-constrained;
|
width: $width-page-constrained;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
main.main--refreshing {
|
|
||||||
|
.reloading {
|
||||||
&:before {
|
&:before {
|
||||||
$width: 30px;
|
$width: 30px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -60,3 +60,11 @@ table.table-standard {
|
||||||
table.table-stretch {
|
table.table-stretch {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.table-transactions {
|
||||||
|
td:nth-of-type(1) { width: 15%; }
|
||||||
|
td:nth-of-type(2) { width: 15%; }
|
||||||
|
td:nth-of-type(3) { width: 15%; }
|
||||||
|
td:nth-of-type(4) { width: 40%; }
|
||||||
|
td:nth-of-type(5) { width: 15%; }
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue