Sweep all

Sweep all
pull/260/head
Shahana Farooqui 5 years ago
parent 125099fe08
commit 55eb1f17b9

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -9,8 +9,8 @@
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest"> <link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.6429b7a9527a146e7054.css"></head> <link rel="stylesheet" href="styles.93709d9cb38e5e717354.css"></head>
<body> <body>
<rtl-app></rtl-app> <rtl-app></rtl-app>
<script src="runtime.85f0111a60b784d662a7.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.136ca1019950c55334b6.js"></script></body> <script src="runtime.8f0530cea64d73898b16.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.f1e6e0c51b8b63b3a908.js"></script></body>
</html> </html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
!function(e){function r(r){for(var n,a,i=r[0],f=r[1],c=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,c||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={0:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+""+({}[e]||e)+"."+{1:"180f16dffe826f0afab2",6:"6461d7eefa28dc4efa39",7:"84ad670c3bfef8117d18"}[e]+".js"}(e);var f=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(c);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;f.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",f.name="ChunkLoadError",f.type=n,f.request=u,t[1](f)}o[e]=void 0}};var c=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,(function(r){return e[r]}).bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var c=0;c<i.length;c++)r(i[c]);var l=f;t()}([]); !function(e){function r(r){for(var n,a,i=r[0],f=r[1],c=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,c||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={0:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+""+({}[e]||e)+"."+{1:"180f16dffe826f0afab2",6:"aa83a4ccf47ad807eb8d",7:"e89ae7e15a1c87bbd30d"}[e]+".js"}(e);var f=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(c);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;f.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",f.name="ChunkLoadError",f.type=n,f.request=u,t[1](f)}o[e]=void 0}};var c=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,(function(r){return e[r]}).bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var c=0;c<i.length;c++)r(i[c]);var l=f;t()}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -24,7 +24,7 @@ export interface CLState {
export const initCLState: CLState = { export const initCLState: CLState = {
effectErrorsCl: [], effectErrorsCl: [],
nodeSettings: { channelBackupPath: '', satsToBTC: false, currencyUnits: [] }, nodeSettings: { currencyUnit: 'USD', channelBackupPath: '', satsToBTC: false, currencyUnits: [] },
information: {}, information: {},
fees: {}, fees: {},
feeRatesPerKB: {}, feeRatesPerKB: {},

@ -54,7 +54,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
}); });
this.selNode = rtlStore.nodeSettings; this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information; this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes; // this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = rtlStore.blockchainBalance; this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) { if (undefined === this.blockchainBalance.total_balance) {

@ -1,14 +1,14 @@
<div fxLayout="column"> <div fxLayout="column">
<div fxLayout="row" fxLayoutAlign="space-between end" fxLayoutAlign.gt-sm="start end"> <div fxLayout="row" fxLayoutAlign="space-between end" fxLayoutAlign.gt-sm="start end">
<mat-form-field fxFlex="48" fxFlex.gt-sm="25" fxLayoutAlign="start end"> <mat-form-field fxFlex="48" fxFlex.gt-sm="25" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selectedAddress" placeholder="Address Type" name="address_type" tabindex="1"> <mat-select [(ngModel)]="selectedAddressType" placeholder="Address Type" name="address_type" tabindex="1">
<mat-option *ngFor="let addressType of addressTypes" [value]="addressType"> <mat-option *ngFor="let addressType of addressTypes" [value]="addressType">
{{addressType.addressTp}} {{addressType.addressTp}}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div class="mt-2" fxFlex="48" fxFlex.gt-sm="25"> <div class="mt-2" fxFlex="48" fxFlex.gt-sm="25">
<button fxFlex="100" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onGenerateAddress()" [disabled]="undefined === selectedAddress.addressId" tabindex="2" class="top-minus-15px">Generate Address</button> <button fxFlex="100" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onGenerateAddress()" [disabled]="undefined === selectedAddressType.addressId" tabindex="2" class="top-minus-15px">Generate Address</button>
</div> </div>
</div> </div>
<rtl-on-chain-transaction-history fxLayout="row" fxFlex="100"></rtl-on-chain-transaction-history> <rtl-on-chain-transaction-history fxLayout="row" fxFlex="100"></rtl-on-chain-transaction-history>

