parent
42425ebe26
commit
04bb6eaade
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var n=g[e];if(void 0!==n)return n.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=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(i--,1);var l=f();void 0!==l&&(n=l)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{275:"517caefe8eeb635c",508:"06f7dec065381b97",515:"cb8cf5fc374ab82d",924:"1c1eb885f1f101d2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==o)for(var d=document.getElementsByTagName("script"),l=0;l<d.length;l++){var u=d[l];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==n+o){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",n+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.tt=()=>(void 0===e&&(e={createScriptURL:n=>n},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((u,c)=>i=e[f]=[u,c]);o.push(i[2]=a);var s=r.p+r.u(f),d=new Error;r.l(s,u=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var c=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;d.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,i[1](d)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var d,l,[i,a,s]=o,u=0;if(i.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(f&&f(o);u<i.length;u++)r.o(e,l=i[u])&&e[l]&&e[l][0](),e[l]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var n=g[e];if(void 0!==n)return n.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=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(i--,1);var l=f();void 0!==l&&(n=l)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{253:"256a01ccdc95a5d7",508:"06f7dec065381b97",515:"da134be35cc26574",924:"e98936d5bf0dd5da"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==o)for(var d=document.getElementsByTagName("script"),l=0;l<d.length;l++){var u=d[l];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==n+o){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",n+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.tt=()=>(void 0===e&&(e={createScriptURL:n=>n},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((u,c)=>i=e[f]=[u,c]);o.push(i[2]=a);var s=r.p+r.u(f),d=new Error;r.l(s,u=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var c=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;d.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,i[1](d)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var d,l,[i,a,s]=o,u=0;if(i.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(f&&f(o);u<i.length;u++)r.o(e,l=i[u])&&e[l]&&e[l][0](),e[l]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();
|
@ -0,0 +1,36 @@
|
||||
<div fxLayout="row">
|
||||
<div fxFlex="100">
|
||||
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
|
||||
<div fxFlex="95" fxLayoutAlign="start start">
|
||||
<span class="page-title">Initiate a Swapin</span>
|
||||
</div>
|
||||
<button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default
|
||||
mat-button>X</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="padding-gap-x-large">
|
||||
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapInForm="ngForm">
|
||||
<p fxLayoutAlign="start center" class="pb-2 word-break">Swapin with {{sPeer?.alias}}</p>
|
||||
<mat-form-field fxFlex="100" fxLayoutAlign="start end">
|
||||
<input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="100">
|
||||
<input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount"
|
||||
type="number" [step]="100" [min]="1" [max]="sPeer.remote_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required>
|
||||
<span matSuffix class="ml-1"> Sats </span>
|
||||
<mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error>
|
||||
<mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.remote_balance}}.</mat-error>
|
||||
<mat-hint>Remaining Local: {{sPeer.remote_balance - ((swapAmount) ? swapAmount : 0) | number}}<br>{{swapAmountHint}}</mat-hint>
|
||||
</mat-form-field>
|
||||
<div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapInError !== ''">
|
||||
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
|
||||
<span *ngIf="swapInError !== ''">{{swapInError}}</span>
|
||||
</div>
|
||||
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">
|
||||
<button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear
|
||||
Field</button>
|
||||
<button mat-button color="primary" (click)="onExecuteSwapin()" tabindex="4">Execute</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,95 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
import { CommonService } from '../../../../shared/services/common.service';
|
||||
import { DataService } from '../../../../shared/services/data.service';
|
||||
import { RootReducer } from '../../../../store/rtl.reducers';
|
||||
import { LNDReducer } from '../../../../lnd/store/lnd.reducers';
|
||||
import { CLNReducer } from '../../../store/cln.reducers';
|
||||
import { ECLReducer } from '../../../../eclair/store/ecl.reducers';
|
||||
import { mockCLEffects, mockDataService, mockECLEffects, mockLNDEffects, mockMatDialogRef, mockRTLEffects } from '../../../../shared/test-helpers/mock-services';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
|
||||
import { CLNSwapInModalComponent } from './swap-in-modal.component';
|
||||
|
||||
describe('CLNSwapInModalComponent', () => {
|
||||
let component: CLNSwapInModalComponent;
|
||||
let fixture: ComponentFixture<CLNSwapInModalComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CLNSwapInModalComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
SharedModule,
|
||||
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer }),
|
||||
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
|
||||
],
|
||||
providers: [
|
||||
CommonService,
|
||||
{ provide: DataService, useClass: mockDataService },
|
||||
{ provide: MatDialogRef, useClass: mockMatDialogRef },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA, useValue: {
|
||||
swapPeer: {
|
||||
nodeid: '02c9fc0cc737abcff2b502076c43f123451e542e96a79ae177059f3bb796add784',
|
||||
swaps_allowed: true,
|
||||
supported_assets: [
|
||||
'btc'
|
||||
],
|
||||
channels: [
|
||||
{
|
||||
short_channel_id: '104239x1x1',
|
||||
local_balance: 9589761,
|
||||
remote_balance: 410239,
|
||||
local_percentage: 0.9589761,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
},
|
||||
{
|
||||
short_channel_id: '104770x6x1',
|
||||
local_balance: 200000,
|
||||
remote_balance: 0,
|
||||
local_percentage: 1,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
}
|
||||
],
|
||||
sent: {
|
||||
total_swaps_out: 2,
|
||||
total_swaps_in: 2,
|
||||
total_sats_swapped_out: 1110154,
|
||||
total_sats_swapped_in: 600154
|
||||
},
|
||||
received: {
|
||||
total_swaps_out: 1,
|
||||
total_swaps_in: 0,
|
||||
total_sats_swapped_out: 100000,
|
||||
total_sats_swapped_in: 0
|
||||
},
|
||||
total_fee_paid: 478,
|
||||
alias: 'nodeSignet',
|
||||
short_channel_id: '104239x1x1',
|
||||
local_balance: 9589761,
|
||||
remote_balance: 410239,
|
||||
local_percentage: 0.9589761,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}).
|
||||
compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLNSwapInModalComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,91 @@
|
||||
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { CLNSwapInformation } from '../../../../shared/models/alertData';
|
||||
import { CurrencyUnitEnum, CURRENCY_UNIT_FORMATS, APICallStatusEnum, CLNActions } from '../../../../shared/services/consts-enums-functions';
|
||||
import { SwapPeerChannelsFlattened } from '../../../../shared/models/clnModels';
|
||||
import { CommonService } from '../../../../shared/services/common.service';
|
||||
|
||||
import { RTLState } from '../../../../store/rtl.state';
|
||||
import { SelNodeChild } from '../../../../shared/models/RTLconfig';
|
||||
import { clnNodeSettings } from '../../../store/cln.selector';
|
||||
import { swapIn } from '../../../store/cln.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-swap-in-modal',
|
||||
templateUrl: './swap-in-modal.component.html',
|
||||
styleUrls: ['./swap-in-modal.component.scss']
|
||||
})
|
||||
export class CLNSwapInModalComponent implements OnInit, OnDestroy {
|
||||
|
||||
public faExclamationTriangle = faExclamationTriangle;
|
||||
public selNode: SelNodeChild | null = {};
|
||||
public sPeer: SwapPeerChannelsFlattened | null = null;
|
||||
public swapAmount: number | null;
|
||||
public swapAmountHint = '';
|
||||
public swapInError = '';
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<CLNSwapInModalComponent>, @Inject(MAT_DIALOG_DATA) public data: CLNSwapInformation, private store: Store<RTLState>, private decimalPipe: DecimalPipe, private commonService: CommonService, private actions: Actions) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.sPeer = this.data.swapPeer;
|
||||
this.store.select(clnNodeSettings).pipe(takeUntil(this.unSubs[0])).subscribe((nodeSettings: SelNodeChild | null) => {
|
||||
this.selNode = nodeSettings;
|
||||
});
|
||||
this.actions.pipe(
|
||||
takeUntil(this.unSubs[1]),
|
||||
filter((action) => action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN)).
|
||||
subscribe((action: any) => {
|
||||
if (action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN && action.payload.action === 'PeerswapSwapin') {
|
||||
if (action.payload.status === APICallStatusEnum.ERROR) {
|
||||
this.swapInError = action.payload.message;
|
||||
}
|
||||
if (action.payload.status === APICallStatusEnum.COMPLETED) {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onExecuteSwapin(): boolean | void {
|
||||
this.swapInError = '';
|
||||
if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; }
|
||||
this.store.dispatch(swapIn({ payload: { amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } }));
|
||||
}
|
||||
|
||||
resetData() {
|
||||
this.swapAmount = null;
|
||||
this.swapAmountHint = '';
|
||||
this.swapInError = '';
|
||||
}
|
||||
|
||||
onAmountChange() {
|
||||
if (this.selNode && this.selNode.fiatConversion && this.swapAmount && this.swapAmount > 99) {
|
||||
this.swapAmountHint = '';
|
||||
this.commonService.convertCurrency(this.swapAmount, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
|
||||
pipe(takeUntil(this.unSubs[3])).
|
||||
subscribe({
|
||||
next: (data) => {
|
||||
this.swapAmountHint = '= ' + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.symbol;
|
||||
}, error: (err) => {
|
||||
this.swapAmountHint = 'Conversion Error: ' + err;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach((completeSub) => {
|
||||
completeSub.next(<any>null);
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<div fxLayout="row">
|
||||
<div fxFlex="100">
|
||||
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
|
||||
<div fxFlex="95" fxLayoutAlign="start start">
|
||||
<span class="page-title">Initiate a Swapout</span>
|
||||
</div>
|
||||
<button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default
|
||||
mat-button>X</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="padding-gap-x-large">
|
||||
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapOutForm="ngForm">
|
||||
<p fxLayoutAlign="start center" class="pb-2 word-break">Swapout with {{sPeer?.alias}}</p>
|
||||
<mat-form-field fxFlex="100" fxLayoutAlign="start end">
|
||||
<input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="100">
|
||||
<input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount"
|
||||
type="number" [step]="100" [min]="1" [max]="sPeer.local_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required>
|
||||
<span matSuffix class="ml-1"> Sats </span>
|
||||
<mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error>
|
||||
<mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.local_balance}}.</mat-error>
|
||||
<mat-hint>Remaining Local: {{sPeer.local_balance - ((swapAmount) ? swapAmount : 0) | number}}<br>{{swapAmountHint}}</mat-hint>
|
||||
</mat-form-field>
|
||||
<div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapOutError !== ''">
|
||||
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
|
||||
<span *ngIf="swapOutError !== ''">{{swapOutError}}</span>
|
||||
</div>
|
||||
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">
|
||||
<button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear
|
||||
Field</button>
|
||||
<button mat-button color="primary" (click)="onExecuteSwapout()" tabindex="4">Execute</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,95 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
import { CommonService } from '../../../../shared/services/common.service';
|
||||
import { DataService } from '../../../../shared/services/data.service';
|
||||
import { RootReducer } from '../../../../store/rtl.reducers';
|
||||
import { LNDReducer } from '../../../../lnd/store/lnd.reducers';
|
||||
import { CLNReducer } from '../../../../cln/store/cln.reducers';
|
||||
import { ECLReducer } from '../../../../eclair/store/ecl.reducers';
|
||||
import { mockCLEffects, mockDataService, mockECLEffects, mockLNDEffects, mockMatDialogRef, mockRTLEffects } from '../../../../shared/test-helpers/mock-services';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
|
||||
import { CLNSwapOutModalComponent } from './swap-out-modal.component';
|
||||
|
||||
describe('CLNSwapOutModalComponent', () => {
|
||||
let component: CLNSwapOutModalComponent;
|
||||
let fixture: ComponentFixture<CLNSwapOutModalComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CLNSwapOutModalComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
SharedModule,
|
||||
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer }),
|
||||
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
|
||||
],
|
||||
providers: [
|
||||
CommonService,
|
||||
{ provide: DataService, useClass: mockDataService },
|
||||
{ provide: MatDialogRef, useClass: mockMatDialogRef },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA, useValue: {
|
||||
swapPeer: {
|
||||
nodeid: '02c9fc0cc737abcff2b502076c43f123451e542e96a79ae177059f3bb796add784',
|
||||
swaps_allowed: true,
|
||||
supported_assets: [
|
||||
'btc'
|
||||
],
|
||||
channels: [
|
||||
{
|
||||
short_channel_id: '104239x1x1',
|
||||
local_balance: 9589761,
|
||||
remote_balance: 410239,
|
||||
local_percentage: 0.9589761,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
},
|
||||
{
|
||||
short_channel_id: '104770x6x1',
|
||||
local_balance: 200000,
|
||||
remote_balance: 0,
|
||||
local_percentage: 1,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
}
|
||||
],
|
||||
sent: {
|
||||
total_swaps_out: 2,
|
||||
total_swaps_in: 2,
|
||||
total_sats_swapped_out: 1110154,
|
||||
total_sats_swapped_in: 600154
|
||||
},
|
||||
received: {
|
||||
total_swaps_out: 1,
|
||||
total_swaps_in: 0,
|
||||
total_sats_swapped_out: 100000,
|
||||
total_sats_swapped_in: 0
|
||||
},
|
||||
total_fee_paid: 478,
|
||||
alias: 'nodeSignet',
|
||||
short_channel_id: '104239x1x1',
|
||||
local_balance: 9589761,
|
||||
remote_balance: 410239,
|
||||
local_percentage: 0.9589761,
|
||||
state: 'CHANNELD_NORMAL'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}).
|
||||
compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLNSwapOutModalComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,91 @@
|
||||
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { CLNSwapInformation } from '../../../../shared/models/alertData';
|
||||
import { CurrencyUnitEnum, CURRENCY_UNIT_FORMATS, APICallStatusEnum, CLNActions } from '../../../../shared/services/consts-enums-functions';
|
||||
import { SwapPeerChannelsFlattened } from '../../../../shared/models/clnModels';
|
||||
import { CommonService } from '../../../../shared/services/common.service';
|
||||
|
||||
import { RTLState } from '../../../../store/rtl.state';
|
||||
import { SelNodeChild } from '../../../../shared/models/RTLconfig';
|
||||
import { clnNodeSettings } from '../../../store/cln.selector';
|
||||
import { swapOut } from '../../../store/cln.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-swap-out-modal',
|
||||
templateUrl: './swap-out-modal.component.html',
|
||||
styleUrls: ['./swap-out-modal.component.scss']
|
||||
})
|
||||
export class CLNSwapOutModalComponent implements OnInit, OnDestroy {
|
||||
|
||||
public faExclamationTriangle = faExclamationTriangle;
|
||||
public selNode: SelNodeChild | null = {};
|
||||
public sPeer: SwapPeerChannelsFlattened | null = null;
|
||||
public swapAmount: number | null;
|
||||
public swapAmountHint = '';
|
||||
public swapOutError = '';
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<CLNSwapOutModalComponent>, @Inject(MAT_DIALOG_DATA) public data: CLNSwapInformation, private store: Store<RTLState>, private decimalPipe: DecimalPipe, private commonService: CommonService, private actions: Actions) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.sPeer = this.data.swapPeer;
|
||||
this.store.select(clnNodeSettings).pipe(takeUntil(this.unSubs[0])).subscribe((nodeSettings: SelNodeChild | null) => {
|
||||
this.selNode = nodeSettings;
|
||||
});
|
||||
this.actions.pipe(
|
||||
takeUntil(this.unSubs[1]),
|
||||
filter((action) => action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN)).
|
||||
subscribe((action: any) => {
|
||||
if (action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN && action.payload.action === 'PeerswapSwapout') {
|
||||
if (action.payload.status === APICallStatusEnum.ERROR) {
|
||||
this.swapOutError = action.payload.message;
|
||||
}
|
||||
if (action.payload.status === APICallStatusEnum.COMPLETED) {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onExecuteSwapout(): boolean | void {
|
||||
this.swapOutError = '';
|
||||
if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; }
|
||||
this.store.dispatch(swapOut({ payload: { amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } }));
|
||||
}
|
||||
|
||||
resetData() {
|
||||
this.swapAmount = null;
|
||||
this.swapAmountHint = '';
|
||||
this.swapOutError = '';
|
||||
}
|
||||
|
||||
onAmountChange() {
|
||||
if (this.selNode && this.selNode.fiatConversion && this.swapAmount && this.swapAmount > 99) {
|
||||
this.swapAmountHint = '';
|
||||
this.commonService.convertCurrency(this.swapAmount, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
|
||||
pipe(takeUntil(this.unSubs[3])).
|
||||
subscribe({
|
||||
next: (data) => {
|
||||
this.swapAmountHint = '= ' + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.symbol;
|
||||
}, error: (err) => {
|
||||
this.swapAmountHint = 'Conversion Error: ' + err;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach((completeSub) => {
|
||||
completeSub.next(<any>null);
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
.mat-column-actions {
|
||||
min-height: 4.8rem;
|
||||
}
|
Loading…
Reference in New Issue