CL Transactions

CL Transactions
pull/260/head
Shahana Farooqui 4 years ago
parent 7d0cc9803b
commit 1e5a8179ab

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="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.09fbe043baaff9d23c8b.css"></head>
<link rel="stylesheet" href="styles.87b171242d5c32215e74.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.c0640a7d980d0f45293a.js" defer></script><script src="polyfills-es5.b8e32dec482ae69710a2.js" nomodule defer></script><script src="polyfills.ebf9033c33aa4a5af12a.js" defer></script><script src="main.e7acd0ef6dea6ff42ca6.js" defer></script></body>
<script src="runtime.6f62e75da92af0a26161.js" defer></script><script src="polyfills-es5.b8e32dec482ae69710a2.js" nomodule defer></script><script src="polyfills.ebf9033c33aa4a5af12a.js" defer></script><script src="main.500c2732a03d69d31b76.js" defer></script></body>
</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,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(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,i),t.l=!0,t.exports}i.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,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"."+{1:"77d491bf73b15683870f",6:"c8931fec6b13b67089b8",7:"abeee4f18b52040bed44"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);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;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(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,i),t.l=!0,t.exports}i.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,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"."+{1:"77d491bf73b15683870f",6:"7ec7a8ccc7b784fef94e",7:"f713f0d2f12d75fb95b0"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);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;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -48,11 +48,11 @@ exports.getFees = (req, res, next) => {
return res.status(200).json(body);
})
.catch(err => {
logger.error({fileName: 'Fees', lineNum: 54, msg: 'Fetch Fee Error: ' + JSON.stringify(err)});
return res.status(500).json({
message: "Fetching fee failed!",
error: err.error
});
logger.error({fileName: 'Fees', lineNum: 54, msg: 'Fetch Forwarding Events Error: ' + JSON.stringify(err)});
body.daily_tx_count = 0;
body.weekly_tx_count = 0;
body.monthly_tx_count = 0;
return res.status(200).json(body);
});
}
})

@ -22,13 +22,14 @@ exports.getAllForwardingEvents = (start, end, offset, max_events) => {
error: (undefined === body) ? 'Error From Server!' : body.error
});
} else {
if (undefined !== body.forwarding_events && body.forwarding_events.length > 0) {
logger.info({fileName: 'Switch', msg: 'Forwarding History Received: ' + JSON.stringify(body)});
if (body.forwarding_events && body.forwarding_events.length > 0) {
body.forwarding_events.forEach(event => {
event.timestamp_str = (undefined === event.timestamp) ? '' : common.convertTimestampToDate(event.timestamp);
});
body.forwarding_events = common.sortDescByKey(body.forwarding_events, 'timestamp');
}
logger.info({fileName: 'Switch', msg: 'Forwarding History Received: ' + JSON.stringify(body)});
logger.info({fileName: 'Switch', msg: 'Forwarding History before Resolve: ' + JSON.stringify(body)});
resolve(body);
}
})

