[accelerator] refactor bitcoin-payment component

This commit is contained in:
Mononaut 2024-06-30 08:15:20 +00:00
parent 0b663c1a77
commit f114a8ca75
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
3 changed files with 64 additions and 51 deletions

View File

@ -355,7 +355,7 @@
<div class="col-sm text-center d-flex flex-column justify-content-center align-items-center">
@if (invoice) {
<p>Pay <span><small style="font-family: monospace;">{{ cost | number }}</small>&nbsp;<span class="symbol" i18n="shared.sats">sats</span></span></p>
<app-bitcoin-invoice style="width: 100%;" [invoiceId]="invoice.btcpayInvoiceId" [minimal]="true" (completed)="moveToStep('paid')"></app-bitcoin-invoice>
<app-bitcoin-invoice style="width: 100%;" [invoice]="invoice" [invoiceId]="invoice.btcpayInvoiceId" [minimal]="true" (completed)="moveToStep('paid')"></app-bitcoin-invoice>
} @else {
<p>Loading invoice...</p>
<div class="d-flex align-items-center justify-content-center" style="width: 100%; height: 292px;">

View File

@ -6,7 +6,7 @@
</span>
<span *ngIf="paymentStatus === 4" class="valid-feedback d-block mt-5">
A transaction <a [href]="'/tx/' + invoice.cryptoInfo[0].payments[0].id.split('-')[0]">has been detected in the mempool</a> fully paying for this invoice. Waiting for on-chain confirmation.
A transaction <a [href]="'/tx/' + loadedInvoice.cryptoInfo[0].payments[0].id.split('-')[0]">has been detected in the mempool</a> fully paying for this invoice. Waiting for on-chain confirmation.
</span>
}
@ -16,13 +16,13 @@
<div *ngIf="availableMethods.length > 1" class="form-group">
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<!-- <label *ngIf="invoice.addresses.BTC" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'chain'}">
<!-- <label *ngIf="loadedInvoice.addresses.BTC" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'chain'}">
<input type="radio" value="chain" formControlName="method"> <fa-icon [icon]="['fas', 'link']" [fixedWidth]="true" title="Onchain"></fa-icon>
</label> -->
<label *ngIf="invoice.addresses.BTC_LightningLike" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'lightning'}">
<label *ngIf="loadedInvoice.addresses.BTC_LightningLike" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'lightning'}">
<input type="radio" value="lightning" formControlName="method"> <fa-icon [icon]="['fas', 'bolt']" [fixedWidth]="true" title="Lightning"></fa-icon>
</label>
<!-- <label *ngIf="invoice.addresses.LBTC" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'lbtc'}">
<!-- <label *ngIf="loadedInvoice.addresses.LBTC" class="btn btn-primary" [ngClass]="{'active': paymentForm.get('method')?.value === 'lbtc'}">
<input type="radio" value="lbtc" formControlName="method"> <fa-icon [icon]="['fas', 'tint']" [fixedWidth]="true" title="Liquid Bitcoin"></fa-icon>
</label> -->
</div>
@ -30,63 +30,63 @@
</form>
<ng-template [ngIf]="paymentForm.get('method')?.value === 'chain' && invoice">
<ng-template [ngIf]="paymentForm.get('method')?.value === 'chain' && loadedInvoice">
<div class="qr-wrapper" [class.mt-0]="minimal">
<a [href]="bypassSecurityTrustUrl('bitcoin:' + invoice.addresses.BTC + '?amount=' + invoice.btcDue)" target="_blank">
<app-qrcode imageUrl="/resources/bitcoin-logo.png" [size]="200" [data]="'bitcoin:' + invoice.addresses.BTC + '?amount=' + invoice.btcDue"></app-qrcode>
<a [href]="bypassSecurityTrustUrl('bitcoin:' + loadedInvoice.addresses.BTC + '?amount=' + loadedInvoice.btcDue)" target="_blank">
<app-qrcode imageUrl="/resources/bitcoin-logo.png" [size]="200" [data]="'bitcoin:' + loadedInvoice.addresses.BTC + '?amount=' + loadedInvoice.btcDue"></app-qrcode>
</a>
</div>
<div class="input-group input-group-sm info-group">
<input type="text" class="form-control input-dark" readonly [value]="invoice.addresses.BTC">
<input type="text" class="form-control input-dark" readonly [value]="loadedInvoice.addresses.BTC">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="invoice.addresses.BTC"></app-clipboard></button>
<button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="loadedInvoice.addresses.BTC"></app-clipboard></button>
</div>
</div>
@if (!minimal) {
<p>{{ invoice.btcDue | number: '1.0-8' }} <span class="symbol">BTC</span></p>
<p>{{ loadedInvoice.btcDue | number: '1.0-8' }} <span class="symbol">BTC</span></p>
}
</ng-template>
<ng-template [ngIf]="paymentForm.get('method')?.value === 'lightning' && invoice && invoice.addresses.BTC_LightningLike">
<ng-template [ngIf]="paymentForm.get('method')?.value === 'lightning' && loadedInvoice && loadedInvoice.addresses.BTC_LightningLike">
<div class="qr-wrapper" [class.mt-0]="minimal">
<a [href]="bypassSecurityTrustUrl('lightning:' + invoice.addresses.BTC_LightningLike)" target="_blank">
<app-qrcode imageUrl="/resources/lightning-logo.png" [size]="200" [data]="invoice.addresses.BTC_LightningLike.toUpperCase()"></app-qrcode>
<a [href]="bypassSecurityTrustUrl('lightning:' + loadedInvoice.addresses.BTC_LightningLike)" target="_blank">
<app-qrcode imageUrl="/resources/lightning-logo.png" [size]="200" [data]="loadedInvoice.addresses.BTC_LightningLike.toUpperCase()"></app-qrcode>
</a>
</div>
<div class="input-group input-group-sm info-group">
<input type="text" class="form-control input-dark" readonly [value]="invoice.addresses.BTC_LightningLike">
<input type="text" class="form-control input-dark" readonly [value]="loadedInvoice.addresses.BTC_LightningLike">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button"><app-clipboard [text]="invoice.addresses.BTC_LightningLike"></app-clipboard></button>
<button class="btn btn-outline-secondary" type="button"><app-clipboard [text]="loadedInvoice.addresses.BTC_LightningLike"></app-clipboard></button>
</div>
</div>
@if (!minimal) {
<p>{{ invoice.btcDue * 100_000_000 | number: '1.0-0' }} <span class="symbol">sats</span></p>
<p>{{ loadedInvoice.btcDue * 100_000_000 | number: '1.0-0' }} <span class="symbol">sats</span></p>
}
</ng-template>
<ng-template [ngIf]="invoice && (paymentForm.get('method')?.value === 'lbtc' || paymentForm.get('method')?.value === 'tlbtc')">
<ng-template [ngIf]="loadedInvoice && (paymentForm.get('method')?.value === 'lbtc' || paymentForm.get('method')?.value === 'tlbtc')">
<div class="qr-wrapper" [class.mt-0]="minimal">
<a [href]="bypassSecurityTrustUrl('liquidnetwork:' + invoice.addresses.LBTC + '?amount=' + invoice.btcDue + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank">
<app-qrcode imageUrl="/resources/liquid-bitcoin.png" [size]="200" [data]="'liquidnetwork:' + invoice.addresses.LBTC + '?amount=' + invoice.btcDue + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d'"></app-qrcode>
<a [href]="bypassSecurityTrustUrl('liquidnetwork:' + loadedInvoice.addresses.LBTC + '?amount=' + loadedInvoice.btcDue + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank">
<app-qrcode imageUrl="/resources/liquid-bitcoin.png" [size]="200" [data]="'liquidnetwork:' + loadedInvoice.addresses.LBTC + '?amount=' + loadedInvoice.btcDue + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d'"></app-qrcode>
</a>
</div>
<br>
<div class="input-group input-group-sm info-group">
<input type="text" class="form-control input-dark" readonly [value]="invoice.addresses.LBTC" />
<input type="text" class="form-control input-dark" readonly [value]="loadedInvoice.addresses.LBTC" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="invoice.addresses.LBTC"></app-clipboard></button>
<button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="loadedInvoice.addresses.LBTC"></app-clipboard></button>
</div>
</div>
@if (!minimal) {
<p>{{ invoice.btcDue | number: '1.0-8' }} <span class="symbol">BTC</span></p>
<p>{{ loadedInvoice.btcDue | number: '1.0-8' }} <span class="symbol">BTC</span></p>
}
</ng-template>

