Copy Icon and Invoices

Copy Icon and Invoices
pull/209/head
Shahana Farooqui 5 years ago
parent 56d47b7afa
commit f517357702

@ -166,6 +166,85 @@ MIT
@angular/router
MIT
@fortawesome/angular-fontawesome
MIT
@fortawesome/fontawesome-svg-core
MIT
Font Awesome Free License
-------------------------
Font Awesome Free is free, open source, and GPL friendly. You can use it for
commercial projects, open source projects, or really almost whatever you want.
Full Font Awesome Free license: https://fontawesome.com/license/free.
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
packaged as SVG and JS file types.
# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
In the Font Awesome Free download, the SIL OFL license applies to all icons
packaged as web and desktop font files.
# Code: MIT License (https://opensource.org/licenses/MIT)
In the Font Awesome Free download, the MIT license applies to all non-font and
non-icon files.
# Attribution
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
Awesome Free files already contain embedded comments with sufficient
attribution, so you shouldn't need to do anything additional when using these
files normally.
We've kept attribution comments terse, so we ask that you do not actively work
to remove them from files, especially code. They're a great way for folks to
learn about Font Awesome.
# Brand Icons
All brand icons are trademarks of their respective owners. The use of these
trademarks does not indicate endorsement of the trademark holder by Font
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
to represent the company, product, or service to which they refer.**
@fortawesome/free-solid-svg-icons
(CC-BY-4.0 AND MIT)
Font Awesome Free License
-------------------------
Font Awesome Free is free, open source, and GPL friendly. You can use it for
commercial projects, open source projects, or really almost whatever you want.
Full Font Awesome Free license: https://fontawesome.com/license/free.
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
packaged as SVG and JS file types.
# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
In the Font Awesome Free download, the SIL OFL license applies to all icons
packaged as web and desktop font files.
# Code: MIT License (https://opensource.org/licenses/MIT)
In the Font Awesome Free download, the MIT license applies to all non-font and
non-icon files.
# Attribution
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
Awesome Free files already contain embedded comments with sufficient
attribution, so you shouldn't need to do anything additional when using these
files normally.
We've kept attribution comments terse, so we ask that you do not actively work
to remove them from files, especially code. They're a great way for folks to
learn about Font Awesome.
# Brand Icons
All brand icons are trademarks of their respective owners. The use of these
trademarks does not indicate endorsement of the trademark holder by Font
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
to represent the company, product, or service to which they refer.**
@ngrx/effects
MIT

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,5 +9,5 @@
<link rel="stylesheet" href="styles.13a9674cdbdfd014a4cf.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.04b3d5b5c3fa2d5708c0.js"></script><script src="polyfills-es5.763f4f23e8aee5ec234d.js" nomodule></script><script src="polyfills.e59b6f9dc696bd89cf7f.js"></script><script src="main.1c9e26206d1b7d79ae0c.js"></script></body>
<script src="runtime.6d7f4fc1b563aa79d526.js"></script><script src="polyfills-es5.763f4f23e8aee5ec234d.js" nomodule></script><script src="polyfills.e59b6f9dc696bd89cf7f.js"></script><script src="main.59fa2b3afa7a6b0831a3.js"></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 +0,0 @@
!function(e){function r(r){for(var n,i,a=r[0],f=r[1],c=r[2],p=0,d=[];p<a.length;p++)o[i=a[p]]&&d.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(l&&l(r);d.length;)d.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,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:"5d20dbfb50eaa379bb80",6:"f83f8ddeebe4d6732db3",7:"095b1a1985ddfc74e193"}[e]+".js"}(e);var f=new Error;u=function(r){a.onerror=a.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: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||[],f=a.push.bind(a);a.push=r,a=a.slice();for(var c=0;c<a.length;c++)r(a[c]);var l=f;t()}([]);

@ -0,0 +1 @@
!function(e){function r(r){for(var n,a,i=r[0],c=r[1],f=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=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,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:"5d20dbfb50eaa379bb80",6:"12388ed64e707cd157b5",7:"a5c863be17d1f63652ca"}[e]+".js"}(e);var c=new Error;u=function(r){i.onerror=i.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: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||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var f=0;f<i.length;f++)r(i[f]);var l=c;t()}([]);

