Adding transaction type bolt11/bolt12

Adding transaction type bolt11/bolt12
Release-0.12.0
Shahana Farooqui 2 years ago
parent d68ea24b1e
commit 4092378690

@ -46,22 +46,24 @@ Contributions via code is the most sought after contribution and something we en
* Assuming that nodejs (v12 & above) and npm are already installed on your local machine. Go into your RTL root folder and run `npm install`.
* Sometimes after installation, user receives a message from npm to fix dependency vulnerability by running `npm audit fix`. Please do not follow this step as it can break some of the working RTL code on your machine. We audit and fix these vulnerabilities as soon as possible at our end.
##### Node Server for Development
* The RTL server code has been written in typescript and `npm run watchserver` script can be used to compile and generate their javascript equivalents. Keep the script running to watch for realtime changes and compilation. `watchserver` and `buildserver` scripts get the configuration options from tsconfig, read .ts files from the `./server` folder and save the compiled .js and .map files in `./backend` folder.
##### Node Backend Server for Development
* The RTL server code has been written in typescript and `npm run watchbackend` script can be used to compile and generate their javascript equivalents. Keep the script running to watch for realtime changes and compilation. `watchbackend` and `buildbackend` scripts get the configuration options from tsconfig, read .ts files from the `./server` folder and save the compiled .js and .map files in `./backend` folder.
* To run RTL node server in development mode, open another command window, go to workspace/RTL and excute `npm run server`. This will run the script named `server` defined in package.json. This script sets the node environment as development and starts the server from rtl.js. Nodemon restarts the node application when file changes in the directory are detected.
* This `server` script has been written for windows machine. Please update the script to set the `NODE_ENV=development` according to your machine's OS.
* To check all available scripts for the project, explore the `scripts` section of package.json.
![](./screenshots/node-server-dev.jpg)
##### Angular Server for Development
##### Angular Frontend Server for Development
* The last step starts the node server but it cannot detect and update the code written in Angular. We run the angular development server separately while working on the frontend of the project and package the final build once the development is finished.
* To run the angular development server, go to workspace/RTL and run `npm run start`. It will start the angular server at default '4200' port and serve the application on localhost:4200.
![](./screenshots/angular-server-dev.jpg)
![](./screenshots/localhost-ui-dev.jpg)
##### Package Angular Build
* If the change/update were only made for the backend, you can directly move to the next step.
* In case the code was updated for the frontend (in the src folder), the Angular application code needs to be compiled into the output directory named `angular` at workspace/RTL. It can be done by running `npm run build` command in the RTL root.
* Run `npm run test` script to verify and fix, if needed, automated test cases.
* Execute `npm run lint` to lint the code before final compilation.
* To compile the backend code, `npm run buildbackend` script should be used. It will compile the code written in typescript in `server` folder and create a folder named `backend` with final compiled javascript code.
* The Angular application code needs to be compiled into the output directory named `frontend` at workspace/RTL. It can be done by running `npm run buildfrontend` command in the RTL root.
* Please make sure to remove all linting and other errors thrown by the build command before moving to the next step.
![](./screenshots/angular-build.jpg)

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -13,6 +13,6 @@
<style>@font-face{font-family:Roboto;src:url(Roboto-Thin.f7a95c9c5999532c.woff2) format("woff2"),url(Roboto-Thin.c13c157cb81e8ebb.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.b0e084abf689f393.woff2) format("woff2"),url(Roboto-ThinItalic.1111028df6cea564.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Light.0e01b6cd13b3857f.woff2) format("woff2"),url(Roboto-Light.603ca9a537b88428.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.232ef4b20215f720.woff2) format("woff2"),url(Roboto-LightItalic.1b5e142f787151c8.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Regular.475ba9e4e2d63456.woff2) format("woff2"),url(Roboto-Regular.bcefbfee882bc1cb.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.e3a9ebdaac06bbc4.woff2) format("woff2"),url(Roboto-RegularItalic.0668fae6af0cf8c2.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Medium.457532032ceb0168.woff2) format("woff2"),url(Roboto-Medium.6e1ae5f0b324a0aa.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.872f7060602d55d2.woff2) format("woff2"),url(Roboto-MediumItalic.e06fb533801cbb08.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Bold.447291a88c067396.woff2) format("woff2"),url(Roboto-Bold.fc482e6133cf5e26.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.1b15168ef6fa4e16.woff2) format("woff2"),url(Roboto-BoldItalic.e26ba339b06f09f7.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Black.2eaa390d458c877d.woff2) format("woff2"),url(Roboto-Black.b25f67ad8583da68.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.7dc03ee444552bc5.woff2) format("woff2"),url(Roboto-BlackItalic.c8dc642467cb3099.woff) format("woff");font-weight:900;font-style:italic}html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:62.5%}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}</style><link rel="stylesheet" href="styles.2c38f7d09aa7e379.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.2c38f7d09aa7e379.css"></noscript></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.77fc1f1ea80fb7e3.js" type="module"></script><script src="polyfills.6d989da208bd6fd1.js" type="module"></script><script src="main.b5f3491dacb032ca.js" type="module"></script>
<script src="runtime.6d7dad18cf0cb4ec.js" type="module"></script><script src="polyfills.6d989da208bd6fd1.js" type="module"></script><script src="main.7a0c21b6686b7ea4.js" type="module"></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