@ -1,16 +1,13 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { AddressType } from '../../../shared/models/lndModels';
import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels'; import { ADDRESS_TYPES } from '../../../shared/models/enums';
import { RTLConfiguration } from '../../../shared/models/RTLconfig'; import { OnChainGeneratedAddressComponent } from '../../../shared/components/data-modal/on-chain-generated-address/on-chain-generated-address.component';
import { LoggerService } from '../../../shared/services/logger.service';
import * as sha256 from 'sha256';
import { LNDEffects } from '../../store/lnd.effects'; import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions'; import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers'; import * as fromRTLReducer from '../../../store/rtl.reducers';
@ -20,162 +17,31 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
styleUrls: ['./on-chain-receive.component.scss'] styleUrls: ['./on-chain-receive.component.scss']
}) })
export class OnChainReceiveComponent implements OnInit, OnDestroy { export class OnChainReceiveComponent implements OnInit, OnDestroy {
public selNode: SelNodeChild = {}; public addressTypes = ADDRESS_TYPES;
public appConfig: RTLConfiguration; public selectedAddressType: AddressType = {};
public addressTypes = [];
public flgLoadingWallet: Boolean | 'error' = true;
public selectedAddress: AddressType = {};
public blockchainBalance: Balance = {};
public information: GetInfo = {};
public newAddress = ''; public newAddress = '';
public transaction: ChannelsTransaction = {}; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1';
public flgCustomAmount = '1';
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) {} constructor(private store: Store<fromRTLReducer.RTLState>, private lndEffects: LNDEffects) {}
ngOnInit() { ngOnInit() {}
this.store.select('root')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rootStore) => {
this.appConfig = rootStore.appConfig;
this.logger.info(rootStore);
});
this.store.select('lnd')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsLnd.forEach(effectsErr => {
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoadingWallet = 'error';
}
});
this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = 0;
}
if (undefined === this.blockchainBalance.confirmed_balance) {
this.blockchainBalance.confirmed_balance = 0;
}
if (undefined === this.blockchainBalance.unconfirmed_balance) {
this.blockchainBalance.unconfirmed_balance = 0;
}
if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false;
}
this.logger.info(rtlStore);
});
}
onGenerateAddress() { onGenerateAddress() {
this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...')); this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...'));
this.store.dispatch(new RTLActions.GetNewAddress(this.selectedAddress)); this.store.dispatch(new RTLActions.GetNewAddress(this.selectedAddressType));
this.lndEffects.setNewAddress this.lndEffects.setNewAddress
.pipe(takeUntil(this.unsub[1])) .pipe(takeUntil(this.unSubs[0]))
.subscribe(newAddress => { .subscribe(newAddress => {
this.newAddress = newAddress; this.newAddress = newAddress;
this.store.dispatch(new RTLActions.OpenAlert({
config: { width: '58%', data: { type: 'INFO', message: JSON.stringify({address: this.newAddress, addressType: this.selectedAddressType.addressTp})}},
component: OnChainGeneratedAddressComponent
}));
}); });
} }
onSendFunds() {
const confirmationMsg = {
'BTC Address': this.transaction.address,
};
if (!+this.flgCustomAmount) {
confirmationMsg['Sweep All'] = 'True';
this.transaction.sendAll = true;
} else {
confirmationMsg['Amount (' + this.information.smaller_currency_unit + ')'] = this.transaction.amount;
this.transaction.sendAll = false;
}
if (this.selTransType === '1') {
delete this.transaction.fees;
confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
} else {
delete this.transaction.blocks;
confirmationMsg['Fee (' + this.information.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
}
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsub[2]))
.subscribe(confirmRes => {
if (confirmRes) {
if (this.transaction.sendAll && !+this.appConfig.sso.rtlSSO) {
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', titleMessage: 'Enter Login Password', noBtnText: 'Cancel', yesBtnText: 'Authorize', flgShowInput: true, getInputs: [
{placeholder: 'Enter Login Password', inputType: 'password', inputValue: ''}
]}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsub[3]))
.subscribe(pwdConfirmRes => {
if (pwdConfirmRes) {
const pwd = pwdConfirmRes[0].inputValue;
this.store.dispatch(new RTLActions.IsAuthorized(sha256(pwd)));
this.rtlEffects.isAuthorizedRes
.pipe(take(1))
.subscribe(authRes => {
if (authRes !== 'ERROR') {
this.dispatchToSendFunds();
}
});
}
});
} else {
this.dispatchToSendFunds();
}
}
});
}
dispatchToSendFunds() {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
this.transaction = {address: '', amount: 0, blocks: 0, fees: 0};
}
get invalidValues(): boolean {
return (undefined === this.transaction.address || this.transaction.address === '')
|| (+this.flgCustomAmount && (undefined === this.transaction.amount || this.transaction.amount <= 0))
|| (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0))
|| (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0));
}
onCustomClicked() {
this.flgCustomAmount = '1';
}
onOptionChange(event) {
if (!+this.flgCustomAmount) {
delete this.transaction.amount;
}
}
resetData() {
this.transaction.address = '';
this.transaction.amount = 0;
this.transaction.blocks = 0;
this.transaction.fees = 0;
}
resetReceiveData() {
this.selectedAddress = {};
this.newAddress = '';
}
ngOnDestroy() { ngOnDestroy() {
this.unsub.forEach(completeSub => { this.unSubs.forEach(completeSub => {
completeSub.next(); completeSub.next();
completeSub.complete(); completeSub.complete();
}); });

@ -1,68 +1,42 @@
<div fxLayout="column" fxLayout.gt-sm="row wrap"> <div fxLayout="column" fxFlex="98" fxLayout.gt-sm="row wrap" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="space-between start">
<div fxFlex="100" class="padding-gap"> <mat-form-field fxFlex.gt-sm="55">
<div fxLayout="column" fxLayout.gt-sm="row wrap"> <input matInput [(ngModel)]="transaction.address" placeholder="Bitcoin Address" tabindex="1" name="address" #address="ngModel">
<div fxFlex="58" fxLayoutAlign="start end"> </mat-form-field>
<mat-form-field fxFlex="99"> <mat-form-field fxFlex.gt-sm="30">
<input matInput [(ngModel)]="transaction.address" placeholder="Bitcoin Address" <input matInput [(ngModel)]="transaction.amount" placeholder="Amount" name="amount" type="number" step="100" min="0" tabindex="2" #amount="ngModel" [disabled]="sweepAll">
tabindex="1" name="address" #address="ngModel"> <span matSuffix> {{selAmountUnit}} </span>
</mat-form-field> <mat-hint *ngIf="sweepAll">{{sweepAllHint}}</mat-hint>
</div> </mat-form-field>
<!-- <div fxFlex="38" fxLayoutAlign="start end"> <mat-form-field fxFlex.gt-sm="10" fxLayoutAlign="start end">
<mat-radio-group fxFlex="100" fxLayoutAlign="space-between center" (change)="onOptionChange($event)" [(ngModel)]="flgCustomAmount"> <mat-select [value]="selAmountUnit" tabindex="3" required name="amountUnit" (selectionChange)="onAmountUnitChange($event)">
<mat-radio-button fxFlex="35" value="0">Sweep All</mat-radio-button> <mat-option *ngFor="let amountUnit of amountUnits" [value]="amountUnit">{{amountUnit}}</mat-option>
<mat-radio-button fxFlex="60" value="1"> </mat-select>
<mat-form-field fxFlex="70"><input matInput [(ngModel)]="transaction.amount" (click)="onCustomClicked()" placeholder="Amount ({{information?.smaller_currency_unit}})" name="amount" type="number" step="100" min="0" tabindex="5" #amount="ngModel"></mat-form-field> </mat-form-field>
</mat-radio-button> <div fxLayout="column" fxFlex="100" fxFlex.gt-sm="60" fxLayout.gt-sm="row wrap" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="space-between start">
</mat-radio-group> <mat-form-field fxFlex="48">
</div> --> <mat-select [(value)]="selTransType" tabindex="4">
<div fxFlex="30" fxLayoutAlign="start end"> <mat-option *ngFor="let transType of transTypes" [value]="transType.id">
<mat-form-field fxFlex="70"> {{transType.name}}
<input matInput [(ngModel)]="transaction.amount" placeholder="Amount" name="amount" type="number" step="100" min="0" tabindex="2" #amount="ngModel"> </mat-option>
<span matSuffix> {{selAmountUnit}} </span> </mat-select>
</mat-form-field> </mat-form-field>
</div> <mat-form-field fxFlex="48" *ngIf="selTransType=='1'">
<mat-form-field fxFlex="10" fxLayoutAlign="start end"> <input matInput [(ngModel)]="transaction.blocks" placeholder="Number of Blocks" type="number" name="blocks" step="1" min="0" required tabindex="5" #blocks="ngModel">
<mat-select [value]="selAmountUnit" tabindex="3" required name="amountUnit" (selectionChange)="onAmountUnitChange($event)"> </mat-form-field>
<mat-option *ngFor="let amountUnit of amountUnits" [value]="amountUnit">{{amountUnit}}</mat-option> <mat-form-field fxFlex="48" *ngIf="selTransType=='2'">
</mat-select> <input matInput [(ngModel)]="transaction.fees" placeholder="Fee ({{nodeData?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1" min="0" required tabindex="6" #fees="ngModel">
</mat-form-field> </mat-form-field>
</div>
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="30" fxLayoutAlign="start start">
<mat-form-field fxFlex="99">
<mat-select [(value)]="selTransType" tabindex="4">
<mat-option *ngFor="let transType of transTypes" [value]="transType.id">
{{transType.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxFlex="30" fxLayoutAlign="start start">
<mat-form-field fxFlex="99" *ngIf="selTransType=='1'">
<input matInput [(ngModel)]="transaction.blocks" placeholder="Target Confirmation Blocks" type="number"
name="blocks" step="1" min="0" required tabindex="5" #blocks="ngModel">
</mat-form-field>
<mat-form-field fxFlex="99" *ngIf="selTransType=='2'">
<input matInput [(ngModel)]="transaction.fees"
placeholder="Fee ({{information?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1"
min="0" required tabindex="6" #fees="ngModel">
</mat-form-field>
</div>
<div fxFlex="40" fxLayoutAlign="space-between start">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="7"
type="reset" (click)="resetData()">Clear Fields</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="invalidValues" type="submit" tabindex="8" (click)="onSendFunds()">
<p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">
Invalid Values</p>
<ng-template #sendText>
<p>Send Funds</p>
</ng-template>
</button>
</div>
</div>
</div> </div>
<div fxFlex="50" fxLayoutAlign="space-between start">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="7" type="reset" (click)="resetData()">Clear Fields</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="invalidValues" type="submit" tabindex="8" (click)="onSendFunds()">
<p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">
Invalid Values</p>
<ng-template #sendText>
<p>Send Funds</p>
</ng-template>
</button>
</div>
<rtl-on-chain-transaction-history fxLayout="row" fxFlex="100"></rtl-on-chain-transaction-history>
</div> </div>
<ng-template #withoutData>
<h3>Sats</h3>
</ng-template>

@ -1,17 +1,17 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { DecimalPipe } from '@angular/common';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators'; import { takeUntil, take } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { SelNodeChild, GetInfoRoot } from '../../../shared/models/RTLconfig';
import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels'; import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels';
import { CURRENCY_UNITS } from '../../../shared/models/enums'; import { CURRENCY_UNITS, CurrencyUnitEnum, CURRENCY_UNIT_FORMATS } from '../../../shared/models/enums';
import { RTLConfiguration } from '../../../shared/models/RTLconfig'; import { RTLConfiguration } from '../../../shared/models/RTLconfig';
import { CommonService } from '../../../shared/services/common.service';
import { LoggerService } from '../../../shared/services/logger.service'; import { LoggerService } from '../../../shared/services/logger.service';
import * as sha256 from 'sha256'; import * as sha256 from 'sha256';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects'; import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions'; import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers'; import * as fromRTLReducer from '../../../store/rtl.reducers';
@ -22,8 +22,19 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
styleUrls: ['./on-chain-send.component.scss'] styleUrls: ['./on-chain-send.component.scss']
}) })
export class OnChainSendComponent implements OnInit, OnDestroy { export class OnChainSendComponent implements OnInit, OnDestroy {
@Input() sweepAll = false;
private _sweepBalance = 0;
get sweepBalance() {
return this._sweepBalance;
}
@Input() set sweepBalance(bal) {
this._sweepBalance = bal;
this.transaction.amount = this._sweepBalance;
}
public sweepAllHint = 'Sending all your funds';
public selNode: SelNodeChild = {}; public selNode: SelNodeChild = {};
public appConfig: RTLConfiguration; public appConfig: RTLConfiguration;
public nodeData: GetInfoRoot;
public addressTypes = []; public addressTypes = [];
public flgLoadingWallet: Boolean | 'error' = true; public flgLoadingWallet: Boolean | 'error' = true;
public selectedAddress: AddressType = {}; public selectedAddress: AddressType = {};
@ -33,46 +44,37 @@ export class OnChainSendComponent implements OnInit, OnDestroy {
public transaction: ChannelsTransaction = {}; public transaction: ChannelsTransaction = {};
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}]; public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1'; public selTransType = '1';
public flgCustomAmount = '1';
public amountUnits = CURRENCY_UNITS; public amountUnits = CURRENCY_UNITS;
public selAmountUnit = CURRENCY_UNITS[0]; public selAmountUnit = CURRENCY_UNITS[0];
public currConvertorRate = {}; public currConvertorRate = {};
public unitConversionValue = 0; public unitConversionValue = 0;
public currencyUnitFormats = CURRENCY_UNIT_FORMATS;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private httpClient: HttpClient) {} constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private commonService: CommonService, private decimalPipe: DecimalPipe) {}
ngOnInit() { ngOnInit() {
this.store.select('root') this.store.select('root')
.pipe(takeUntil(this.unSubs[0])) .pipe(takeUntil(this.unSubs[0]))
.subscribe((rootStore) => { .subscribe((rootStore) => {
this.amountUnits = rootStore.selNode.settings.currencyUnits;
this.appConfig = rootStore.appConfig; this.appConfig = rootStore.appConfig;
this.nodeData = rootStore.nodeData;
this.logger.info(rootStore); this.logger.info(rootStore);
}); });
} }
onSendFunds() { onSendFunds() {
const confirmationMsg = { if(this.transaction.amount && this.selAmountUnit !== CurrencyUnitEnum.SATS) {
'BTC Address': this.transaction.address, this.commonService.convertCurrency(this.transaction.amount, this.selAmountUnit === this.amountUnits[2] ? CurrencyUnitEnum.OTHER : this.selAmountUnit, this.amountUnits[2])
}; .pipe(takeUntil(this.unSubs[1]))
if (!+this.flgCustomAmount) { .subscribe(data => {
confirmationMsg['Sweep All'] = 'True'; this.transaction.amount = parseInt(data[CurrencyUnitEnum.SATS]);
this.transaction.sendAll = true; this.confirmSend();
});
} else { } else {
confirmationMsg['Amount (' + this.information.smaller_currency_unit + ')'] = this.transaction.amount; this.confirmSend();
this.transaction.sendAll = false;
} }
if (this.selTransType === '1') {
delete this.transaction.fees;
confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
} else {
delete this.transaction.blocks;
confirmationMsg['Fee (' + this.information.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
}
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
}));
this.rtlEffects.closeConfirm this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[2])) .pipe(takeUntil(this.unSubs[2]))
.subscribe(confirmRes => { .subscribe(confirmRes => {
@ -105,83 +107,57 @@ export class OnChainSendComponent implements OnInit, OnDestroy {
}); });
} }
confirmSend() {
const confirmationMsg = {
'BTC Address': this.transaction.address,
};
if (this.sweepAll) {
confirmationMsg['Sweep All'] = 'True';
this.transaction.sendAll = true;
} else {
confirmationMsg['Amount (' + this.nodeData.smaller_currency_unit + ')'] = this.transaction.amount;
this.transaction.sendAll = false;
}
if (this.selTransType === '1') {
delete this.transaction.fees;
confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
} else {
delete this.transaction.blocks;
confirmationMsg['Fee (' + this.nodeData.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
}
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
}));
}
dispatchToSendFunds() { dispatchToSendFunds() {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...')); this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction)); this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
this.transaction = {address: '', amount: 0, blocks: 0, fees: 0}; this.transaction = {};
} }
get invalidValues(): boolean { get invalidValues(): boolean {
return (undefined === this.transaction.address || this.transaction.address === '') return (undefined === this.transaction.address || this.transaction.address === '')
|| (+this.flgCustomAmount && (undefined === this.transaction.amount || this.transaction.amount <= 0)) || (undefined === this.transaction.amount || this.transaction.amount <= 0)
|| (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0)) || (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0))
|| (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0)); || (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0));
} }
onCustomClicked() {
this.flgCustomAmount = '1';
}
onOptionChange(event) {
if (!+this.flgCustomAmount) {
delete this.transaction.amount;
}
}
resetData() { resetData() {
this.transaction.address = ''; this.transaction = {};
this.transaction.amount = 0;
this.transaction.blocks = 0;
this.transaction.fees = 0;
}
resetReceiveData() {
this.selectedAddress = {};
this.newAddress = '';
} }
onAmountUnitChange(event: any) { onAmountUnitChange(event: any) {
let self = this;
let prevSelectedUnit = (this.sweepAll) ? CurrencyUnitEnum.SATS : (this.selAmountUnit === this.amountUnits[2]) ? CurrencyUnitEnum.OTHER : this.selAmountUnit;
let currSelectedUnit = event.value === this.amountUnits[2] ? CurrencyUnitEnum.OTHER : event.value;
if(this.transaction.amount && this.selAmountUnit !== event.value) { if(this.transaction.amount && this.selAmountUnit !== event.value) {
switch (this.selAmountUnit) { let amount = (this.sweepAll) ? this.sweepBalance : this.transaction.amount;
case this.amountUnits[0]: this.commonService.convertCurrency(amount, prevSelectedUnit, this.amountUnits[2])
switch (event.value) { .pipe(takeUntil(this.unSubs[4]))
case this.amountUnits[1]: .subscribe(data => {
this.transaction.amount = this.transaction.amount * 0.00000001; self.transaction.amount = +self.decimalPipe.transform(data[currSelectedUnit], self.currencyUnitFormats[currSelectedUnit]).replace(/,/g, '');
break; });
case this.amountUnits[2]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last * 0.00000001);
break;
default:
break;
}
break;
case this.amountUnits[1]:
switch (event.value) {
case this.amountUnits[0]:
this.transaction.amount = this.transaction.amount * 100000000;
break;
case this.amountUnits[2]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last);
break;
default:
break;
}
break;
case this.amountUnits[2]:
switch (event.value) {
case this.amountUnits[0]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last) * 10000000;
break;
case this.amountUnits[1]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last);
break;
default:
break;
}
break;
default:
break;
}
} }
this.selAmountUnit = event.value; this.selAmountUnit = event.value;
} }