@ -11,7 +11,7 @@ import { PeerCL, GetInfoCL } from '../../../shared/models/clModels';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, AlertTypeEnum, DataTypeEnum, ScreenSizeEnum } from '../../../shared/services/consts-enums-functions';
import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service';
import { OpenChannelComponent } from '../../../shared/components/data-modal/open-channel/open-channel.component';
import { OpenChannelComponent } from '../../../lnd/peers-channels/open-channel-modal/open-channel.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import { CLEffects } from '../../store/cl.effects';
import { RTLEffects } from '../../../store/rtl.effects';
@ -99,6 +99,7 @@ export class CLPeersComponent implements OnInit, OnDestroy {
}
onConnectPeer() {
if(!this.peerAddress) { return true; }
this.flgAnimate = true;
this.newlyAddedPeer = this.peerAddress;
this.store.dispatch(new RTLActions.OpenSpinner('Adding Peer...'));

@ -73,6 +73,10 @@ export class CLFailedTransactionsComponent implements OnInit, OnChanges {
this.forwardingHistoryEvents = new MatTableDataSource<ForwardingEventCL>([...forwardingEvents]);
this.forwardingHistoryEvents.sort = this.sort;
this.forwardingHistoryEvents.paginator = this.paginator;
this.forwardingHistoryEvents.filterPredicate = (event: ForwardingEventCL, fltr: string) => {
const newEvent = event.status + event.received_time_str + event.resolved_time_str + event.in_channel + event.out_channel + (event.in_msatoshi/1000) + (event.out_msatoshi/1000) + event.fee;
return newEvent.includes(fltr.toLowerCase());
};
this.logger.info(this.forwardingHistoryEvents);
}

@ -13,7 +13,11 @@
</ng-container>
<ng-container matColumnDef="received_time_str">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Received Time</th>
<td mat-cell *matCellDef="let fhEvent">{{fhEvent?.received_time_str}}</td>
<td mat-cell *matCellDef="let fhEvent">
<!-- <span *ngIf="fhEvent.status === 'settled'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="fhEvent.status !== 'settled'" class="dot yellow" matTooltip="Unsettled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> -->
{{fhEvent?.received_time_str}}
</td>
</ng-container>
<ng-container matColumnDef="resolved_time_str">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Resolved Time</th>

@ -57,7 +57,7 @@ export class CLForwardingHistoryComponent implements OnInit, OnChanges {
{key: 'resolved_time_str', value: selFEvent.resolved_time_str, title: 'Resolved Time', width: 50, type: DataTypeEnum.DATE_TIME}],
[{key: 'in_channel', value: selFEvent.in_channel, title: 'Inbound Channel ID', width: 50, type: DataTypeEnum.STRING},
{key: 'out_channel', value: selFEvent.out_channel, title: 'Outbound Channel ID', width: 50, type: DataTypeEnum.STRING}],
[{key: 'status', value: (selFEvent.status=== 'settled' ? 'Settled' : 'Unsettled'), title: 'Status', width: 50, type: DataTypeEnum.STRING},
[{key: 'status', value: (selFEvent.status === 'settled' ? 'Settled' : 'Failed'), title: 'Status', width: 50, type: DataTypeEnum.STRING},
{key: 'fee', value: selFEvent.fee, title: 'Fee (mSats)', width: 50, type: DataTypeEnum.NUMBER}],
[{key: 'in_msatoshi', value: selFEvent.in_msatoshi, title: 'In (mSats)', width: 50, type: DataTypeEnum.NUMBER},
{key: 'out_msatoshi', value: selFEvent.out_msatoshi, title: 'Out (mSats)', width: 50, type: DataTypeEnum.NUMBER}]
@ -73,6 +73,10 @@ export class CLForwardingHistoryComponent implements OnInit, OnChanges {
this.forwardingHistoryEvents = new MatTableDataSource<ForwardingEventCL>([...forwardingEvents]);
this.forwardingHistoryEvents.sort = this.sort;
this.forwardingHistoryEvents.paginator = this.paginator;
this.forwardingHistoryEvents.filterPredicate = (event: ForwardingEventCL, fltr: string) => {
const newEvent = event.received_time_str + event.resolved_time_str + event.in_channel + event.out_channel + (event.in_msatoshi/1000) + (event.out_msatoshi/1000) + event.fee;
return newEvent.includes(fltr.toLowerCase());
};
this.logger.info(this.forwardingHistoryEvents);
}

@ -37,7 +37,7 @@ export class CLRoutingComponent implements OnInit, OnDestroy {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {}
ngOnInit() {
// this.onEventsFetch();
this.onEventsFetch();
// this.actions$.pipe(takeUntil(this.unSubs[1]), filter((action) => action.type === RTLActions.RESET_CL_STORE))
// .subscribe((resetClStore: RTLActions.ResetCLStore) => {
// this.onEventsFetch();

@ -10,12 +10,14 @@ import { Location } from '@angular/common';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service';
import { CommonService } from '../../shared/services/common.service';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
import { CLInvoiceInformationComponent } from '../../shared/components/data-modal/invoice-information-cl/invoice-information.component';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, PaymentCL, FeeRatesCL, ListInvoicesCL, InvoiceCL } from '../../shared/models/clModels';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
import { AlertTypeEnum, DataTypeEnum } from '../../shared/services/consts-enums-functions';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
import { AlertTypeEnum } from '../../shared/services/consts-enums-functions';
@Injectable()
export class CLEffects implements OnDestroy {
@ -28,6 +30,7 @@ export class CLEffects implements OnDestroy {
private store: Store<fromRTLReducer.RTLState>,
private sessionService: SessionService,
private logger: LoggerService,
private commonService: CommonService,
private router: Router,
private location: Location) { }
@ -235,7 +238,7 @@ export class CLEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ data: { type: AlertTypeEnum.SUCCESS, alertTitle: 'Peer Disconnected', titleMessage: 'Peer Disconnected Successfully!' }}));
this.store.dispatch(new RTLActions.OpenSnackBar('Peer Disconnected Successfully!'));
return {
type: RTLActions.REMOVE_PEER_CL,
payload: { id: action.payload.id }
@ -304,7 +307,7 @@ export class CLEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ data: { type: AlertTypeEnum.SUCCESS, alertTitle: 'Channel Updated', titleMessage: 'Channel Updated Successfully!' }}));
this.store.dispatch(new RTLActions.OpenSnackBar('Channel Updated Successfully!'));
return {
type: RTLActions.FETCH_CHANNELS_CL
};
@ -405,17 +408,7 @@ export class CLEffects implements OnDestroy {
if (sendRes.error) {
this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, { status: sendRes.status, error: sendRes.error.message });
} else {
const reorderedRes = [
[{key: 'status', value: sendRes.status, title: 'Status', width: 100, type: DataTypeEnum.NUMBER}]
];
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%',
data: {
type: AlertTypeEnum.SUCCESS,
alertTitle: 'Payment Sent',
titleMessage: 'Payment Sent Successfully!',
message: reorderedRes
}}));
this.store.dispatch(new RTLActions.OpenSnackBar('Payment Sent Successfully!'));
this.store.dispatch(new RTLActions.FetchChannelsCL());
this.store.dispatch(new RTLActions.FetchBalanceCL());
this.store.dispatch(new RTLActions.FetchPaymentsCL());
@ -426,7 +419,7 @@ export class CLEffects implements OnDestroy {
}
}),
catchError((err: any) => {
this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, err);
this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, err.error ? err.error : err);
return of({type: RTLActions.VOID});
})
);
@ -581,10 +574,7 @@ export class CLEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%',
data: { type: AlertTypeEnum.SUCCESS, alertTitle: 'Invoice Deleted', titleMessage: 'Invoices Deleted Successfully!' }
}));
this.store.dispatch(new RTLActions.OpenSnackBar('Invoices Deleted Successfully!'));
return {
type: RTLActions.FETCH_INVOICES_CL,
payload: { num_max_invoices: 100, reversed: true }
@ -607,25 +597,19 @@ export class CLEffects implements OnDestroy {
})
.pipe(
map((postRes: InvoiceCL) => {
postRes.label = action.payload.label;
postRes.msatoshi = action.payload.amount;
postRes.description = action.payload.description;
postRes.expires_at = Math.round(new Date().getTime() / 1000);
postRes.expires_at_str = new Date(+postRes.expires_at * 1000).toUTCString();
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
const reorderedRes = [
[{key: 'status', value: postRes.bolt11, title: 'Status', width: 100, type: DataTypeEnum.NUMBER}]
];
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%',
data: {
type: AlertTypeEnum.SUCCESS,
alertTitle: 'Invoice Created',
titleMessage: 'Invoice Added Successfully!',
message: reorderedRes
}
}));
postRes.msatoshi = action.payload.amount;
postRes.label = action.payload.label;
postRes.expires_at = Math.round((new Date().getTime() / 1000) + action.payload.expiry);
postRes.expires_at_str = this.commonService.convertTimestampToDate(+postRes.expires_at);
postRes.description = action.payload.description;
postRes.status = 'unpaid';
this.store.dispatch(new RTLActions.OpenAlert({ data: {
invoice: postRes,
newlyAdded: false,
component: CLInvoiceInformationComponent
}}));
return {
type: RTLActions.FETCH_INVOICES_CL,
payload: { num_max_invoices: 100, reversed: true }
@ -735,7 +719,6 @@ export class CLEffects implements OnDestroy {
} else {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({
width: '55%',
data: {
type: alerType,
alertTitle: alertTitle,

@ -12,7 +12,7 @@ import { GetInfoCL, InvoiceCL } from '../../../shared/models/clModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service';
import { InvoiceInformationComponent } from '../../../shared/components/data-modal/invoice-information/invoice-information.component';
import { CLInvoiceInformationComponent } from '../../../shared/components/data-modal/invoice-information-cl/invoice-information.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
@ -112,15 +112,15 @@ export class CLLightningInvoicesComponent implements OnInit, OnDestroy {
this.newlyAddedInvoiceValue = this.invoiceValue;
this.store.dispatch(new RTLActions.OpenSpinner('Adding Invoice...'));
this.store.dispatch(new RTLActions.SaveNewInvoiceCL({
label: this.label, amount: this.invoiceValue, description: this.description, expiry: expiryInSecs, private: this.private
label: this.label, amount: this.invoiceValue*1000, description: this.description, expiry: expiryInSecs, private: this.private
}));
this.resetData();
}
onDeleteExpiredInvoices() {
this.store.dispatch(new RTLActions.OpenConfirmation({
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Delete Expired Invoices', noBtnText: 'Cancel', yesBtnText: 'Delete Invoices'
}}));
data: { type: 'CONFIRM', titleMessage: 'Delete Expired Invoices', noBtnText: 'Cancel', yesBtnText: 'Delete Invoices' }
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1]))
.subscribe(confirmRes => {
@ -132,28 +132,21 @@ export class CLLightningInvoicesComponent implements OnInit, OnDestroy {
}
onInvoiceClick(selInvoice: InvoiceCL, event: any) {
let reCreatedInvoice = {
payment_request: selInvoice.bolt11,
value: selInvoice.amount_msat,
let reCreatedInvoice: InvoiceCL = {
msatoshi: selInvoice.msatoshi,
label: selInvoice.label,
settle_date_str: selInvoice.paid_at_str,
expiry: selInvoice.expires_at_str
expires_at_str: selInvoice.expires_at_str,
paid_at_str: selInvoice.paid_at_str,
bolt11: selInvoice.bolt11,
payment_hash: selInvoice.payment_hash,
description: selInvoice.description,
status: selInvoice.status,
msatoshi_received: selInvoice.msatoshi_received
};
// msatoshi
// label
// expires_at
// paid_at
// bolt11
// Advanced:
// payment_hash
// description
// status
// msatoshi_received
this.store.dispatch(new RTLActions.OpenAlert({ data: {
invoice: reCreatedInvoice,
newlyAdded: false,
component: InvoiceInformationComponent
component: CLInvoiceInformationComponent
}}));
}

@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild, Input } from '@angular/core';
import { DecimalPipe } from '@angular/common';
import { DecimalPipe, TitleCasePipe } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@ -51,7 +51,7 @@ export class CLLightningPaymentsComponent implements OnInit, OnDestroy {
public screenSizeEnum = ScreenSizeEnum;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private lndEffects: CLEffects, private decimalPipe: DecimalPipe) {
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private lndEffects: CLEffects, private decimalPipe: DecimalPipe, private titleCasePipe: TitleCasePipe) {
this.screenSize = this.commonService.getScreenSize();
if(this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
@ -159,7 +159,7 @@ export class CLLightningPaymentsComponent implements OnInit, OnDestroy {
[{key: 'payee', value: this.paymentDecoded.payee, title: 'Payee', width: 100}],
[{key: 'description', value: this.paymentDecoded.description, title: 'Description', width: 100}],
[{key: 'created_at_str', value: this.paymentDecoded.created_at_str, title: 'Creation Date', width: 50},
{key: 'num_satoshis', value: this.paymentDecoded.msatoshi, title: 'Amount (Sats)', width: 50, type: DataTypeEnum.NUMBER}],
{key: 'num_satoshis', value: this.paymentDecoded.msatoshi/1000, title: 'Amount (Sats)', width: 50, type: DataTypeEnum.NUMBER}],
[{key: 'expiry', value: this.paymentDecoded.expiry, title: 'Expiry', width: 50, type: DataTypeEnum.NUMBER},
{key: 'min_final_cltv_expiry', value: this.paymentDecoded.min_final_cltv_expiry, title: 'CLTV Expiry', width: 50}]
];
@ -210,21 +210,21 @@ export class CLLightningPaymentsComponent implements OnInit, OnDestroy {
onPaymentClick(selPayment: PaymentCL, event: any) {
const reorderedPayment = [
[{key: 'bolt11', value: selPayment.bolt11, title: 'Bolt 11', width: 100, type: DataTypeEnum.STRING}],
[{key: 'payment_hash', value: selPayment.payment_hash, title: 'Payment Hash', width: 100, type: DataTypeEnum.STRING}],
[{key: 'payment_preimage', value: selPayment.payment_preimage, title: 'Payment Preimage', width: 100, type: DataTypeEnum.STRING}],
[{key: 'id', value: selPayment.id, title: 'ID', width: 100, type: DataTypeEnum.STRING}],
[{key: 'destination', value: selPayment.destination, title: 'Destination', width: 50, type: DataTypeEnum.STRING},
{key: 'status', value: selPayment.status, title: 'Status', width: 50, type: DataTypeEnum.STRING}],
[{key: 'id', value: selPayment.id, title: 'ID', width: 20, type: DataTypeEnum.STRING},
{key: 'destination', value: selPayment.destination, title: 'Destination', width: 80, type: DataTypeEnum.STRING}],
[{key: 'created_at_str', value: selPayment.created_at_str, title: 'Creation Date', width: 50, type: DataTypeEnum.DATE_TIME},
{key: 'bolt11', value: selPayment.bolt11, title: 'Bolt 11', width: 50, type: DataTypeEnum.STRING}],
[{key: 'msatoshi', value: selPayment.msatoshi, title: 'mSatoshi', width: 50, type: DataTypeEnum.STRING},
{key: 'msatoshi_sent', value: selPayment.msatoshi_sent, title: 'Sent mSatoshi', width: 50, type: DataTypeEnum.STRING}],
[{key: 'amount_msat', value: selPayment.amount_msat, title: 'Amount (mSats)', width: 50, type: DataTypeEnum.STRING},
{key: 'amount_sent_msat', value: selPayment.amount_sent_msat, title: 'Amount Sent (mSats)', width: 50, type: DataTypeEnum.STRING}]
{key: 'status', value: this.titleCasePipe.transform(selPayment.status), title: 'Status', width: 50, type: DataTypeEnum.STRING}],
[{key: 'msatoshi', value: selPayment.msatoshi, title: 'Amount (mSats)', width: 50, type: DataTypeEnum.NUMBER},
{key: 'msatoshi_sent', value: selPayment.msatoshi_sent, title: 'Amount Sent (mSats)', width: 50, type: DataTypeEnum.NUMBER}]
];
this.store.dispatch(new RTLActions.OpenAlert({ data: {
type: AlertTypeEnum.INFORMATION,
alertTitle: 'Payment Information',
showCopyName: 'Bolt 11',
showCopyField: selPayment.bolt11,
message: reorderedPayment
}}));
}

@ -42,20 +42,20 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header> Direction </th>
<td mat-cell *matCellDef="let hop"> {{hop?.direction}} </td>
</ng-container>
<ng-container matColumnDef="delay">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Delay </th>
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.delay | number}} </span>
</td>
</ng-container>
<ng-container matColumnDef="msatoshi">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> mSatoshi </th>
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.msatoshi | number}}
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount (Sats) </th>
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.msatoshi/1000 | number}}
</span></td>
</ng-container>
<ng-container matColumnDef="amount_msat">
<th mat-header-cell class="pl-4" *matHeaderCellDef mat-sort-header> Amount mSat </th>
<td mat-cell class="pl-4" *matCellDef="let hop"> {{hop?.amount_msat}} </td>
</ng-container>
<ng-container matColumnDef="delay">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Delay </th>
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.delay | number}} </span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pl-4 pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let hop" class="pl-4">

