Repository: busyorg/busy
Pull request #976 (2017-11-02 07:56:53)

Add Infinite Scroll to User Wallet Page & Refactor getAccountHistory parsing
Fixes # .
- https://github.com/busyorg/busy/issues/928
- https://github.com/busyorg/busy/projects/6#card-5384665
Changes:
- Add Infinite Scroller, (Used Redux Infinite Scroller since React Infinite Scroller did not have a loader option)
- Refactor the parsing of getAccountHistory, to fetch all account histories and create 2 maps, one for all of the users account history and another for just user wallet transactions.




bonustrack: LGTM, what you think @Sekhmet ?
jm90m: @Sekhmet updated based on your feedback, I think we should keep it @ 2500 transactions, since we have to filter out the wallet transactions from all account history, it gives some room to for wallet transactions to fill out the page, and it's a reasonable size rather than 10,000. I think 100-1000 is too small of a range. 

Patch:
diff --git a/src/helpers/apiHelpers.js b/src/helpers/apiHelpers.js
index f6db0c58..10c26175 100644
--- a/src/helpers/apiHelpers.js
+++ b/src/helpers/apiHelpers.js
@@ -1,5 +1,4 @@
 import Promise from 'bluebird';
-import _ from 'lodash';
 import SteemAPI from '../steemAPI';
 import { jsonParse } from '../helpers/formatter';
 