@ -3,22 +3,23 @@ var common = require('../../common');
var logger = require('../logger');
var options = {};
exports.getInvoice = (req, res, next) => {
exports.deleteExpiredInvoice = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/invoice/' + req.params.rHashStr;
request(options).then((body) => {
logger.info({fileName: 'Invoice', msg: 'Invoice Info Received: ' + JSON.stringify(body)});
const queryStr = req.query.maxExpiry ? '?maxexpiry=' + req.query.maxExpiry : '';
options.url = common.getSelLNServerUrl() + '/invoice/delExpiredInvoice' + queryStr;
request.delete(options).then((body) => {
logger.info({fileName: 'Invoice', msg: 'Invoices Deleted: ' + JSON.stringify(body)});
if(undefined === body || body.error) {
res.status(500).json({
message: "Fetching Invoice Info Failed!",
message: "Deleting Invoice Failed!",
error: (undefined === body) ? 'Error From Server!' : body.error
});
}
res.status(200).json(body);
res.status(204).json({status: 'Invoice Deleted Successfully'});
})
.catch((err) => {
return res.status(500).json({
message: "Fetching Invoice Info Failed!",
message: "Deleting Invoice Failed!",
error: err.error
});
});
@ -57,13 +58,8 @@ exports.listInvoices = (req, res, next) => {
exports.addInvoice = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/invoices';
options.form = JSON.stringify({
memo: req.body.memo,
value: req.body.amount,
private: req.body.private,
expiry: req.body.expiry
});
options.url = common.getSelLNServerUrl() + '/invoice/genInvoice';
options.body = req.body;
request.post(options).then((body) => {
logger.info({fileName: 'Invoice', msg: 'Add Invoice Responce: ' + JSON.stringify(body)});
if(undefined === body || body.error) {

29
package-lock.json generated

@ -1449,6 +1449,35 @@
}
}
},
"@fortawesome/angular-fontawesome": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.5.0.tgz",
"integrity": "sha512-5IR/jNMddiEpgApcqSMfp7l5kZqOtxQYzkSLW6iZ4MZHbQQ+Kc9tu9qi2hro6VFSk/sPxeYEzkzGZUNrMYiwOg==",
"requires": {
"tslib": "^1.9.0"
}
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.22",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.22.tgz",
"integrity": "sha512-QmEuZsipX5/cR9JOg0fsTN4Yr/9lieYWM8AQpmRa0eIfeOcl/HLYoEa366BCGRSrgNJEexuvOgbq9jnJ22IY5g=="
},
"@fortawesome/fontawesome-svg-core": {
"version": "1.2.22",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.22.tgz",
"integrity": "sha512-Q941E4x8UfnMH3308n0qrgoja+GoqyiV846JTLoCcCWAKokLKrixCkq6RDBs8r+TtAWaLUrBpI+JFxQNX/WNPQ==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.22"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.10.2.tgz",
"integrity": "sha512-9Os/GRUcy+iVaznlg8GKcPSQFpIQpAg14jF0DWsMdnpJfIftlvfaQCWniR/ex9FoOpSEOrlXqmUCFL+JGeciuA==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.22"
}
},
"@ngrx/effects": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-8.1.0.tgz",

@ -27,6 +27,9 @@
"@angular/platform-browser": "~8.1.2",
"@angular/platform-browser-dynamic": "~8.1.2",
"@angular/router": "~8.1.2",
"@fortawesome/angular-fontawesome": "^0.5.0",
"@fortawesome/fontawesome-svg-core": "^1.2.22",
"@fortawesome/free-solid-svg-icons": "^5.10.2",
"@ngrx/effects": "^8.1.0",
"@ngrx/router-store": "^8.1.0",
"@ngrx/store": "^8.1.0",

@ -4,7 +4,7 @@ const router = express.Router();
const authCheck = require("../authCheck");
router.get("/", authCheck, invoicesController.listInvoices);
router.get("/:rHashStr", authCheck, invoicesController.getInvoice);
router.post("/", authCheck, invoicesController.addInvoice);
router.delete("/", authCheck, invoicesController.deleteExpiredInvoice);
module.exports = router;

@ -22,7 +22,8 @@
<mat-icon [ngClass]="{'icon-smaller': smallScreen}">vpn_key</mat-icon>
<div [ngClass]="{'word-break font-9px': smallScreen, 'word-break': !smallScreen}">&nbsp;{{information?.identity_pubkey}}
<mat-spinner [diameter]="20" *ngIf="flgLoading[0]" class="inline-spinner foreground"></mat-spinner>
<mat-icon [ngClass]="{'icon-smaller cursor-pointer copy-icon-smaller': smallScreen, 'icon-small cursor-pointer copy-icon': !smallScreen}">file_copy</mat-icon><span [hidden]="!flgCopied">Copied</span>
<fa-icon [icon]="faCopy"></fa-icon>
<span [hidden]="!flgCopied">Copied</span>
</div>
</div>
<mat-toolbar color="primary" *ngIf="settings.menu === 'Horizontal'" class="padding-gap-x horizontal-nav">

@ -2,6 +2,8 @@ import { Component, OnInit, AfterViewInit, OnDestroy, ViewChild, HostListener }
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { faCopy } from '@fortawesome/free-solid-svg-icons';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { UserIdleService } from 'angular-user-idle';
@ -21,6 +23,7 @@ import * as fromRTLReducer from './store/rtl.reducers';
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('sideNavigation', { static: false }) sideNavigation: any;
@ViewChild('settingSidenav', { static: true }) settingSidenav: any;
faCopy = faCopy;
public selNode: LightningNode;
public settings: Settings;
public information: GetInfoRoot = {};

@ -43,7 +43,7 @@ import { CLEffects } from './clightning/store/cl.effects';
UserIdleModule.forRoot({idle: 60 * 60, timeout: 1, ping: null}),
StoreModule.forRoot(RTLReducer),
EffectsModule.forRoot([RTLEffects, LNDEffects, CLEffects]),
!environment.production ? StoreDevtoolsModule.instrument() : []
!environment.production ? StoreDevtoolsModule.instrument() : []
],
declarations: [
AppComponent

@ -101,9 +101,9 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header> Short Channel ID </th>
<td mat-cell *matCellDef="let channel"> {{channel?.short_channel_id}}</td>
</ng-container>
<ng-container matColumnDef="peer_id">
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Alias </th>
<td mat-cell *matCellDef="let channel">{{channel?.peer_id | slice:0:10}}...</td>
<td mat-cell *matCellDef="let channel">{{channel?.alias}}</td>
</ng-container>
<ng-container matColumnDef="connected">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Connected </th>

@ -53,19 +53,19 @@ export class CLChannelsComponent implements OnInit, OnDestroy {
break;
case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.displayedColumns = [
'close', 'update', 'short_channel_id', 'peer_id', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
'close', 'update', 'short_channel_id', 'alias', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
];
break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.flgSticky = true;
this.displayedColumns = [
'close', 'update', 'short_channel_id', 'peer_id', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
'close', 'update', 'short_channel_id', 'alias', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
];
break;
default:
this.flgSticky = true;
this.displayedColumns = [
'close', 'update', 'short_channel_id', 'peer_id', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
'close', 'update', 'short_channel_id', 'alias', 'connected', 'private', 'state', 'msatoshi_to_us', 'msatoshi_total', 'spendable_msatoshi'
];
break;
}
@ -216,7 +216,7 @@ export class CLChannelsComponent implements OnInit, OnDestroy {
return channel.channel_id === selRow.channel_id;
})[0];
const reorderedChannel = JSON.parse(JSON.stringify(selChannel, [
'channel_id', 'short_channel_id', 'peer_id', 'connected', 'private', 'state', 'funding_txid', 'msatoshi_to_us', 'msatoshi_total', 'their_channel_reserve_satoshis', 'our_channel_reserve_satoshis', 'spendable_msatoshi'
'channel_id', 'short_channel_id', 'id', 'alias', 'connected', 'private', 'state', 'funding_txid', 'msatoshi_to_us', 'msatoshi_total', 'their_channel_reserve_satoshis', 'our_channel_reserve_satoshis', 'spendable_msatoshi'
] , 2));
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'INFO',
@ -226,13 +226,13 @@ export class CLChannelsComponent implements OnInit, OnDestroy {
loadChannelsTable(channels) {
channels.sort(function(a, b) {
return (a.active === b.active) ? 0 : ((b.active) ? 1 : -1);
return (a && a.active === b.active) ? 0 : ((b.active) ? 1 : -1);
});
this.channels = new MatTableDataSource<ChannelCL>([...channels]);
this.channels.sort = this.sort;
this.channels.filterPredicate = (channel: ChannelCL, fltr: string) => {
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id : '') +
(channel.short_channel_id ? channel.short_channel_id : '') + (channel.peer_id ? channel.peer_id : '') + (channel.peer_alias ? channel.peer_alias : '') +
(channel.short_channel_id ? channel.short_channel_id : '') + (channel.id ? channel.id : '') + (channel.alias ? channel.alias : '') +
(channel.private ? 'private' : 'public') + (channel.state ? channel.state.toLowerCase() : '') +
(channel.funding_txid ? channel.funding_txid : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.msatoshi_total ? channel.msatoshi_total : '') + (channel.their_channel_reserve_satoshis ? channel.their_channel_reserve_satoshis : '') +

@ -1,4 +1,4 @@
<!-- <div fxLayout="column">
<div fxLayout="column">
<div class="padding-gap">
<mat-card>
<mat-card-header>
@ -7,21 +7,32 @@
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<form fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign.gt-sm="space-between center" (ngSubmit)="addInvoiceForm.form.valid && onAddInvoice(addInvoiceForm)" #addInvoiceForm="ngForm">
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
<input matInput [(ngModel)]="memo" placeholder="Memo" tabindex="1" name="memo">
<form fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign.gt-sm="space-between center"
(ngSubmit)="addInvoiceForm.form.valid && onAddInvoice(addInvoiceForm)" #addInvoiceForm="ngForm">
<mat-form-field fxFlex="15" fxLayoutAlign="start end">
<input matInput [(ngModel)]="label" placeholder="Label" tabindex="1" name="label" required>
</mat-form-field>
<mat-form-field fxFlex="15" fxLayoutAlign="start end">
<input matInput [(ngModel)]="invoiceValue" placeholder="Invoice Value ({{information?.smaller_currency_unit}})" type="number" step="100" min="1" tabindex="2" name="invoiceValue">
<input matInput [(ngModel)]="description" placeholder="Description" tabindex="2" name="description">
</mat-form-field>
<mat-form-field fxFlex="15" fxLayoutAlign="start end">
<input matInput [(ngModel)]="expiry" placeholder="Expiry (Sec)" type="number" step="100" min="1" tabindex="3" name="expiry">
<input matInput [(ngModel)]="amount" placeholder="Amount (mSat)" type="number" step="100" min="1" tabindex="3"
name="amount" required>
</mat-form-field>
<mat-form-field fxFlex="10" fxLayoutAlign="start end">
<input matInput [(ngModel)]="expiry" placeholder="Expiry (Sec)" type="number" step="100" min="1"
tabindex="4" name="expiry">
</mat-form-field>
<div fxFlex="15" tabindex="4" fxLayoutAlign="start center" class="chkbox-private">
<mat-checkbox [(ngModel)]="private" matTooltip="Include routing hints for private channels" [matTooltipPosition]="'above'" name="private">Private</mat-checkbox>
<div fxFlex="10" tabindex="5" fxLayoutAlign="start center" class="chkbox-private">
<mat-checkbox [(ngModel)]="private" matTooltip="Include routing hints for private channels"
[matTooltipPosition]="'above'" name="private">Private</mat-checkbox>
</div>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit" tabindex="5">Add</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="6" type="reset" (click)="resetData()">Clear</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit"
tabindex="5" [disabled]="!addInvoiceForm.valid">Add</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="6" type="reset"
(click)="resetData()">Clear</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="warn" tabindex="7" type="button"
(click)="onDeleteExpiredInvoices()">Delete Expired</button>
</form>
</mat-card-content>
</mat-card>
@ -36,50 +47,55 @@
</div>
<div perfectScrollbar class="table-container mat-elevation-z8">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="invoices" matSort [ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
<ng-container matColumnDef="settled">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Settled </th>
<table mat-table #table [dataSource]="invoices" matSort
[ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Status </th>
<td mat-cell *matCellDef="let invoice">
<span *ngIf="invoice.settled"><i class="material-icons primary">done_all</i></span>
<span *ngIf="!invoice.settled"><i class="material-icons accent">done</i></span>
<span *ngIf="invoice.status === 'paid'"><i class="material-icons primary">done_all</i></span>
<span *ngIf="invoice.status !== 'paid'"><i class="material-icons accent">done</i></span>
</td>
</ng-container>
<ng-container matColumnDef="creation_date">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Creation Date </th>
<td mat-cell *matCellDef="let invoice">{{invoice.creation_date_str}}</td>
<ng-container matColumnDef="expires_at_str">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Expiry Date </th>
<td mat-cell *matCellDef="let invoice">{{invoice.expires_at_str}}</td>
</ng-container>
<ng-container matColumnDef="settle_date">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Settle Date </th>
<td mat-cell *matCellDef="let invoice">{{invoice.settle_date_str}}</td>
<ng-container matColumnDef="paid_at_str">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Paid Date </th>
<td mat-cell *matCellDef="let invoice">{{invoice.paid_at_str}}</td>
</ng-container>
<ng-container matColumnDef="memo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Memo </th>
<td mat-cell *matCellDef="let invoice">{{invoice.memo}}</td>
<ng-container matColumnDef="label">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Label </th>
<td mat-cell *matCellDef="let invoice">{{invoice.label}}</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Value ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{(selNode?.satsToBTC) ? (invoice?.btc_value | number:'1.0-3') : (invoice?.value | number)}} </span></td>
<ng-container matColumnDef="pay_index">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Pay Index </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice?.pay_index | number}}
</span></td>
</ng-container>
<ng-container matColumnDef="expiry">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Expiry (Sec)</th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.expiry | number}} </span></td>
<ng-container matColumnDef="msatoshi">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.msatoshi | number}}
</span></td>
</ng-container>
<ng-container matColumnDef="cltv_expiry">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> CLTV Expiry </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.cltv_expiry | number}} </span></td>
<ng-container matColumnDef="msatoshi_received">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Received mSatoshi </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center">
{{invoice.msatoshi_received | number}} </span></td>
</ng-container>
<ng-container matColumnDef="amt_paid_sat">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount Paid ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}})</th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{(selNode?.satsToBTC) ? (invoice?.btc_amt_paid_sat | number:'1.0-3') : (invoice?.amt_paid_sat | number)}} </span></td>
<ng-container matColumnDef="description">
<th mat-header-cell class="pl-4" *matHeaderCellDef mat-sort-header> Description </th>
<td mat-cell class="pl-4" *matCellDef="let invoice">{{invoice.description}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.memo == newlyAddedInvoiceMemo && row.value == newlyAddedInvoiceValue && flgAnimate) ? 'added' : 'notAdded'" (click)="onInvoiceClick(row, $event)" class="row-invoices"
[ngClass]="{'settled': row.settled, 'unsettled': !row.settled}"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
[@newlyAddedRowAnimation]="(row.label == newlyAddedLabel && row.msatoshi == newlyAddedAmount && flgAnimate) ? 'added' : 'notAdded'"
(click)="onInvoiceClick(row, $event)" class="row-invoices"
[ngClass]="{'settled': row.status === 'paid', 'unsettled': row.status !== 'paid'}"></tr>
</table>
<mat-paginator [length]="totalInvoices" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" (page)="onPageChange($event)"></mat-paginator>
<!-- <mat-paginator [length]="totalInvoices" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" (page)="onPageChange($event)"></mat-paginator> -->
</div>
</mat-card-content>
</mat-card>
</div>
</div> -->
<h3>INVOICES</h3>
</div>

