Skip to content

Commit

Permalink
bitshares#422 PriceAlert Notifications component to track and fire no…
Browse files Browse the repository at this point in the history
…tifications
  • Loading branch information
gibbsfromncis committed Nov 6, 2018
1 parent ff28cc6 commit cbe0f1b
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 1 deletion.
2 changes: 2 additions & 0 deletions app/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ import RegistrationSelector from "./components/Registration/RegistrationSelector
import WalletRegistration from "./components/Registration/WalletRegistration";
import AccountRegistration from "./components/Registration/AccountRegistration";
import {CreateWalletFromBrainkey} from "./components/Wallet/WalletCreate";
import PriceAlertNotifications from "./components/PriceAlertNotifications";

class App extends React.Component {
constructor() {
Expand Down Expand Up @@ -513,6 +514,7 @@ class App extends React.Component {
/>
<TransactionConfirm />
<BrowserNotifications />
<PriceAlertNotifications />
<WalletUnlockModal />
<BrowserSupportModal
visible={this.state.isBrowserSupportModalVisible}
Expand Down
6 changes: 5 additions & 1 deletion app/assets/locales/locale-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,11 @@
"lower_than": "Lower Than",
"higher_than": "Higher Than",
"add_rule": "add rule",
"price": "Price"
"price": "Price",
"notification": {
"lower_than": "The price of %(pair)s fell lower than %(expectedPrice)s and now is %(actualPrice)s",
"higher_than": "The price of %(pair)s rose higher than %(expectedPrice)s and now is %(actualPrice)s"
}
},
"add_quote": "Add",
"asks": "Sell orders",
Expand Down
22 changes: 22 additions & 0 deletions app/assets/stylesheets/themes/_theme-template.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@
color: $link-text-color;
}

.price-alert--notification--pair-name {
font-weight: 600;
}

.price-alert--notification--icon {
&.price-alert--notification--icon--up {
color: $positive-color;
}
&.price-alert--notification--icon--down {
color: $negative-color;
}
}

.price-alert--notification--actual-price {
&.price-alert--notification--actual-price-up {
color: $positive-color;
}
&.price-alert--notification--actual-price-down {
color: $negative-color;
}
}

.explore-witness--info {
width: 100%;

Expand Down
196 changes: 196 additions & 0 deletions app/components/PriceAlertNotifications.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import React from "react";
import {connect} from "alt-react";
import MarketsStore from "../stores/MarketsStore";
import SettingsStore from "../stores/SettingsStore";
import {PRICE_ALERT_TYPES} from "../services/Exchange";
import {Notification, Icon} from "bitshares-ui-style-guide";
import Translate from "react-translate-component";
import counterpart from "counterpart";
import SettingsActions from "../actions/SettingsActions";
import AssetName from "./Utility/AssetName";

class PriceAlertNotifications extends React.Component {
_getRulesForCheck(priceAlertRules, markets) {
return priceAlertRules.map((rule, key) => {
let pair = `${rule.quoteAssetSymbol}_${rule.baseAssetSymbol}`;

let price = null;

try {
let market = markets.get(pair);

price = market && market.price && market.price.toReal();
} catch (e) {
console.error(
`PriceAlertNotifications: Unable to get real price for pair ${pair}: `,
e
);
}

return {
ruleKey: key,
type: rule.type,
pair: pair,
quoteAssetSymbol: rule.quoteAssetSymbol,
baseAssetSymbol: rule.baseAssetSymbol,
actualPrice: price,
expectedPrice: rule.price
};
});
}

_getFulfilledRules(rules) {
return rules.filter(rule => {
if (isNaN(Number(rule.actualPrice))) return false;

if (
Number(rule.type) === Number(PRICE_ALERT_TYPES.HIGHER_THAN) &&
Number(rule.actualPrice) >= Number(rule.expectedPrice)
) {
return true;
} else if (
Number(rule.type) === Number(PRICE_ALERT_TYPES.LOWER_THAN) &&
Number(rule.actualPrice) <= Number(rule.expectedPrice)
) {
return true;
}

return false;
});
}

_filterByFulfilledRules(fulfilledRules) {
return (rule, key) => {
return !fulfilledRules.some(fulfilledRule => {
return key === fulfilledRule.ruleKey;
});
};
}

notifyAboutRules(rules) {
// Notification.

rules.forEach(rule => {
if (Number(rule.type) === Number(PRICE_ALERT_TYPES.LOWER_THAN)) {
Notification.info({
message: counterpart.translate(
"exchange.price_alert.title"
),
description: (
<Translate
content="exchange.price_alert.notification.lower_than"
component="div"
pair={
<span className="price-alert--notification--pair-name">
<AssetName name={rule.quoteAssetSymbol} />/
<AssetName name={rule.baseAssetSymbol} />
</span>
}
expectedPrice={
<span className="price-alert--notification--expected-price">
{rule.expectedPrice}
</span>
}
actualPrice={
<span className="price-alert--notification--actual-price price-alert--notification--actual-price-down">
{rule.actualPrice}
</span>
}
/>
),
icon: (
<Icon
type="caret-down"
className="price-alert--notification--icon price-alert--notification--icon--down"
/>
)
});
}

if (Number(rule.type) === Number(PRICE_ALERT_TYPES.HIGHER_THAN)) {
Notification.info({
message: counterpart.translate(
"exchange.price_alert.title"
),
description: (
<Translate
content="exchange.price_alert.notification.higher_than"
component="div"
pair={
<span className="price-alert--notification--pair-name">
<AssetName name={rule.quoteAssetSymbol} />/
<AssetName name={rule.baseAssetSymbol} />
</span>
}
expectedPrice={
<span className="price-alert--notification--expected-price">
{rule.expectedPrice}
</span>
}
actualPrice={
<span className="price-alert--notification--actual-price price-alert--notification--actual-price-up">
{rule.actualPrice}
</span>
}
/>
),
icon: (
<Icon
type="caret-up"
className="price-alert--notification--icon price-alert--notification--icon--up"
/>
)
});
}
});
}

render() {
const {priceAlert, allMarketStats} = this.props;

if (
!priceAlert ||
!priceAlert.length ||
!allMarketStats ||
!allMarketStats.size
) {
return null;
}

const notificationsRules = this._getRulesForCheck(
priceAlert,
allMarketStats
);

// do notifications for
const fulfilledRules = this._getFulfilledRules(notificationsRules);

this.notifyAboutRules(fulfilledRules);

// update notifications array
let updatedPriceAlert = this.props.priceAlert.filter(
this._filterByFulfilledRules(fulfilledRules)
);

if (updatedPriceAlert.length !== this.props.priceAlert.length) {
SettingsActions.setPriceAlert(updatedPriceAlert);
}

return null;
}
}

export default connect(
PriceAlertNotifications,
{
listenTo() {
return [MarketsStore, SettingsStore];
},
getProps() {
return {
allMarketStats: MarketsStore.getState().allMarketStats,
priceAlert: SettingsStore.getState().priceAlert
};
}
}
);

0 comments on commit cbe0f1b

Please sign in to comment.