diff --git a/app/containers/transactions.js b/app/containers/transactions.js
new file mode 100644
index 0000000..6789a0f
--- /dev/null
+++ b/app/containers/transactions.js
@@ -0,0 +1,61 @@
+// @flow
+import { connect } from 'react-redux';
+import eres from 'eres';
+import flow from 'lodash.flow';
+import groupBy from 'lodash.groupby';
+import dateFns from 'date-fns';
+
+import { TransactionsView } from '../views/transactions';
+import {
+ loadTransactions,
+ loadTransactionsSuccess,
+ loadTransactionsError,
+} from '../redux/modules/transactions';
+import rpc from '../../services/api';
+import store from '../../config/electron-store';
+
+import type { AppState } from '../types/app-state';
+import type { Dispatch } from '../types/redux';
+
+const mapStateToProps = ({ transactions }: AppState) => ({
+ transactions: transactions.list,
+ isLoading: transactions.isLoading,
+ error: transactions.error,
+ zecPrice: transactions.zecPrice,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ getTransactions: async () => {
+ dispatch(loadTransactions());
+
+ const [transactionsErr, transactions = []] = await eres(
+ rpc.listtransactions(),
+ );
+
+ if (transactionsErr) {
+ return dispatch(
+ loadTransactionsError({ error: transactionsErr.message }),
+ );
+ }
+
+ dispatch(
+ loadTransactionsSuccess({
+ list: flow([
+ arr => arr.map(transaction => ({
+ type: transaction.category,
+ date: new Date(transaction.time * 1000).toISOString(),
+ address: transaction.address,
+ amount: Math.abs(transaction.amount),
+ })),
+ arr => groupBy(arr, obj => dateFns.format(obj.date, 'MMM DD, YYYY')),
+ ])(transactions),
+ zecPrice: store.get('ZEC_DOLLAR_PRICE'),
+ }),
+ );
+ },
+});
+
+export const TransactionsContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(TransactionsView);
diff --git a/app/redux/modules/reducer.js b/app/redux/modules/reducer.js
index 87ad85a..8c9e2ad 100644
--- a/app/redux/modules/reducer.js
+++ b/app/redux/modules/reducer.js
@@ -5,8 +5,10 @@ import { connectRouter } from 'connected-react-router';
import type { RouterHistory } from 'react-router-dom';
import wallet from './wallet';
+import transactions from './transactions';
export const createRootReducer = (history: RouterHistory) => combineReducers({
walletSummary: wallet,
+ transactions,
router: connectRouter(history),
});
diff --git a/app/redux/modules/transactions.js b/app/redux/modules/transactions.js
new file mode 100644
index 0000000..2529ebb
--- /dev/null
+++ b/app/redux/modules/transactions.js
@@ -0,0 +1,64 @@
+// @flow
+import type { Action } from '../../types/redux';
+import type { Transaction } from '../../components/transaction-item';
+
+// Actions
+export const LOAD_TRANSACTIONS = 'LOAD_TRANSACTIONS';
+export const LOAD_TRANSACTIONS_SUCCESS = 'LOAD_TRANSACTIONS_SUCCESS';
+export const LOAD_TRANSACTIONS_ERROR = 'LOAD_TRANSACTIONS_ERROR';
+
+export const loadTransactions = () => ({
+ type: LOAD_TRANSACTIONS,
+ payload: {},
+});
+
+export const loadTransactionsSuccess = ({
+ list,
+ zecPrice,
+}: {
+ list: { [day: string]: Transaction[] },
+ zecPrice: number,
+}) => ({
+ type: LOAD_TRANSACTIONS_SUCCESS,
+ payload: {
+ list,
+ zecPrice,
+ },
+});
+
+export const loadTransactionsError = ({ error }: { error: string }) => ({
+ type: LOAD_TRANSACTIONS_ERROR,
+ payload: { error },
+});
+
+export type State = {
+ isLoading: boolean,
+ error: string | null,
+ list: { [day: string]: Transaction[] },
+ zecPrice: number,
+};
+
+const initialState = {
+ zecPrice: 0,
+ list: {},
+ error: null,
+ isLoading: false,
+};
+
+export default (state: State = initialState, action: Action) => {
+ switch (action.type) {
+ case LOAD_TRANSACTIONS:
+ return { ...state, error: null, isLoading: true };
+ case LOAD_TRANSACTIONS_SUCCESS:
+ return {
+ ...state,
+ ...action.payload,
+ isLoading: false,
+ error: null,
+ };
+ case LOAD_TRANSACTIONS_ERROR:
+ return { ...state, isLoading: false, error: action.payload.error };
+ default:
+ return state;
+ }
+};
diff --git a/app/router/router.js b/app/router/router.js
index d3eaaff..9b6050b 100644
--- a/app/router/router.js
+++ b/app/router/router.js
@@ -7,6 +7,7 @@ import styled from 'styled-components';
import { ScrollTopComponent } from './scroll-top';
import { SidebarContainer } from '../containers/sidebar';
import { DashboardContainer } from '../containers/dashboard';
+import { TransactionsContainer } from '../containers/transactions';
import { SendView } from '../views/send';
import { ReceiveView } from '../views/receive';
import { SettingsView } from '../views/settings';
@@ -21,6 +22,7 @@ import {
RECEIVE_ROUTE,
SETTINGS_ROUTE,
CONSOLE_ROUTE,
+ TRANSACTIONS_ROUTE,
} from '../constants/routes';
const FullWrapper = styled.div`
@@ -59,6 +61,10 @@ export const RouterComponent = ({ location }: { location: Location }) => (
+
diff --git a/app/types/app-state.js b/app/types/app-state.js
index 684a66c..281fa60 100644
--- a/app/types/app-state.js
+++ b/app/types/app-state.js
@@ -1,7 +1,9 @@
// @flow
import type { State as WalletSummaryState } from '../redux/modules/wallet';
+import type { State as TransactionsState } from '../redux/modules/transactions';
export type AppState = {
walletSummary: WalletSummaryState,
+ transactions: TransactionsState,
};
diff --git a/app/views/transactions.js b/app/views/transactions.js
new file mode 100644
index 0000000..beb89c1
--- /dev/null
+++ b/app/views/transactions.js
@@ -0,0 +1,47 @@
+// @flow
+import React, { Component, Fragment } from 'react';
+
+import { TransactionDailyComponent } from '../components/transaction-daily';
+
+import type { Transaction } from '../components/transaction-item';
+
+type Props = {
+ isLoading: boolean,
+ error: string | null,
+ transactions: { [day: string]: Transaction[] },
+ zecPrice: number,
+ getTransactions: () => void,
+};
+
+export class TransactionsView extends Component {
+ componentDidMount() {
+ // eslint-disable-next-line
+ this.props.getTransactions();
+ }
+
+ render() {
+ const {
+ error, isLoading, transactions, zecPrice,
+ } = this.props;
+
+ if (error) {
+ return error;
+ }
+
+ const days = Object.keys(transactions);
+
+ return (
+
+ {isLoading
+ ? 'Loading'
+ : days.map(day => (
+
+ ))}
+
+ );
+ }
+}