@ -3,7 +3,6 @@ import { formatDate } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { SelNodeChild } from '../../shared/models/RTLconfig';
@ -11,6 +10,7 @@ import { GetInfoCL, InvoiceCL } from '../../shared/models/clModels';
import { LoggerService } from '../../shared/services/logger.service';
import { newlyAddedRowAnimation } from '../../shared/animation/row-animation';
import { RTLEffects } from '../../store/rtl.effects';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
@ -23,12 +23,13 @@ import * as fromRTLReducer from '../../store/rtl.reducers';
export class CLInvoicesComponent implements OnInit, OnDestroy {
@ViewChild(MatSort, { static: true }) sort: MatSort;
public selNode: SelNodeChild = {};
public newlyAddedInvoiceMemo = '';
public newlyAddedInvoiceValue = 0;
public newlyAddedLabel = '';
public newlyAddedAmount = 0;
public flgAnimate = true;
public memo = '';
public label = '';
public expiry: number;
public invoiceValue: number;
public amount: number;
public description = '';
public displayedColumns = [];
public invoicePaymentReq = '';
public invoices: any;
@ -43,103 +44,116 @@ export class CLInvoicesComponent implements OnInit, OnDestroy {
private lastOffset = -1;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
ngOnInit() {}
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
// switch (true) {
// case (window.innerWidth <= 415):
// this.displayedColumns = ['settled', 'creation_date', 'memo', 'value'];
// break;
// case (window.innerWidth > 415 && window.innerWidth <= 730):
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat'];
// break;
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat'];
// break;
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
// this.flgSticky = true;
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat', 'expiry', 'cltv_expiry'];
// break;
// default:
// this.flgSticky = true;
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat', 'expiry', 'cltv_expiry'];
// break;
// }
// }
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['status', 'expires_at_str', 'label', 'msatoshi'];
break;
case (window.innerWidth > 415 && window.innerWidth <= 730):
this.displayedColumns = ['status', 'expires_at_str', 'paid_at_str', 'label', 'msatoshi', 'msatoshi_received'];
break;
case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.displayedColumns = ['status', 'expires_at_str', 'paid_at_str', 'label', 'pay_index', 'msatoshi', 'msatoshi_received', 'description'];
break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.flgSticky = true;
this.displayedColumns = ['status', 'expires_at_str', 'paid_at_str', 'label', 'pay_index', 'msatoshi', 'msatoshi_received', 'description'];
break;
default:
this.flgSticky = true;
this.displayedColumns = ['status', 'expires_at_str', 'paid_at_str', 'label', 'pay_index', 'msatoshi', 'msatoshi_received', 'description'];
break;
}
}
// ngOnInit() {
// this.store.select('cl')
// .pipe(takeUntil(this.unSubs[0]))
// .subscribe((rtlStore) => {
// rtlStore.effectErrorsCl.forEach(effectsErr => {
// if (effectsErr.action === 'FetchInvoices') {
// this.flgLoading[0] = 'error';
// }
// });
// this.selNode = rtlStore.nodeSettings;
// this.information = rtlStore.information;
// this.totalInvoices = rtlStore.totalInvoices;
// this.firstOffset = +rtlStore.invoices.first_index_offset;
// this.lastOffset = +rtlStore.invoices.last_index_offset;
// this.logger.info(rtlStore);
// this.loadInvoicesTable(rtlStore.invoices.invoices);
// if (this.flgLoading[0] !== 'error') {
// this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
// }
// });
ngOnInit() {
this.store.dispatch(new RTLActions.FetchInvoicesCL({num_max_invoices: 100, index_offset: 0, reversed: false}));
this.store.select('cl')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsCl.forEach(effectsErr => {
if (effectsErr.action === 'FetchInvoicesCL') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information;
this.totalInvoices = rtlStore.totalInvoices;
this.firstOffset = +rtlStore.invoices.first_index_offset;
this.lastOffset = +rtlStore.invoices.last_index_offset;
this.logger.info(rtlStore);
this.loadInvoicesTable(rtlStore.invoices.invoices);
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
}
});
// }
}
// onAddInvoice(form: any) {
// this.flgAnimate = true;
// this.newlyAddedInvoiceMemo = this.memo;
// this.newlyAddedInvoiceValue = this.invoiceValue;
// this.store.dispatch(new RTLActions.OpenSpinner('Adding Invoice...'));
// this.store.dispatch(new RTLActions.SaveNewInvoice({
// memo: this.memo, invoiceValue: this.invoiceValue, private: this.private, expiry: (this.expiry ? this.expiry : 3600), pageSize: this.pageSize
// }));
// this.resetData();
// }
onAddInvoice(form: any) {
this.flgAnimate = true;
this.newlyAddedLabel = this.label;
this.newlyAddedAmount = this.amount;
this.store.dispatch(new RTLActions.OpenSpinner('Adding Invoice...'));
this.store.dispatch(new RTLActions.SaveNewInvoiceCL({
label: this.label, amount: this.amount, description: this.description, expiry: (this.expiry ? this.expiry : 3600), private: this.private
}));
this.resetData();
}
// onInvoiceClick(selRow: Invoice, event: any) {
// const selInvoice = this.invoices.data.filter(invoice => {
// return invoice.payment_request === selRow.payment_request;
// })[0];
// const reorderedInvoice = JSON.parse(JSON.stringify(selInvoice, [
// 'settled', 'creation_date_str', 'settle_date_str', 'memo', 'receipt', 'r_preimage', 'r_hash', 'value', 'payment_request',
// 'description_hash', 'expiry', 'fallback_addr', 'cltv_expiry', 'route_hints', 'private', 'add_index', 'settle_index',
// 'amt_paid', 'amt_paid_sat', 'amt_paid_msat'
// ] , 2));
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
// type: 'INFO',
// message: JSON.stringify(reorderedInvoice)
// }}));
// }
onDeleteExpiredInvoices() {
this.store.dispatch(new RTLActions.OpenConfirmation({
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Delete Expired Invoices', noBtnText: 'Cancel', yesBtnText: 'Delete Invoices'
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1]))
.subscribe(confirmRes => {
if (confirmRes) {
this.store.dispatch(new RTLActions.OpenSpinner('Deleting Invoices...'));
this.store.dispatch(new RTLActions.DeleteExpiredInvoiceCL());
}
});
}
// loadInvoicesTable(invoices) {
// this.invoices = new MatTableDataSource<Invoice>([...invoices]);
// this.invoices.sort = this.sort;
// this.invoices.data.forEach(invoice => {
// if (undefined !== invoice.creation_date_str) {
// invoice.creation_date_str = (invoice.creation_date_str === '') ? '' : formatDate(invoice.creation_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
// }
// if (undefined !== invoice.settle_date_str) {
// invoice.settle_date_str = (invoice.settle_date_str === '') ? '' : formatDate(invoice.settle_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
// }
// });
// setTimeout(() => { this.flgAnimate = false; }, 30000);
// this.logger.info(this.invoices);
// }
onInvoiceClick(selRow: InvoiceCL, event: any) {
const selInvoice = this.invoices.data.filter(invoice => {
return invoice.bolt11 === selRow.bolt11;
})[0];
const reorderedInvoice = JSON.parse(JSON.stringify(selInvoice, [
'status', 'expires_at_str', 'paid_at_str', 'pay_index', 'label', 'bolt11', 'payment_hash', 'msatoshi', 'msatoshi_received', 'description'
] , 2));
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'INFO',
message: JSON.stringify(reorderedInvoice)
}}));
}
// resetData() {
// this.memo = '';
// this.invoiceValue = 0;
// this.private = false;
// this.expiry = undefined;
// }
loadInvoicesTable(invoices) {
this.invoices = new MatTableDataSource<InvoiceCL>([...invoices]);
this.invoices.sort = this.sort;
this.invoices.data.forEach(invoice => {
if (undefined !== invoice.paid_at_str) {
invoice.paid_at_str = (invoice.paid_at_str === '') ? '' : formatDate(invoice.paid_at_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
}
if (undefined !== invoice.expires_at_str) {
invoice.expires_at_str = (invoice.expires_at_str === '') ? '' : formatDate(invoice.expires_at_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
}
});
setTimeout(() => { this.flgAnimate = false; }, 5000);
this.logger.info(this.invoices);
}
// applyFilter(selFilter: string) {
// this.invoices.filter = selFilter;
// }
resetData() {
this.label = '';
this.description = '';
this.amount = 0;
this.private = false;
this.expiry = undefined;
}
applyFilter(selFilter: string) {
this.invoices.filter = selFilter;
}
// onPageChange(event: any) {
// let reversed = true;

@ -4,10 +4,11 @@ import { Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Subject, of } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { formatDate } from '@angular/common';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, PaymentCL, FeeRatesCL } from '../../shared/models/clModels';
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';
@ -88,7 +89,7 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchFeesCL', err);
}
));
));
@Effect()
fetchFeeRatesCL = this.actions$.pipe(
@ -107,7 +108,7 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchFeeRatesCL', err);
}
));
));
@Effect()
fetchBalanceCL = this.actions$.pipe(
@ -126,7 +127,7 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchBalanceCL', err);
}
));
));
@Effect()
fetchLocalRemoteBalanceCL = this.actions$.pipe(
@ -145,13 +146,13 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchLocalRemoteBalanceCL', err);
}
));
));
@Effect()
getNewAddressCL = this.actions$.pipe(
ofType(RTLActions.GET_NEW_ADDRESS_CL),
mergeMap((action: RTLActions.GetNewAddressCL) => {
return this.httpClient.get(this.CHILD_API_URL + environment.ON_CHAIN_API + '?type=' + action.payload.addressId)
return this.httpClient.get(this.CHILD_API_URL + environment.ON_CHAIN_API + '?type=' + action.payload.addressTp)
.pipe(map((newAddress: any) => {
this.logger.info(newAddress);
this.store.dispatch(new RTLActions.CloseSpinner());
@ -160,9 +161,9 @@ export class CLEffects implements OnDestroy {
payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {}
};
}),
catchError((err: any) => {
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.ON_CHAIN_API + '?type=' + action.payload.addressId, err);
}));
}));
})
);
@ -215,8 +216,8 @@ export class CLEffects implements OnDestroy {
return this.handleErrorWithAlert('ERROR', 'Add Peer Failed', this.CHILD_API_URL + environment.PEERS_API, err);
})
);
}
));
}
));
@Effect()
detachPeerCL = this.actions$.pipe(
@ -238,7 +239,7 @@ export class CLEffects implements OnDestroy {
})
);
}
));
));
@Effect()
channelsFetchCL = this.actions$.pipe(
@ -249,10 +250,10 @@ export class CLEffects implements OnDestroy {
.pipe(
map((channels: any) => {
this.logger.info(channels);
return {
type: RTLActions.SET_CHANNELS_CL,
payload: (undefined !== channels && channels.length > 0) ? channels : []
};
return {
type: RTLActions.SET_CHANNELS_CL,
payload: (undefined !== channels && channels.length > 0) ? channels : []
};
},
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchChannelsCL', err);
@ -277,7 +278,7 @@ export class CLEffects implements OnDestroy {
};
}),
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
return this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
})
);
}
@ -345,7 +346,7 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchPaymentsCL', err);
}
));
));
@Effect()
decodePaymentCL = this.actions$.pipe(
@ -362,7 +363,7 @@ export class CLEffects implements OnDestroy {
};
}),
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API + '/' + action.payload, err);
return this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API + '/' + action.payload, err);
})
);
})
@ -436,8 +437,8 @@ export class CLEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.SetQueryRoutesCL({routes: []}));
return this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount, err);
this.store.dispatch(new RTLActions.SetQueryRoutesCL({ routes: [] }));
return this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount, err);
})
);
}
@ -549,29 +550,110 @@ export class CLEffects implements OnDestroy {
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'GetForwardingHistory', code: err.status, message: err.error.error }));
return this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/listForwards', err);
return this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/listForwards', err);
})
);
})
);
handleErrorWithoutAlert(actionName: string, err: {status: number, error: any}) {
@Effect()
deleteExpiredInvoiceCL = this.actions$.pipe(
ofType(RTLActions.DELETE_EXPIRED_INVOICE_CL),
mergeMap((action: RTLActions.DeleteExpiredInvoiceCL) => {
const queryStr = (action.payload) ? '?maxexpiry=' + action.payload : '';
return this.httpClient.delete(this.CHILD_API_URL + environment.INVOICES_API + queryStr)
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%',
data: { type: 'SUCCESS', titleMessage: 'Invoices Deleted Successfully!' }
}));
return {
type: RTLActions.FETCH_INVOICES_CL,
payload: { num_max_invoices: 100, reversed: true }
};
}),
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Delete Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
})
);
}
));
@Effect()
saveNewInvoiceCL = this.actions$.pipe(
ofType(RTLActions.SAVE_NEW_INVOICE_CL),
mergeMap((action: RTLActions.SaveNewInvoiceCL) => {
return this.httpClient.post(this.CHILD_API_URL + environment.INVOICES_API, {
label: action.payload.label, amount: action.payload.amount, description: action.payload.description, expiry: action.payload.expiry, private: action.payload.private
})
.pipe(
map((postRes: InvoiceCL) => {
postRes.label = action.payload.label;
postRes.msatoshi = action.payload.amount;
postRes.description = action.payload.description;
postRes.expires_at_str = new Date(postRes.expires_at * 1000).toUTCString();
postRes.expires_at_str = formatDate(postRes.expires_at_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({
width: '70%',
data: { type: 'SUCCESS', titleMessage: 'Invoice Added Successfully!', message: JSON.stringify(postRes) }
}));
return {
type: RTLActions.FETCH_INVOICES_CL,
payload: { num_max_invoices: 100, reversed: true }
};
}),
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Add Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
})
);
}
));
@Effect()
invoicesFetchCL = this.actions$.pipe(
ofType(RTLActions.FETCH_INVOICES_CL),
mergeMap((action: RTLActions.FetchInvoicesCL) => {
this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchInvoicesCL'));
const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 100;
const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0;
const reversed = (action.payload.reversed) ? action.payload.reversed : false;
return this.httpClient.get<ListInvoicesCL>(this.CHILD_API_URL + environment.INVOICES_API + '?num_max_invoices=' + num_max_invoices + '&index_offset=' + index_offset + '&reversed=' + reversed)
.pipe(map((res: ListInvoicesCL) => {
this.logger.info(res);
this.store.dispatch(new RTLActions.SetTotalInvoicesCL(res.invoices ? res.invoices.length : 0));
return {
type: RTLActions.SET_INVOICES_CL,
payload: res
};
}),
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchInvoicesCL', err);
}
));
}));
handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) {
this.logger.error(err);
if(err.status === 401) {
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
return of({ type: RTLActions.SIGNOUT });
} else {
this.store.dispatch(new RTLActions.EffectErrorCl({ action: actionName, code: err.status.toString(), message: err.error.error }));
this.logger.error(err);
return of({type:RTLActions.VOID});
return of({ type: RTLActions.VOID });
}
}
handleErrorWithAlert(alerType: string, alertTitle: string, errURL: string, err: {status: number, error: any}) {
handleErrorWithAlert(alerType: string, alertTitle: string, errURL: string, err: { status: number, error: any }) {
this.logger.error(err);
if(err.status === 401) {
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
return of({ type: RTLActions.SIGNOUT });
} else {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
@ -589,11 +671,11 @@ export class CLEffects implements OnDestroy {
}
}
ngOnDestroy() {
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
});
}
}