@ -20,6 +20,7 @@ import { AlertTypeEnum, DataTypeEnum, ScreenSizeEnum } from '../../../shared/ser
})
export class CLQueryRoutesComponent implements OnInit, OnDestroy {
@ViewChild(MatSort, { static: true }) sort: MatSort;
@ViewChild('queryRoutesForm', { static: false }) form: any;
public destinationPubkey = '';
public amount = null;
public qrHops: any;
@ -42,10 +43,10 @@ export class CLQueryRoutesComponent implements OnInit, OnDestroy {
this.displayedColumns = ['alias', 'direction', 'msatoshi', 'actions'];
} else if(this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['alias', 'direction', 'msatoshi', 'amount_msat', 'actions'];
this.displayedColumns = ['alias', 'direction', 'delay', 'msatoshi', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['alias', 'channel', 'direction', 'msatoshi', 'amount_msat', 'actions'];
this.displayedColumns = ['alias', 'channel', 'direction', 'delay', 'msatoshi', 'actions'];
}
}
@ -69,24 +70,26 @@ export class CLQueryRoutesComponent implements OnInit, OnDestroy {
onQueryRoutes() {
if(!this.destinationPubkey || !this.amount) { return true; }
this.flgLoading[0] = true;
this.store.dispatch(new RTLActions.GetQueryRoutesCL({destPubkey: this.destinationPubkey, amount: this.amount}));
this.store.dispatch(new RTLActions.GetQueryRoutesCL({destPubkey: this.destinationPubkey, amount: this.amount*1000}));
}
resetData() {
this.destinationPubkey = '';
this.amount = null;
this.flgLoading[0] = false;
this.qrHops.data = [];
this.form.resetForm();
}
onHopClick(selHop: RoutesCL, event: any) {
const reorderedHop = [
[{key: 'id', value: selHop.id, title: 'ID', width: 30, type: DataTypeEnum.NUMBER},
{key: 'alias', value: selHop.alias, title: 'Peer Alias', width: 30, type: DataTypeEnum.NUMBER},
{key: 'channel', value: selHop.channel, title: 'Channel', width: 40, type: DataTypeEnum.NUMBER}],
[{key: 'direction', value: selHop.direction, title: 'Direction', width: 30, type: DataTypeEnum.STRING},
{key: 'msatoshi', value: selHop.msatoshi, title: 'mSatoshi', width: 70, type: DataTypeEnum.STRING}],
[{key: 'amount_msat', value: selHop.amount_msat, title: 'Amount mSat', width: 50, type: DataTypeEnum.NUMBER},
{key: 'delay', value: selHop.delay, title: 'Delay', width: 50, type: DataTypeEnum.STRING}]
[{key: 'id', value: selHop.id, title: 'ID', width: 100, type: DataTypeEnum.STRING}],
[{key: 'channel', value: selHop.channel, title: 'Channel', width: 50, type: DataTypeEnum.STRING},
{key: 'alias', value: selHop.alias, title: 'Peer Alias', width: 50, type: DataTypeEnum.STRING}],
[{key: 'msatoshi', value: selHop.msatoshi, title: 'mSatoshi', width: 50, type: DataTypeEnum.NUMBER},
{key: 'amount_msat', value: selHop.amount_msat, title: 'Amount mSat', width: 50, type: DataTypeEnum.STRING}],
[{key: 'direction', value: selHop.direction, title: 'Direction', width: 50, type: DataTypeEnum.STRING},
{key: 'delay', value: selHop.delay, title: 'Delay', width: 50, type: DataTypeEnum.NUMBER}]
];
this.store.dispatch(new RTLActions.OpenAlert({ data: {
type: AlertTypeEnum.INFORMATION,

@ -11,7 +11,7 @@ import { Peer, GetInfo } from '../../../shared/models/lndModels';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, AlertTypeEnum, DataTypeEnum, ScreenSizeEnum } from '../../../shared/services/consts-enums-functions';
import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service';
import { OpenChannelComponent } from '../../../shared/components/data-modal/open-channel/open-channel.component';
import { OpenChannelComponent } from '../../../shared/components/data-modal/open-channel-lnd/open-channel.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';

@ -10,16 +10,17 @@ import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { CommonService } from '../../shared/services/common.service';
import { SessionService } from '../../shared/services/session.service';
import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices, PendingChannelsGroup } from '../../shared/models/lndModels';
import { InvoiceInformationComponent } from '../../shared/components/data-modal/invoice-information/invoice-information.component';
import { OpenChannelComponent } from '../../shared/components/data-modal/open-channel/open-channel.component';
import { CurrencyUnitEnum, AlertTypeEnum, FEE_LIMIT_TYPES, DataTypeEnum } from '../../shared/services/consts-enums-functions';
import { InvoiceInformationComponent } from '../../shared/components/data-modal/invoice-information-lnd/invoice-information.component';
import { OpenChannelComponent } from '../../shared/components/data-modal/open-channel-lnd/open-channel.component';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
import { CurrencyUnitEnum, AlertTypeEnum, FEE_LIMIT_TYPES } from '../../shared/services/consts-enums-functions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as fromLNDReducers from '../store/lnd.reducers';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
@Injectable()
export class LNDEffects implements OnDestroy {
@ -32,6 +33,7 @@ export class LNDEffects implements OnDestroy {
private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService,
private commonService: CommonService,
private sessionService: SessionService,
public dialog: MatDialog,
private router: Router,
@ -191,15 +193,15 @@ export class LNDEffects implements OnDestroy {
})
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
postRes.memo = action.payload.memo;
postRes.value = action.payload.invoiceValue;
postRes.expiry = action.payload.expiry;
postRes.cltv_expiry = '144';
postRes.private = action.payload.private;
postRes.creation_date = Math.round(new Date().getTime() / 1000).toString();
postRes.creation_date_str = new Date(+postRes.creation_date * 1000).toUTCString().substring(5, 22).replace(' ', '/').replace(' ', '/').toUpperCase();
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
postRes.creation_date_str = this.commonService.convertTimestampToDate(+postRes.creation_date);
this.store.dispatch(new RTLActions.OpenAlert({ data: {
invoice: postRes,
newlyAdded: true,

@ -12,7 +12,7 @@ import { GetInfo, Invoice } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service';
import { InvoiceInformationComponent } from '../../../shared/components/data-modal/invoice-information/invoice-information.component';
import { InvoiceInformationComponent } from '../../../shared/components/data-modal/invoice-information-lnd/invoice-information.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';

@ -239,6 +239,8 @@ export class LightningPaymentsComponent implements OnInit, OnDestroy {
this.store.dispatch(new RTLActions.OpenAlert({ data: {
type: AlertTypeEnum.INFORMATION,
alertTitle: 'Payment Information',
showCopyName: 'Payment Hash',
showCopyField: selPayment.payment_hash,
message: reorderedPayment
}}));
}

@ -9,7 +9,7 @@
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px mb-0">
<mat-card-content class="mt-5px mb-0 pr-2">
<div fxLayout="column">
<div fxFlex="50" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large mb-1" [ngClass]="{'display-none': showQRField === '' || (screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM)}">
<qrcode [qrdata]="showQRField" [size]="210" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>
@ -22,8 +22,8 @@
<div fxLayout="column" fxFlex="100" fxFlex.gt-md="{{obj.width}}" *ngFor="let obj of objs; index as j;">
<h4 fxLayoutAlign="start" class="font-bold-500">{{obj.title}}</h4>
<span *ngIf="obj && obj.value; else emptyField">
<span [ngSwitch]="obj.type" class="foreground-secondary-text" fxLayout="row" fxFlex="100" fxLayoutAlign="start stretch">
<ng-container *ngSwitchCase="dataTypeEnum.ARRAY"><span *ngFor="let arrayObj of obj.value" class="display-block">{{arrayObj}}</span></ng-container>
<span [ngSwitch]="obj.type" class="foreground-secondary-text" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<ng-container *ngSwitchCase="dataTypeEnum.ARRAY"><span *ngFor="let arrayObj of obj.value" class="display-block w-100">{{arrayObj}}</span></ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.NUMBER">{{obj.value | number:'1.0-3'}}</ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.BOOLEAN">{{obj.value === true ? 'True' : 'False'}}</ng-container>
<ng-container *ngSwitchDefault>{{obj.value}}</ng-container>

@ -0,0 +1,90 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="35" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.bolt11" [size]="qrWidth" [level]="'L'" [allowEmptyString]="true" [ngClass]="{'qr-border': screenSize !== screenSizeEnum.XS, 'qr-thin-border': screenSize === screenSizeEnum.XS}"></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">{{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}}</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxFlex="30" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.bolt11" [size]="qrWidth" [level]="'L'" [allowEmptyString]="true" [ngClass]="{'qr-border': screenSize !== screenSizeEnum.XS, 'qr-thin-border': screenSize === screenSizeEnum.XS}"></qrcode>
</div>
<div fxLayout="row" *ngIf="invoice.warning_capacity">
<div fxFlex="100" class="alert alert-warn">
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
<span>{{invoice.warning_capacity}}</span>
</div>
</div>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">{{screenSize === screenSizeEnum.XS ? 'Amount' : 'Amount Requested'}}</h4>
<span class="foreground-secondary-text">{{(invoice.msatoshi/1000 || 0) | number}} Sats<ng-container *ngIf="!invoice.msatoshi"> (zero amount) </ng-container></span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Label</h4>
<span class="foreground-secondary-text">{{invoice.label}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Date Expiry</h4>
<span class="foreground-secondary-text">{{invoice.expires_at_str}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Date Settled</h4>
<span class="foreground-secondary-text">{{invoice.paid_at_str || '-'}}</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">Bolt11</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice.bolt11}}</span>
</div>
</div>
<div *ngIf="showAdvanced">
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Payment Hash</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice.payment_hash}}</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">Description</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice.description || '-'}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Status</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice.status | titlecase}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Amount Received</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice.msatoshi_received/1000 | number}} {{invoice.msatoshi_received ? 'Sats' : ''}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
</div>
<div [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}" fxLayout="row" fxLayoutAlign="end center" fxFlex="100">
<button fxFlex="50" fxFlex.gt-sm="25" fxLayoutAlign="center center" mat-stroked-button color="primary" type="reset" (click)="onShowAdvanced()" tabindex="1" class="mr-2">
<p *ngIf="!showAdvanced; else hideAdvancedText">Show Advanced</p>
<ng-template #hideAdvancedText><p>Hide Advanced</p></ng-template>
</button>
<button autoFocus fxFlex="50" fxFlex.gt-sm="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="invoice.bolt11" (copied)="onCopyPayment($event)">{{screenSize === screenSizeEnum.XS ? 'Copy Bolt11' : 'Copy Bolt11'}}</button>
</div>
</div>
</mat-card-content>
</div>
</div>

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

@ -0,0 +1,50 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faReceipt, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { MatSnackBar } from '@angular/material/snack-bar';
import { LoggerService } from '../../../services/logger.service';
import { CommonService } from '../../../services/common.service';
import { CLInvoiceInformation } from '../../../models/alertData';
import { InvoiceCL } from '../../../models/clModels';
import { ScreenSizeEnum } from '../../../services/consts-enums-functions';
@Component({
selector: 'rtl-cl-invoice-information',
templateUrl: './invoice-information.component.html',
styleUrls: ['./invoice-information.component.scss']
})
export class CLInvoiceInformationComponent implements OnInit {
public faReceipt = faReceipt;
public faExclamationTriangle = faExclamationTriangle;
public showAdvanced = false;
public newlyAdded = false;
public invoice: InvoiceCL;
public qrWidth = 240;
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
constructor(public dialogRef: MatDialogRef<CLInvoiceInformationComponent>, @Inject(MAT_DIALOG_DATA) public data: CLInvoiceInformation, private logger: LoggerService, private commonService: CommonService, private snackBar: MatSnackBar) { }
ngOnInit() {
this.invoice = this.data.invoice;
this.newlyAdded = this.data.newlyAdded;
this.screenSize = this.commonService.getScreenSize();
if(this.screenSize === ScreenSizeEnum.XS) {
this.qrWidth = 220;
}
}
onClose() {
this.dialogRef.close(false);
}
onShowAdvanced() {
this.showAdvanced = !this.showAdvanced;
}
onCopyPayment(payload: string) {
this.snackBar.open('Bolt11 copied.');
this.logger.info('Copied Text: ' + payload);
}
}

@ -10,7 +10,7 @@
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxFlex="30" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.payment_request" [size]="qrWidth" [level]="'L'" [allowEmptyString]="true" [ngClass]="{'qr-border': screenSize !== screenSizeEnum.XS, 'qr-thin-border': screenSize === screenSizeEnum.XS}"></qrcode>
@ -83,6 +83,6 @@
<button autoFocus fxFlex="50" fxFlex.gt-sm="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="invoice.payment_request" (copied)="onCopyPayment($event)">{{screenSize === screenSizeEnum.XS ? 'Copy Payment' : 'Copy Payment Request'}}</button>
</div>
</div>
</mat-card-content>
</mat-card-content>
</div>
</div>

@ -30,7 +30,7 @@ export class InvoiceInformationComponent implements OnInit {
this.newlyAdded = this.data.newlyAdded;
this.screenSize = this.commonService.getScreenSize();
if(this.screenSize === ScreenSizeEnum.XS) {
this.qrWidth = 140;
this.qrWidth = 220;
}
}
@ -43,7 +43,7 @@ export class InvoiceInformationComponent implements OnInit {
}
onCopyPayment(payload: string) {
this.snackBar.open('Payment request copied');
this.snackBar.open('Payment request copied.');
this.logger.info('Copied Text: ' + payload);
}
}

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

@ -0,0 +1,68 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { Store } from '@ngrx/store';
import { Peer, GetInfo } from '../../../models/lndModels';
import { OpenChannelAlert } from '../../../models/alertData';
import { TRANS_TYPES } from '../../../services/consts-enums-functions';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromRTLReducer from '../../../../store/rtl.reducers';
@Component({
selector: 'rtl-cl-open-channel',
templateUrl: './open-channel.component.html',
styleUrls: ['./open-channel.component.scss']
})
export class CLOpenChannelComponent implements OnInit {
public alertTitle: string;
public peer: Peer;
public information: GetInfo;
public totalBalance = 0;
public fundingAmount: number;
public isPrivate = false;
public selTransType = '0';
public newlyAdded = false;
public spendUnconfirmed = false;
public transTypeValue = {blocks: '', fees: ''};
public transTypes = TRANS_TYPES;
constructor(public dialogRef: MatDialogRef<CLOpenChannelComponent>, @Inject(MAT_DIALOG_DATA) public data: OpenChannelAlert, private store: Store<fromRTLReducer.RTLState>) { }
ngOnInit() {
this.peer = this.data.message.peer;
this.information = this.data.message.information;
this.totalBalance = this.data.message.balance;
this.newlyAdded = this.data.newlyAdded;
this.alertTitle = this.data.alertTitle;
}
onClose() {
this.dialogRef.close(false);
}
resetData() {
this.fundingAmount = null;
this.isPrivate = false;
this.spendUnconfirmed = false;
this.selTransType = '0';
this.transTypeValue = {blocks: '', fees: ''};
}
onOpenChannel() {
if (!this.fundingAmount || ((this.totalBalance - this.fundingAmount) < 0) || (this.selTransType === '1' && !this.transTypeValue.blocks) || (this.selTransType === '2' && !this.transTypeValue.fees)) { return true; }
let transTypeValue = '0';
if (this.selTransType === '1') {
transTypeValue = this.transTypeValue.blocks;
} else if (this.selTransType === '2') {
transTypeValue = this.transTypeValue.fees;
}
this.store.dispatch(new RTLActions.OpenSpinner('Opening Channel...'));
this.store.dispatch(new RTLActions.SaveNewChannel({
selectedPeerPubkey: this.peer.pub_key, fundingAmount: this.fundingAmount, private: this.isPrivate,
transType: this.selTransType, transTypeValue: transTypeValue, spendUnconfirmed: this.spendUnconfirmed
}));
this.dialogRef.close(false);
}
}

@ -0,0 +1,98 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{alertTitle}}</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<form fxLayout="column" (ngSubmit)="openChannelForm.form.valid && onOpenChannel()" #openChannelForm="ngForm">
<mat-expansion-panel class="flat-expansion-panel">
<mat-expansion-panel-header>
<mat-panel-title>
<span>{{newlyAdded ? '' : 'Open channel with'}}&nbsp;</span><strong class="font-weight-900">{{peer.alias || peer.address}}</strong>&nbsp;{{newlyAdded ? 'added as a peer.' : '.'}}
</mat-panel-title>
</mat-expansion-panel-header>
<div fxLayout="column">
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Pubkey</h4>
<span class="foreground-secondary-text">{{peer.pub_key}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Address</h4>
<span class="overflow-wrap foreground-secondary-text">{{peer.address}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Inbound</h4>
<span class="overflow-wrap foreground-secondary-text">{{peer.inbound ? 'True' : 'False'}}</span>
</div>
</div>
</div>
</mat-expansion-panel>
<div fxLayout="column" class="bordered-box mt-2 open-inputs-box">
<div fxLayout="row" fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="100" fxLayoutAlign="start start">
<span class="page-title">Open Channel</span>
</div>
</mat-card-header>
</div>
<div fxLayout="row" fxFlex="100">
Available balance: {{totalBalance | number}} {{information.smaller_currency_unit}}
</div>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center" class="mt-1">
<mat-form-field fxFlex="60" fxLayoutAlign="start end">
<input matInput [(ngModel)]="fundingAmount" placeholder="Amount" type="number" step="1000" min="1" max="{{totalBalance}}" tabindex="1" required name="amount" #amount="ngModel" nonNegativeAmount="{{totalBalance}}">
<mat-hint>(Remaining Bal: {{totalBalance - ((fundingAmount) ? fundingAmount : 0)}})</mat-hint>
<span matSuffix> {{information?.smaller_currency_unit}} </span>
<mat-error *ngIf="!fundingAmount">Amount is required.</mat-error>
<mat-error *ngIf="amount.errors?.negative">Amount must be less than or equal to {{totalBalance}}.</mat-error>
</mat-form-field>
<div fxFlex="35" fxLayoutAlign="start center">
<mat-slide-toggle tabindex="2" color="primary" [(ngModel)]="isPrivate" name="isPrivate">Private Channel</mat-slide-toggle>
</div>
</div>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center">
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
<mat-select tabindex="3" [(value)]="selTransType">
<mat-option *ngFor="let transType of transTypes" [value]="transType.id">
{{transType.name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="30" *ngIf="selTransType=='0'">
<input matInput placeholder="Default" disabled>
</mat-form-field>
<mat-form-field fxFlex="30" *ngIf="selTransType=='1'">
<input matInput [(ngModel)]="transTypeValue.blocks" placeholder="Target Confirmation Blocks" type="number" name="blocks" step="1" min="0" required tabindex="4" #blocks="ngModel">
<mat-error *ngIf="!transTypeValue.blocks">Target confirmation block is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30" *ngIf="selTransType=='2'">
<input matInput [(ngModel)]="transTypeValue.fees" placeholder="Fee ({{information?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1" min="0" required tabindex="5" #fees="ngModel">
<mat-error *ngIf="!transTypeValue.fees">Fee is required.</mat-error>
</mat-form-field>
<div fxFlex="35" fxLayoutAlign="start center">
<mat-slide-toggle tabindex="6" color="primary" [(ngModel)]="spendUnconfirmed" name="spendUnconfirmed">Spend Unconfirmed Output</mat-slide-toggle>
</div>
</div>
</div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="end center">
<div *ngIf="newlyAdded" fxLayoutAlign="space-between center" fxFlex="60">
<button fxFlex="33" fxLayoutAlign="center center" mat-stroked-button color="warn" (click)="onClose()" tabindex="7">Do It Later</button>
<button fxFlex="32" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="8" type="reset" (click)="resetData()">Clear Field</button>
<button autoFocus fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit" tabindex="9">Open Channel</button>
</div>
<div *ngIf="!newlyAdded" fxLayout="row" fxLayoutAlign="space-between stretch" fxFlex="30" class="mt-2">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="7" type="reset" (click)="resetData()">Clear Field</button>
<button autoFocus fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit" tabindex="8">Open Channel</button>
</div>
</div>
</form>
</mat-card-content>
</div>
</div>

@ -0,0 +1,3 @@
.open-inputs-box {
padding: 1.2rem 2.4rem 0.8rem 2.4rem !important;
}

@ -10,7 +10,7 @@
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content>
<mat-card-content class="pr-2">
<div fxLayout="column">
<div fxFlex="50" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qrcode qrdata="{{selInfoType.infoID === 1 ? information.uris[0] : information.identity_pubkey}}" [size]="qrWidth" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>

@ -1,6 +1,7 @@
import { DataTypeEnum } from '../services/consts-enums-functions';
import { GetInfoRoot } from './RTLconfig';
import { GetInfo, Invoice } from './lndModels';
import { InvoiceCL } from './clModels';
export interface MessageErrorField {
code: number;
@ -40,6 +41,12 @@ export interface InvoiceInformation {
component?: any;
}
export interface CLInvoiceInformation {
invoice: InvoiceCL;
newlyAdded?: boolean;
component?: any;
}
export interface OnChainAddressInformation {
alertTitle?: string;
address: string;
@ -86,5 +93,5 @@ export interface ErrorData {
export interface DialogConfig {
width?: string;
data: AlertData | ConfirmationData | ErrorData | OpenChannelAlert | InvoiceInformation | OnChainAddressInformation | ShowPubkeyData;
data: AlertData | ConfirmationData | ErrorData | OpenChannelAlert | InvoiceInformation | CLInvoiceInformation | OnChainAddressInformation | ShowPubkeyData;
}

@ -93,6 +93,7 @@ export interface InvoiceCL {
expires_at?: number;
paid_at_str?: string;
expires_at_str?: string;
warning_capacity?: string;
}
export interface ListInvoicesCL {

@ -159,6 +159,10 @@ export class CommonService implements OnInit, OnDestroy {
return value;
}
convertTimestampToDate(num: number) {
return new Date(num * 1000).toUTCString().substring(5, 22).replace(' ', '/').replace(' ', '/').toUpperCase();
};
ngOnDestroy() {
this.containerWidthChanged.next();
this.containerWidthChanged.complete();

@ -15,7 +15,7 @@ import {
import { QRCodeModule } from 'angularx-qrcode';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { DecimalPipe } from '@angular/common';
import { DecimalPipe, TitleCasePipe } from '@angular/common';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar';
import { PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
@ -25,7 +25,8 @@ const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollY: false
};
import { InvoiceInformationComponent } from './components/data-modal/invoice-information/invoice-information.component';
import { CLInvoiceInformationComponent } from './components/data-modal/invoice-information-cl/invoice-information.component';
import { InvoiceInformationComponent } from './components/data-modal/invoice-information-lnd/invoice-information.component';
import { OnChainGeneratedAddressComponent } from './components/data-modal/on-chain-generated-address/on-chain-generated-address.component';
import { AppSettingsComponent } from './components/settings/app-settings/app-settings.component';
import { AlertMessageComponent } from './components/data-modal/alert-message/alert-message.component';
@ -42,7 +43,8 @@ import { SettingsComponent } from './components/settings/settings.component';
import { ServerConfigComponent } from './components/settings/server-config/server-config.component';
import { ErrorComponent } from './components/error/error.component';
import { CurrencyUnitConverterComponent } from './components/currency-unit-converter/currency-unit-converter.component';
import { OpenChannelComponent } from './components/data-modal/open-channel/open-channel.component';
import { CLOpenChannelComponent } from './components/data-modal/open-channel-cl/open-channel.component';
import { OpenChannelComponent } from './components/data-modal/open-channel-lnd/open-channel.component';
import { ShowPubkeyComponent } from './components/data-modal/show-pubkey/show-pubkey.component';
import { ClipboardDirective } from './directive/clipboard.directive';
import { AutoFocusDirective } from './directive/auto-focus.directive';
@ -134,7 +136,10 @@ import { SocketService } from './services/socket.service';
MatSnackBarModule,
AppSettingsComponent,
SettingsComponent,
CLInvoiceInformationComponent,
InvoiceInformationComponent,
CLOpenChannelComponent,
OpenChannelComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent,
ConfirmationMessageComponent,
@ -159,6 +164,7 @@ import { SocketService } from './services/socket.service';
declarations: [
AppSettingsComponent,
SettingsComponent,
CLInvoiceInformationComponent,
InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent,
@ -178,12 +184,15 @@ import { SocketService } from './services/socket.service';
AutoFocusDirective,
NonNegativeAmountValidator,
RemoveLeadingZerosPipe,
CLOpenChannelComponent,
OpenChannelComponent,
ShowPubkeyComponent
],
entryComponents: [
CLInvoiceInformationComponent,
InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
CLOpenChannelComponent,
OpenChannelComponent,
ShowPubkeyComponent,
SpinnerDialogComponent,
@ -196,7 +205,7 @@ import { SocketService } from './services/socket.service';
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG },
{ provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: { hasBackdrop: true, autoFocus: true, disableClose: true, role: 'dialog', width: '55%' } },
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 2000, verticalPosition: 'bottom', panelClass: 'rtl-snack-bar' } },
DecimalPipe, SocketService
DecimalPipe, TitleCasePipe, SocketService
]
})
export class SharedModule { }

@ -960,3 +960,8 @@ table {
.mat-vertical-content-container {
margin-left: 2rem !important;
}
.xs-scroll-y {
overflow-y: scroll;
max-height: 600px;
}

Loading…
Cancel
Save