@ -18,13 +18,13 @@
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<mat-tab-group> <mat-tab-group>
<mat-tab label="Send"> <mat-tab label="Send">
<rtl-on-chain-send></rtl-on-chain-send> <rtl-on-chain-send [sweepAll]="false"></rtl-on-chain-send>
</mat-tab> </mat-tab>
<mat-tab label="Receive"> <mat-tab label="Receive">
<rtl-on-chain-receive></rtl-on-chain-receive> <rtl-on-chain-receive></rtl-on-chain-receive>
</mat-tab> </mat-tab>
<mat-tab label="Sweep All"> <mat-tab label="Sweep All">
<rtl-on-chain-send></rtl-on-chain-send> <rtl-on-chain-send [sweepAll]="true" [sweepBalance]="balances[0].dataValue"></rtl-on-chain-send>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</mat-card-content> </mat-card-content>

@ -47,7 +47,6 @@ export class OnChainComponent implements OnInit, OnDestroy {
}); });
this.selNode = rtlStore.nodeSettings; this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information; this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = rtlStore.blockchainBalance; this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) { if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = 0; this.blockchainBalance.total_balance = 0;

@ -13,7 +13,7 @@ import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service'; import { SessionService } from '../../shared/services/session.service';
import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels'; import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels';
import { CurrencyUnitEnum } from '../../shared/models/enums'; import { CurrencyUnitEnum } from '../../shared/models/enums';
import { InvoiceInformationComponent } from '../../shared/components/invoice-information/invoice-information.component'; import { InvoiceInformationComponent } from '../../shared/components/data-modal/invoice-information/invoice-information.component';
import * as RTLActions from '../../store/rtl.actions'; import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromRTLReducer from '../../store/rtl.reducers';

@ -27,12 +27,11 @@ export interface LNDState {
payments: Payment[]; payments: Payment[];
invoices: ListInvoices; invoices: ListInvoices;
forwardingHistory: SwitchRes; forwardingHistory: SwitchRes;
addressTypes: AddressType[];
} }
export const initLNDState: LNDState = { export const initLNDState: LNDState = {
effectErrorsLnd: [], effectErrorsLnd: [],
nodeSettings: { channelBackupPath: '', satsToBTC: false, currencyUnits: [] }, nodeSettings: { currencyUnit: 'USD', channelBackupPath: '', satsToBTC: false, currencyUnits: [] },
information: {}, information: {},
peers: [], peers: [],
fees: {}, fees: {},
@ -51,11 +50,7 @@ export const initLNDState: LNDState = {
transactions: [], transactions: [],
payments: [], payments: [],
invoices: {invoices: []}, invoices: {invoices: []},
forwardingHistory: {}, forwardingHistory: {}
addressTypes: [
{ addressId: '0', addressTp: 'p2wkh', addressDetails: 'Pay to witness key hash'},
{ addressId: '1', addressTp: 'np2wkh', addressDetails: 'Pay to nested witness key hash (default)'}
]
} }
export function LNDReducer(state = initLNDState, action: RTLActions.RTLActions) { export function LNDReducer(state = initLNDState, action: RTLActions.RTLActions) {

@ -7,7 +7,7 @@
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="70" fxLayoutAlign.gt-sm="space-between center"> <div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="70" fxLayoutAlign.gt-sm="space-between center">
<mat-form-field fxFlex="40" fxLayoutAlign="start end"> <mat-form-field fxFlex="40" fxLayoutAlign="start end">
<input matInput [(ngModel)]="invoiceValue" (keyup)="onInvoiceValueChange()" placeholder="Amount" type="number" step="100" min="1" tabindex="2" name="invoiceValue"> <input matInput [(ngModel)]="invoiceValue" (keyup)="onInvoiceValueChange()" placeholder="Amount" type="number" step="100" min="1" tabindex="2" name="invoiceValue">
<span matSuffix> {{information?.smaller_currency_unit | titlecase}} </span> <span matSuffix> {{information?.smaller_currency_unit}} </span>
<mat-hint>{{invoiceValueHint}}</mat-hint> <mat-hint>{{invoiceValueHint}}</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="15" fxLayoutAlign="start end"> <mat-form-field fxFlex="15" fxLayoutAlign="start end">

@ -7,13 +7,13 @@ import { faHistory } from '@fortawesome/free-solid-svg-icons';
import { MatTableDataSource, MatSort, MatPaginatorIntl } from '@angular/material'; import { MatTableDataSource, MatSort, MatPaginatorIntl } from '@angular/material';
import { getInvoicesPaginator } from '../../../shared/services/paginator.service'; import { getInvoicesPaginator } from '../../../shared/services/paginator.service';
import { TimeUnitEnum, CurrencyUnitEnum, TIME_UNITS } from '../../../shared/models/enums'; import { TimeUnitEnum, CurrencyUnitEnum, TIME_UNITS, CURRENCY_UNIT_FORMATS } from '../../../shared/models/enums';
import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { SelNodeChild } from '../../../shared/models/RTLconfig';
import { GetInfo, Invoice } from '../../../shared/models/lndModels'; import { GetInfo, Invoice } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service'; import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service'; import { CommonService } from '../../../shared/services/common.service';
import { InvoiceInformationComponent } from '../../../shared/components/invoice-information/invoice-information.component'; import { InvoiceInformationComponent } from '../../../shared/components/data-modal/invoice-information/invoice-information.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation'; import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import * as RTLActions from '../../../store/rtl.actions'; import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers'; import * as fromRTLReducer from '../../../store/rtl.reducers';
@ -171,7 +171,7 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
this.commonService.convertCurrency(this.invoiceValue, CurrencyUnitEnum.SATS, this.selNode.currencyUnits[2]) this.commonService.convertCurrency(this.invoiceValue, CurrencyUnitEnum.SATS, this.selNode.currencyUnits[2])
.pipe(takeUntil(this.unSubs[1])) .pipe(takeUntil(this.unSubs[1]))
.subscribe(data => { .subscribe(data => {
this.invoiceValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, '1.2-2') + ' ' + data.unit; this.invoiceValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
}); });
} }
} }