@ -1,5 +1,5 @@
import { SelNodeChild } from '../../shared/models/RTLconfig';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, AddressTypeCL, PeerCL, PaymentCL, ChannelCL, FeeRatesCL, ForwardingHistoryResCL } from '../../shared/models/clModels';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, AddressTypeCL, PeerCL, PaymentCL, ChannelCL, FeeRatesCL, ForwardingHistoryResCL, ListInvoicesCL } from '../../shared/models/clModels';
import { ErrorPayload } from '../../shared/models/errorPayload';
import * as RTLActions from '../../store/rtl.actions';
@ -16,6 +16,8 @@ export interface CLState {
allChannels: ChannelCL[];
payments: PaymentCL[];
forwardingHistory: ForwardingHistoryResCL;
invoices: ListInvoicesCL;
totalInvoices: number;
addressTypes: AddressTypeCL[];
}
@ -32,6 +34,8 @@ export const initCLState: CLState = {
allChannels: [],
payments: [],
forwardingHistory: {},
invoices: { invoices: [] },
totalInvoices: -1,
addressTypes: [
{ addressId: '0', addressTp: 'bech32', addressDetails: 'bech32' },
{ addressId: '1', addressTp: 'p2sh-segwit', addressDetails: 'p2sh-segwit (default)' }
@ -73,7 +77,7 @@ export function CLReducer(state = initCLState, action: RTLActions.RTLActions) {
fees: action.payload
};
case RTLActions.SET_FEE_RATES_CL:
if(action.payload.perkb) {
if (action.payload.perkb) {
return {
...state,
feeRatesPerKB: action.payload
@ -120,34 +124,51 @@ export function CLReducer(state = initCLState, action: RTLActions.RTLActions) {
...state,
peers: modifiedPeers
};
case RTLActions.SET_CHANNELS_CL:
return {
...state,
allChannels: action.payload,
};
case RTLActions.REMOVE_CHANNEL_CL:
const modifiedChannels = [...state.allChannels];
const removeChannelIdx = state.allChannels.findIndex(channel => {
return channel.channel_id === action.payload.channelId;
});
if (removeChannelIdx > -1) {
modifiedChannels.splice(removeChannelIdx, 1);
}
return {
...state,
allChannels: modifiedChannels
};
case RTLActions.SET_PAYMENTS_CL:
case RTLActions.SET_CHANNELS_CL:
return {
...state,
allChannels: action.payload,
};
case RTLActions.REMOVE_CHANNEL_CL:
const modifiedChannels = [...state.allChannels];
const removeChannelIdx = state.allChannels.findIndex(channel => {
return channel.channel_id === action.payload.channelId;
});
if (removeChannelIdx > -1) {
modifiedChannels.splice(removeChannelIdx, 1);
}
return {
...state,
allChannels: modifiedChannels
};
case RTLActions.SET_PAYMENTS_CL:
return {
...state,
payments: action.payload
};
case RTLActions.SET_FORWARDING_HISTORY_CL:
return {
...state,
forwardingHistory: action.payload
};
default:
case RTLActions.SET_FORWARDING_HISTORY_CL:
return {
...state,
forwardingHistory: action.payload
};
case RTLActions.ADD_INVOICE_CL:
const newInvoices = state.invoices;
newInvoices.invoices.unshift(action.payload);
return {
...state,
invoices: newInvoices
};
case RTLActions.SET_INVOICES_CL:
return {
...state,
invoices: action.payload
};
case RTLActions.SET_TOTAL_INVOICES_CL:
return {
...state,
totalInvoices: action.payload
};
default:
return state;
}

@ -125,7 +125,7 @@ export class InvoicesComponent implements OnInit, OnDestroy {
invoice.settle_date_str = (invoice.settle_date_str === '') ? '' : formatDate(invoice.settle_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
}
});
setTimeout(() => { this.flgAnimate = false; }, 30000);
setTimeout(() => { this.flgAnimate = false; }, 5000);
this.logger.info(this.invoices);
}

@ -17,7 +17,8 @@
</div>
<ng-template #notNumberTemplate>
<span fxFlex="100">{{obj[1]}}
<mat-icon *ngIf="showCopyOption(obj[0])" class="icon-small cursor-pointer pl-1 top-5px" rtlClipboard [payload]="obj[1]" (copied)="copiedText($event)">file_copy</mat-icon><span *ngIf="showCopyOption(obj[0])" [hidden]="!flgCopied">Copied</span>
<fa-icon *ngIf="showCopyOption(obj[0])" rtlClipboard [payload]="obj[1]" (copied)="copiedText($event)" [icon]="faCopy"></fa-icon>
<span *ngIf="showCopyOption(obj[0])" [hidden]="!flgCopied">Copied</span>
</span>
<div *ngIf="showCopyOption(obj[0])" fxFlex="100" fxLayoutAlign.gt-sm="start center">
<qrcode [qrdata]="obj[1]" [size]="120" [level]="'L'" [allowEmptyString]="true" [ngStyle]="{'visibility': (obj[1] === '') ? 'hidden' : 'visible'}" class="qr-border"></qrcode>

@ -1,5 +1,6 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faCopy } from '@fortawesome/free-solid-svg-icons';
import { LoggerService } from '../../../shared/services/logger.service';
import { AlertData } from '../../../shared/models/alertData';
@ -14,7 +15,8 @@ export class AlertMessageComponent implements OnInit {
public msgTypeForeground = 'primary';
public messageObj = [];
public flgCopied = false;
faCopy = faCopy;
constructor(public dialogRef: MatDialogRef<AlertMessageComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService) { }
ngOnInit() {
@ -69,7 +71,7 @@ export class AlertMessageComponent implements OnInit {
showCopyOption(key): boolean {
let flgFoundKey = false;
const showCopyOnKeys = ['payment request'];
const showCopyOnKeys = ['payment request', 'bolt11'];
showCopyOnKeys.filter((arrKey) => {
if (arrKey === key) {
flgFoundKey = true;

@ -23,7 +23,8 @@
<ng-template #notNumberTemplate>
<span>{{obj[1]}}</span>
</ng-template>
<mat-icon *ngIf="showCopyOption(obj[0])" class="icon-small cursor-pointer pl-1 top-5px" rtlClipboard [payload]="obj[1]" (copied)="copiedText($event)">file_copy</mat-icon><span *ngIf="showCopyOption(obj[0])" [hidden]="!flgCopied">Copied</span>
<fa-icon *ngIf="showCopyOption(obj[0])" rtlClipboard [payload]="obj[1]" (copied)="copiedText($event)" [icon]="faCopy"></fa-icon>
<span *ngIf="showCopyOption(obj[0])" [hidden]="!flgCopied">Copied</span>
</div>
</div>
</div>

@ -1,6 +1,7 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { Store } from '@ngrx/store';
import { faCopy } from '@fortawesome/free-solid-svg-icons';
import { LoggerService } from '../../../shared/services/logger.service';
import { AlertData, InputData } from '../../../shared/models/alertData';
@ -21,6 +22,7 @@ export class ConfirmationMessageComponent implements OnInit {
public messageObj = [];
public flgCopied = false;
public flgShowInput = false;
faCopy = faCopy;
public getInputs: Array<InputData> = [{placeholder: '', inputType: 'text', inputValue: ''}];
constructor(public dialogRef: MatDialogRef<ConfirmationMessageComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService,
@ -70,7 +72,7 @@ export class ConfirmationMessageComponent implements OnInit {
showCopyOption(key): boolean {
let flgFoundKey = false;
const showCopyOnKeys = ['payment request'];
const showCopyOnKeys = ['payment request', 'bolt11'];
showCopyOnKeys.filter((arrKey) => {
if (arrKey === key) {
flgFoundKey = true;

@ -59,30 +59,26 @@ export interface PeerCL {
}
export interface InvoiceCL {
memo?: string;
receipt?: string;
r_preimage?: string;
r_hash?: string;
value?: string;
btc_value?: string;
settled?: boolean;
creation_date?: string;
creation_date_str?: string;
settle_date?: string;
settle_date_str?: string;
payment_request?: string;
description_hash?: string;
expiry?: string;
fallback_addr?: string;
cltv_expiry?: string;
route_hints?: any[];
private?: boolean;
add_index?: string;
settle_index?: string;
amt_paid?: string;
amt_paid_sat?: string;
btc_amt_paid_sat?: string;
amt_paid_msat?: string;
label?: string;
bolt11?: string;
payment_hash?: string;
msatoshi?: number;
amount_msat?: string;
status?: string;
pay_index?: number;
msatoshi_received?: number;
amount_received_msat?: string;
paid_at?: number;
description?: string;
expires_at?: number;
paid_at_str?: string;
expires_at_str?: string;
}
export interface ListInvoicesCL {
invoices?: InvoiceCL[];
last_index_offset?: string;
first_index_offset?: string;
}
export interface OnChainCL {
@ -179,8 +175,8 @@ export interface RoutesCL {
}
export interface ChannelCL {
peer_id?: string;
peer_alias?: string;
id?: string;
alias?: string;
connected?: boolean;
state?: string;
short_channel_id?: string;

@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatDialogModule, MatExpansionModule, MatGridListModule, MatDatepickerModule,
@ -34,6 +35,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
CommonModule,
FormsModule,
ReactiveFormsModule,
FontAwesomeModule,
FlexLayoutModule,
MatButtonModule,
MatButtonToggleModule,
@ -70,6 +72,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
exports: [
FormsModule,
ReactiveFormsModule,
FontAwesomeModule,
FlexLayoutModule,
MatButtonModule,
MatButtonToggleModule,

@ -3,7 +3,7 @@ import { Action } from '@ngrx/store';
import { ErrorPayload } from '../shared/models/errorPayload';
import { RTLConfiguration, Settings, LightningNode, GetInfoRoot, SelNodeChild } from '../shared/models/RTLconfig';
import { GetInfoCL, FeesCL, AddressTypeCL, PeerCL, PaymentCL, PayRequestCL, QueryRoutesCL, ChannelCL, FeeRatesCL, ForwardingHistoryResCL } from '../shared/models/clModels';
import { GetInfoCL, FeesCL, AddressTypeCL, PeerCL, PaymentCL, PayRequestCL, QueryRoutesCL, ChannelCL, FeeRatesCL, ForwardingHistoryResCL, InvoiceCL, ListInvoicesCL } from '../shared/models/clModels';
import {
GetInfo, Peer, Balance, NetworkInfo, Fees, Channel, Invoice, ListInvoices, Payment, GraphNode, AddressType,
PayRequest, ChannelsTransaction, PendingChannels, ClosedChannel, Transaction, SwitchReq, SwitchRes, QueryRoutes
@ -135,6 +135,12 @@ export const INVOICE_LOOKUP_CL = 'INVOICE_LOOKUP_CL';
export const SET_LOOKUP_CL = 'SET_LOOKUP_CL';
export const GET_FORWARDING_HISTORY_CL = 'GET_FORWARDING_HISTORY_CL';
export const SET_FORWARDING_HISTORY_CL = 'SET_FORWARDING_HISTORY_CL';
export const FETCH_INVOICES_CL = 'FETCH_INVOICES_CL';
export const SET_INVOICES_CL = 'SET_INVOICES_CL';
export const SET_TOTAL_INVOICES_CL = 'SET_TOTAL_INVOICES_CL';
export const SAVE_NEW_INVOICE_CL = 'SAVE_NEW_INVOICE_CL';
export const ADD_INVOICE_CL = 'ADD_INVOICE_CL';
export const DELETE_EXPIRED_INVOICE_CL = 'DELETE_EXPIRED_INVOICE_CL';
export class VoidAction implements Action {
readonly type = VOID;
@ -728,6 +734,36 @@ export class SetForwardingHistoryCL implements Action {
constructor(public payload: ForwardingHistoryResCL) {}
}
export class FetchInvoicesCL implements Action {
readonly type = FETCH_INVOICES_CL;
constructor(public payload: {num_max_invoices?: number, index_offset?: number, reversed?: boolean}) {}
}
export class SetInvoicesCL implements Action {
readonly type = SET_INVOICES_CL;
constructor(public payload: ListInvoicesCL) {}
}
export class SetTotalInvoicesCL implements Action {
readonly type = SET_TOTAL_INVOICES_CL;
constructor(public payload: number) {}
}
export class SaveNewInvoiceCL implements Action {
readonly type = SAVE_NEW_INVOICE_CL;
constructor(public payload: {amount: number, label: string, description: string, expiry: number, private: boolean}) {}
}
export class AddInvoiceCL implements Action {
readonly type = ADD_INVOICE_CL;
constructor(public payload: InvoiceCL) {}
}
export class DeleteExpiredInvoiceCL implements Action {
readonly type = DELETE_EXPIRED_INVOICE_CL;
constructor(public payload?: number) {} // maxexpiry
}
export type RTLActions =
ClearEffectErrorRoot | EffectErrorRoot | ClearEffectErrorLnd | EffectErrorLnd | ClearEffectErrorCl | EffectErrorCl |
VoidAction | OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings |
@ -759,4 +795,5 @@ export type RTLActions =
FetchPaymentsCL | SetPaymentsCL | SendPaymentCL | DecodePaymentCL | SetDecodedPaymentCL |
GetQueryRoutesCL | SetQueryRoutesCL |
PeerLookupCL | ChannelLookupCL | InvoiceLookupCL | SetLookupCL |
GetForwardingHistoryCL | SetForwardingHistoryCL;
GetForwardingHistoryCL | SetForwardingHistoryCL |
FetchInvoicesCL | SetInvoicesCL | SetTotalInvoicesCL | SaveNewInvoiceCL | AddInvoiceCL | DeleteExpiredInvoiceCL;

Loading…
Cancel
Save