View File

@ -1,8 +1,8 @@
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
import { Subscription, timer } from 'rxjs';
import { Subscription, of, timer } from 'rxjs';
import { retry, switchMap, tap } from 'rxjs/operators';
import { ServicesApiServices } from '../../services/services-api.service';
@ -11,7 +11,8 @@ import { ServicesApiServices } from '../../services/services-api.service';
templateUrl: './bitcoin-invoice.component.html',
styleUrls: ['./bitcoin-invoice.component.scss']
})
export class BitcoinInvoiceComponent implements OnInit, OnDestroy {
export class BitcoinInvoiceComponent implements OnInit, OnChanges, OnDestroy {
@Input() invoice;
@Input() invoiceId: string;
@Input() redirect = true;
@Input() minimal = false;
@ -20,7 +21,7 @@ export class BitcoinInvoiceComponent implements OnInit, OnDestroy {
paymentForm: FormGroup;
requestSubscription: Subscription | undefined;
paymentStatusSubscription: Subscription | undefined;
invoice: any;
loadedInvoice: any;
paymentStatus = 1; // 1 - Waiting for invoice | 2 - Pending payment | 3 - Payment completed
paramMapSubscription: Subscription | undefined;
invoiceSubscription: Subscription | undefined;
@ -60,35 +61,47 @@ export class BitcoinInvoiceComponent implements OnInit, OnDestroy {
this.paramMapSubscription = this.activatedRoute.paramMap
.pipe(
tap((paramMap) => {
const invoiceId = paramMap.get('invoiceId') ?? this.invoiceId;
if (invoiceId) {
this.paymentStatusSubscription = this.apiService.retreiveInvoice$(invoiceId).pipe(
tap((invoice: any) => {
this.invoice = invoice;
if (this.invoice.btcDue > 0) {
this.paymentStatus = 2;
} else {
this.paymentStatus = 4;
}
}),
switchMap(() => this.apiService.getPaymentStatus$(this.invoice.id)
.pipe(
retry({ delay: () => timer(2000)})
)
),
).subscribe({
next: ((result) => {
this.paymentStatus = 3;
this.completed.emit();
}),
});
}
this.fetchInvoice(paramMap.get('invoiceId') ?? this.invoiceId);
})
).subscribe();
}
ngOnChanges(changes: SimpleChanges): void {
if ((changes.invoice || changes.invoiceId) && this.invoiceId) {
this.fetchInvoice(this.invoiceId);
}
}
fetchInvoice(invoiceId: string): void {
if (invoiceId) {
if (this.paymentStatusSubscription) {
this.paymentStatusSubscription.unsubscribe();
}
this.paymentStatusSubscription = ((this.invoice && (this.invoice.btcpayInvoiceId || this.invoice.id) === invoiceId) ? of(this.invoice) : this.apiService.retreiveInvoice$(invoiceId)).pipe(
tap((invoice: any) => {
this.loadedInvoice = invoice;
if (this.loadedInvoice.btcDue > 0) {
this.paymentStatus = 2;
} else {
this.paymentStatus = 4;
}
}),
switchMap(() => this.apiService.getPaymentStatus$(this.loadedInvoice.id)
.pipe(
retry({ delay: () => timer(2000)})
)
),
).subscribe({
next: ((result) => {
this.paymentStatus = 3;
this.completed.emit();
}),
});
}
}
get availableMethods(): string[] {
return Object.keys(this.invoice?.addresses || {}).filter(k => k === 'BTC_LightningLike');
return Object.keys(this.loadedInvoice?.addresses || {}).filter(k => k === 'BTC_LightningLike');
}
bypassSecurityTrustUrl(text: string): SafeUrl {