@ -72,9 +72,9 @@ export class AppSettingsComponent implements OnInit, OnDestroy {
} }
onCurrencyChange(event: any) { onCurrencyChange(event: any) {
this.selNode.settings.currencyUnit = event.value; this.selNode.settings.currencyUnits = [...CURRENCY_UNITS, event.value];
this.store.dispatch(new RTLActions.SetChildNodeSettings({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnits: [...CURRENCY_UNITS, this.selNode.settings.currencyUnit]})); this.store.dispatch(new RTLActions.SetChildNodeSettings({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnit: event.value, currencyUnits: this.selNode.settings.currencyUnits}));
this.store.dispatch(new RTLActions.SetChildNodeSettingsCL({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnits: [...CURRENCY_UNITS, this.selNode.settings.currencyUnit]})); this.store.dispatch(new RTLActions.SetChildNodeSettingsCL({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnit: event.value, currencyUnits: this.selNode.settings.currencyUnits}));
} }
chooseMenuType() { chooseMenuType() {
@ -88,8 +88,8 @@ export class AppSettingsComponent implements OnInit, OnDestroy {
toggleSettings(toggleField: string, event?: any) { toggleSettings(toggleField: string, event?: any) {
if (toggleField === 'satsToBTC') { if (toggleField === 'satsToBTC') {
this.store.dispatch(new RTLActions.SetChildNodeSettings({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnits: [...CURRENCY_UNITS, this.selNode.settings.currencyUnit]})); this.store.dispatch(new RTLActions.SetChildNodeSettings({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnit: this.selNode.settings.currencyUnit, currencyUnits: this.selNode.settings.currencyUnits}));
this.store.dispatch(new RTLActions.SetChildNodeSettingsCL({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnits: [...CURRENCY_UNITS, this.selNode.settings.currencyUnit]})); this.store.dispatch(new RTLActions.SetChildNodeSettingsCL({channelBackupPath: this.selNode.settings.channelBackupPath, satsToBTC: this.selNode.settings.satsToBTC, currencyUnit: this.selNode.settings.currencyUnit, currencyUnits: this.selNode.settings.currencyUnits}));
} }
if(toggleField === 'menu') { if(toggleField === 'menu') {
this.selNode.settings.flgSidenavOpened = (!event.checked) ? false : true; this.selNode.settings.flgSidenavOpened = (!event.checked) ? false : true;

@ -4,8 +4,8 @@
<div fxLayout="column" *ngFor="let value of values" [matTooltip]="value.tooltip" [matTooltipPosition]="'below'" class="cc-data-block"> <div fxLayout="column" *ngFor="let value of values" [matTooltip]="value.tooltip" [matTooltipPosition]="'below'" class="cc-data-block">
<div class="cc-data-title">{{value.title}}</div> <div class="cc-data-title">{{value.title}}</div>
<span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.SATS">{{value.dataValue | number}}</span> <span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.SATS">{{value.dataValue | number}}</span>
<span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.BTC">{{value.dataValueBTC | number:'1.6-6'}}</span> <span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.BTC">{{value[currencyUnitEnum.BTC] | number:currencyUnitFormats.BTC}}</span>
<span class="cc-data-value" *ngIf="currencyUnit !== currencyUnitEnum.SATS && currencyUnit !== currencyUnitEnum.BTC">{{value.dataValueOTHER | number:'1.2-2'}}</span> <span class="cc-data-value" *ngIf="currencyUnit !== currencyUnitEnum.SATS && currencyUnit !== currencyUnitEnum.BTC">{{value[currencyUnitEnum.OTHER] | number:currencyUnitFormats.OTHER}}</span>
</div> </div>
</div> </div>
</mat-tab> </mat-tab>

@ -2,7 +2,7 @@ import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { CurrencyUnitEnum } from '../../models/enums'; import { CurrencyUnitEnum, CURRENCY_UNIT_FORMATS } from '../../models/enums';
import { CommonService } from '../../services/common.service'; import { CommonService } from '../../services/common.service';
@Component({ @Component({
@ -12,6 +12,7 @@ import { CommonService } from '../../services/common.service';
}) })
export class CurrencyUnitConverterComponent implements OnInit, OnDestroy { export class CurrencyUnitConverterComponent implements OnInit, OnDestroy {
public currencyUnitEnum = CurrencyUnitEnum; public currencyUnitEnum = CurrencyUnitEnum;
public currencyUnitFormats = CURRENCY_UNIT_FORMATS;
private _values: Array<any>; private _values: Array<any>;
private _currencyUnits = []; private _currencyUnits = [];
private unSubs = [new Subject()]; private unSubs = [new Subject()];
@ -40,12 +41,12 @@ export class CurrencyUnitConverterComponent implements OnInit, OnDestroy {
this.commonService.convertCurrency(value.dataValue, CurrencyUnitEnum.SATS, this.currencyUnits[2]) this.commonService.convertCurrency(value.dataValue, CurrencyUnitEnum.SATS, this.currencyUnits[2])
.pipe(takeUntil(this.unSubs[0])) .pipe(takeUntil(this.unSubs[0]))
.subscribe(data => { .subscribe(data => {
value.dataValueBTC = data.BTC; value[CurrencyUnitEnum.BTC] = data.BTC;
value.dataValueOTHER = data.OTHER; value[CurrencyUnitEnum.OTHER] = data.OTHER;
}); });
} else { } else {
value.dataValueBTC = value.dataValue; value[CurrencyUnitEnum.BTC] = value.dataValue;
value.dataValueOTHER = value.dataValue; value[CurrencyUnitEnum.OTHER] = value.dataValue;
} }
}); });
} }

@ -1,9 +1,9 @@
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="35" fxLayoutAlign="center start" class="invoice-qr-code-container padding-gap-large"> <div fxFlex="35" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large">
<qrcode [qrdata]="invoice.payment_request" [size]="230" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode> <qrcode [qrdata]="invoice.payment_request" [size]="230" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>
</div> </div>
<div fxFlex="65" class="padding-gap-large"> <div fxFlex="65" class="padding-gap-large">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="invoice-info-header mb-2"> <mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-2">
<div fxFlex="95" fxLayoutAlign="start start"> <div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon> <fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Invoice Information</span> <span class="page-title">Invoice Information</span>

@ -3,9 +3,9 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faReceipt } from '@fortawesome/free-solid-svg-icons'; import { faReceipt } from '@fortawesome/free-solid-svg-icons';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { LoggerService } from '../../../shared/services/logger.service'; import { LoggerService } from '../../../services/logger.service';
import { AlertData } from '../../../shared/models/alertData'; import { AlertData } from '../../../models/alertData';
import { Invoice } from '../../../shared/models/lndModels'; import { Invoice } from '../../../models/lndModels';
@Component({ @Component({
selector: 'rtl-invoice-information', selector: 'rtl-invoice-information',

@ -0,0 +1,35 @@
<div fxLayout="row">
<div fxFlex="35" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large">
<qrcode [qrdata]="address.address" [size]="230" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>
</div>
<div fxFlex="65" class="padding-gap-large">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-2">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Generated Address</span>
</div>
<mat-icon tabindex="3" fxFlex="5" type="button" fxLayoutAlign="center center" (click)="onClose()" class="cursor-pointer icon-medium">close</mat-icon>
</mat-card-header>
<mat-card-content>
<div fxLayout="column">
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Address Type</h4>
<span class="foreground-secondary-text">{{address.addressType}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Address</h4>
<span class="overflow-wrap foreground-secondary-text">{{address.address}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div class="mt-2" fxLayout="row" fxLayoutAlign="end center">
<button autoFocus fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="1" type="submit" rtlClipboard [payload]="address.address" (copied)="onCopyAddress($event)">Copy Address</button>
</div>
</div>
</mat-card-content>
</div>
</div>

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OnChainGeneratedAddressComponent } from './on-chain-generated-address.component';
describe('OnChainGeneratedAddressComponent', () => {
let component: OnChainGeneratedAddressComponent;
let fixture: ComponentFixture<OnChainGeneratedAddressComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OnChainGeneratedAddressComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OnChainGeneratedAddressComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,32 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faReceipt } from '@fortawesome/free-solid-svg-icons';
import { MatSnackBar } from '@angular/material/snack-bar';
import { LoggerService } from '../../../services/logger.service';
import { AlertData } from '../../../models/alertData';
@Component({
selector: 'rtl-on-chain-generated-address',
templateUrl: './on-chain-generated-address.component.html',
styleUrls: ['./on-chain-generated-address.component.scss']
})
export class OnChainGeneratedAddressComponent implements OnInit {
public faReceipt = faReceipt;
public address: {address: '', addressType: ''};
constructor(public dialogRef: MatDialogRef<OnChainGeneratedAddressComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService, private snackBar: MatSnackBar) { }
ngOnInit() {
this.address = JSON.parse(this.data.message);
}
onClose() {
this.dialogRef.close(false);
}
onCopyAddress(payload: string) {
this.snackBar.open('Generated Address copied');
this.logger.info('Copied Text: ' + payload);
}
}

@ -17,11 +17,12 @@ export class Settings {
public themeMode: string, public themeMode: string,
public themeColor: string, public themeColor: string,
public satsToBTC: boolean, public satsToBTC: boolean,
public currencyUnits: Array<string>,
public bitcoindConfigPath?: string, public bitcoindConfigPath?: string,
public enableLogging?: boolean, public enableLogging?: boolean,
public lnServerUrl?: string, public lnServerUrl?: string,
public channelBackupPath?: string, public channelBackupPath?: string,
public currencyUnit?: string public currencyUnit?: string,
) { } ) { }
} }
@ -66,5 +67,6 @@ export interface GetInfoRoot {
export interface SelNodeChild { export interface SelNodeChild {
channelBackupPath?: string; channelBackupPath?: string;
satsToBTC?: boolean; satsToBTC?: boolean;
currencyUnit?: string;
currencyUnits?: string[]; currencyUnits?: string[];
} }

@ -1,7 +1,14 @@
export const CURRENCY_UNITS = [ 'SATS', 'BTC' ]; export const CURRENCY_UNITS = [ 'Sats', 'BTC' ];
export const CURRENCY_UNIT_FORMATS = { Sats: '1.0-0', BTC: '1.6-6', OTHER: '1.2-2'};
export const TIME_UNITS = ['SECS', 'MINS', 'HOURS', 'DAYS']; export const TIME_UNITS = ['SECS', 'MINS', 'HOURS', 'DAYS'];
export const ADDRESS_TYPES = [
{ addressId: '0', addressTp: 'p2wkh', addressDetails: 'Pay to witness key hash'},
{ addressId: '1', addressTp: 'np2wkh', addressDetails: 'Pay to nested witness key hash (default)'}
];
export enum AuthenticateWith { export enum AuthenticateWith {
TOKEN = 'TOKEN', TOKEN = 'TOKEN',
PASSWORD = 'PASSWORD' PASSWORD = 'PASSWORD'
@ -15,7 +22,7 @@ export enum TimeUnitEnum {
} }
export enum CurrencyUnitEnum { export enum CurrencyUnitEnum {
SATS = 'SATS', SATS = 'Sats',
BTC = 'BTC', BTC = 'BTC',
LITOSHIS = 'LITOSHIS', LITOSHIS = 'LITOSHIS',
LTC = 'LTC', LTC = 'LTC',

@ -54,22 +54,25 @@ export class CommonService implements OnInit, OnDestroy {
} }
convert(value: number, from: string, otherCurrencyUnit: string) { convert(value: number, from: string, otherCurrencyUnit: string) {
let returnValue = {unit: otherCurrencyUnit, symbol: this.conversionData.data[otherCurrencyUnit].symbol, SATS: 0, BTC: 0, OTHER: 0}; let returnValue = {unit: otherCurrencyUnit, symbol: this.conversionData.data[otherCurrencyUnit].symbol};
returnValue[CurrencyUnitEnum.SATS] = 0;
returnValue[CurrencyUnitEnum.BTC] = 0;
returnValue[CurrencyUnitEnum.OTHER] = 0;
switch (from) { switch (from) {
case CurrencyUnitEnum.SATS: case CurrencyUnitEnum.SATS:
returnValue.SATS = value; returnValue[CurrencyUnitEnum.SATS] = value;
returnValue.BTC = value * 0.00000001; returnValue[CurrencyUnitEnum.BTC] = value * 0.00000001;
returnValue.OTHER = value * 0.00000001 * this.unitConversionValue; returnValue[CurrencyUnitEnum.OTHER] = value * 0.00000001 * this.unitConversionValue;
break; break;
case CurrencyUnitEnum.BTC: case CurrencyUnitEnum.BTC:
returnValue.SATS = value * 100000000; returnValue[CurrencyUnitEnum.SATS] = value * 100000000;
returnValue.BTC = value; returnValue[CurrencyUnitEnum.BTC] = value;
returnValue.OTHER = value * this.unitConversionValue; returnValue[CurrencyUnitEnum.OTHER] = value * this.unitConversionValue;
break; break;
case CurrencyUnitEnum.OTHER: case (CurrencyUnitEnum.OTHER):
returnValue.SATS = value / this.unitConversionValue * 100000000; returnValue[CurrencyUnitEnum.SATS] = value / this.unitConversionValue * 100000000;
returnValue.BTC = value / this.unitConversionValue; returnValue[CurrencyUnitEnum.BTC] = value / this.unitConversionValue;
returnValue.OTHER = value; returnValue[CurrencyUnitEnum.OTHER] = value;
break; break;
default: default:
break; break;

@ -16,7 +16,8 @@ import { QRCodeModule } from 'angularx-qrcode';
import { NgxChartsModule } from '@swimlane/ngx-charts'; import { NgxChartsModule } from '@swimlane/ngx-charts';
import { DecimalPipe } from '@angular/common'; import { DecimalPipe } from '@angular/common';
import { InvoiceInformationComponent } from './components/invoice-information/invoice-information.component'; import { InvoiceInformationComponent } from './components/data-modal/invoice-information/invoice-information.component';
import { OnChainGeneratedAddressComponent } from './components/data-modal/on-chain-generated-address/on-chain-generated-address.component';
import { AppSettingsComponent } from './components/app-settings/app-settings.component'; import { AppSettingsComponent } from './components/app-settings/app-settings.component';
import { AlertMessageComponent } from './components/alert-message/alert-message.component'; import { AlertMessageComponent } from './components/alert-message/alert-message.component';
import { ConfirmationMessageComponent } from './components/confirmation-message/confirmation-message.component'; import { ConfirmationMessageComponent } from './components/confirmation-message/confirmation-message.component';
@ -114,6 +115,7 @@ import { CommonService } from './services/common.service';
MatSnackBarModule, MatSnackBarModule,
AppSettingsComponent, AppSettingsComponent,
InvoiceInformationComponent, InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent, AlertMessageComponent,
ConfirmationMessageComponent, ConfirmationMessageComponent,
SpinnerDialogComponent, SpinnerDialogComponent,
@ -134,6 +136,7 @@ import { CommonService } from './services/common.service';
declarations: [ declarations: [
AppSettingsComponent, AppSettingsComponent,
InvoiceInformationComponent, InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent, AlertMessageComponent,
ConfirmationMessageComponent, ConfirmationMessageComponent,
SpinnerDialogComponent, SpinnerDialogComponent,
@ -152,6 +155,7 @@ import { CommonService } from './services/common.service';
], ],
entryComponents: [ entryComponents: [
InvoiceInformationComponent, InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent, AlertMessageComponent,
SpinnerDialogComponent, SpinnerDialogComponent,
ConfirmationMessageComponent ConfirmationMessageComponent

@ -42,7 +42,7 @@
height: $small-font-size * 2.1; height: $small-font-size * 2.1;
font-size: 2.2rem; font-size: 2.2rem;
} }
.material-icons, .invoice-info-header { .material-icons, .modal-info-header {
font-size: $small-font-size * 1.5; font-size: $small-font-size * 1.5;
line-height: 2rem; line-height: 2rem;
} }
@ -105,7 +105,7 @@
.mat-button .mat-icon-button .top-toolbar-icon.icon-pinned { .mat-button .mat-icon-button .top-toolbar-icon.icon-pinned {
font-size: $regular-font-size; font-size: $regular-font-size;
} }
.fa-icon-small, .top-icon-small, .invoice-info-header { .fa-icon-small, .top-icon-small, .modal-info-header {
font-size: $regular-font-size * 1.5; font-size: $regular-font-size * 1.5;
} }
.top-toolbar-icon.icon-pinned { .top-toolbar-icon.icon-pinned {
@ -178,7 +178,7 @@
font-size: $large-font-size * 1.5; font-size: $large-font-size * 1.5;
} }
} }
.fa-icon-small, .top-icon-small, .invoice-info-header { .fa-icon-small, .top-icon-small, .modal-info-header {
font-size: $large-font-size * 1.4; font-size: $large-font-size * 1.4;
} }
.top-toolbar-icon.icon-pinned { .top-toolbar-icon.icon-pinned {

@ -216,7 +216,7 @@
} }
} }
.invoice-info-header { .modal-info-header {
color: $foreground-text; color: $foreground-text;
font-weight: 500; font-weight: 500;
& .page-title-img svg { & .page-title-img svg {
@ -224,7 +224,7 @@
} }
} }
.invoice-qr-code-container { .modal-qr-code-container {
background: $foreground-divider; background: $foreground-divider;
} }

@ -100,7 +100,9 @@ export class RTLEffects implements OnDestroy {
}), }),
map((rtlConfig: RTLConfiguration) => { map((rtlConfig: RTLConfiguration) => {
this.logger.info(rtlConfig); this.logger.info(rtlConfig);
this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: rtlConfig.nodes.find(node => +node.index === rtlConfig.selectedNodeIndex), isInitialSetup: true})) let searchNode = rtlConfig.nodes.find(node => +node.index === rtlConfig.selectedNodeIndex);
searchNode.settings.currencyUnits = [...CURRENCY_UNITS, searchNode.settings.currencyUnit];
this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: searchNode, isInitialSetup: true}))
return { return {
type: RTLActions.SET_RTL_CONFIG, type: RTLActions.SET_RTL_CONFIG,
payload: rtlConfig payload: rtlConfig
@ -226,6 +228,7 @@ export class RTLEffects implements OnDestroy {
this.logger.info(postRes); this.logger.info(postRes);
this.logger.info('Successfully Authorized!'); this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token); this.SetToken(postRes.token);
rootStore.selNode.settings.currencyUnits = [...CURRENCY_UNITS, rootStore.selNode.settings.currencyUnit];
this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: rootStore.selNode, isInitialSetup: true})) this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: rootStore.selNode, isInitialSetup: true}))
}), }),
catchError((err) => { catchError((err) => {
@ -284,8 +287,7 @@ export class RTLEffects implements OnDestroy {
initializeNode(node: any, isInitialSetup: boolean) { initializeNode(node: any, isInitialSetup: boolean) {
const landingPage = isInitialSetup ? '' : 'HOME'; const landingPage = isInitialSetup ? '' : 'HOME';
let selNode = {}; let selNode = { channelBackupPath: node.settings.channelBackupPath, satsToBTC: node.settings.satsToBTC, selCurrencyUnit: node.settings.currencyUnit, currencyUnits: [...CURRENCY_UNITS, node.settings.currencyUnit] };
selNode = { channelBackupPath: node.settings.channelBackupPath, satsToBTC: node.settings.satsToBTC, currencyUnits: [...CURRENCY_UNITS, node.settings.currencyUnit] };
this.store.dispatch(new RTLActions.ResetRootStore(node)); this.store.dispatch(new RTLActions.ResetRootStore(node));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode)); this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode)); this.store.dispatch(new RTLActions.ResetCLStore(selNode));

@ -13,7 +13,7 @@ export interface RootState {
nodeData: GetInfoRoot; nodeData: GetInfoRoot;
} }
const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'vertical', menuType: 'regular', fontSize: 'regular-font', themeMode: 'night', themeColor: 'blue', satsToBTC: false, channelBackupPath: '', currencyUnit: 'USD' }; const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'vertical', menuType: 'regular', fontSize: 'regular-font', themeMode: 'night', themeColor: 'blue', satsToBTC: false, channelBackupPath: '', selCurrencyUnit: 'USD', currencyUnits: ['Sats', 'BTC', 'USD'] };
const initNodeAuthentication = { nodeAuthType: 'CUSTOM', configPath: '', bitcoindConfigPath: '' }; const initNodeAuthentication = { nodeAuthType: 'CUSTOM', configPath: '', bitcoindConfigPath: '' };
const initRootState: RootState = { const initRootState: RootState = {

Loading…
Cancel
Save