@@ -108,29 +107,9 @@ export const mapToId = (content) => {
 
 export const mapAPIContentToId = apiRes => mapToId(apiRes.content);
 
-const isWalletTransaction = actionType =>
-  actionType === 'transfer' ||
-  actionType === 'transfer_to_vesting' ||
-  actionType === 'cancel_transfer_from_savings' ||
-  actionType === 'transfer_from_savings' ||
-  actionType === 'transfer_to_savings' ||
-  actionType === 'delegate_vesting_shares' ||
-  actionType === 'claim_reward_balance';
+export const defaultAccountLimit = 2500;
 
-export const getTransactionHistory = account =>
-  SteemAPI.getAccountHistoryAsync(account, -1, 2500).then(results =>
-    _.compact(
-      results.map((action) => {
-        const actionDetails = action[1] || { op: [] };
-        const actionType = actionDetails.op[0];
-
-        if (isWalletTransaction(actionType)) {
-          return actionDetails;
-        }
-
-        return null;
-      }),
-    ),
-  );
+export const getAccountHistory = (account, from = -1, limit = defaultAccountLimit) =>
+  SteemAPI.getAccountHistoryAsync(account, from, limit);
 
 export const getDynamicGlobalProperties = () => SteemAPI.getDynamicGlobalPropertiesAsync();
diff --git a/src/reducers.js b/src/reducers.js
index c4e99de2..d994b810 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -96,6 +96,7 @@ export const getVotePercent = state => fromSettings.getVotePercent(state.setting
 export const getTotalVestingShares = state => fromWallet.getTotalVestingShares(state.wallet);
 export const getTotalVestingFundSteem = state => fromWallet.getTotalVestingFundSteem(state.wallet);
 export const getUsersTransactions = state => fromWallet.getUsersTransactions(state.wallet);
+export const getUsersAccountHistory = state => fromWallet.getUsersAccountHistory(state.wallet);
 export const getUsersTransactionsLoading = state =>
   fromWallet.getUsersTransactionsLoading(state.wallet);
 export const getUsersEstAccountsValues = state =>
diff --git a/src/user/UserWallet.js b/src/user/UserWallet.js
index 6ed53c8f..5d183f32 100644
--- a/src/user/UserWallet.js
+++ b/src/user/UserWallet.js
@@ -13,6 +13,7 @@ import {
   getTotalVestingShares,
   getTotalVestingFundSteem,
   getUsersTransactions,
+  getUsersAccountHistory,
   getUsersTransactionsLoading,
   getUsersEstAccountsValues,
   getLoadingEstAccountValue,
@@ -20,8 +21,9 @@ import {
 } from '../reducers';
 import {
   getGlobalProperties,
-  getUserTransactions,
   getUserEstAccountValue,
+  getUserAccountHistory,
+  getMoreUserAccountHistory,
 } from '../wallet/walletActions';
 import { getAccountWithFollowingCount } from './usersActions';
 
@@ -35,6 +37,7 @@ import { getAccountWithFollowingCount } from './usersActions';
     totalVestingShares: getTotalVestingShares(state),
     totalVestingFundSteem: getTotalVestingFundSteem(state),
     usersTransactions: getUsersTransactions(state),
+    usersAccountHistory: getUsersAccountHistory(state),
     usersTransactionsLoading: getUsersTransactionsLoading(state),
     usersEstAccountsValues: getUsersEstAccountsValues(state),
     loadingEstAccountValue: getLoadingEstAccountValue(state),
@@ -42,7 +45,8 @@ import { getAccountWithFollowingCount } from './usersActions';
   }),
   {
     getGlobalProperties,
-    getUserTransactions,
+    getUserAccountHistory,
+    getMoreUserAccountHistory,
     getAccountWithFollowingCount,
     getUserEstAccountValue,
   },
@@ -54,7 +58,8 @@ class Wallet extends Component {
     totalVestingFundSteem: PropTypes.string.isRequired,
     user: PropTypes.shape().isRequired,
     getGlobalProperties: PropTypes.func.isRequired,
-    getUserTransactions: PropTypes.func.isRequired,
+    getUserAccountHistory: PropTypes.func.isRequired,
+    getMoreUserAccountHistory: PropTypes.func.isRequired,
     getUserEstAccountValue: PropTypes.func.isRequired,
     getAccountWithFollowingCount: PropTypes.func.isRequired,
     usersTransactions: PropTypes.shape().isRequired,
@@ -64,6 +69,7 @@ class Wallet extends Component {
     loadingGlobalProperties: PropTypes.bool.isRequired,
     isCurrentUser: PropTypes.bool,
     authenticatedUserName: PropTypes.string,
+
   };
 
   static defaultProps = {
@@ -90,7 +96,7 @@ class Wallet extends Component {
     }
 
     if (_.isEmpty(usersTransactions[username])) {
-      this.props.getUserTransactions(username);
+      this.props.getUserAccountHistory(username);
     }
 
     if (_.isEmpty(user)) {
@@ -144,6 +150,7 @@ class Wallet extends Component {
             currentUsername={user.name}
             totalVestingShares={totalVestingShares}
             totalVestingFundSteem={totalVestingFundSteem}
+            getMoreUserAccountHistory={this.props.getMoreUserAccountHistory}
           />}
       </div>
     );
diff --git a/src/wallet/UserWalletTransactions.js b/src/wallet/UserWalletTransactions.js
index cea15e01..0dce47da 100644
--- a/src/wallet/UserWalletTransactions.js
+++ b/src/wallet/UserWalletTransactions.js
@@ -1,6 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import _ from 'lodash';
 import { FormattedNumber } from 'react-intl';
+import ReduxInfiniteScroll from 'redux-infinite-scroll';
+import { defaultAccountLimit } from '../helpers/apiHelpers';
+import Loading from '../components/Icon/Loading';
 import ReceiveTransaction from './ReceiveTransaction';
 import TransferTransaction from './TransferTransaction';
 import SavingsTransaction from './SavingsTransaction';
@@ -8,107 +12,158 @@ import PowerUpTransaction from './PowerUpTransaction';
 import ClaimReward from './ClaimReward';
 import './UserWalletTransactions.less';
 
-const getFormattedTransactionAmount = (amount, currency) => {
-  const transaction = amount.split(' ');
-  const transactionAmount = parseFloat(transaction[0]).toFixed(3);
-  const transactionCurrency = currency || transaction[1];
-  return (
-    <span>
-      <FormattedNumber
-        value={transactionAmount}
-        minimumFractionDigits={3}
-        maximumFractionDigits={3}
-      />
-      {` ${transactionCurrency}`}
-    </span>
-  );
-};
+class UserWalletTransactions extends React.Component {
+  static propTypes = {
+    transactions: PropTypes.arrayOf(PropTypes.shape()),
+    getMoreUserAccountHistory: PropTypes.func.isRequired,
+    currentUsername: PropTypes.string,
+    totalVestingShares: PropTypes.string.isRequired,
+    totalVestingFundSteem: PropTypes.string.isRequired,
+  };
 
-const UserWalletTransactions = ({
-  transactions,
-  currentUsername,
-  totalVestingShares,
-  totalVestingFundSteem,
-}) => (
-  <div className="UserWalletTransactions">
-    {transactions
-      .map((transaction, index) => {
-        const key = `${transaction.trx_id}${index}`;
-        const transactionType = transaction.op[0];
-        const transactionDetails = transaction.op[1];
+  static defaultProps = {
+    transactions: [],
+    currentUsername: '',
+  };
 
-        switch (transactionType) {
-          case 'transfer_to_vesting':
-            return (
-              <PowerUpTransaction
-                key={key}
-                amount={getFormattedTransactionAmount(transactionDetails.amount, 'SP')}
-                timestamp={transaction.timestamp}
-              />
-            );
-          case 'transfer':
-            if (transactionDetails.to === currentUsername) {
-              return (
-                <ReceiveTransaction
-                  key={key}
-                  from={transactionDetails.from}
-                  memo={transactionDetails.memo}
-                  amount={getFormattedTransactionAmount(transactionDetails.amount)}
-                  timestamp={transaction.timestamp}
-                />
-              );
-            }
-            return (
-              <TransferTransaction
-                key={key}
-                to={transactionDetails.to}
-                memo={transactionDetails.memo}
-                amount={getFormattedTransactionAmount(transactionDetails.amount)}
-                timestamp={transaction.timestamp}
-              />
-            );
-          case 'claim_reward_balance':
-            return (
-              <ClaimReward
-                key={key}
-                timestamp={transaction.timestamp}
-                rewardSteem={transactionDetails.reward_steem}
-                rewardSbd={transactionDetails.reward_sbd}
-                rewardVests={transactionDetails.reward_vests}
-                totalVestingShares={totalVestingShares}
-                totalVestingFundSteem={totalVestingFundSteem}
-              />
-            );
-          case 'transfer_to_savings':
-          case 'transfer_from_savings':
-          case 'cancel_transfer_from_savings':
-            return (
-              <SavingsTransaction
-                key={key}
-                transactionDetails={transactionDetails}
-                transactionType={transactionType}
-                amount={getFormattedTransactionAmount(transactionDetails.amount)}
-                timestamp={transaction.timestamp}
-              />
-            );
-          default:
-            return null;
+  constructor(props) {
+    super(props);
+    const firstTransaction = _.head(props.transactions);
+    this.state = {
+      userHasMoreTransactions: firstTransaction.actionCount > defaultAccountLimit,
+      lastActionCount: firstTransaction ? firstTransaction.actionCount : 0,
+      loadingMoreTransactions: false,
+    };
+  }
+
+  getFormattedTransactionAmount = (amount, currency) => {
+    const transaction = amount.split(' ');
+    const transactionAmount = parseFloat(transaction[0]);
+    const transactionCurrency = currency || transaction[1];
+    return (
+      <span>
+        <FormattedNumber
+          value={transactionAmount}
+          minimumFractionDigits={3}
+          maximumFractionDigits={3}
+        />
+        {` ${transactionCurrency}`}
+      </span>
+    );
+  };
+
+  handleLoadMore = () => {
+    const { currentUsername } = this.props;
+    const { lastActionCount } = this.state;
+    const limit = lastActionCount < defaultAccountLimit ? lastActionCount : defaultAccountLimit;
+    this.setState({
+      loadingMoreTransactions: true,
+    });
+    this.props
+      .getMoreUserAccountHistory(currentUsername, lastActionCount, limit)
+      .then((result) => {
+        const newLastActionCount = _.last(result.value.userAccountHistory).actionCount;
+        if (newLastActionCount === 0) {
+          this.setState({
+            userHasMoreTransactions: false,
+            loadingMoreTransactions: false,
+          });
+        } else {
+          this.setState({
+            lastActionCount: newLastActionCount,
+            loadingMoreTransactions: false,
+          });
         }
       })
-      .reverse()}
-  </div>
-);
+      .catch(() => {
+        this.setState({
+          userHasMoreTransactions: false,
+          loadingMoreTransactions: false,
+        });
+      });
+  };
 
-UserWalletTransactions.propTypes = {
-  transactions: PropTypes.arrayOf(PropTypes.shape()),
-  currentUsername: PropTypes.string,
-  totalVestingShares: PropTypes.string.isRequired,
-  totalVestingFundSteem: PropTypes.string.isRequired,
-};
+  render() {
+    const { transactions, currentUsername, totalVestingShares, totalVestingFundSteem } = this.props;
+    const { loadingMoreTransactions } = this.state;
 
-UserWalletTransactions.defaultProps = {
-  transactions: [],
-  currentUsername: '',
-};
+    return (
+      <div className="UserWalletTransactions">
+        <ReduxInfiniteScroll
+          loadMore={this.handleLoadMore}
+          hasMore={this.state.userHasMoreTransactions}
+          elementIsScrollable={false}
+          threshold={200}
+          loader={<div style={{ margin: '20px' }}><Loading /></div>}
+          loadingMore={loadingMoreTransactions}
+        >
+          {transactions.map((transaction, index) => {
+            const key = `${transaction.trx_id}${index}`;
+            const transactionType = transaction.op[0];
+            const transactionDetails = transaction.op[1];
+
+            switch (transactionType) {
+              case 'transfer_to_vesting':
+                return (
+                  <PowerUpTransaction
+                    key={key}
+                    amount={this.getFormattedTransactionAmount(transactionDetails.amount, 'SP')}
+                    timestamp={transaction.timestamp}
+                  />
+                );
+              case 'transfer':
+                if (transactionDetails.to === currentUsername) {
+                  return (
+                    <ReceiveTransaction
+                      key={key}
+                      from={transactionDetails.from}
+                      memo={transactionDetails.memo}
+                      amount={this.getFormattedTransactionAmount(transactionDetails.amount)}
+                      timestamp={transaction.timestamp}
+                    />
+                  );
+                }
+                return (
+                  <TransferTransaction
+                    key={key}
+                    to={transactionDetails.to}
+                    memo={transactionDetails.memo}
+                    amount={this.getFormattedTransactionAmount(transactionDetails.amount)}
+                    timestamp={transaction.timestamp}
+                  />
+                );
+              case 'claim_reward_balance':
+                return (
+                  <ClaimReward
+                    key={key}
+                    timestamp={transaction.timestamp}
+                    rewardSteem={transactionDetails.reward_steem}
+                    rewardSbd={transactionDetails.reward_sbd}
+                    rewardVests={transactionDetails.reward_vests}
+                    totalVestingShares={totalVestingShares}
+                    totalVestingFundSteem={totalVestingFundSteem}
+                  />
+                );
+              case 'transfer_to_savings':
+              case 'transfer_from_savings':
+              case 'cancel_transfer_from_savings':
+                return (
+                  <SavingsTransaction
+                    key={key}
+                    transactionDetails={transactionDetails}
+                    transactionType={transactionType}
+                    amount={this.getFormattedTransactionAmount(transactionDetails.amount)}
+                    timestamp={transaction.timestamp}
+                  />
+                );
+              default:
+                return null;
+            }
+          })}
+        </ReduxInfiniteScroll>
+      </div>
+    );
+  }
+}
 
 export default UserWalletTransactions;
diff --git a/src/wallet/walletActions.js b/src/wallet/walletActions.js
index 8327d954..bd5dbcd4 100644
--- a/src/wallet/walletActions.js
+++ b/src/wallet/walletActions.js
@@ -1,41 +1,98 @@
 import steem from 'steem';
+import _ from 'lodash';
 import { createAction } from 'redux-actions';
 import { createAsyncActionType } from '../helpers/stateHelpers';
-import { getTransactionHistory, getDynamicGlobalProperties } from '../helpers/apiHelpers';
+import { getAccountHistory, getDynamicGlobalProperties } from '../helpers/apiHelpers';
 
 export const OPEN_TRANSFER = '@wallet/OPEN_TRANSFER';
 export const CLOSE_TRANSFER = '@wallet/CLOSE_TRANSFER';
 export const GET_GLOBAL_PROPERTIES = createAsyncActionType('@wallet/GET_GLOBAL_PROPERTIES');
-export const GET_USER_TRANSACTIONS = createAsyncActionType('@users/GET_USER_TRANSACTIONS');
+export const GET_USER_ACCOUNT_HISTORY = createAsyncActionType('@users/GET_USER_ACCOUNT_HISTORY');
+export const GET_MORE_USER_ACCOUNT_HISTORY = createAsyncActionType(
+  '@users/GET_MORE_USER_ACCOUNT_HISTORY',
+);
 export const GET_USER_EST_ACCOUNT_VALUE = createAsyncActionType(
   '@users/GET_USER_EST_ACCOUNT_VALUE',
 );
-
 export const openTransfer = createAction(OPEN_TRANSFER);
 export const closeTransfer = createAction(CLOSE_TRANSFER);
 
-export const getGlobalProperties = () => (dispatch) => {
+const isWalletTransaction = actionType =>
+  actionType === 'transfer' ||
+  actionType === 'transfer_to_vesting' ||
+  actionType === 'cancel_transfer_from_savings' ||
+  actionType === 'transfer_from_savings' ||
+  actionType === 'transfer_to_savings' ||
+  actionType === 'delegate_vesting_shares' ||
+  actionType === 'claim_reward_balance';
+
+const getParsedUserActions = (userActions) => {
+  const userWalletTransactions = [];
+  const userAccountHistory = [];
+
+  _.each(userActions.reverse(), (action) => {
+    const actionCount = action[0];
+    const actionDetails = {
+      ...action[1],
+      actionCount,
+    };
+    const actionType = actionDetails.op[0];
+
+    if (isWalletTransaction(actionType)) {
+      userWalletTransactions.push(actionDetails);
+    }
+
+    userAccountHistory.push(actionDetails);
+  });
+
+  return {
+    userWalletTransactions,
+    userAccountHistory,
+  };
+};
+
+export const getGlobalProperties = () => dispatch =>
   dispatch({
     type: GET_GLOBAL_PROPERTIES.ACTION,
     payload: {
       promise: getDynamicGlobalProperties(),
     },
   });
-};
 
-export const getUserTransactions = username => (dispatch) => {
+export const getUserAccountHistory = username => dispatch =>
   dispatch({
-    type: GET_USER_TRANSACTIONS.ACTION,
+    type: GET_USER_ACCOUNT_HISTORY.ACTION,
     payload: {
-      promise: getTransactionHistory(username).then(transactions => ({
-        username,
-        transactions,
-      })),
+      promise: getAccountHistory(username).then((userActions) => {
+        const parsedUserActions = getParsedUserActions(userActions);
+
+        return {
+          username,
+          userWalletTransactions: parsedUserActions.userWalletTransactions,
+          userAccountHistory: parsedUserActions.userAccountHistory,
+        };
+      }),
     },
   });
-};
 
-export const getUserEstAccountValue = user => (dispatch) => {
+export const getMoreUserAccountHistory = (username, start, limit) => dispatch =>
+  dispatch({
+    type: GET_MORE_USER_ACCOUNT_HISTORY.ACTION,
+    payload: {
+      promise: getAccountHistory(username, start, limit)
+        .then((userActions) => {
+          const parsedUserActions = getParsedUserActions(userActions);
+
+          return {
+            username,
+            userWalletTransactions: parsedUserActions.userWalletTransactions,
+            userAccountHistory: parsedUserActions.userAccountHistory,
+          };
+        }),
+    },
+  });
+
+export const getUserEstAccountValue = user => dispatch =>
   dispatch({
     type: GET_USER_EST_ACCOUNT_VALUE.ACTION,
     payload: {
@@ -45,4 +102,3 @@ export const getUserEstAccountValue = user => (dispatch) => {
       })),
     },
   });
-};
diff --git a/src/wallet/walletReducer.js b/src/wallet/walletReducer.js
index 830f5f36..29adceea 100644
--- a/src/wallet/walletReducer.js
+++ b/src/wallet/walletReducer.js
@@ -1,3 +1,4 @@
+import _ from 'lodash';
 import * as walletActions from './walletActions';
 
 const initialState = {
@@ -6,10 +7,12 @@ const initialState = {
   totalVestingShares: '',
   totalVestingFundSteem: '',
   usersTransactions: {},
+  usersAccountHistory: {},
   usersEstAccountsValues: {},
   usersTransactionsLoading: true,
   loadingEstAccountValue: true,
   loadingGlobalProperties: true,
+  moreUsersAccountHistoryLoading: true,
 };
 
 export default function walletReducer(state = initialState, action) {
@@ -44,19 +47,57 @@ export default function walletReducer(state = initialState, action) {
         loadingGlobalProperties: false,
       };
     }
-    case walletActions.GET_USER_TRANSACTIONS.START:
+
+    case walletActions.GET_USER_ACCOUNT_HISTORY.START:
       return {
         ...state,
-        usersTransactionsLoading: true,
+        usersAccountHistoryLoading: true,
       };
-    case walletActions.GET_USER_TRANSACTIONS.SUCCESS:
+    case walletActions.GET_USER_ACCOUNT_HISTORY.SUCCESS:
       return {
         ...state,
         usersTransactions: {
           ...state.usersTransactions,
-          [action.payload.username]: action.payload.transactions,
+          [action.payload.username]: action.payload.userWalletTransactions,
+        },
+        usersAccountHistory: {
+          ...state.usersAccountHistory,
+          [action.payload.username]: action.payload.userAccountHistory,
         },
-        usersTransactionsLoading: false,
+        usersAccountHistoryLoading: false,
+      };
+    case walletActions.GET_MORE_USER_ACCOUNT_HISTORY.START:
+      return {
+        ...state,
+        moreUsersAccountHistoryLoading: true,
+      };
+    case walletActions.GET_MORE_USER_ACCOUNT_HISTORY.SUCCESS: {
+      const userCurrentWalletTransactions = state.usersTransactions[action.payload.username] || [];
+      const userCurrentAccountHistory = state.usersAccountHistory[action.payload.username] || [];
+
+      return {
+        ...state,
+        usersTransactions: {
+          ...state.usersTransactions,
+          [action.payload.username]: _.uniqBy(
+            userCurrentWalletTransactions.concat(action.payload.userWalletTransactions),
+            'actionCount',
+          ),
+        },
+        usersAccountHistory: {
+          ...state.usersAccountHistory,
+          [action.payload.username]: _.uniqBy(
+            userCurrentAccountHistory.concat(action.payload.userAccountHistory),
+            'actionCount',
+          ),
+        },
+        moreUsersAccountHistoryLoading: false,
+      };
+    }
+    case walletActions.GET_MORE_USER_ACCOUNT_HISTORY.ERROR:
+      return {
+        ...state,
+        moreUsersAccountHistoryLoading: false,
       };
     case walletActions.GET_USER_EST_ACCOUNT_VALUE.START:
       return {
@@ -91,3 +132,4 @@ export const getUsersEstAccountsValues = state => state.usersEstAccountsValues;
 export const getUsersTransactionsLoading = state => state.usersTransactionsLoading;
 export const getLoadingEstAccountValue = state => state.loadingEstAccountValue;
 export const getLoadingGlobalProperties = state => state.loadingGlobalProperties;
+export const getUsersAccountHistory = state => state.usersAccountHistory;


Test patch:
diff --git a/src/wallet/__tests__/__snapshots__/UserWalletTransactions.test.js.snap b/src/wallet/__tests__/__snapshots__/UserWalletTransactions.test.js.snap
index b8703709..8ecfd393 100644
--- a/src/wallet/__tests__/__snapshots__/UserWalletTransactions.test.js.snap
+++ b/src/wallet/__tests__/__snapshots__/UserWalletTransactions.test.js.snap
@@ -11,74 +11,128 @@ ShallowWrapper {
   "node": <div
     className="UserWalletTransactions"
   >
-    <TransferTransaction
-      amount={
-        <span>
-          <FormattedNumber
-            maximumFractionDigits={3}
-            minimumFractionDigits={3}
-            value="100.000"
-          />
-           STEEM
-        </span>
-      }
-      memo="transfer memo"
-      timestamp="0"
-      to=""
-    />
-    <PowerUpTransaction
-      amount={
-        <span>
-          <FormattedNumber
-            maximumFractionDigits={3}
-            minimumFractionDigits={3}
-            value="100.000"
+    <ReduxInfiniteScroll
+      className=""
+      containerHeight="100%"
+      elementIsScrollable={false}
+      hasMore={false}
+      holderType="div"
+      items={Array []}
+      loadMore={[Function]}
+      loader={
+        <div
+          style={
+            Object {
+              "margin": "20px",
+            }
+          }
+        >
+          <Loading
+            center={true}
+            style={Object {}}
           />
-           SP
-        </span>
+        </div>
       }
-      timestamp="0"
-    />
-  </div>,
-  "nodes": Array [
-    <div
-      className="UserWalletTransactions"
+      loadingMore={false}
+      showLoader={true}
+      threshold={200}
     >
-      <TransferTransaction
+      <PowerUpTransaction
         amount={
           <span>
             <FormattedNumber
               maximumFractionDigits={3}
               minimumFractionDigits={3}
-              value="100.000"
+              value={100}
             />
-             STEEM
+             SP
           </span>
         }
-        memo="transfer memo"
         timestamp="0"
-        to=""
       />
-      <PowerUpTransaction
+      <TransferTransaction
         amount={
           <span>
             <FormattedNumber
               maximumFractionDigits={3}
               minimumFractionDigits={3}
-              value="100.000"
+              value={100}
             />
-             SP
+             STEEM
           </span>
         }
+        memo="transfer memo"
         timestamp="0"
+        to=""
       />
+    </ReduxInfiniteScroll>
+  </div>,
+  "nodes": Array [
+    <div
+      className="UserWalletTransactions"
+    >
+      <ReduxInfiniteScroll
+        className=""
+        containerHeight="100%"
+        elementIsScrollable={false}
+        hasMore={false}
+        holderType="div"
+        items={Array []}
+        loadMore={[Function]}
+        loader={
+          <div
+            style={
+              Object {
+                "margin": "20px",
+              }
+            }
+          >
+            <Loading
+              center={true}
+              style={Object {}}
+            />
+          </div>
+        }
+        loadingMore={false}
+        showLoader={true}
+        threshold={200}
+      >
+        <PowerUpTransaction
+          amount={
+            <span>
+              <FormattedNumber
+                maximumFractionDigits={3}
+                minimumFractionDigits={3}
+                value={100}
+              />
+               SP
+            </span>
+          }
+          timestamp="0"
+        />
+        <TransferTransaction
+          amount={
+            <span>
+              <FormattedNumber
+                maximumFractionDigits={3}
+                minimumFractionDigits={3}
+                value={100}
+              />
+               STEEM
+            </span>
+          }
+          memo="transfer memo"
+          timestamp="0"
+          to=""
+        />
+      </ReduxInfiniteScroll>
     </div>,
   ],
   "options": Object {},
   "renderer": ReactShallowRenderer {
     "_instance": ShallowComponentWrapper {
       "_calledComponentWillUnmount": false,
-      "_compositeType": 2,
+      "_compositeType": 0,
       "_context": Object {},
       "_currentElement": <UserWalletTransactions
         currentUsername="hellosteem"
@@ -112,9 +166,11 @@ ShallowWrapper {
       "_debugID": 1,
       "_hostContainerInfo": null,
       "_hostParent": null,
-      "_instance": StatelessComponent {
+      "_instance": UserWalletTransactions {
         "_reactInternalInstance": [Circular],
         "context": Object {},
+        "getFormattedTransactionAmount": [Function],
+        "handleLoadMore": [Function],
         "props": Object {
           "currentUsername": "hellosteem",
           "totalVestingFundSteem": "0",
@@ -143,7 +199,11 @@ ShallowWrapper {
           ],
         },
         "refs": Object {},
-        "state": null,
+        "state": Object {
+          "lastActionCount": undefined,
+          "loadingMoreTransactions": false,
+          "userHasMoreTransactions": false,
+        },
         "updater": Object {
           "enqueueCallback": [Function],
           "enqueueCallbackInternal": [Function],
@@ -165,67 +225,121 @@ ShallowWrapper {
         "_currentElement": <div
           className="UserWalletTransactions"
         >
-          <TransferTransaction
-            amount={
-              <span>
-                <FormattedNumber
-                  maximumFractionDigits={3}
-                  minimumFractionDigits={3}
-                  value="100.000"
+          <ReduxInfiniteScroll
+            className=""
+            containerHeight="100%"
+            elementIsScrollable={false}
+            hasMore={false}
+            holderType="div"
+            items={Array []}
+            loadMore={[Function]}
+            loader={
+              <div
+                style={
+                  Object {
+                    "margin": "20px",
+                  }
+                }
+              >
+                <Loading
+                  center={true}
+                  style={Object {}}
                 />
-                 STEEM
-              </span>
+              </div>
             }
-            memo="transfer memo"
-            timestamp="0"
-            to=""
-          />
-          <PowerUpTransaction
-            amount={
-              <span>
-                <FormattedNumber
-                  maximumFractionDigits={3}
-                  minimumFractionDigits={3}
-                  value="100.000"
-                />
-                 SP
-              </span>
-            }
-            timestamp="0"
-          />
+            loadingMore={false}
+            showLoader={true}
+            threshold={200}
+          >
+            <PowerUpTransaction
+              amount={
+                <span>
+                  <FormattedNumber
+                    maximumFractionDigits={3}
+                    minimumFractionDigits={3}
+                    value={100}
+                  />
+                   SP
+                </span>
+              }
+              timestamp="0"
+            />
+            <TransferTransaction
+              amount={
+                <span>
+                  <FormattedNumber
+                    maximumFractionDigits={3}
+                    minimumFractionDigits={3}
+                    value={100}
+                  />
+                   STEEM
+                </span>
+              }
+              memo="transfer memo"
+              timestamp="0"
+              to=""
+            />
+          </ReduxInfiniteScroll>
         </div>,
         "_debugID": 2,
         "_renderedOutput": <div
           className="UserWalletTransactions"
         >
-          <TransferTransaction
-            amount={
-              <span>
-                <FormattedNumber
-                  maximumFractionDigits={3}
-                  minimumFractionDigits={3}
-                  value="100.000"
-                />
-                 STEEM
-              </span>
-            }
-            memo="transfer memo"
-            timestamp="0"
-            to=""
-          />
-          <PowerUpTransaction
-            amount={
-              <span>
-                <FormattedNumber
-                  maximumFractionDigits={3}
-                  minimumFractionDigits={3}
-                  value="100.000"
+          <ReduxInfiniteScroll
+            className=""
+            containerHeight="100%"
+            elementIsScrollable={false}
+            hasMore={false}
+            holderType="div"
+            items={Array []}
+            loadMore={[Function]}
+            loader={
+              <div
+                style={
+                  Object {
+                    "margin": "20px",
+                  }
+                }
+              >
+                <Loading
+                  center={true}
+                  style={Object {}}
                 />
-                 SP
-              </span>
+              </div>
             }
-            timestamp="0"
-          />
+            loadingMore={false}
+            showLoader={true}
+            threshold={200}
+          >
+            <PowerUpTransaction
+              amount={
+                <span>
+                  <FormattedNumber
+                    maximumFractionDigits={3}
+                    minimumFractionDigits={3}
+                    value={100}
+                  />
+                   SP
+                </span>
+              }
+              timestamp="0"
+            />
+            <TransferTransaction
+              amount={
+                <span>
+                  <FormattedNumber
+                    maximumFractionDigits={3}
+                    minimumFractionDigits={3}
+                    value={100}
+                  />
+                   STEEM
+                </span>
+              }
+              memo="transfer memo"
+              timestamp="0"
+              to=""
+            />
+          </ReduxInfiniteScroll>
         </div>,
       },
       "_renderedNodeType": 0,
diff --git a/src/wallet/__tests__/walletReducer.js b/src/wallet/__tests__/walletReducer.js
index 493471e2..f1413ff1 100644
--- a/src/wallet/__tests__/walletReducer.js
+++ b/src/wallet/__tests__/walletReducer.js
@@ -5,10 +5,12 @@ const reducerInitialState = {
   totalVestingShares: '',
   totalVestingFundSteem: '',
   usersTransactions: {},
+  usersAccountHistory: {},
   usersEstAccountsValues: {},
   usersTransactionsLoading: true,
   loadingEstAccountValue: true,
   loadingGlobalProperties: true,
+  moreUsersAccountHistoryLoading: true,
 };
 
 describe('walletReducer', () => {