Skip to content

Commit

Permalink
Properly populate recent regular and stake transactions (decred#1174)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlyp authored Feb 19, 2018
1 parent 36b69c6 commit fdc325f
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 57 deletions.
69 changes: 57 additions & 12 deletions app/actions/ClientActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const getStartupWalletInfo = () => (dispatch) => {
setTimeout( async () => {
try {
await dispatch(getAccountsAttempt(true));
await dispatch(getMostRecentRegularTransactions());
await dispatch(getMostRecentStakeTransactions());
await dispatch(getMostRecentTransactions());
dispatch(findImmatureTransactions());
//dispatch(getStartupStats());
Expand Down Expand Up @@ -472,8 +474,8 @@ function filterTransactions(transactions, filter) {
// `grpc.noMoreTransactions` is set to true.
export const getTransactions = () => async (dispatch, getState) => {
const { getAccountsResponse, getTransactionsRequestAttempt,
transactionsFilter, walletService, maximumTransactionCount } = getState().grpc;
let { noMoreTransactions, lastTransaction, minedTransactions } = getState().grpc;
transactionsFilter, walletService, maximumTransactionCount, recentTransactionCount} = getState().grpc;
let { noMoreTransactions, lastTransaction, minedTransactions, recentRegularTransactions, recentStakeTransactions } = getState().grpc;
if (getTransactionsRequestAttempt || noMoreTransactions) return;

// Check to make sure getAccountsResponse (which has current block height) is available
Expand Down Expand Up @@ -521,8 +523,17 @@ export const getTransactions = () => async (dispatch, getState) => {
}

minedTransactions = [...minedTransactions, ...filtered];

if (transactionsFilter.types.indexOf(TransactionDetails.TransactionType.REGULAR) > -1) {
recentRegularTransactions = [...unminedTransactions, ...minedTransactions];
recentRegularTransactions = recentRegularTransactions.slice(0, recentTransactionCount);
} else if (transactionsFilter.types.indexOf(TransactionDetails.TransactionType.VOTE) > -1) {
recentStakeTransactions = [...unminedTransactions, ...minedTransactions];
recentStakeTransactions = recentStakeTransactions.slice(0, recentTransactionCount);
}

const stateChange = { unminedTransactions, minedTransactions,
noMoreTransactions, lastTransaction, type: GETTRANSACTIONS_COMPLETE};
noMoreTransactions, lastTransaction, recentRegularTransactions, recentStakeTransactions, type: GETTRANSACTIONS_COMPLETE};
dispatch(stateChange);
return stateChange;
};
Expand Down Expand Up @@ -553,7 +564,7 @@ function checkForStakeTransactions(txs) {
export const newTransactionsReceived = (newlyMinedTransactions, newlyUnminedTransactions) => (dispatch, getState) => {
if (!newlyMinedTransactions.length && !newlyUnminedTransactions.length) return;

let { unminedTransactions, minedTransactions, recentTransactions } = getState().grpc;
let { unminedTransactions, minedTransactions, recentRegularTransactions, recentStakeTransactions } = getState().grpc;
const { transactionsFilter, recentTransactionCount } = getState().grpc;
const chainParams = sel.chainParams(getState());

Expand All @@ -579,11 +590,30 @@ export const newTransactionsReceived = (newlyMinedTransactions, newlyUnminedTran
...unminedTransactions.filter(tx => !newlyMinedMap[tx.hash] && !newlyUnminedMap[tx.hash])
], transactionsFilter);

recentTransactions = [

const regularTransactionFilter = {
listDirection: "desc",
types: [TransactionDetails.TransactionType.REGULAR],
direction: null,
};

recentRegularTransactions = filterTransactions([
...newlyUnminedTransactions,
...newlyMinedTransactions,
...recentRegularTransactions.filter(tx => !newlyMinedMap[tx.hash] && !newlyUnminedMap[tx.hash])
], regularTransactionFilter).slice(0, recentTransactionCount);

const stakeTransactionFilter = {
listDirection: "desc",
types: [TransactionDetails.TransactionType.TICKET_PURCHASE, TransactionDetails.TransactionType.VOTE, TransactionDetails.TransactionType.REVOCATION],
direction: null,
};

recentStakeTransactions = filterTransactions([
...newlyUnminedTransactions,
...newlyMinedTransactions,
...recentTransactions.filter(tx => !newlyMinedMap[tx.hash] && !newlyUnminedMap[tx.hash])
].slice(0, recentTransactionCount);
...recentStakeTransactions.filter(tx => !newlyMinedMap[tx.hash] && !newlyUnminedMap[tx.hash])
], stakeTransactionFilter).slice(0, recentTransactionCount);

const { maturingBlockHeights } = getState().grpc;
const newMaturingHeights = {...maturingBlockHeights};
Expand All @@ -607,22 +637,37 @@ export const newTransactionsReceived = (newlyMinedTransactions, newlyUnminedTran
minedTransactions = filterTransactions(minedTransactions, transactionsFilter);

dispatch({unminedTransactions, minedTransactions, newlyUnminedTransactions,
newlyMinedTransactions, recentTransactions, type: NEW_TRANSACTIONS_RECEIVED});
newlyMinedTransactions, recentRegularTransactions, recentStakeTransactions, type: NEW_TRANSACTIONS_RECEIVED});
};

export const CLEAR_MOSTRECENTTRANSACTIONS = "CLEAR_MOSTRECENTTRANSACTIONS";

// getMostRecentTransactions clears the transaction filter and refetches
// getMostRecentRegularTransactions clears the transaction filter and refetches
// the first page of transactions. This is used to get and store the initial
// list of recent transactions.
export const getMostRecentRegularTransactions = () => dispatch => {
const defaultFilter = {
listDirection: "desc",
types: [TransactionDetails.TransactionType.REGULAR],
direction: null,
};
return dispatch(changeTransactionsFilter(defaultFilter));
};

export const getMostRecentStakeTransactions = () => dispatch => {
const defaultFilter = {
listDirection: "desc",
types: [TransactionDetails.TransactionType.TICKET_PURCHASE, TransactionDetails.TransactionType.VOTE, TransactionDetails.TransactionType.REVOCATION],
direction: null,
};
return dispatch(changeTransactionsFilter(defaultFilter));
};

export const getMostRecentTransactions = () => dispatch => {
const defaultFilter = {
search: null,
listDirection: "desc",
types: [],
direction: null,
};
dispatch({type: CLEAR_MOSTRECENTTRANSACTIONS});
return dispatch(changeTransactionsFilter(defaultFilter));
};

Expand Down
11 changes: 7 additions & 4 deletions app/components/views/HomePage/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import HomeHeader from "./HomeHeader";
const HomePage = ({
routes,
totalBalance,
tickets,
transactions,
getTransactionsRequestAttempt,
getAccountsResponse,
Expand All @@ -21,12 +22,14 @@ const HomePage = ({
{children}
</TabbedComponent>
<div className="overview-transactions-ticket-wrapper">
<div className="recent-transactions">
<div className={tickets.length > 0 ? "recent-transactions" : "recent-transactions-full"}>
<RecentTransactions {...{ routes, transactions, getTransactionsRequestAttempt, getAccountsResponse }} />
</div>
<div className="ticket-activity">
<TicketActivity {...{ routes, transactions, getTransactionsRequestAttempt, getAccountsResponse }} />
</div>
{tickets.length > 0 &&
<div className="recent-transactions">
<TicketActivity {...{ routes, tickets, getTransactionsRequestAttempt, getAccountsResponse }} />
</div>
}
</div>
</div>
);
Expand Down
9 changes: 6 additions & 3 deletions app/components/views/HomePage/RecentTransactions.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// @flow
import { home } from "connectors";
import { DecredLoading } from "indicators";
import TxHistory from "./TxHistory";
import SmallTxHistory from "./TxHistory";
import LargeTxHistory from "TxHistory";
import { FormattedMessage as T } from "react-intl";
import "style/Fonts.less";
import "style/HomePage.less";

const RecentTransactions = ({
tickets,
transactions,
getTransactionsRequestAttempt,
getAccountsResponse,
Expand All @@ -18,8 +20,9 @@ const RecentTransactions = ({
<T id="home.recentTransactionsTitle" m="Recent Transactions" />
</div>
<div className="home-content-nest">
{transactions.length > 0 ?
<TxHistory limit={5} {...{ getAccountsResponse, transactions }} /> :
{transactions.length > 0 ? tickets.length > 0 ?
<SmallTxHistory limit={6} {...{ getAccountsResponse, transactions }} /> :
<LargeTxHistory limit={6} {...{ getAccountsResponse, transactions }} /> :
<p><T id="home.noTransactions" m="No transactions" /></p>}
</div>
</Aux>
Expand Down
8 changes: 3 additions & 5 deletions app/components/views/HomePage/TicketActivity.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
import { home } from "connectors";
import { DecredLoading } from "indicators";
import TxHistory from "TxHistory";
import TxHistory from "./TxHistory";
import { FormattedMessage as T } from "react-intl";
import "style/Fonts.less";
import "style/HomePage.less";
Expand All @@ -15,12 +15,10 @@ const RecentTickets = ({
getTransactionsRequestAttempt ? <DecredLoading /> :
<Aux>
<div className="home-content-title">
<T id="home.ticketActivityTitle" m="Recent Tickets" />
<T id="home.ticketActivityTitle" m="Recent Staking Activity" />
</div>
<div className="home-content-nest">
{tickets.length > 0 ?
<TxHistory limit={5} {...{ getAccountsResponse, transactions: tickets }} /> :
<p><T id="home.noTickets" m="No tickets" /></p>}
<TxHistory limit={6} {...{ getAccountsResponse, transactions: tickets }} />
</div>
</Aux>
);
Expand Down
29 changes: 29 additions & 0 deletions app/components/views/HomePage/TxHistory/TxHistoryRow/StakeTxRow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Row from "./Row";
import { createElement as h } from "react";
import { FormattedMessage as T } from "react-intl";

const messageByType = { // TODO: use constants instead of string
"Ticket": <T id="transaction.type.ticket" m="Ticket" />,
"Revocation": <T id="transaction.type.revoke" m="Revoke" />,
"Vote": <T id="transaction.type.vote" m="Vote" />,
};

const StakeTxRow = ({ ...props }) => (
<Row {...props}>
<div className="transaction-info-overview">
<span className="icon" />
<span className="transaction-stake-type">{messageByType[props.className.split(" ")[0]] || "(unknown type)"}</span>
</div>
</Row>
);

export const StakeTxRowOfType = (className) => {
const Comp = ({ ...p }) => {
if(p.pending) {
className += " Pending";
}
return h(StakeTxRow, { className, ...p });
};
Comp.displayName = `StakeTxRowOfClass: ${className}`;
return Comp;
};
17 changes: 10 additions & 7 deletions app/components/views/HomePage/TxHistory/TxHistoryRow/Status.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import { FormattedDate, FormattedMessage } from "react-intl";
import { FormattedDate, FormattedTime, FormattedMessage as T } from "react-intl";
import "style/TxHistory.less";
import { tsToDate } from "helpers/dateFormat";
import { Tooltip } from "shared";

const Status = ({ pending, txTimestamp }) => (
<Aux>
{!pending ? (
<div className="transaction-time-date-spacer">
<FormattedMessage
<T
id="myId"
defaultMessage="{day} {month} {year} {hour}:{minute}"
defaultMessage="{day} {month} {year} {time}"
values={{
day: <FormattedDate value={tsToDate(txTimestamp)} day="2-digit"/>,
month: <FormattedDate value={tsToDate(txTimestamp)} month="short"/>,
year: <FormattedDate value={tsToDate(txTimestamp)} year="numeric"/>,
hour: <FormattedDate value={tsToDate(txTimestamp)} hour="2-digit" hour12={false}/>,
minute: <FormattedDate value={tsToDate(txTimestamp)} minute="2-digit"/>
time: <FormattedTime value={tsToDate(txTimestamp)} hour12={false}/>,
}}
/>
</div>) : (
<div className="pending-overview-details">
<Tooltip text={<T id="txHistory.Pending" m="Pending"/>}>
<div className="pending-overview-details">
...
</div>
</div>
</Tooltip>

)}
</Aux>
);
Expand Down
11 changes: 8 additions & 3 deletions app/components/views/HomePage/TxHistory/TxHistoryRow/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { RegularTxRowOfClass as regular } from "./RegularTxRow";
import { StakeTxRowOfType as stake } from "./StakeTxRow";
import "style/TxHistory.less";

const TxRow = ({ tx }, { router }) => {
const TxRowByType = {
"out": regular("Send", true),
"in": regular("Receive", false),
"transfer": regular("Transfer", true),
"out": regular("Send", true),
"in": regular("Receive", false),
"transfer": regular("Transfer", true),
"Ticket": stake("Ticket"),
"Vote": stake("Vote"),
"Revocation": stake("Revocation"),

};
const rowType = tx.txType || tx.txDirection;
const Component = TxRowByType[rowType];
Expand Down
18 changes: 8 additions & 10 deletions app/reducers/grpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
GETACCOUNTS_ATTEMPT, GETACCOUNTS_FAILED, GETACCOUNTS_SUCCESS,
GETTRANSACTIONS_ATTEMPT, GETTRANSACTIONS_FAILED, GETTRANSACTIONS_COMPLETE,
NEW_TRANSACTIONS_RECEIVED, CHANGE_TRANSACTIONS_FILTER,
CLEAR_MOSTRECENTTRANSACTIONS,
UPDATETIMESINCEBLOCK,
GETTICKETS_ATTEMPT, GETTICKETS_FAILED, GETTICKETS_COMPLETE,
GETAGENDASERVICE_ATTEMPT, GETAGENDASERVICE_FAILED, GETAGENDASERVICE_SUCCESS,
Expand Down Expand Up @@ -267,17 +266,21 @@ export default function grpc(state = {}, action) {
lastTransaction: action.lastTransaction,
getTransactionsRequestError: "",
getTransactionsRequestAttempt: false,
recentTransactions: state.recentTransactions.length
? state.recentTransactions
: transactions.slice(0, state.recentTransactionCount)
recentRegularTransactions: action.recentRegularTransactions
? action.recentRegularTransactions
: state.recentRegularTransactions,
recentStakeTransactions: action.recentStakeTransactions
? action.recentStakeTransactions
: state.recentStakeTransactions
};
case NEW_TRANSACTIONS_RECEIVED:
return {
...state,
minedTransactions: action.minedTransactions,
unminedTransactions: action.unminedTransactions,
transactions: [...action.unminedTransactions, ...action.minedTransactions],
recentTransactions: action.recentTransactions,
recentRegularTransactions: action.recentRegularTransactions,
recentStakeTransactions: action.recentStakeTransactions,
};
case CHANGE_TRANSACTIONS_FILTER:
return {
Expand All @@ -289,11 +292,6 @@ export default function grpc(state = {}, action) {
lastTransaction: null,
noMoreTransactions: false
};
case CLEAR_MOSTRECENTTRANSACTIONS:
return {
...state,
recentTransactions: [],
};
case UPDATETIMESINCEBLOCK:
return {
...state,
Expand Down
12 changes: 2 additions & 10 deletions app/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,20 +259,12 @@ export const transactions = createSelector(
[transactionsNormalizer, get(["grpc", "transactions"])], apply
);

const recentTransactions = createSelector(
[transactionsNormalizer, get(["grpc", "recentTransactions"])], apply
);

export const homeHistoryTransactions = createSelector(
[transactions],
(transactions) =>
transactions.map(tx => {if (!tx.txType || tx.txType == "Regular" || tx.txType == "Coinbase") return tx; }).filter(tx => tx !== undefined)
[transactionsNormalizer, get(["grpc", "recentRegularTransactions"])], apply
);

export const homeHistoryTickets = createSelector(
[recentTransactions],
(recentTransactions) =>
recentTransactions.map(tx => {if (tx.txType && tx.txType !== "Regular" && tx.txType !== "Coinbase") return tx; }).filter(tx => tx !== undefined)
[transactionsNormalizer, get(["grpc", "recentStakeTransactions"])], apply
);

//fake data for balance chart
Expand Down
Loading

0 comments on commit fdc325f

Please sign in to comment.