Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some stats to the Trades view #357

Merged
merged 2 commits into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions app/renderer/containers/SuperContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ const addLifeCycleHooks = (self, lifecycleHooks) => {
if (typeof originalMethod === 'function') {
originalMethod.call(this, ...args);
}
hook(...args);
hook.call(this, ...args);
};
}
};

// eslint-disable-next-line no-unused-vars
const withState = (FunctionalComponent, initialState = {}, lifecycleHooks = {}) => {
return toClassComponent(FunctionalComponent, self => {
self.state = initialState;
Expand Down Expand Up @@ -141,3 +140,7 @@ class SuperContainer extends Container {
}

export default SuperContainer;

export {
withState,
};
58 changes: 50 additions & 8 deletions app/renderer/swap-db.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import cryptoPouch from 'crypto-pouch';
import Emittery from 'emittery';
import PQueue from 'p-queue';
import roundTo from 'round-to';
import {subDays} from 'date-fns';
import appContainer from 'containers/App';
import swapTransactions from './swap-transactions';

PouchDB.plugin(pouchDBFind);
Expand Down Expand Up @@ -191,28 +193,68 @@ class SwapDB {
return swap;
}

async _getAllSwapData() {
async _getAllSwapData(options = {}) {
await this.ready;

options = {
since: true,
sort: 'desc',
...options,
};

const query = {
selector: {
timeStarted: {
$gt: options.since,
},
},
sort: [
{
timeStarted: options.sort,
},
],
};

// We need `timeStarted: {$gt: true}` so PouchDB can sort.
// https://github.com/pouchdb/pouchdb/issues/7206
const {docs} = await this.db.find({
selector: {timeStarted: {$gt: true}},
sort: [{timeStarted: 'desc'}],
});
const {docs} = await this.db.find(options.query || query);

return docs;
}

async getSwaps() {
const swapData = await this._getAllSwapData();

async getSwaps(options) {
const swapData = await this._getAllSwapData(options);
return swapData.map(this._formatSwap);
}

async destroy() {
await this.db.destroy();
}

async statsSince(timestamp) {
const swaps = await this.getSwaps({since: timestamp});
const successfulSwaps = swaps.filter(swap => swap.status === 'completed');

const quoteCurrencies = new Set();
for (const swap of successfulSwaps) {
quoteCurrencies.add(swap.quoteCurrency);
}

let totalSwapsWorthInUsd = 0;
for (const swap of successfulSwaps) {
totalSwapsWorthInUsd += swap.quoteCurrencyAmount * appContainer.getCurrency(swap.quoteCurrency).cmcPriceUsd;
}

return {
successfulSwapCount: successfulSwaps.length,
currencyCount: quoteCurrencies.size,
totalSwapsWorthInUsd,
};
}

statsSinceLastMonth() {
return this.statsSince(subDays(Date.now(), 30).getTime());
}
}

export default SwapDB;
66 changes: 44 additions & 22 deletions app/renderer/views/Trades.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from 'react';
import {classNames} from 'react-extras';
import {Subscribe} from 'unstated';
import {withState} from 'containers/SuperContainer';
import appContainer from 'containers/App';
import exchangeContainer from 'containers/Exchange'; // TODO(sindresorhus): Find a better place to have the SwapDB data, since both the Exchange and Trades view uses it
import tradesContainer from 'containers/Trades';
import View from 'components/View';
import SwapList from 'components/SwapList';
import {formatCurrency} from '../util';
import AppTabView from './TabView';
import './Exchange/Swaps.scss';
import './Trades.scss';
Expand Down Expand Up @@ -43,29 +46,48 @@ const SwapHistory = () => {
return <SwapList swaps={filteredData} showCancel/>;
};

const Trades = () => (
const Trades = props => (
<Subscribe to={[tradesContainer, /* Temp => */exchangeContainer]}>
{() => (
<AppTabView title="Trades" className="Trades">
<header>
<nav>
<TabButton
title="Open Orders"
component={OpenOrders}
/>
<TabButton
title="Swap History"
component={SwapHistory}
/>
</nav>
</header>
<main>
<TabView component={OpenOrders}/>
<TabView component={SwapHistory}/>
</main>
</AppTabView>
)}
{() => {
const {state} = props;
const {stats} = state;

return (
<AppTabView title="Trades" className="Trades">
<header>
<nav>
<TabButton
title="Open Orders"
component={OpenOrders}
/>
<TabButton
title="Swap History"
component={SwapHistory}
/>
</nav>
<div className="stats">
{stats &&
<p>In the last month you did {stats.successfulSwapCount} successful {stats.successfulSwapCount === 1 ? 'trade' : 'trades'} for {stats.currencyCount} {stats.currencyCount === 1 ? 'currency' : 'currencies'} worth {formatCurrency(stats.totalSwapsWorthInUsd)} in total</p>
}
</div>
</header>
<main>
<TabView component={OpenOrders}/>
<TabView component={SwapHistory}/>
</main>
</AppTabView>
);
}}
</Subscribe>
);

export default Trades;
export default withState(Trades, {}, {
async componentDidMount() {
/// TODO: This is only here temporarily until we move the swap stuff to the App container
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to move the swap state to state in the AppContainer instead of being in the Exchange container as it's also needed by the Trades view, and it's awkward import the Exchange container there.

exchangeContainer.setSwapHistory();

this.setState({
stats: await appContainer.swapDB.statsSinceLastMonth(),
});
},
});
16 changes: 16 additions & 0 deletions app/renderer/views/Trades.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '../styles/variables';

.Trades {
display: flex;
height: 100%;
Expand All @@ -11,6 +13,20 @@

header {
padding: 20px;
position: relative;

.stats {
position: absolute;
top: 0;
right: 20px;
@include center-vertically;

p {
font-size: 12px;
margin: 0;
padding: 0;
}
}
}

main {
Expand Down