@ -0,0 +1 @@
(()=>{"use strict";var e,v={},g={};function r(e){var i=g[e];if(void 0!==i)return i.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(i,t,f,d)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,d]=e[n],s=!0,o=0;o<t.length;o++)(!1&d||a>=d)&&Object.keys(r.O).every(b=>r.O[b](t[o]))?t.splice(o--,1):(s=!1,d<a&&(a=d));if(s){e.splice(n--,1);var l=f();void 0!==l&&(i=l)}}return i}d=d||0;for(var n=e.length;n>0&&e[n-1][2]>d;n--)e[n]=e[n-1];e[n]=[t,f,d]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>e+"."+{632:"bd4a9acc24f320d6",637:"29ddcd6ee5e670da",859:"6757fb0bc883e0b0",893:"a44950223f73d9f3"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="RTLApp:";r.l=(t,f,d,n)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==d)for(var o=document.getElementsByTagName("script"),l=0;l<o.length;l++){var u=o[l];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+d){a=u;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+d),a.src=r.tu(t)),e[t]=[f];var c=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,d)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)d.push(n[2]);else if(666!=f){var a=new Promise((u,c)=>n=e[f]=[u,c]);d.push(n[2]=a);var s=r.p+r.u(f),o=new Error;r.l(s,u=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var c=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;o.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",o.name="ChunkLoadError",o.type=c,o.request=p,n[1](o)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,d)=>{var o,l,[n,a,s]=d,u=0;if(n.some(p=>0!==e[p])){for(o in a)r.o(a,o)&&(r.m[o]=a[o]);if(s)var c=s(r)}for(f&&f(d);u<n.length;u++)r.o(e,l=n[u])&&e[l]&&e[l][0](),e[n[u]]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();

@ -1 +0,0 @@
(()=>{"use strict";var e,v={},g={};function r(e){var i=g[e];if(void 0!==i)return i.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(i,t,f,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,o]=e[n],s=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var l=f();void 0!==l&&(i=l)}}return i}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,f,o]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>e+"."+{632:"aec518afc6a9ef81",637:"f36f77f963d6131f",859:"30e8d3bbb6d699a7",893:"a44950223f73d9f3"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="RTLApp:";r.l=(t,f,o,n)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==o)for(var u=document.getElementsByTagName("script"),l=0;l<u.length;l++){var d=u[l];if(d.getAttribute("src")==t||d.getAttribute("data-webpack")==i+o){a=d;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+o),a.src=r.tu(t)),e[t]=[f];var c=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=f){var a=new Promise((d,c)=>n=e[f]=[d,c]);o.push(n[2]=a);var s=r.p+r.u(f),u=new Error;r.l(s,d=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var c=d&&("load"===d.type?"missing":d.type),p=d&&d.target&&d.target.src;u.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",u.name="ChunkLoadError",u.type=c,u.request=p,n[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,o)=>{var u,l,[n,a,s]=o,d=0;if(n.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(s)var c=s(r)}for(f&&f(o);d<n.length;d++)r.o(e,l=n[d])&&e[l]&&e[l][0](),e[n[d]]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();

@ -1,21 +1,26 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="35" [fxLayoutAlign]="invoice?.bolt11 && invoice?.bolt11 !== '' ? 'center start' : 'center center'" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qr-code *ngIf="invoice?.bolt11 && invoice?.bolt11 !== ''" [value]="invoice?.bolt11" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code>
<span *ngIf="!invoice?.bolt11 || invoice?.bolt11 === ''" class="font-size-300">N/A</span>
<div fxFlex="35" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code>
<span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-300">N/A</span>
</div>
<div fxFlex="65">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<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>
<span class="page-title">
{{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}}
<span *ngIf="invoice?.status === 'paid'" class="dot green ml-1" matTooltip="Paid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.status === 'unpaid'" class="dot yellow ml-1" matTooltip="Unpaid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.status === 'expired'" class="dot red ml-1" matTooltip="Expired" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
</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 class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxFlex="30" [fxLayoutAlign]="invoice?.bolt11 && invoice?.bolt11 !== '' ? 'center start' : 'center center'" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qr-code *ngIf="invoice?.bolt11 && invoice?.bolt11 !== ''" [value]="invoice?.bolt11" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code>
<span *ngIf="!invoice?.bolt11 || invoice?.bolt11 === ''" class="font-size-120">QR Code Not Applicable</span>
<div fxFlex="30" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code>
<span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-120">QR Code Not Applicable</span>
</div>
<mat-divider *ngIf="screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM" [inset]="true" class="my-1"></mat-divider>
<div fxLayout="row" *ngIf="invoice?.warning_capacity">
@ -27,7 +32,9 @@
<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 || invoice?.msatoshi === '0'"> (zero amount) </ng-container></span>
<span class="foreground-secondary-text">
{{(invoice?.msatoshi/1000 || 0) | number}} Sats<ng-container *ngIf="!invoice?.msatoshi || invoice?.msatoshi === '0'"> (zero amount) </ng-container>
</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Amount Received</h4>
@ -55,8 +62,8 @@
<span class="foreground-secondary-text">{{(invoice?.expires_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Status</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.status | titlecase}}</span>
<h4 fxLayoutAlign="start" class="font-bold-500">Date Settled</h4>
<span class="foreground-secondary-text">{{((invoice?.paid_at * 1000) | date:'dd/MMM/YYYY HH:mm') || '-'}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
@ -69,8 +76,8 @@
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Invoice</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.bolt11 || 'N/A'}}</span>
<h4 fxLayoutAlign="start" class="font-bold-500">{{ invoice?.bolt12 ? 'Bolt12' : 'Bolt11' }} Invoice</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.bolt11 || invoice?.bolt12}}</span>
</div>
</div>
<div *ngIf="showAdvanced">
@ -83,14 +90,10 @@
</div>
<mat-divider class="w-100 my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Label</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.label}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Date Settled</h4>
<span class="foreground-secondary-text">{{((invoice?.paid_at * 1000) | date:'dd/MMM/YYYY HH:mm') || '-'}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>
</div>
@ -99,8 +102,8 @@
<p *ngIf="!showAdvanced; else hideAdvancedText">Show Advanced</p>
<ng-template #hideAdvancedText><p>Hide Advanced</p></ng-template>
</button>
<button *ngIf="invoice?.bolt11 && invoice?.bolt11 !== ''" autoFocus mat-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="invoice?.bolt11" (copied)="onCopyPayment($event)">Copy Invoice</button>
<button *ngIf="!invoice?.bolt11 || invoice?.bolt11 === ''" autoFocus mat-button color="primary" tabindex="2" type="button" (click)="onClose()">OK</button>
<button *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" autoFocus mat-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="invoice?.bolt11 || invoice?.bolt12" (copied)="onCopyPayment($event)">Copy Invoice</button>
<button *ngIf="!invoice?.bolt11 && !invoice?.bolt12" autoFocus mat-button color="primary" tabindex="2" type="button" (click)="onClose()">OK</button>
</div>
</div>
</mat-card-content>

@ -33,31 +33,35 @@
<ng-container matColumnDef="expires_at">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Expiry Date </th>
<td mat-cell *matCellDef="let invoice">
<span *ngIf="invoice.status === 'paid'" class="dot green" matTooltip="Paid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice.status === 'unpaid'" class="dot yellow" matTooltip="Unpaid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice.status === 'expired'" class="dot red" matTooltip="Expired" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(invoice.expires_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
<span *ngIf="invoice?.status === 'paid'" class="dot green" matTooltip="Paid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.status === 'unpaid'" class="dot yellow" matTooltip="Unpaid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.status === 'expired'" class="dot red" matTooltip="Expired" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(invoice?.expires_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
</td>
</ng-container>
<ng-container matColumnDef="paid_at">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date Settled </th>
<td mat-cell *matCellDef="let invoice">{{((invoice.paid_at * 1000) | date:'dd/MMM/YYYY HH:mm') || '-'}}</td>
<td mat-cell *matCellDef="let invoice">{{((invoice?.paid_at * 1000) | date:'dd/MMM/YYYY HH:mm') || '-'}}</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
<td mat-cell *matCellDef="let invoice">{{ invoice?.bolt12 ? 'Bolt12' : 'Bolt11' }}</td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Description </th>
<td mat-cell *matCellDef="let invoice">
<div class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '32rem'}">
<span class="ellipsis-child">{{invoice.description}}</span>
<span class="ellipsis-child">{{invoice?.description}}</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="msatoshi">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount (Sats) </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.msatoshi/1000 | number:invoice.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice?.msatoshi/1000 | number:invoice?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_received">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount Settled (Sats) </th>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.msatoshi_received/1000 | number:invoice.msatoshi_received < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice?.msatoshi_received/1000 | number:invoice?.msatoshi_received < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">

@ -74,10 +74,10 @@ export class CLLightningInvoicesTableComponent implements OnInit, AfterViewInit,
this.displayedColumns = ['expires_at', 'description', 'msatoshi', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['expires_at', 'description', 'msatoshi', 'msatoshi_received', 'actions'];
this.displayedColumns = ['expires_at', 'type', 'description', 'msatoshi', 'msatoshi_received', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['expires_at', 'paid_at', 'description', 'msatoshi', 'msatoshi_received', 'actions'];
this.displayedColumns = ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received', 'actions'];
}
}
@ -222,7 +222,7 @@ export class CLLightningInvoicesTableComponent implements OnInit, AfterViewInit,
this.invoices.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.invoices.sort = this.sort;
this.invoices.filterPredicate = (rowData: Invoice, fltr: string) => {
const newRowData = ((rowData.paid_at) ? this.datePipe.transform(new Date(rowData.paid_at * 1000), 'dd/MMM/YYYY HH:mm').toLowerCase() : '') + ((rowData.expires_at) ? this.datePipe.transform(new Date(rowData.expires_at * 1000), 'dd/MMM/YYYY HH:mm').toLowerCase() : '') + JSON.stringify(rowData).toLowerCase();
const newRowData = ((rowData.paid_at) ? this.datePipe.transform(new Date(rowData.paid_at * 1000), 'dd/MMM/YYYY HH:mm').toLowerCase() : '') + ((rowData.expires_at) ? this.datePipe.transform(new Date(rowData.expires_at * 1000), 'dd/MMM/YYYY HH:mm').toLowerCase() : '') + ((rowData.bolt12) ? 'bolt12' : 'bolt11') + JSON.stringify(rowData).toLowerCase();
return newRowData.includes(fltr);
};
this.invoices.paginator = this.paginator;

@ -23,119 +23,135 @@
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" placeholder="Filter">
</mat-form-field>
</div>
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
<table mat-table #table fxFlex="100" [dataSource]="payments" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
<ng-container matColumnDef="created_at">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Created At</th>
<td mat-cell *matCellDef="let payment">
<span *ngIf="payment.status === 'complete'" class="dot green" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="payment.status !== 'complete'" class="dot yellow" matTooltip="Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(payment?.created_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
</td>
</ng-container>
<ng-container matColumnDef="payment_hash">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Payment Hash</th>
<td mat-cell *matCellDef="let payment">
<div>{{payment?.payment_hash}}</div>
</td>
</ng-container>
<ng-container matColumnDef="msatoshi_sent">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Sent</th>
<td mat-cell *matCellDef="let payment"><span
fxLayoutAlign="end center">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="msatoshi">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Received</th>
<td mat-cell *matCellDef="let payment"><span
fxLayoutAlign="end center">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">
<div class="bordered-box table-actions-select">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select>
</div>
</th>
<td mat-cell *matCellDef="let payment" class="px-3" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onPaymentClick(payment)">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_payment">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.COMPLETED">No payment available.</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.INITIATED">Getting payments...</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
</td>
</ng-container>
<div fxLayout="row" fxLayoutAlign="start start">
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
<table mat-table #table fxFlex="100" [dataSource]="payments" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
<ng-container matColumnDef="created_at">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Created At</th>
<td mat-cell *matCellDef="let payment">
<span *ngIf="payment.status === 'complete'" class="dot green" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="payment.status !== 'complete'" class="dot yellow" matTooltip="Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(payment?.created_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
<td mat-cell *matCellDef="let invoice">{{ payment?.bolt12 ? 'Bolt12' : 'Bolt11' }}</td>
</ng-container>
<ng-container matColumnDef="payment_hash">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Payment Hash</th>
<td mat-cell *matCellDef="let payment">
<span fxLayout="row" class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '30rem'}">
<span class="ellipsis-child">{{payment?.payment_hash}}</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="msatoshi_sent">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Sent</th>
<td mat-cell *matCellDef="let payment"><span
fxLayoutAlign="end center">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="msatoshi">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Received</th>
<td mat-cell *matCellDef="let payment"><span
fxLayoutAlign="end center">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">
<div class="bordered-box table-actions-select">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select>
</div>
</th>
<td mat-cell *matCellDef="let payment" class="px-3" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onPaymentClick(payment)">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_payment">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.COMPLETED">No payment available.</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.INITIATED">Getting payments...</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
</td>
</ng-container>
<!-- Payment Group Row Start -->
<ng-container matColumnDef="groupTotal">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="mpp-row-span">
<span *ngIf="payment.status === 'complete'" class="dot green mt-0" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="payment.status !== 'complete'" class="dot yellow mt-0" matTooltip="Incomplete/Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
Total Attempts: {{payment?.total_parts}}
</span>
<ng-container *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="start center" class="mpp-row-span pl-3">
<span *ngIf="mpp.status === 'complete'" class="dot green mt-0" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="mpp.status !== 'complete'" class="dot yellow mt-0" matTooltip="Incomplete/Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(mpp.created_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
<!-- Payment Group Row Start -->
<ng-container matColumnDef="groupTotal">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="mpp-row-span">
<span *ngIf="payment.status === 'complete'" class="dot green mt-0" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="payment.status !== 'complete'" class="dot yellow mt-0" matTooltip="Incomplete/Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
Total Attempts: {{payment?.total_parts}}
</span>
<ng-container *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="start center" class="mpp-row-span pl-3">
<span *ngIf="mpp.status === 'complete'" class="dot green mt-0" matTooltip="Completed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="mpp.status !== 'complete'" class="dot yellow mt-0" matTooltip="Incomplete/Failed" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(mpp.created_at * 1000) | date:'dd/MMM/YYYY HH:mm'}}
</span>
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="groupType">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="mpp-row-span">{{ payment?.bolt12 ? 'Bolt12' : 'Bolt11' }}</span>
<span *ngIf="payment.is_expanded"><span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="start center" class="mpp-row-span">{{ payment?.bolt12 ? 'Bolt12' : 'Bolt11' }}</span></span>
</td>
</ng-container>
<ng-container matColumnDef="groupHash">
<td mat-cell *matCellDef="let payment">
<span fxLayout="row" class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '30rem'}">
<span class="ellipsis-child">{{payment?.payment_hash}}</span>
</span>
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="groupHash">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="mpp-row-span">{{payment?.payment_hash}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="start center" class="mpp-row-span">
Part ID {{mpp.partid ? mpp.partid : 0}}
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="start center" class="mpp-row-span">
Part ID {{mpp.partid ? mpp.partid : 0}}
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAmtSent">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi_sent/1000 | number:mpp.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}
</td>
</ng-container>
<ng-container matColumnDef="groupAmtSent">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi_sent/1000 | number:mpp.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAmtRecv">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi/1000 | number:mpp.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</td>
</ng-container>
<ng-container matColumnDef="groupAmtRecv">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi/1000 | number:mpp.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAction">
<td mat-cell *matCellDef="let payment" class="px-3">
<span fxLayoutAlign="end center">
<button mat-flat-button class="btn-mpp-expand" color="primary" type="button" tabindex="5" (click)="payment.is_expanded = !payment.is_expanded">{{payment.is_expanded ? 'Hide' : 'Show'}}</button>
</span>
<div *ngIf="payment.is_expanded">
<div *ngFor="let mpp of payment?.mpps; index as i" fxLayoutAlign="end center">
<button mat-stroked-button class="btn-mpp-info" color="primary" type="button" tabindex="6" (click)="onPaymentClick(mpp)">View {{mpp.partid ? mpp.partid : 0}}</button>
</td>
</ng-container>
<ng-container matColumnDef="groupAction">
<td mat-cell *matCellDef="let payment" class="px-3">
<span fxLayoutAlign="end center">
<button mat-flat-button class="btn-mpp-expand" color="primary" type="button" tabindex="5" (click)="payment.is_expanded = !payment.is_expanded">{{payment.is_expanded ? 'Hide' : 'Show'}}</button>
</span>
<div *ngIf="payment.is_expanded">
<div *ngFor="let mpp of payment?.mpps; index as i" fxLayoutAlign="end center">
<button mat-stroked-button class="btn-mpp-info" color="primary" type="button" tabindex="6" (click)="onPaymentClick(mpp)">View {{mpp.partid ? mpp.partid : 0}}</button>
</div>
</div>
</div>
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: mppColumns; when: is_group;"></tr>
<!-- Payment Group Row End -->
<tr mat-footer-row *matFooterRowDef="['no_payment']" [ngClass]="{'display-none': payments?.data && payments?.data?.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns; when: !is_group;"></tr>
</table>
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: mppColumns; when: is_group;"></tr>
<!-- Payment Group Row End -->
<tr mat-footer-row *matFooterRowDef="['no_payment']" [ngClass]="{'display-none': payments?.data && payments?.data?.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns; when: !is_group;"></tr>
</table>
</div>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,8 +1,9 @@
.mat-column-bolt11 {
flex: 1 1 20%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.mat-column-payment_hash {
flex: 0 0 25%;
width: 25%;
& .ellipsis-parent {
display: flex;
}
}
.mat-column-actions {

@ -73,12 +73,12 @@ export class CLLightningPaymentsComponent implements OnInit, AfterViewInit, OnDe
this.mppColumns = ['groupTotal', 'groupAmtRecv', 'groupAction'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['created_at', 'msatoshi_sent', 'msatoshi', 'actions'];
this.mppColumns = ['groupTotal', 'groupAmtSent', 'groupAmtRecv', 'groupAction'];
this.displayedColumns = ['created_at', 'type', 'msatoshi_sent', 'msatoshi', 'actions'];
this.mppColumns = ['groupTotal', 'groupType', 'groupAmtSent', 'groupAmtRecv', 'groupAction'];
} else {
this.flgSticky = true;
this.displayedColumns = ['created_at', 'payment_hash', 'msatoshi_sent', 'msatoshi', 'actions'];
this.mppColumns = ['groupTotal', 'groupHash', 'groupAmtSent', 'groupAmtRecv', 'groupAction'];
this.displayedColumns = ['created_at', 'type', 'payment_hash', 'msatoshi_sent', 'msatoshi', 'actions'];
this.mppColumns = ['groupTotal', 'groupType', 'groupHash', 'groupAmtSent', 'groupAmtRecv', 'groupAction'];
}
}
@ -249,9 +249,8 @@ export class CLLightningPaymentsComponent implements OnInit, AfterViewInit, OnDe
this.form.resetForm();
}
onPaymentClick(selPayment) {
onPaymentClick(selPayment: Payment) {
const reorderedPayment = [
[{ key: 'bolt11', value: selPayment.bolt11, title: 'Bolt 11', 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: 20, type: DataTypeEnum.STRING },
{ key: 'destination', value: selPayment.destination, title: 'Destination', width: 80, type: DataTypeEnum.STRING }],
@ -260,6 +259,12 @@ export class CLLightningPaymentsComponent implements OnInit, AfterViewInit, OnDe
[{ 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 }]
];
if (selPayment.bolt11 && selPayment.bolt11 !== '') {
reorderedPayment.unshift([{ key: 'bolt11', value: selPayment.bolt11, title: 'Bolt 11', width: 100, type: DataTypeEnum.STRING }]);
}
if (selPayment.bolt12 && selPayment.bolt12 !== '') {
reorderedPayment.unshift([{ key: 'bolt12', value: selPayment.bolt12, title: 'Bolt 12', width: 100, type: DataTypeEnum.STRING }]);
}
if (selPayment.memo && selPayment.memo !== '') {
reorderedPayment.splice(2, 0, [{ key: 'memo', value: selPayment.memo, title: 'Memo', width: 100, type: DataTypeEnum.STRING }]);
}

@ -53,7 +53,7 @@ export class ECLLookupsComponent implements OnInit, OnDestroy {
this.flgLoading[0] = true;
switch (this.selectedFieldId) {
case 0:
this.nodeLookupValue = JSON.parse(JSON.stringify(resLookup.payload[0])) || { nodeid: '' };
this.nodeLookupValue = resLookup.payload[0] ? JSON.parse(JSON.stringify(resLookup.payload[0])) : { nodeid: '' };
break;
case 1:
this.channelLookupValue = JSON.parse(JSON.stringify(resLookup.payload)) || [];

@ -23,124 +23,126 @@
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" placeholder="Filter">
</mat-form-field>
</div>
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
<table mat-table #table fxFlex="100" [dataSource]="payments" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
<ng-container matColumnDef="firstPartTimestamp">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Date/Time</th>
<td mat-cell *matCellDef="let payment">{{payment?.firstPartTimestamp | date:'dd/MMM/YYYY HH:mm'}}</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>ID</th>
<div fxLayout="row" fxLayoutAlign="start start">
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
<table mat-table #table fxFlex="100" [dataSource]="payments" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
<ng-container matColumnDef="firstPartTimestamp">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Date/Time</th>
<td mat-cell *matCellDef="let payment">{{payment?.firstPartTimestamp | date:'dd/MMM/YYYY HH:mm'}}</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>ID</th>
<td mat-cell *matCellDef="let payment">
<div class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.id}}</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="recipientNodeAlias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Destination</th>
<td mat-cell *matCellDef="let payment">
<div class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.recipientNodeAlias}}</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="recipientAmount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount (Sats)</th>
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{(payment?.recipientAmount) | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">
<div class="bordered-box table-actions-select">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select>
</div>
</th>
<td mat-cell *matCellDef="let payment" class="px-3" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onPaymentClick(payment)">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_payment">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.COMPLETED">No payment available.</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.INITIATED">Getting payments...</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
</td>
</ng-container>
<!-- Payment Group Row Start -->
<ng-container matColumnDef="groupTotal">
<td mat-cell *matCellDef="let payment">
<div class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.id}}</span>
</div>
<span fxLayoutAlign="start center" class="part-row-span">
Total Attempts: {{payment?.parts?.length}}
</span>
<ng-container *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span pl-3">
{{part.timestamp | date:'dd/MMM/YYYY HH:mm'}}
</span>
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="recipientNodeAlias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Destination</th>
<ng-container matColumnDef="groupId">
<td mat-cell *matCellDef="let payment">
<div class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.recipientNodeAlias}}</span>
<div fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.id}}</span>
</div>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span">
<span fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{part.id}}</span>
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="recipientAmount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount (Sats)</th>
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{(payment?.recipientAmount) | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">
<div class="bordered-box table-actions-select">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select>
<ng-container matColumnDef="groupChannelAlias">
<td mat-cell *matCellDef="let payment">
<div fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment?.recipientNodeAlias}}</span>
</div>
</th>
<td mat-cell *matCellDef="let payment" class="px-3" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onPaymentClick(payment)">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_payment">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.COMPLETED">No payment available.</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.INITIATED">Getting payments...</p>
<p *ngIf="(!payments?.data || payments?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
</td>
</ng-container>
<!-- Payment Group Row Start -->
<ng-container matColumnDef="groupTotal">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="part-row-span">
Total Attempts: {{payment?.parts?.length}}
</span>
<ng-container *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span pl-3">
{{part.timestamp | date:'dd/MMM/YYYY HH:mm'}}
</span>
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="groupId">
<td mat-cell *matCellDef="let payment">
<div fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment.id}}</span>
</div>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span">
<span fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{part.id}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span">
<span fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{part.toChannelAlias}}</span>
</span>
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupChannelAlias">
<td mat-cell *matCellDef="let payment">
<div fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{payment?.recipientNodeAlias}}</span>
</div>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="start center" class="part-row-span">
<span fxLayoutAlign="start center" class="ellipsis-parent part-row-span" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '22rem'}">
<span class="ellipsis-child">{{part.toChannelAlias}}</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAmount">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="part-row-span">{{payment?.recipientAmount | number:'1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="end center" class="part-row-span">
{{part.amount | number:'1.0-0'}}
</span>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAmount">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="end center" class="part-row-span">{{payment?.recipientAmount | number:'1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let part of payment?.parts" fxLayoutAlign="end center" class="part-row-span">
{{part.amount | number:'1.0-0'}}
</td>
</ng-container>
<ng-container matColumnDef="groupAction">
<td mat-cell *matCellDef="let payment" class="px-3">
<span fxLayoutAlign="end start">
<button mat-flat-button class="btn-part-expand" color="primary" type="button" tabindex="5" (click)="payment.is_expanded = !payment.is_expanded">{{payment.is_expanded ? 'Hide' : 'Show'}}</button>
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="groupAction">
<td mat-cell *matCellDef="let payment" class="px-3">
<span fxLayoutAlign="end start">
<button mat-flat-button class="btn-part-expand" color="primary" type="button" tabindex="5" (click)="payment.is_expanded = !payment.is_expanded">{{payment.is_expanded ? 'Hide' : 'Show'}}</button>
</span>
<div *ngIf="payment.is_expanded">
<div *ngFor="let part of payment?.parts; index as i" fxLayoutAlign="end start">
<button mat-stroked-button class="btn-part-info" color="primary" type="button" tabindex="6" (click)="onPartClick(part, payment)">View {{i + 1}}</button>
<div *ngIf="payment.is_expanded">
<div *ngFor="let part of payment?.parts; index as i" fxLayoutAlign="end start">
<button mat-stroked-button class="btn-part-info" color="primary" type="button" tabindex="6" (click)="onPartClick(part, payment)">View {{i + 1}}</button>
</div>
</div>
</div>
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: partColumns; when: is_group;"></tr>
<!-- Payment Group Row End -->
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: partColumns; when: is_group;"></tr>
<!-- Payment Group Row End -->
<tr mat-footer-row *matFooterRowDef="['no_payment']" [ngClass]="{'display-none': payments?.data && payments?.data?.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<tr mat-footer-row *matFooterRowDef="['no_payment']" [ngClass]="{'display-none': payments?.data && payments?.data?.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -306,7 +306,7 @@ export class ECLLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
pipe(take(1)).
subscribe({
next: (sentPaymentInfo) => {
this.showPaymentView(selPayment, (sentPaymentInfo[0] || []));
this.showPaymentView(selPayment, (sentPaymentInfo.length && sentPaymentInfo.length > 0) ? sentPaymentInfo[0] : []);
}, error: (error) => {
this.showPaymentView(selPayment, []);
}

@ -37,7 +37,11 @@
</ng-container>
<ng-container matColumnDef="payment_hash">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Payment Hash</th>
<td mat-cell *matCellDef="let payment" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '35rem'}">{{payment?.payment_hash}}</td>
<td mat-cell *matCellDef="let payment">
<span fxLayout="row" class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '30rem'}">
<span class="ellipsis-child">{{payment?.payment_hash}}</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="fee">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Fee (Sats)</th>
@ -90,7 +94,9 @@
</ng-container>
<ng-container matColumnDef="groupHash">
<td mat-cell *matCellDef="let payment">
<span fxLayoutAlign="start center" class="htlc-row-span">{{payment?.payment_hash}}</span>
<span fxLayout="row" class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '30rem'}">
<span class="ellipsis-child">{{payment?.payment_hash}}</span>
</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let htlc of payment?.htlcs; index as i" fxLayoutAlign="start center" class="htlc-row-span">
HTLC {{i + 1}}

@ -3,10 +3,11 @@
}
.mat-column-payment_hash {
flex: 1 1 20%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 0 0 20%;
width: 20%;
& .ellipsis-parent {
display: flex;
}
}
.mat-column-groupAction {

@ -75,6 +75,7 @@ export interface Peer {
export interface Invoice {
label?: string;
bolt11?: string;
bolt12?: string;
payment_hash?: string;
msatoshi?: number;
amount_msat?: string;
@ -83,9 +84,11 @@ export interface Invoice {
msatoshi_received?: number;
amount_received_msat?: string;
paid_at?: number;
payment_preimage?: string;
description?: string;
expires_at?: number;
warning_capacity?: string;
local_offer_id?: string;
}
export interface Offer {
@ -152,6 +155,7 @@ export interface Payment {
amount_msat?: string;
amount_sent_msat?: string;
bolt11?: string;
bolt12?: string;
created_at?: number;
destination?: string;
id?: number;
@ -160,6 +164,8 @@ export interface Payment {
payment_hash?: string;
payment_preimage?: string;
status?: string;
memo?: string;
partid?: string;
is_group?: boolean;
is_expanded?: boolean;
total_parts?: number;

Loading…
Cancel
Save