mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-01 15:10:44 +00:00
Reorganisation + Electron fixes (#118)
* Updates package versions
* Updating versions with RCs
* Updated landing page with stock images
* Begins refactoring of websocket
Adds Help component
* Dark theme for charts
* event Event
* Adds cryptocurrency font
Updates wallet to use it
* Rejigs the location of assets
* rxjs update
wallet font correction
* renaming websocket service
* Refactors websocket use
Destroys and subscribes appropriately
Also handles when websocket is not available with intervals
* Fixes issues with electron by rebasing with Maxime GRIS electron builder
* License change
* Readme update
* Parses available and enabled currencies to create an object {Name:X, Enabled:Y}
* Adds methods to convert from string arrays to objects with enabled status for all currencies
* Uses a localstorage cache for config for 15 minutes
* Moves handling of settings to config object
* Fix typescripting
* Fixes issue with saving and loading
* Slows websocket repeats
Adds cool new dictionary style item and iterable.
Updatres currency-list.component to list all enabled currencies and exchanges (still doesn't do anything)
* Updates selected-currency.component to display all currencies ticker updates if there is no selected currency
Will display only selected currency results once it is set
Sets a new property to ensure all currency names are consistent for currency list plans
* Fixes issue where only one component could listen to the websocket at once
Allows you to select a currency in exchange grid mode
* Adds selected currency support to buy & sell components
Updates selected currency ticker to update on change faster
* Adds Online status indicator
* Removal of console.logs for working features
* Allows currency-list.component to aggregate on currency and list exchanges that match it
* Highlights selected currency in currency-list.component
Allows you to select a currency
This commit is contained in:
@@ -53,6 +53,10 @@ const routes: Routes = [
|
||||
{
|
||||
path: 'currency-list',
|
||||
component: CurrencyListComponent
|
||||
},
|
||||
{
|
||||
path: 'help',
|
||||
component: CurrencyListComponent
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
@@ -1,58 +1,70 @@
|
||||
<app-navbar class="navbar mat-elevation-z6"></app-navbar>
|
||||
|
||||
<mat-sidenav-container class="container ">
|
||||
<mat-sidenav #sidenav mode="side" class="sidebar" opened="true">
|
||||
<mat-nav-list>
|
||||
<mat-list-item routerLink="dashboard" routerLinkActive="dashboard-highlight">
|
||||
<mat-icon>view_quilt</mat-icon>
|
||||
<h3>Dashboard</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="wallet" routerLinkActive="wallet-highlight">
|
||||
<mat-icon>account_balance_wallet</mat-icon>
|
||||
<h3>Wallet</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="trading" routerLinkActive="trading-highlight">
|
||||
<mat-icon>swap_horiz</mat-icon>
|
||||
<h3>Trading</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="history" routerLinkActive="history-highlight">
|
||||
<mat-icon>history</mat-icon>
|
||||
<h3>History</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="settings" routerLinkActive="settings-highlight">
|
||||
<mat-icon>settings</mat-icon>
|
||||
<h3>Settings</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="donate" routerLinkActive="donate-highlight">
|
||||
<mat-icon>thumb_up</mat-icon>
|
||||
<h3>Donate</h3>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-list-item>
|
||||
<mat-icon>grade</mat-icon>
|
||||
<a href="https://github.com/thrasher-/gocryptotrader" target="_blank">
|
||||
<h3>GitHub</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>view_agenda</mat-icon>
|
||||
<a href="https://trello.com/b/ZAhMhpOy/gocryptotrader" target="_blank">
|
||||
<h3>Trello</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>apps</mat-icon>
|
||||
<a href="https://gocryptotrader.herokuapp.com/" target="_blank">
|
||||
<h3>Slack</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>bug_report</mat-icon>
|
||||
<a href="https://github.com/thrasher-/gocryptotrader/issues/new" target="_blank">
|
||||
<h3>Report a bug</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
</mat-nav-list>
|
||||
</mat-sidenav>
|
||||
<router-outlet class="main"></router-outlet>
|
||||
</mat-sidenav-container>
|
||||
<mat-sidenav #sidenav mode="side" class="sidebar" opened="true">
|
||||
<mat-nav-list>
|
||||
<mat-list-item routerLink="dashboard" routerLinkActive="dashboard-highlight">
|
||||
<mat-icon>view_quilt</mat-icon>
|
||||
<h3>Dashboard</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="wallet" routerLinkActive="wallet-highlight">
|
||||
<mat-icon>account_balance_wallet</mat-icon>
|
||||
<h3>Wallet</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="trading" routerLinkActive="trading-highlight">
|
||||
<mat-icon>swap_horiz</mat-icon>
|
||||
<h3>Trading</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="history" routerLinkActive="history-highlight">
|
||||
<mat-icon>history</mat-icon>
|
||||
<h3>History</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="settings" routerLinkActive="settings-highlight">
|
||||
<mat-icon>settings</mat-icon>
|
||||
<h3>Settings</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="help_outline" routerLinkActive="help-highlight">
|
||||
<mat-icon>help</mat-icon>
|
||||
<h3>Help</h3>
|
||||
</mat-list-item>
|
||||
<mat-list-item routerLink="donate" routerLinkActive="donate-highlight">
|
||||
<mat-icon>thumb_up</mat-icon>
|
||||
<h3>Donate</h3>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-list-item>
|
||||
<mat-icon>grade</mat-icon>
|
||||
<a href="https://github.com/thrasher-/gocryptotrader" target="_blank">
|
||||
<h3>GitHub</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>view_agenda</mat-icon>
|
||||
<a href="https://trello.com/b/ZAhMhpOy/gocryptotrader" target="_blank">
|
||||
<h3>Trello</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>apps</mat-icon>
|
||||
<a href="https://gocryptotrader.herokuapp.com/" target="_blank">
|
||||
<h3>Slack</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-list-item>
|
||||
<mat-icon>bug_report</mat-icon>
|
||||
<a href="https://github.com/thrasher-/gocryptotrader/issues/new" target="_blank">
|
||||
<h3>Report a bug</h3>
|
||||
</a>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-list-item *ngIf="isConnected" matTooltip="Online!">
|
||||
<mat-icon>network_wifi</mat-icon>
|
||||
</mat-list-item>
|
||||
<mat-list-item *ngIf="!isConnected" matTooltip="Offline">
|
||||
<mat-icon>signal_wifi_off</mat-icon>
|
||||
</mat-list-item>
|
||||
</mat-nav-list>
|
||||
|
||||
</mat-sidenav>
|
||||
<router-outlet class="main"></router-outlet>
|
||||
</mat-sidenav-container>
|
||||
@@ -41,6 +41,10 @@
|
||||
color: blueviolet !important;
|
||||
}
|
||||
|
||||
.help-highlight {
|
||||
color: red !important;
|
||||
}
|
||||
|
||||
.settings-highlight {
|
||||
color: magenta !important;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ElectronService } from './providers/electron.service';
|
||||
import { MatSidenav } from '@angular/material';
|
||||
import { SidebarService } from './services/sidebar/sidebar.service';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import {WebsocketResponseHandlerService }from './services/websocket-response-handler/websocket-response-handler.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -11,10 +12,12 @@ import { Router, NavigationEnd } from '@angular/router';
|
||||
})
|
||||
export class AppComponent {
|
||||
sidebarService: SidebarService
|
||||
public currentUrl:string;
|
||||
public currentUrl: string;
|
||||
@ViewChild('sidenav') public sidenav: MatSidenav;
|
||||
private ws : WebsocketResponseHandlerService;
|
||||
public isConnected :boolean = false;
|
||||
|
||||
constructor(public electronService: ElectronService,something: SidebarService, private router:Router) {
|
||||
constructor(public electronService: ElectronService, sidebarService: SidebarService, private router: Router, private websocketHandler: WebsocketResponseHandlerService) {
|
||||
|
||||
if (electronService.isElectron()) {
|
||||
console.log('Mode electron');
|
||||
@@ -26,18 +29,26 @@ export class AppComponent {
|
||||
console.log('Mode web');
|
||||
}
|
||||
|
||||
this.sidebarService = something;
|
||||
|
||||
router.events.subscribe(event => {
|
||||
this.isConnected = this.websocketHandler.isConnected;
|
||||
this.sidebarService = sidebarService;
|
||||
router.events.subscribe(event => {
|
||||
|
||||
if (event instanceof NavigationEnd ) {
|
||||
console.log("current url",event.url); // event.url has current url
|
||||
this.currentUrl = event.url;
|
||||
}
|
||||
});
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.isConnected = this.websocketHandler.isConnected;
|
||||
console.log("current url", event.url); // event.url has current url
|
||||
this.currentUrl = event.url;
|
||||
}
|
||||
});
|
||||
var interval = setInterval(() => {
|
||||
this.isConnected = this.websocketHandler.isConnected;
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.sidebarService.setSidenav(this.sidenav);
|
||||
}
|
||||
//This will be replaced with a log in prompt which will then add the credentials to session storage
|
||||
window.sessionStorage["username"] = "admin";
|
||||
window.sessionStorage["password"] = "e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a";
|
||||
}
|
||||
}
|
||||
|
||||
23
web/src/app/app.config.ts
Normal file
23
web/src/app/app.config.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { CONF_LOCAL } from '../environments/environment.local';
|
||||
import { CONF_DEV } from '../environments/environment.dev';
|
||||
import { CONF_PROD } from '../environments/environment.prod';
|
||||
|
||||
const ENV = 'local';
|
||||
|
||||
const LOCAL: String = 'local';
|
||||
const DEV: String = 'dev';
|
||||
const PROD: String = 'prod';
|
||||
|
||||
let conf: any;
|
||||
|
||||
console.log('Env', ENV);
|
||||
|
||||
if (ENV === PROD) {
|
||||
conf = CONF_PROD;
|
||||
} else if (ENV === DEV) {
|
||||
conf = CONF_DEV;
|
||||
} else {
|
||||
conf = CONF_LOCAL;
|
||||
}
|
||||
|
||||
export const AppConfig = Object.assign({}, conf);
|
||||
@@ -42,9 +42,10 @@ import { DonateComponent } from './pages/donate/donate.component';
|
||||
import { NavbarComponent } from './shared/navbar/navbar.component';
|
||||
import { AllEnabledCurrencyTickersComponent } from './shared/all-updates-ticker/all-updates-ticker.component';
|
||||
import { ThemePickerComponent } from './shared/theme-picker/theme-picker';
|
||||
import {IterateMapPipe, EnabledCurrenciesPipe} from './shared/classes/pipes';
|
||||
//services
|
||||
import { WebsocketService } from './services/websocket/websocket.service';
|
||||
import { WebsocketHandlerService } from './services/websocket-handler/websocket-handler.service';
|
||||
import { WebsocketResponseHandlerService } from './services/websocket-response-handler/websocket-response-handler.service';
|
||||
import { SidebarService } from './services/sidebar/sidebar.service';
|
||||
import { ElectronService } from './providers/electron.service';
|
||||
import { StyleManagerService } from './services/style-manager/style-manager.service';
|
||||
@@ -69,6 +70,7 @@ import { BuyFormComponent } from './shared/buy-form/buy-form.component';
|
||||
import { ExchangeGridComponent } from './pages/exchange-grid/exchange-grid.component';
|
||||
import { CurrencyListComponent } from './pages/currency-list/currency-list.component';
|
||||
import { SellFormComponent } from './shared/sell-form/sell-form.component';
|
||||
import { HelpComponent } from './pages/help/help.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -95,6 +97,9 @@ import { SellFormComponent } from './shared/sell-form/sell-form.component';
|
||||
ExchangeGridComponent,
|
||||
CurrencyListComponent,
|
||||
SellFormComponent,
|
||||
HelpComponent,
|
||||
IterateMapPipe,
|
||||
EnabledCurrenciesPipe
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -124,7 +129,7 @@ import { SellFormComponent } from './shared/sell-form/sell-form.component';
|
||||
providers: [
|
||||
ElectronService,
|
||||
WebsocketService,
|
||||
WebsocketHandlerService,
|
||||
WebsocketResponseHandlerService,
|
||||
SidebarService,
|
||||
StyleManagerService,
|
||||
ThemeStorageService,
|
||||
|
||||
@@ -1,35 +1,23 @@
|
||||
<mat-list>
|
||||
<h3 matSubheader>Poloniex</h3>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>BTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>LTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>ETH_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
<h3 matSubheader>Kraken</h3>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>BTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>LTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>ETH_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel *ngFor="let currency of exchangeCurrencies | iterateMap">
|
||||
<mat-expansion-panel-header [ngClass]="{'selected' : selectedCurrency == currency.value}" >
|
||||
<mat-panel-title>
|
||||
{{currency.value}}
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
image and blurb
|
||||
<div>
|
||||
<i>Only displaying enabled currencies</i>
|
||||
</div>
|
||||
<form class="form-content">
|
||||
<mat-list>
|
||||
<mat-list-item [ngClass]="{'selected' : selectedExchange == exchange}" *ngFor="let exchange of currency.key" >
|
||||
<h4 matLine>{{exchange}}</h4>
|
||||
<button mat-button (click)="selectCurrency(exchange, currency.value)">SELECT</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</form>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
@@ -6,4 +6,8 @@
|
||||
}
|
||||
.ETH {
|
||||
color:darkslategrey;
|
||||
}
|
||||
|
||||
.selected, .selected:hover, .selected:focus, .selected::selection {
|
||||
background: rgba(100,250,100,0.2);
|
||||
}
|
||||
@@ -1,15 +1,73 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, Pipe, PipeTransform} from '@angular/core';
|
||||
import { WebsocketResponseHandlerService} from './../../services/websocket-response-handler/websocket-response-handler.service';
|
||||
import { WebSocketMessageType, WebSocketMessage} from './../../shared/classes/websocket';
|
||||
import { Config, CurrencyPairRedux} from './../../shared/classes/config';
|
||||
import { EnabledCurrenciesPipe, IterateMapPipe} from './../../shared/classes/pipes';
|
||||
|
||||
@Component({
|
||||
selector: 'app-currency-list',
|
||||
templateUrl: './currency-list.component.html',
|
||||
styleUrls: ['./currency-list.component.scss']
|
||||
styleUrls: ['./currency-list.component.scss'],
|
||||
})
|
||||
export class CurrencyListComponent implements OnInit {
|
||||
public settings: Config = new Config();
|
||||
private ws: WebsocketResponseHandlerService;
|
||||
public selectedCurrency :string;
|
||||
public selectedExchange :string;
|
||||
public exchangeCurrencies: Map <string, string[] > = new Map < string, string[] > ();
|
||||
|
||||
constructor() { }
|
||||
|
||||
constructor(private websocketHandler: WebsocketResponseHandlerService) {
|
||||
this.selectedExchange = window.localStorage["selectedExchange"];
|
||||
this.selectedCurrency = window.localStorage["selectedCurrency"];
|
||||
this.ws = websocketHandler;
|
||||
this.ws.shared.subscribe(msg => {
|
||||
if (msg.event === WebSocketMessageType.GetConfig) {
|
||||
this.settings.setConfig(msg.data);
|
||||
this.getExchangeCurrencies();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
public selectCurrency(exchange:string,currency:string) {
|
||||
window.localStorage["selectedExchange"] = exchange;
|
||||
window.localStorage["selectedCurrency"] = currency;
|
||||
this.selectedExchange = window.localStorage["selectedExchange"];
|
||||
this.selectedCurrency = window.localStorage["selectedCurrency"];
|
||||
}
|
||||
|
||||
public getExchangeCurrencies(): void {
|
||||
for (var i = 0; i < this.settings.Exchanges.length; i++) {
|
||||
if (this.settings.Exchanges[i].Enabled === true) {
|
||||
for (var j = 0; j < this.settings.Exchanges[i].Pairs.length; j++) {
|
||||
if(this.settings.Exchanges[i].Pairs[j].Enabled) {
|
||||
if(this.exchangeCurrencies.has(this.settings.Exchanges[i].Pairs[j].ParsedName)) {
|
||||
var array = this.exchangeCurrencies.get(this.settings.Exchanges[i].Pairs[j].ParsedName);
|
||||
array.push(this.settings.Exchanges[i].Name);
|
||||
this.exchangeCurrencies.set(this.settings.Exchanges[i].Pairs[j].ParsedName, array);
|
||||
} else {
|
||||
var exchangeArray = new Array<string>();
|
||||
exchangeArray.push(this.settings.Exchanges[i].Name);
|
||||
this.exchangeCurrencies.set(this.settings.Exchanges[i].Pairs[j].ParsedName, exchangeArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.exchangeCurrencies.forEach((value: string[], key: string) => {});
|
||||
}
|
||||
|
||||
private getSettings(): void {
|
||||
if (this.settings.isConfigCacheValid()) {
|
||||
this.settings.setConfig(JSON.parse(window.localStorage['config']))
|
||||
this.getExchangeCurrencies();
|
||||
} else {
|
||||
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ mat-card-footer button {
|
||||
position: fixed;
|
||||
top: auto;
|
||||
right: 5rem;
|
||||
bottom: 3rem;
|
||||
bottom: 5rem;
|
||||
left: auto;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
@@ -49,7 +49,7 @@ mat-card-footer button {
|
||||
|
||||
.buy-sell-card {
|
||||
width: 20rem;
|
||||
height: 22rem;
|
||||
height: 24rem;
|
||||
margin-left: auto;
|
||||
margin-right: 1rem;
|
||||
z-index: 3;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<mat-card class="full-card">
|
||||
<mat-card class="full-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Donations</mat-card-title>
|
||||
<mat-card-subtitle>We give our thanks</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<img class="heart" src="/assets/early-dumb-donate.png"/>
|
||||
<p>If this framework helped you in any way, or you would like to support the developers working on it, please donate</p>
|
||||
<mat-list>
|
||||
<mat-list-item >
|
||||
<mat-icon mat-list-icon class="BTC">attach_money</mat-icon>
|
||||
<h4 mat-line>Address:</h4>
|
||||
<h4 mat-line>1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB</h4>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
<img class="heart" src="./assets/images/donate.png" />
|
||||
<p>If this framework helped you in any way, or you would like to support the developers working on it, please donate</p>
|
||||
<mat-list>
|
||||
<mat-list-item>
|
||||
<mat-icon mat-list-icon class="BTC">attach_money</mat-icon>
|
||||
<h4 mat-line>Address:</h4>
|
||||
<h4 mat-line>1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB</h4>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,59 +1,22 @@
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel >
|
||||
<mat-expansion-panel-header>
|
||||
<mat-expansion-panel *ngFor="let exchange of exchangeCurrencies | iterateMap">
|
||||
<mat-expansion-panel-header [ngClass]="{'selected' : selectedExchange == exchange.value}">
|
||||
<mat-panel-title>
|
||||
Poloniex
|
||||
{{exchange.value}}
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
image and blurb
|
||||
<div>
|
||||
<i>Only displaying enabled currencies</i>
|
||||
</div>
|
||||
<form class="form-content">
|
||||
<mat-list>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>BTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
<mat-list-item [ngClass]="{'selected' : selectedCurrency == currency.ParsedName}" *ngFor="let currency of exchange.key | enabledCurrencies" >
|
||||
<h4 matLine>{{currency.ParsedName}}</h4>
|
||||
<button mat-button (click)="selectCurrency(exchange.value,currency.ParsedName)">SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>LTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>ETH_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</form>
|
||||
</mat-expansion-panel><mat-expansion-panel >
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Kraken
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
image and blurb
|
||||
<form class="form-content">
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>BTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>LTC_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
<mat-list-item >
|
||||
<mat-icon matListIcon>attach_money</mat-icon>
|
||||
<h4 matLine>ETH_USD</h4>
|
||||
<button mat-button>SELECT</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</form>
|
||||
</mat-expansion-panel>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.selected, .selected:hover, .selected:focus, .selected::selection {
|
||||
background: rgba(100,250,100,0.2);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, Pipe, PipeTransform} from '@angular/core';
|
||||
import { WebsocketResponseHandlerService} from './../../services/websocket-response-handler/websocket-response-handler.service';
|
||||
import { WebSocketMessageType, WebSocketMessage} from './../../shared/classes/websocket';
|
||||
import { Config, CurrencyPairRedux} from './../../shared/classes/config';
|
||||
import { EnabledCurrenciesPipe, IterateMapPipe} from './../../shared/classes/pipes';
|
||||
|
||||
@Component({
|
||||
selector: 'app-exchange-grid',
|
||||
@@ -6,10 +10,54 @@ import { Component, OnInit } from '@angular/core';
|
||||
styleUrls: ['./exchange-grid.component.scss']
|
||||
})
|
||||
export class ExchangeGridComponent implements OnInit {
|
||||
public settings: Config = new Config();
|
||||
private ws: WebsocketResponseHandlerService;
|
||||
public selectedCurrency :string;
|
||||
public selectedExchange :string;
|
||||
public exchangeCurrencies: Map < string, CurrencyPairRedux[] > = new Map < string, CurrencyPairRedux[] > ();
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
constructor(private websocketHandler: WebsocketResponseHandlerService) {
|
||||
this.selectedExchange = window.localStorage["selectedExchange"];
|
||||
this.selectedCurrency = window.localStorage["selectedCurrency"];
|
||||
this.ws = websocketHandler;
|
||||
this.ws.shared.subscribe(msg => {
|
||||
if (msg.event === WebSocketMessageType.GetConfig) {
|
||||
this.settings.setConfig(msg.data);
|
||||
this.getExchangeCurrencies();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
|
||||
public selectCurrency(exchange:string,currency:string) {
|
||||
window.localStorage["selectedExchange"] = exchange;
|
||||
window.localStorage["selectedCurrency"] = currency;
|
||||
this.selectedExchange = window.localStorage["selectedExchange"];
|
||||
this.selectedCurrency = window.localStorage["selectedCurrency"];
|
||||
}
|
||||
|
||||
public getExchangeCurrencies(): void {
|
||||
for (var i = 0; i < this.settings.Exchanges.length; i++) {
|
||||
if (this.settings.Exchanges[i].Enabled === true) {
|
||||
this.exchangeCurrencies.set(this.settings.Exchanges[i].Name, this.settings.Exchanges[i].Pairs)
|
||||
}
|
||||
}
|
||||
this.exchangeCurrencies.forEach((value: CurrencyPairRedux[], key: string) => {});
|
||||
}
|
||||
|
||||
private getSettings(): void {
|
||||
if (this.settings.isConfigCacheValid()) {
|
||||
this.settings.setConfig(JSON.parse(window.localStorage['config']))
|
||||
this.getExchangeCurrencies();
|
||||
} else {
|
||||
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
3
web/src/app/pages/help/help.component.html
Normal file
3
web/src/app/pages/help/help.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<p>
|
||||
help works!
|
||||
</p>
|
||||
0
web/src/app/pages/help/help.component.scss
Normal file
0
web/src/app/pages/help/help.component.scss
Normal file
25
web/src/app/pages/help/help.component.spec.ts
Normal file
25
web/src/app/pages/help/help.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HelpComponent } from './help.component';
|
||||
|
||||
describe('HelpComponent', () => {
|
||||
let component: HelpComponent;
|
||||
let fixture: ComponentFixture<HelpComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ HelpComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HelpComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
web/src/app/pages/help/help.component.ts
Normal file
15
web/src/app/pages/help/help.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-help',
|
||||
templateUrl: './help.component.html',
|
||||
styleUrls: ['./help.component.scss']
|
||||
})
|
||||
export class HelpComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,56 @@
|
||||
<div class="docs-homepage-promo">
|
||||
<h2 class="mat-h1">Welcome to GoCryptoTrader</h2>
|
||||
|
||||
<h1 class="mat-h1">Welcome to GoCryptoTrader</h1>
|
||||
<p>GoCryptoTrader is a multi-currency, multi-exchange trader for cryptocurrencies</p>
|
||||
<p>It is under active development and you can see its development progress by clicking the trello button to the left</p>
|
||||
<p>If you like what you see, consider clicking the donation button to the left</p>
|
||||
<div class="docs-homepage-row">
|
||||
<div class="docs-homepage-promo-img">
|
||||
<img src="./assets/exchanges.jpg" />
|
||||
</div>
|
||||
<div class="docs-homepage-promo-desc">
|
||||
<h2>Multi-currency, multi-exchange</h2>
|
||||
<p>With support for over 25 of the top cryptocurrency exchanges</p>
|
||||
<div class="docs-homepage-bottom-start">
|
||||
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="docs-homepage-row docs-homepage-reverse-row">
|
||||
<div class="docs-homepage-promo-img">
|
||||
<img src="./assets/loop.png" />
|
||||
</div>
|
||||
|
||||
<div class="docs-homepage-promo-desc">
|
||||
<h2>High speed, low drag</h2>
|
||||
<p>Constant checking of all enabled exchanges* to get you the most up to date information</p>
|
||||
<div class="docs-homepage-bottom-start">
|
||||
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="docs-homepage-row">
|
||||
<div class="docs-homepage-promo-img">
|
||||
<img src="./assets/centralised.png" />
|
||||
</div>
|
||||
<div class="docs-homepage-promo-desc">
|
||||
<h2>Centralised management</h2>
|
||||
<p>Add and manage all your wallets from one application</p>
|
||||
<div class="docs-homepage-bottom-start">
|
||||
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="docs-homepage-row docs-homepage-reverse-row">
|
||||
<div class="docs-homepage-promo-img">
|
||||
<img src="./assets/material.png" />
|
||||
</div>
|
||||
<div class="docs-homepage-promo-desc">
|
||||
<h2>Optimized for Angular</h2>
|
||||
<p>The latest tech with Material design lets you focus on what's important</p>
|
||||
<div class="docs-homepage-bottom-start">
|
||||
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="docs-homepage-bottom-start">
|
||||
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,71 @@
|
||||
.example-card {
|
||||
width: 400px;
|
||||
}
|
||||
.docs-homepage-promo {
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.docs-homepage-promo h2 {
|
||||
font-size: 25px;
|
||||
font-weight: 400;
|
||||
margin: 0 0 16px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.docs-homepage-promo p {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 28px;
|
||||
margin: 0 0 24px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.docs-homepage-promo-img img {
|
||||
max-width: 90%;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.docs-homepage-promo-desc {
|
||||
line-height: 2;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.docs-homepage-promo-desc,
|
||||
.docs-homepage-promo-img {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.docs-homepage-promo-img {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.docs-homepage-row {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 50%;
|
||||
margin: 60px 0;
|
||||
}
|
||||
|
||||
.docs-homepage-reverse-row {
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: reverse;
|
||||
-ms-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel *ngIf="settings.SMSGlobal != null">
|
||||
<mat-expansion-panel-header >
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
SMS Global
|
||||
</mat-panel-title>
|
||||
@@ -15,7 +15,7 @@
|
||||
SMS configuration and contact management
|
||||
<mat-icon>phone_iphone</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
</mat-expansion-panel-header>
|
||||
<form class="form-content">
|
||||
<mat-checkbox name="smsEnabled" [(ngModel)]="settings.SMSGlobal.Enabled">Enabled</mat-checkbox>
|
||||
<div mat-line></div>
|
||||
@@ -53,25 +53,23 @@
|
||||
<form class="form-content">
|
||||
<mat-checkbox name="exchangeEnabled" [(ngModel)]="exchange.Enabled">Enabled</mat-checkbox>
|
||||
<div mat-line></div>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiKey" [(ngModel)]="exchange.APIKey" [disabled]="!exchange.Enabled" placeholder="API Key*">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiSecretKey" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiClientId" [(ngModel)]="exchange.ClientID" [disabled]="!exchange.Enabled" placeholder="API ClientID">
|
||||
</mat-form-field>
|
||||
<div mat-line></div>
|
||||
<mat-panel-description>
|
||||
Enabled Currency pairs {{enabledCurrencies.selectedOptions.selected.length}} - Managed via config temporarily
|
||||
</mat-panel-description>
|
||||
<div mat-line></div>
|
||||
<mat-selection-list #enabledCurrencies>
|
||||
<mat-list-option [disabled]="!exchange.Enabled || true" *ngFor="let currency of exchange.AvailablePairs.split(',')">
|
||||
{{currency}}
|
||||
</mat-list-option>
|
||||
</mat-selection-list>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiKey" [(ngModel)]="exchange.APIKey" [disabled]="!exchange.Enabled" placeholder="API Key*">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiSecretKey" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="apiClientId" [(ngModel)]="exchange.ClientID" [disabled]="!exchange.Enabled" placeholder="API ClientID">
|
||||
</mat-form-field>
|
||||
<div mat-line></div>
|
||||
<h4>
|
||||
Enabled currencies
|
||||
</h4>
|
||||
<div *ngFor="let currency of exchange.Pairs">
|
||||
<p>{{currency.Name}}</p>
|
||||
<mat-checkbox name="{{currency.Name}}2" [(ngModel)]="currency.Enabled"></mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
||||
@@ -1,145 +1,50 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { WebsocketResponseHandlerService } from './../../services/websocket-response-handler/websocket-response-handler.service';
|
||||
import { WebSocketMessageType, WebSocketMessage } from './../../shared/classes/websocket';
|
||||
import { Config, CurrencyPairRedux } from './../../shared/classes/config';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.scss']
|
||||
styleUrls: ['./settings.component.scss'],
|
||||
})
|
||||
|
||||
|
||||
export class SettingsComponent implements OnInit {
|
||||
public settings: Config = null;
|
||||
private ws: WebsocketHandlerService;
|
||||
private failCount = 0;
|
||||
private timer: any;
|
||||
public settings: Config = new Config();
|
||||
private ws: WebsocketResponseHandlerService;
|
||||
|
||||
private getSettingsMessage = {
|
||||
Event: 'GetConfig',
|
||||
data: null,
|
||||
};
|
||||
|
||||
constructor(private websocketHandler: WebsocketHandlerService) {
|
||||
constructor(private websocketHandler: WebsocketResponseHandlerService) {
|
||||
this.ws = websocketHandler;
|
||||
this.ws.messages.subscribe(msg => {
|
||||
|
||||
if (msg.Event === 'GetConfig') {
|
||||
this.settings = <Config>msg.data;
|
||||
} else if (msg.Event === 'SaveConfig') {
|
||||
// something!
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
this.ws.shared.subscribe(msg => {
|
||||
if (msg.event === WebSocketMessageType.GetConfig) {
|
||||
this.settings.setConfig(msg.data);
|
||||
} else if (msg.event === WebSocketMessageType.SaveConfig) {
|
||||
// check if err is returned, then display some notification
|
||||
}
|
||||
});
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
|
||||
private getSettings(): void {
|
||||
this.ws.messages.next(this.getSettingsMessage);
|
||||
this.resendMessageIfPageRefreshed();
|
||||
if(this.settings.isConfigCacheValid()) {
|
||||
this.settings.setConfig(JSON.parse(window.localStorage['config']))
|
||||
} else {
|
||||
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private saveSettings(): void {
|
||||
//Send the message
|
||||
|
||||
this.settings.fromReduxToArray()
|
||||
var settingsSave = {
|
||||
Event: 'SaveConfig',
|
||||
data: this.settings,
|
||||
}
|
||||
this.ws.messages.next(settingsSave);
|
||||
}
|
||||
|
||||
//there has to be a better way
|
||||
private resendMessageIfPageRefreshed(): void {
|
||||
if (this.failCount <= 10) {
|
||||
setTimeout(() => {
|
||||
if (this.settings === null) {
|
||||
//console.log(this.failCount);
|
||||
//console.log('Settings hasnt been set. Trying again');
|
||||
this.failCount++;
|
||||
this.getSettings();
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
// something has gone wrong
|
||||
console.log('Could not load settings. Check if GocryptoTrader server is running, otherwise open a ticket');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface CurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Delimiter: string;
|
||||
}
|
||||
|
||||
export interface PortfolioAddresses {
|
||||
Addresses?: any;
|
||||
}
|
||||
|
||||
export interface Contact {
|
||||
Name: string;
|
||||
Number: string;
|
||||
Enabled: boolean;
|
||||
}
|
||||
|
||||
export interface SMSGlobal {
|
||||
Enabled: boolean;
|
||||
Username: string;
|
||||
Password: string;
|
||||
Contacts: Contact[];
|
||||
}
|
||||
|
||||
export interface Webserver {
|
||||
Enabled: boolean;
|
||||
AdminUsername: string;
|
||||
AdminPassword: string;
|
||||
ListenAddress: string;
|
||||
WebsocketConnectionLimit: number;
|
||||
WebsocketAllowInsecureOrigin: boolean;
|
||||
}
|
||||
|
||||
export interface ConfigCurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Index: string;
|
||||
Delimiter: string;
|
||||
}
|
||||
|
||||
export interface RequestCurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Index: string;
|
||||
Delimiter: string;
|
||||
Separator: string;
|
||||
}
|
||||
|
||||
export interface Exchange {
|
||||
Name: string;
|
||||
Enabled: boolean;
|
||||
Verbose: boolean;
|
||||
Websocket: boolean;
|
||||
RESTPollingDelay: number;
|
||||
AuthenticatedAPISupport: boolean;
|
||||
APIKey: string;
|
||||
APISecret: string;
|
||||
AvailablePairs: string;
|
||||
EnabledPairs: string;
|
||||
BaseCurrencies: string;
|
||||
AssetTypes: string;
|
||||
ConfigCurrencyPairFormat: ConfigCurrencyPairFormat;
|
||||
RequestCurrencyPairFormat: RequestCurrencyPairFormat;
|
||||
ClientID: string;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
Name: string;
|
||||
EncryptConfig?: number;
|
||||
Cryptocurrencies: string;
|
||||
CurrencyExchangeProvider: string;
|
||||
CurrencyPairFormat: CurrencyPairFormat;
|
||||
PortfolioAddresses: PortfolioAddresses;
|
||||
SMSGlobal: SMSGlobal;
|
||||
Webserver: Webserver;
|
||||
Exchanges: Exchange[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let coin of wallet?.coin_totals">
|
||||
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
|
||||
<i [ngClass]="coin.icon"></i>
|
||||
<h4 mat-line>{{coin.coin}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}</h4>
|
||||
</mat-list-item>
|
||||
@@ -26,21 +26,21 @@
|
||||
</mat-expansion-panel-header>
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let coin of wallet?.online_summary.BTC">
|
||||
<mat-icon mat-list-icon class="BTC">{{coinIcon('BTC')}}</mat-icon>
|
||||
<i class="cc btc"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-list-item *ngFor="let coin of wallet?.online_summary.LTC">
|
||||
<mat-icon mat-list-icon class="LTC">{{coinIcon('LTC')}}</mat-icon>
|
||||
<i class="cc ltc"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-list-item *ngFor="let coin of wallet?.online_summary.ETH">
|
||||
<mat-icon mat-list-icon class="ETH">{{coinIcon('ETH')}}</mat-icon>
|
||||
<i class="cc eth"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
@@ -55,21 +55,21 @@
|
||||
</mat-expansion-panel-header>
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let coin of wallet?.offline_summary.BTC">
|
||||
<mat-icon mat-list-icon class="BTC">{{coinIcon('BTC')}}</mat-icon>
|
||||
<i class="cc btc"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-list-item *ngFor="let coin of wallet?.offline_summary.LTC">
|
||||
<mat-icon mat-list-icon class="LTC">{{coinIcon('LTC')}}</mat-icon>
|
||||
<i class="cc ltc"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-list-item *ngFor="let coin of wallet?.offline_summary.ETH">
|
||||
<mat-icon mat-list-icon class="ETH">{{coinIcon('ETH')}}</mat-icon>
|
||||
<i class="cc eth"></i>
|
||||
<h4 mat-line>Address: {{coin.address}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
|
||||
</mat-list-item>
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let coin of wallet?.coins_online">
|
||||
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
|
||||
<i [ngClass]="coin.icon"></i>
|
||||
<h4 mat-line>{{coin.coin}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}</h4>
|
||||
</mat-list-item>
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let coin of wallet?.coins_offline">
|
||||
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
|
||||
<i [ngClass]="coin.icon"></i>
|
||||
<h4 mat-line>{{coin.coin}}</h4>
|
||||
<h4 mat-line>{{coin.balance}}</h4>
|
||||
</mat-list-item>
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { WebsocketResponseHandlerService } from './../../services/websocket-response-handler/websocket-response-handler.service';
|
||||
import { Wallet, CoinTotal } from './../../shared/classes/wallet';
|
||||
import {Sort} from '@angular/material';
|
||||
import { Sort } from '@angular/material';
|
||||
import { WebSocketMessageType, WebSocketMessage } from './../../shared/classes/websocket';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet',
|
||||
templateUrl: './wallet.component.html',
|
||||
styleUrls: ['./wallet.component.scss']
|
||||
styleUrls: ['./wallet.component.scss'],
|
||||
})
|
||||
|
||||
export class WalletComponent implements OnInit {
|
||||
private ws: WebsocketHandlerService;
|
||||
private ws: WebsocketResponseHandlerService;
|
||||
private failCount = 0;
|
||||
private timer: any;
|
||||
public wallet: Wallet;
|
||||
displayedColumns = ['coin', 'balance'];
|
||||
|
||||
private getWalletMessage = {
|
||||
Event: 'GetPortfolio',
|
||||
event: 'GetPortfolio',
|
||||
data: null,
|
||||
};
|
||||
|
||||
constructor(private websocketHandler: WebsocketHandlerService) {
|
||||
constructor(private websocketHandler: WebsocketResponseHandlerService) {
|
||||
this.wallet= null;
|
||||
this.ws = websocketHandler;
|
||||
this.ws.messages.subscribe(msg => {
|
||||
if (msg.Event === 'GetPortfolio') {
|
||||
console.log(JSON.stringify(msg.data));
|
||||
this.ws.shared.subscribe(msg => {
|
||||
if (msg.event === WebSocketMessageType.GetPortfolio) {
|
||||
this.wallet = <Wallet>msg.data;
|
||||
|
||||
this.attachIcon(this.wallet.coin_totals);
|
||||
this.attachIcon(this.wallet.coins_offline);
|
||||
this.attachIcon(this.wallet.coins_online);
|
||||
@@ -44,11 +43,19 @@ export class WalletComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.setWallet();
|
||||
}
|
||||
|
||||
private setWallet():void {
|
||||
this.ws.messages.next(this.getWalletMessage);
|
||||
}
|
||||
|
||||
public coinIcon(coin:string) :string {
|
||||
switch(coin) {
|
||||
case "BTC": return "attach_money";
|
||||
case "LTC": return "attach_money";
|
||||
case "ETH": return "attach_money";
|
||||
case "BTC": return "cc BTC";
|
||||
case "LTC": return "cc LTC";
|
||||
case "ETH": return "cc ETH";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,28 +67,5 @@ export class WalletComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.setWallet();
|
||||
}
|
||||
|
||||
//there has to be a better way
|
||||
private resendMessageIfPageRefreshed(): void {
|
||||
if (this.failCount <= 10) {
|
||||
setTimeout(() => {
|
||||
if (this.wallet === null || this.wallet === undefined) {
|
||||
this.failCount++;
|
||||
this.setWallet();
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
console.log('Could not load wallet. Check if GocryptoTrader server is running, otherwise open a ticket');
|
||||
}
|
||||
}
|
||||
|
||||
private setWallet():void {
|
||||
this.ws.messages.next(this.getWalletMessage);
|
||||
this.resendMessageIfPageRefreshed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { WebsocketHandlerService } from './websocket-handler.service';
|
||||
|
||||
describe('WebsocketHandlerService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [WebsocketHandlerService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([WebsocketHandlerService], (service: WebsocketHandlerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs/Rx';
|
||||
import { WebsocketService } from './../../services/websocket/websocket.service';
|
||||
|
||||
const WEBSOCKET_URL = 'ws://localhost:9050/ws';
|
||||
|
||||
export interface Message {
|
||||
Event: string,
|
||||
data:any,
|
||||
Exchange:string,
|
||||
AssetType:string
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class WebsocketHandlerService {
|
||||
public messages: Subject<any>;
|
||||
|
||||
private authenticateMessage = {
|
||||
Event:'auth',
|
||||
data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
|
||||
}
|
||||
|
||||
public authenticate() {
|
||||
this.messages.next(this.authenticateMessage);
|
||||
}
|
||||
|
||||
constructor(wsService: WebsocketService) {
|
||||
this.messages = <Subject<Message>>wsService
|
||||
.connect(WEBSOCKET_URL)
|
||||
.map((response: MessageEvent): Message => {
|
||||
|
||||
let data = JSON.parse(response.data);
|
||||
// variables aren't consistent yet. Here's a hack!
|
||||
var dataData = data.Data === undefined ? data.data : data.Data;
|
||||
var eventEvent = data.Event === undefined ? data.event : data.Event;
|
||||
return {
|
||||
Event: eventEvent,
|
||||
data: dataData,
|
||||
Exchange: data.exchange,
|
||||
AssetType: data.assetType
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { WebsocketResponseHandlerService } from './websocket-response-handler.service';
|
||||
|
||||
describe('WebsocketHandlerService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [WebsocketResponseHandlerService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([WebsocketResponseHandlerService], (service: WebsocketResponseHandlerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { NgModule, Injectable, Optional, SkipSelf } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs/Rx';
|
||||
import { WebsocketService } from './../../services/websocket/websocket.service';
|
||||
import { WebSocketMessage } from './../../shared/classes/websocket';
|
||||
|
||||
const WEBSOCKET_URL = 'ws://localhost:9050/ws';
|
||||
|
||||
@NgModule({
|
||||
})
|
||||
export class WebsocketResponseHandlerService {
|
||||
public messages: Subject<any>;
|
||||
public shared: Observable<WebSocketMessage>;
|
||||
public isConnected :boolean = false;
|
||||
|
||||
constructor(@Optional() @SkipSelf() parentModule: WebsocketResponseHandlerService, wsService: WebsocketService) {
|
||||
this.messages = <Subject<WebSocketMessage>>wsService
|
||||
.connect(WEBSOCKET_URL)
|
||||
|
||||
.map((response: MessageEvent): WebSocketMessage => {
|
||||
this.isConnected = wsService.isConnected;
|
||||
let websocketResponseMessage = JSON.parse(response.data);
|
||||
var websocketResponseData = websocketResponseMessage.Data === undefined ? websocketResponseMessage.data : websocketResponseMessage.Data;
|
||||
var websocketResponseEvent = websocketResponseMessage.Event === undefined ? websocketResponseMessage.event : websocketResponseMessage.Event;
|
||||
let responseMessage = new WebSocketMessage();
|
||||
|
||||
responseMessage.event = websocketResponseEvent;
|
||||
responseMessage.data = websocketResponseData;
|
||||
responseMessage.exchange = websocketResponseMessage.exchange;
|
||||
responseMessage.assetType = websocketResponseMessage.assetType;
|
||||
|
||||
return responseMessage;
|
||||
});
|
||||
this.isConnected = wsService.isConnected;
|
||||
|
||||
this.shared = this.messages.share(); //multicast
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,62 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {Subject, Observable, Observer } from 'rxjs/Rx';
|
||||
import { Injectable, Optional, SkipSelf, NgModule } from '@angular/core';
|
||||
import { Subject, Observable, Observer } from 'rxjs/Rx';
|
||||
import { WebSocketMessage } from './../../shared/classes/websocket';
|
||||
|
||||
@Injectable()
|
||||
@NgModule()
|
||||
export class WebsocketService {
|
||||
constructor() { }
|
||||
public isConnected :boolean = false;
|
||||
constructor (@Optional() @SkipSelf() parentModule: WebsocketService) {
|
||||
if (parentModule) {
|
||||
throw new Error(
|
||||
'WebsocketService is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
|
||||
private subject: Subject<MessageEvent>;
|
||||
|
||||
public connect(url): Subject<MessageEvent> {
|
||||
if (!this.subject) {
|
||||
this.subject = this.create(url);
|
||||
}
|
||||
}
|
||||
return this.subject;
|
||||
}
|
||||
|
||||
private authenticateMessage = {
|
||||
Event:'auth',
|
||||
data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
|
||||
}
|
||||
|
||||
private isAuth = false;
|
||||
|
||||
private create(url): Subject<MessageEvent> {
|
||||
let ws = new WebSocket(url);
|
||||
|
||||
let observable = Observable.create(
|
||||
(obs: Observer<MessageEvent>) => {
|
||||
ws.onmessage = obs.next.bind(obs);
|
||||
ws.onerror = obs.error.bind(obs);
|
||||
ws.onclose = obs.complete.bind(obs);
|
||||
return ws.close.bind(ws);
|
||||
})
|
||||
let observer = {
|
||||
next: (data: any) => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(this.authenticateMessage));
|
||||
|
||||
ws.send(JSON.stringify(data));
|
||||
(obs: Observer<MessageEvent>) => {
|
||||
ws.onmessage = obs.next.bind(obs);
|
||||
ws.onerror = obs.error.bind(obs);
|
||||
ws.onclose = () => {
|
||||
this.isConnected = false;
|
||||
obs.complete.bind(obs) };
|
||||
ws.onopen = () => {
|
||||
this.isConnected = true;
|
||||
ws.send(JSON.stringify(WebSocketMessage.CreateAuthenticationMessage()));
|
||||
};
|
||||
return ws.close.bind(ws);
|
||||
})
|
||||
let observer = {
|
||||
next: (data: any) => {
|
||||
var counter = 0;
|
||||
var interval = setInterval(() => {
|
||||
if (counter == 10) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(data));
|
||||
clearInterval(interval);
|
||||
this.isConnected = true;
|
||||
}
|
||||
counter++;
|
||||
}, 400);
|
||||
|
||||
if (ws.readyState !== WebSocket.OPEN) {
|
||||
new Error("Failed to send message to websocket after 10 attempts");
|
||||
this.isConnected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Subject.create(observer, observable);
|
||||
}
|
||||
return Subject.create(observer, observable);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1 @@
|
||||
<div *ngIf="showTicker" class="one-time-animation" >
|
||||
<p>{{message}}</p>
|
||||
</div>
|
||||
{{tickerCard.Exchange}} {{tickerCard.CurrencyPair}} Last: {{this.tickerCard.Last}}
|
||||
@@ -1,61 +1,86 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
|
||||
import {Component, OnInit, OnDestroy }from '@angular/core';
|
||||
import {WebsocketResponseHandlerService }from './../../services/websocket-response-handler/websocket-response-handler.service';
|
||||
import {WebSocketMessageType }from './../../shared/classes/websocket';
|
||||
|
||||
@Component({
|
||||
selector: 'app-all-updates-ticker',
|
||||
templateUrl: './all-updates-ticker.component.html',
|
||||
styleUrls: ['./all-updates-ticker.component.scss']
|
||||
@Component( {
|
||||
selector:'app-all-updates-ticker',
|
||||
templateUrl:'./all-updates-ticker.component.html',
|
||||
styleUrls:['./all-updates-ticker.component.scss'],
|
||||
})
|
||||
export class AllEnabledCurrencyTickersComponent implements OnInit {
|
||||
private ws: WebsocketHandlerService;
|
||||
allCurrencies:ExchangeCurrency[];
|
||||
tickerCard: TickerUpdate;
|
||||
showTicker:boolean;
|
||||
message:string;
|
||||
allCurrencies:ExchangeCurrency[] = < ExchangeCurrency[] > []; ;
|
||||
private ws:WebsocketResponseHandlerService;
|
||||
tickerCard:TickerUpdate = new TickerUpdate();
|
||||
showTicker:boolean = true;
|
||||
message:string;
|
||||
|
||||
constructor(private websocketHandler: WebsocketHandlerService) {
|
||||
this.ws = websocketHandler;
|
||||
this.allCurrencies = <ExchangeCurrency[]>[];
|
||||
this.ws.messages.subscribe(msg => {
|
||||
if (msg.Event === 'ticker_update') {
|
||||
this.showTicker = false;
|
||||
var modal = <ExchangeCurrency>{};
|
||||
modal.currencyPair = msg.data.CurrencyPair;
|
||||
modal.exchangeName = msg.Exchange;
|
||||
var ticker = <TickerUpdate>msg.data;
|
||||
this.tickerCard = ticker;
|
||||
this.tickerCard.Exchange = msg.Exchange;
|
||||
|
||||
if(this.tickerCard.Last > 0) {
|
||||
this.showTicker = true;
|
||||
this.message = this.tickerCard.Exchange + " " + this.tickerCard.CurrencyPair + " Last: " + this.tickerCard.Last;
|
||||
constructor(private websocketHandler: WebsocketResponseHandlerService) {
|
||||
this.tickerCard.Exchange = "Loading";
|
||||
this.tickerCard.CurrencyPair = "...";
|
||||
this.tickerCard.Last = -1;
|
||||
this.ws = websocketHandler;
|
||||
this.ws.shared.subscribe(msg => {
|
||||
if (msg.event === WebSocketMessageType.TickerUpdate) {
|
||||
if (window.localStorage["selectedExchange"] !== undefined &&
|
||||
window.localStorage["selectedCurrency"] !== undefined) {
|
||||
this.tickerCard.Exchange = window.localStorage["selectedExchange"];
|
||||
this.tickerCard.CurrencyPair = window.localStorage["selectedCurrency"];
|
||||
if (msg.exchange == window.localStorage["selectedExchange"]) {
|
||||
if (this.stripCurrencyCharacters(msg.data.CurrencyPair) == window.localStorage["selectedCurrency"]) {
|
||||
|
||||
this.updateTicker(msg)
|
||||
}
|
||||
}
|
||||
}else {
|
||||
this.updateTicker(msg)
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
ngOnInit() { }
|
||||
|
||||
private updateTicker(msg:any):void {
|
||||
var modal = < ExchangeCurrency > {};
|
||||
modal.currencyPair = msg.data.CurrencyPair;
|
||||
modal.exchangeName = msg.exchange;
|
||||
var ticker = < TickerUpdate > msg.data;
|
||||
this.tickerCard = ticker;
|
||||
this.tickerCard.Exchange = msg.exchange;
|
||||
this.message = this.tickerCard.Exchange + " " + this.tickerCard.CurrencyPair + " Last: " + this.tickerCard.Last;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
private stripCurrencyCharacters(name:string):string {
|
||||
name = name.replace('_', '');
|
||||
name = name.replace('-', '');
|
||||
name = name.replace(' ', '');
|
||||
name = name.toLocaleUpperCase();
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExchangeCurrency {
|
||||
currencyPair: string;
|
||||
exchangeName:string;
|
||||
currencyPair:string;
|
||||
exchangeName:string;
|
||||
}
|
||||
|
||||
export interface CurrencyPair {
|
||||
delimiter: string;
|
||||
first_currency: string;
|
||||
second_currency: string;
|
||||
delimiter:string;
|
||||
first_currency:string;
|
||||
second_currency:string;
|
||||
}
|
||||
|
||||
export interface TickerUpdate {
|
||||
Pair: CurrencyPair;
|
||||
CurrencyPair: string;
|
||||
Last: number;
|
||||
High: number;
|
||||
Low: number;
|
||||
Bid: number;
|
||||
Ask: number;
|
||||
Volume: number;
|
||||
PriceATH: number;
|
||||
Exchange:string;
|
||||
export class TickerUpdate {
|
||||
Pair:CurrencyPair;
|
||||
CurrencyPair:string;
|
||||
Last:number;
|
||||
High:number;
|
||||
Low:number;
|
||||
Bid:number;
|
||||
Ask:number;
|
||||
Volume:number;
|
||||
PriceATH:number;
|
||||
Exchange:string;
|
||||
}
|
||||
@@ -1,12 +1,24 @@
|
||||
<form class="form-content">
|
||||
<div *ngIf="showErrorMessage">
|
||||
<h4>{{chooseCurrencyMessage}}</h4>
|
||||
<button routerLink="/exchange-grid" mat-raised-button color="primary">Choose currency</button>
|
||||
</div>
|
||||
<div *ngIf="!showErrorMessage">
|
||||
<mat-form-field>
|
||||
<input matInput disabled="disabled" name="exchange" [ngModel]="exchangeName" placeholder="Exchange">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput disabled="disabled" name="currency" [ngModel]="currencyName" placeholder="Currency">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<input matInput name="smsUsername" placeholder="Amount">
|
||||
<input matInput name="amount" placeholder="Amount">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="smsPassword" placeholder="Offer">
|
||||
<input matInput name="offer" placeholder="Offer">
|
||||
</mat-form-field>
|
||||
<div mat-line></div>
|
||||
<div class="spacer">
|
||||
<button mat-raised-button color="primary">CONFIRM BUY</button>
|
||||
<button [disabled]="showErrorMessage" mat-raised-button color="primary">CONFIRM BUY</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -6,9 +6,20 @@ import { Component, OnInit } from '@angular/core';
|
||||
styleUrls: ['./buy-form.component.scss']
|
||||
})
|
||||
export class BuyFormComponent implements OnInit {
|
||||
public exchangeName :string;
|
||||
public currencyName :string;
|
||||
public chooseCurrencyMessage :string = "Please select a currency";
|
||||
public showErrorMessage :boolean;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
if (window.localStorage["selectedExchange"] !== undefined &&
|
||||
window.localStorage["selectedCurrency"] !== undefined) {
|
||||
this.exchangeName = window.localStorage["selectedExchange"];
|
||||
this.currencyName = window.localStorage["selectedCurrency"];
|
||||
} else {
|
||||
this.showErrorMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
|
||||
export class Config {
|
||||
Name: string;
|
||||
EncryptConfig?: number;
|
||||
Cryptocurrencies: string;
|
||||
CurrencyExchangeProvider: string;
|
||||
CurrencyPairFormat: CurrencyPairFormat;
|
||||
PortfolioAddresses: PortfolioAddresses;
|
||||
SMSGlobal: SMSGlobal;
|
||||
Webserver: Webserver;
|
||||
Exchanges: Exchange[];
|
||||
|
||||
public isConfigCacheValid() : boolean {
|
||||
let dateStored = +new Date(window.localStorage['configDate']);
|
||||
let dateNow = +new Date();
|
||||
var dateDifference = Math.abs(dateNow - dateStored)
|
||||
var diffMins = Math.floor((dateDifference / 1000) / 60);
|
||||
(diffMins)
|
||||
|
||||
if(isNaN(new Date(dateStored).getTime()) || diffMins > 15) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public setConfig(data: any) : void {
|
||||
var configData = <Config>data;
|
||||
this.Cryptocurrencies = configData.Cryptocurrencies
|
||||
this.CurrencyExchangeProvider = configData.CurrencyExchangeProvider
|
||||
this.Exchanges = configData.Exchanges
|
||||
this.CurrencyPairFormat = configData.CurrencyPairFormat
|
||||
this.EncryptConfig = configData.EncryptConfig
|
||||
this.Exchanges = configData.Exchanges
|
||||
this.Name = configData.Name
|
||||
this.PortfolioAddresses = configData.PortfolioAddresses
|
||||
this.SMSGlobal = configData.SMSGlobal
|
||||
this.Webserver = configData.Webserver
|
||||
this.fromArrayToRedux()
|
||||
}
|
||||
|
||||
public fromArrayToRedux() : void {
|
||||
for (var i = 0; i < this.Exchanges.length; i++) {
|
||||
this.Exchanges[i].Pairs = new Array<CurrencyPairRedux>();
|
||||
var avail = this.Exchanges[i].AvailablePairs.split(',');
|
||||
var enabled = this.Exchanges[i].EnabledPairs.split(',');
|
||||
for (var j = 0; j < avail.length; j++) {
|
||||
var currencyPair = new CurrencyPairRedux();
|
||||
currencyPair.Name = avail[j]
|
||||
currencyPair.ParsedName = this.stripCurrencyCharacters(avail[j]);
|
||||
if (enabled.indexOf(avail[j]) > 0) {
|
||||
currencyPair.Enabled = true;
|
||||
} else {
|
||||
currencyPair.Enabled = false;
|
||||
}
|
||||
this.Exchanges[i].Pairs.push(currencyPair);
|
||||
}
|
||||
}
|
||||
window.localStorage['config'] = JSON.stringify(this);
|
||||
window.localStorage['configDate'] = new Date().toString();
|
||||
}
|
||||
|
||||
public parseSettings() : void {
|
||||
|
||||
}
|
||||
|
||||
private stripCurrencyCharacters(name:string) :string {
|
||||
name = name.replace('_', '');
|
||||
name = name.replace('-', '');
|
||||
name = name.replace(' ', '');
|
||||
name = name.toLocaleUpperCase();
|
||||
return name;
|
||||
}
|
||||
|
||||
public fromReduxToArray() : void {
|
||||
for (var i = 0; i < this.Exchanges.length; i++) {
|
||||
// Step 1, iterate over the Pairs
|
||||
var enabled = this.Exchanges[i].EnabledPairs.split(',');
|
||||
for (var j = 0; j < this.Exchanges[i].Pairs.length; j++) {
|
||||
if (this.Exchanges[i].Pairs[j].Enabled) {
|
||||
if (enabled.indexOf(this.Exchanges[i].Pairs[j].Name) == -1) {
|
||||
// Step 3 if its not in the enabled list, add it
|
||||
enabled.push(this.Exchanges[i].Pairs[j].Name);
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (enabled.indexOf(this.Exchanges[i].Pairs[j].Name) > -1) {
|
||||
enabled.splice(enabled.indexOf(this.Exchanges[i].Pairs[j].Name), 1);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Step 4 JSONifiy the enabled list and set it to the this.settings.Exchanges[i].EnabledPairs
|
||||
this.Exchanges[i].EnabledPairs = enabled.join();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CurrencyPairRedux {
|
||||
Name: string;
|
||||
ParsedName: string;
|
||||
Enabled: boolean;
|
||||
}
|
||||
|
||||
export interface CurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Delimiter: string;
|
||||
}
|
||||
|
||||
export interface PortfolioAddresses {
|
||||
Addresses?: any;
|
||||
}
|
||||
|
||||
export interface Contact {
|
||||
Name: string;
|
||||
Number: string;
|
||||
Enabled: boolean;
|
||||
}
|
||||
|
||||
export interface SMSGlobal {
|
||||
Enabled: boolean;
|
||||
Username: string;
|
||||
Password: string;
|
||||
Contacts: Contact[];
|
||||
}
|
||||
|
||||
export interface Webserver {
|
||||
Enabled: boolean;
|
||||
AdminUsername: string;
|
||||
AdminPassword: string;
|
||||
ListenAddress: string;
|
||||
WebsocketConnectionLimit: number;
|
||||
WebsocketAllowInsecureOrigin: boolean;
|
||||
}
|
||||
|
||||
export interface ConfigCurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Index: string;
|
||||
Delimiter: string;
|
||||
}
|
||||
|
||||
export interface RequestCurrencyPairFormat {
|
||||
Uppercase: boolean;
|
||||
Index: string;
|
||||
Delimiter: string;
|
||||
Separator: string;
|
||||
}
|
||||
|
||||
export interface Exchange {
|
||||
Name: string;
|
||||
Enabled: boolean;
|
||||
Verbose: boolean;
|
||||
Websocket: boolean;
|
||||
RESTPollingDelay: number;
|
||||
AuthenticatedAPISupport: boolean;
|
||||
APIKey: string;
|
||||
APISecret: string;
|
||||
AvailablePairs: string;
|
||||
EnabledPairs: string;
|
||||
BaseCurrencies: string;
|
||||
AssetTypes: string;
|
||||
ConfigCurrencyPairFormat: ConfigCurrencyPairFormat;
|
||||
RequestCurrencyPairFormat: RequestCurrencyPairFormat;
|
||||
ClientID: string;
|
||||
Pairs: CurrencyPairRedux[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
45
web/src/app/shared/classes/pipes.ts
Normal file
45
web/src/app/shared/classes/pipes.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Component, OnInit, OnDestroy, Pipe, PipeTransform } from '@angular/core';
|
||||
import { CurrencyPairRedux } from './../../shared/classes/config';
|
||||
|
||||
|
||||
@Pipe({
|
||||
name: 'iterateMap'
|
||||
})
|
||||
export class IterateMapPipe implements PipeTransform {
|
||||
transform(iterable: any, args: any[]): any {
|
||||
let result = [];
|
||||
|
||||
if (iterable.entries) {
|
||||
iterable.forEach((key, value) => {
|
||||
result.push({
|
||||
key,
|
||||
value
|
||||
});
|
||||
});
|
||||
} else {
|
||||
for (let key in iterable) {
|
||||
if (iterable.hasOwnProperty(key)) {
|
||||
result.push({
|
||||
key,
|
||||
value: iterable[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'enabledCurrencies'
|
||||
})
|
||||
export class EnabledCurrenciesPipe implements PipeTransform {
|
||||
transform(items: CurrencyPairRedux[], args: any[]): any {
|
||||
if (!items) {
|
||||
return items;
|
||||
}
|
||||
return items.filter(item => item.Enabled === true);
|
||||
}
|
||||
}
|
||||
|
||||
32
web/src/app/shared/classes/websocket.ts
Normal file
32
web/src/app/shared/classes/websocket.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
export class WebSocketMessage {
|
||||
public event: string;
|
||||
public data: any;
|
||||
public exchange: string;
|
||||
public assetType: string;
|
||||
|
||||
public static CreateAuthenticationMessage(): WebSocketMessage {
|
||||
var response = new WebSocketMessage();
|
||||
|
||||
response.event = WebSocketMessageType.Auth;
|
||||
response.data = { "username": window.sessionStorage["username"], "password": window.sessionStorage["password"] };
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
public static GetSettingsMessage() : WebSocketMessage {
|
||||
var response = new WebSocketMessage();
|
||||
|
||||
response.event = WebSocketMessageType.GetConfig;
|
||||
response.data = null;
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
export class WebSocketMessageType {
|
||||
public static Auth: string = "auth";
|
||||
public static GetConfig: string = "GetConfig";
|
||||
public static SaveConfig: string = "SaveConfig";
|
||||
public static GetPortfolio: string = "GetPortfolio";
|
||||
public static TickerUpdate: string = "ticker_update";
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
</a>
|
||||
<app-selected-currency></app-selected-currency>
|
||||
<div class="flex-spacer"></div>
|
||||
<app-all-updates-ticker></app-all-updates-ticker>
|
||||
<theme-picker></theme-picker>
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export class PriceHistoryComponent implements OnInit {
|
||||
|
||||
public options = {
|
||||
"type": "serial",
|
||||
"theme": "light",
|
||||
"theme": "dark",
|
||||
"dataDateFormat": "YYYY-MM-DD",
|
||||
"zoomOutOnDataUpdate": false,
|
||||
"valueAxes": [{
|
||||
@@ -158,7 +158,6 @@ export class PriceHistoryComponent implements OnInit {
|
||||
e.chart.firstPoint = e.item;
|
||||
}
|
||||
|
||||
//console.log(e.item);
|
||||
e.chart.validateData();
|
||||
}
|
||||
}],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<button mat-button routerLink="exchange-grid" matTooltip="Change currency">POLONIEX: BTC_USD (placeholder)</button>
|
||||
|
||||
<button class="currency-button" mat-button routerLink="exchange-grid" matTooltip="Change currency"><app-all-updates-ticker></app-all-updates-ticker></button>
|
||||
<button mat-icon-button routerLink="currency-list" matTooltip="View currency list">
|
||||
<mat-icon>
|
||||
view_list
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.currency-button {
|
||||
width: 20rem;
|
||||
text-align: left;
|
||||
}
|
||||
@@ -1,12 +1,24 @@
|
||||
<form class="form-content">
|
||||
<mat-form-field>
|
||||
<input matInput name="smsUsername" placeholder="Amount">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="smsPassword" placeholder="Offer">
|
||||
</mat-form-field>
|
||||
<div mat-line></div>
|
||||
<div *ngIf="showErrorMessage">
|
||||
<h4>{{chooseCurrencyMessage}}</h4>
|
||||
<button routerLink="/exchange-grid" mat-raised-button color="primary">Choose currency</button>
|
||||
</div>
|
||||
<div *ngIf="!showErrorMessage">
|
||||
<mat-form-field>
|
||||
<input matInput disabled="disabled" name="exchange" [ngModel]="exchangeName" placeholder="Exchange">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput disabled="disabled" name="currency" [ngModel]="currencyName" placeholder="Currency">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<input matInput name="amount" placeholder="Amount">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput name="offer" placeholder="Offer">
|
||||
</mat-form-field>
|
||||
<div mat-line></div>
|
||||
<div class="spacer">
|
||||
<button mat-raised-button color="primary">CONFIRM SELL</button>
|
||||
</div>
|
||||
</form>
|
||||
<button [disabled]="showErrorMessage" mat-raised-button color="primary">CONFIRM SELL</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -6,10 +6,20 @@ import { Component, OnInit } from '@angular/core';
|
||||
styleUrls: ['./sell-form.component.scss']
|
||||
})
|
||||
export class SellFormComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
public exchangeName :string;
|
||||
public currencyName :string;
|
||||
public chooseCurrencyMessage :string = "Please select a currency";
|
||||
public showErrorMessage :boolean;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
if (window.localStorage["selectedExchange"] !== undefined &&
|
||||
window.localStorage["selectedCurrency"] !== undefined) {
|
||||
this.exchangeName = window.localStorage["selectedExchange"];
|
||||
this.currencyName = window.localStorage["selectedCurrency"];
|
||||
} else {
|
||||
this.showErrorMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export class ThemePickerComponent {
|
||||
if (theme.isDefault) {
|
||||
this.styleManager.removeStyle('theme');
|
||||
} else {
|
||||
this.styleManager.setStyle('theme', `assets/${theme.href}`);
|
||||
this.styleManager.setStyle('theme', `assets/themes/${theme.href}`);
|
||||
}
|
||||
|
||||
if (this.currentTheme) {
|
||||
|
||||
Reference in New Issue
Block a user