[accelerator] accelerate with lightning
This commit is contained in:
		
							parent
							
								
									f1572f0038
								
							
						
					
					
						commit
						66a88b8422
					
				| @ -58,12 +58,24 @@ | ||||
|         </div> | ||||
|       </div> | ||||
|     </form> | ||||
|   } | ||||
|      | ||||
|   @else if (step === 'checkout') { | ||||
|     <!-- Show checkout page --> | ||||
|    | ||||
|   } @else if (step === 'paymentMethod') { | ||||
|     <div class="row mb-md-1 text-center"> | ||||
|       <div class="col-sm"> | ||||
|         <h1 style="font-size: larger;">Select your payment method</h1> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="pt-2 d-flex justify-content-around"> | ||||
|       @if (cashappEnabled) { | ||||
|         <img class="paymentMethod" src="/resources/cash-app.svg" height=55 (click)="selectPaymentMethod('cashapp')"> | ||||
|       } | ||||
|       <img class="paymentMethod" src="/resources/btcpay.svg" height=55 (click)="selectPaymentMethod('btcpay')"> | ||||
|     </div> | ||||
| 
 | ||||
|   } @else if (step === 'checkout') { | ||||
|     <!-- Show checkout page --> | ||||
|     <div class="row mb-md-1 text-center"> | ||||
|       <div class="col-sm" id="confirm-payment-title"> | ||||
|         <h1 style="font-size: larger;">Confirm your payment</h1> | ||||
|       </div> | ||||
|     </div> | ||||
| @ -76,36 +88,40 @@ | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     @if (!loadingCashapp) { | ||||
|     @if (paymentMethod === 'cashapp') { | ||||
|       @if (!loadingCashapp) { | ||||
|         <div class="row text-center mt-1"> | ||||
|           <div class="col-sm"> | ||||
|             <div class="form-group w-100"> | ||||
|               <span><u><strong>Total additional cost</strong></u><br> | ||||
|                 <span style="font-size: 16px" class="d-block mt-2"> | ||||
|                   Pay | ||||
|                   <strong><app-fiat [value]="cost"></app-fiat></strong> | ||||
|                   with | ||||
|                 </span> | ||||
|               </span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       } | ||||
| 
 | ||||
|       <div class="row text-center mt-1"> | ||||
|         <div class="col-sm"> | ||||
|           <div class="form-group w-100"> | ||||
|             <span><u><strong>Total additional cost</strong></u><br> | ||||
|               <span style="font-size: 16px" class="d-block mt-2"> | ||||
|                 Pay | ||||
|                 <strong><app-fiat [value]="cost"></app-fiat></strong> | ||||
|                 with | ||||
|               </span> | ||||
|             </span> | ||||
|             <div id="cash-app-pay" class="d-inline-block" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> | ||||
|             @if (loadingCashapp) { | ||||
|             <div display="d-flex flex-row justify-content-center"> | ||||
|               <span>Loading payment method...</span> | ||||
|               <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> | ||||
|             </div> | ||||
|             } | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     } @else if (paymentMethod === 'btcpay' && invoice?.btcpayInvoiceId) { | ||||
|       <app-bitcoin-invoice [invoiceId]="invoice.btcpayInvoiceId" (completed)="closeModal(2000)"></app-bitcoin-invoice> | ||||
|     } | ||||
| 
 | ||||
|     <div class="row text-center mt-1"> | ||||
|       <div class="col-sm"> | ||||
|         <div class="form-group w-100"> | ||||
|           <div id="cash-app-pay" class="d-inline-block" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> | ||||
|           @if (loadingCashapp) { | ||||
|           <div display="d-flex flex-row justify-content-center"> | ||||
|             <span>Loading payment method...</span> | ||||
|             <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> | ||||
|           </div> | ||||
|           } | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <hr> | ||||
|     <div class="row mt-2 mb-2 text-center"> | ||||
|       <div class="col-sm d-flex flex-column"> | ||||
| @ -118,7 +134,7 @@ | ||||
|   @else if (step === 'processing') { | ||||
|     <div class="row mb-1 text-center"> | ||||
|       <div class="col-sm"> | ||||
|         <h1 style="font-size: larger;">Confirm your payment</h1> | ||||
|         <h1 style="font-size: larger;">Confirming your payment</h1> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|  | ||||
| @ -7,3 +7,11 @@ | ||||
| .estimating { | ||||
|   color: var(--green) | ||||
| } | ||||
| 
 | ||||
| .paymentMethod { | ||||
|   padding: 10px; | ||||
|   background-color: var(--secondary); | ||||
|   border-radius: 15px; | ||||
|   border: 2px solid var(--bg); | ||||
|   cursor: pointer; | ||||
| } | ||||
| @ -16,12 +16,16 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
|   @Input() eta: number | null = null; | ||||
|   @Input() txid: string = '70c18d76cdb285a1b5bd87fdaae165880afa189809c30b4083ff7c0e69ee09ad'; | ||||
|   @Input() scrollEvent: boolean; | ||||
|   @Input() cashappEnabled: boolean; | ||||
|   @Output() close = new EventEmitter<null>(); | ||||
| 
 | ||||
|   calculating = true; | ||||
|   choosenOption: 'wait' | 'accelerate' = 'wait'; | ||||
|   error = ''; | ||||
| 
 | ||||
|   step: 'paymentMethod' | 'cta' | 'checkout' | 'processing' = 'cta'; | ||||
|   paymentMethod: 'cashapp' | 'btcpay'; | ||||
| 
 | ||||
|   // accelerator stuff
 | ||||
|   square: { appId: string, locationId: string}; | ||||
|   accelerationUUID: string; | ||||
| @ -38,7 +42,10 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
|   cashAppPay: any; | ||||
|   cashAppSubscription: Subscription; | ||||
|   conversionsSubscription: Subscription; | ||||
|   step: 'cta' | 'checkout' | 'processing' = 'cta'; | ||||
|    | ||||
|   // btcpay
 | ||||
|   loadingBtcpayInvoice = false; | ||||
|   invoice = undefined; | ||||
| 
 | ||||
|   constructor( | ||||
|     private servicesApiService: ServicesApiServices, | ||||
| @ -77,19 +84,19 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
| 
 | ||||
|   ngOnChanges(changes: SimpleChanges): void { | ||||
|     if (changes.scrollEvent) { | ||||
|       this.scrollToPreview('acceleratePreviewAnchor', 'start'); | ||||
|       this.scrollToElement('acceleratePreviewAnchor', 'start'); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|   * Scroll to element id with or without setTimeout | ||||
|   */ | ||||
|   scrollToPreviewWithTimeout(id: string, position: ScrollLogicalPosition) { | ||||
|   scrollToElementWithTimeout(id: string, position: ScrollLogicalPosition, timeout: number = 1000) { | ||||
|     setTimeout(() => { | ||||
|       this.scrollToPreview(id, position); | ||||
|     }, 1000); | ||||
|       this.scrollToElement(id, position); | ||||
|     }, timeout); | ||||
|   } | ||||
|   scrollToPreview(id: string, position: ScrollLogicalPosition) { | ||||
|   scrollToElement(id: string, position: ScrollLogicalPosition) { | ||||
|     const acceleratePreviewAnchor = document.getElementById(id); | ||||
|     if (acceleratePreviewAnchor) { | ||||
|       this.cd.markForCheck(); | ||||
| @ -111,7 +118,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
|     this.calculating = true; | ||||
|     this.estimateSubscription = this.servicesApiService.estimate$(this.txid).pipe( | ||||
|       tap((response) => { | ||||
|         this.calculating = false; | ||||
|         if (response.status === 204) { | ||||
|           this.error = `cannot_accelerate_tx`; | ||||
|         } else { | ||||
| @ -126,6 +132,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
|           this.maxBidBoost = minExtraBoost * DEFAULT_BID_RATIO; | ||||
|           this.cost = this.maxBidBoost + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; | ||||
|           this.etaInfo$ = this.etaService.getProjectedEtaObservable(this.estimate); | ||||
|           this.calculating = false; | ||||
|           this.cd.markForCheck(); | ||||
|         } | ||||
|       }), | ||||
| 
 | ||||
| @ -265,19 +273,48 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * BTCPay | ||||
|    */ | ||||
|   async requestBTCPayInvoice() { | ||||
|     this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.txid).subscribe({ | ||||
|       next: (response) => { | ||||
|         this.invoice = response; | ||||
|         this.cd.markForCheck(); | ||||
|         this.scrollToElementWithTimeout('acceleratePreviewAnchor', 'start', 500); | ||||
|       }, | ||||
|       error: (response) => { | ||||
|         console.log(response); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * UI events | ||||
|    */ | ||||
|   enableCheckoutPage() { | ||||
|     this.step = 'paymentMethod'; | ||||
|   } | ||||
|   selectPaymentMethod(paymentMethod: 'cashapp' | 'btcpay') { | ||||
|     this.step = 'checkout'; | ||||
|     this.loadingCashapp = true; | ||||
|     this.insertSquare(); | ||||
|     this.setupSquare(); | ||||
|     this.paymentMethod = paymentMethod; | ||||
|     if (paymentMethod === 'cashapp') { | ||||
|       this.loadingCashapp = true; | ||||
|       this.insertSquare(); | ||||
|       this.setupSquare(); | ||||
|     } else if (paymentMethod === 'btcpay') { | ||||
|       this.loadingBtcpayInvoice = true; | ||||
|       this.requestBTCPayInvoice(); | ||||
|     } | ||||
|   } | ||||
|   selectedOptionChanged(event) { | ||||
|     this.choosenOption = event.target.id; | ||||
|   } | ||||
|   closeModal(): void { | ||||
|     this.close.emit(); | ||||
|   closeModal(timeout: number = 0): void { | ||||
|     setTimeout(() => { | ||||
|       this.step = 'processing'; | ||||
|       this.cd.markForCheck(); | ||||
|       this.close.emit(); | ||||
|     }, timeout); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,89 @@ | ||||
| <div class="wrapper"> | ||||
| 
 | ||||
|   <span *ngIf="paymentStatus === 3" class="valid-feedback d-block mt-5"> | ||||
|     Payment successful. You can close this page. | ||||
|   </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. | ||||
|   </span> | ||||
| 
 | ||||
|   <div *ngIf="paymentStatus === 2"> | ||||
|      | ||||
|     <form [formGroup]="paymentForm"> | ||||
| 
 | ||||
|       <div 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'}"> | ||||
|             <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'}"> | ||||
|             <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'}"> | ||||
|             <input type="radio" value="lbtc" formControlName="method"> <fa-icon [icon]="['fas', 'tint']" [fixedWidth]="true" title="Liquid Bitcoin"></fa-icon> | ||||
|           </label> --> | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|     </form> | ||||
| 
 | ||||
|     <ng-template [ngIf]="paymentForm.get('method')?.value === 'chain' && invoice"> | ||||
| 
 | ||||
|         <div class="qr-wrapper"> | ||||
|           <a [href]="bypassSecurityTrustUrl('bitcoin:' + invoice.addresses.BTC + '?amount=' + invoice.amount)" target="_blank"> | ||||
|               <app-qrcode imageUrl="/resources/bitcoin-logo.png" [size]="200" [data]="'bitcoin:' + invoice.addresses.BTC + '?amount=' + invoice.amount"></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"> | ||||
|           <div class="input-group-append"> | ||||
|               <button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="invoice.addresses.BTC"></app-clipboard></button> | ||||
|           </div> | ||||
|         </div> | ||||
|         <p>{{ invoice.amount }} <span class="symbol">BTC</span></p> | ||||
| 
 | ||||
|     </ng-template> | ||||
| 
 | ||||
|     <ng-template [ngIf]="paymentForm.get('method')?.value === 'lightning' && invoice"> | ||||
| 
 | ||||
|         <div class="qr-wrapper"> | ||||
|           <a [href]="bypassSecurityTrustUrl('lightning:' + invoice.addresses.BTC_LightningLike)" target="_blank"> | ||||
|               <app-qrcode imageUrl="/resources/bitcoin-logo.png" [size]="200" [data]="invoice.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"> | ||||
|           <div class="input-group-append"> | ||||
|               <button class="btn btn-outline-secondary" type="button"><app-clipboard [text]="invoice.addresses.BTC_LightningLike"></app-clipboard></button> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <p>{{ invoice.amount * 100_000_000 }} <span class="symbol">sats</span></p> | ||||
| 
 | ||||
|     </ng-template> | ||||
| 
 | ||||
|     <ng-template [ngIf]="invoice && (paymentForm.get('method')?.value === 'lbtc' || paymentForm.get('method')?.value === 'tlbtc')"> | ||||
| 
 | ||||
|         <div class="qr-wrapper"> | ||||
|           <a [href]="bypassSecurityTrustUrl('liquidnetwork:' + invoice.addresses.LBTC + '?amount=' + invoice.amount + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank"> | ||||
|               <app-qrcode imageUrl="/resources/liquid-bitcoin.png" [size]="200" [data]="'liquidnetwork:' + invoice.addresses.LBTC + '?amount=' + invoice.amount + '&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" /> | ||||
|           <div class="input-group-append"> | ||||
|               <button class="btn btn-outline-secondary" type="button" ><app-clipboard [text]="invoice.addresses.LBTC"></app-clipboard></button> | ||||
|           </div> | ||||
|         </div> | ||||
|         <p>{{ invoice.amount }} <span class="symbol">BTC</span></p> | ||||
| 
 | ||||
|     </ng-template> | ||||
| 
 | ||||
|     <p>Waiting for transaction... </p> | ||||
|     <div class="spinner-border text-light"></div> | ||||
|   </div> | ||||
| </div> | ||||
| @ -0,0 +1,149 @@ | ||||
| .form-panel { | ||||
|   background-color: #292b45; | ||||
|   padding: 20px; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .sponsor-page { | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .qr-wrapper { | ||||
|     background-color: #FFF; | ||||
|     padding: 10px; | ||||
|     display: inline-block; | ||||
|     padding-bottom: 5px; | ||||
|     margin: 20px auto 0px; | ||||
| } | ||||
| 
 | ||||
| .info-group { | ||||
|   max-width: 400px; | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   width: 240px; | ||||
|   height: 220px; | ||||
|   background-color: var(--bg); | ||||
|   border: 2px solid var(--bg); | ||||
|   cursor: pointer; | ||||
|   position: relative; | ||||
|   transition: 100ms all; | ||||
|   margin: 30px 30px 20px 30px; | ||||
|   @media(min-width: 476px) { | ||||
|     margin: 30px 100px 20px 100px; | ||||
|   } | ||||
|   @media(min-width: 851px) { | ||||
|     margin: 60px 20px 40px 20px; | ||||
|   } | ||||
| 
 | ||||
|   .card-title { | ||||
|     font-weight: bold; | ||||
|     span { | ||||
|       font-weight: 100; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &.bigger { | ||||
|     height: 220px; | ||||
|     width: 240px; | ||||
|     margin-top: 40px; | ||||
|   } | ||||
| 
 | ||||
|   &:hover { | ||||
|     background-color: #5058926b; | ||||
|     border: 2px solid #505892; | ||||
|     transform: scale(1.1) translateY(-10px); | ||||
|     margin-top: 70px; | ||||
| 
 | ||||
|     .card-header { | ||||
|       background-color: #505892; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .donation-form { | ||||
|   max-width: 280px; | ||||
|   margin: auto; | ||||
|   button { | ||||
|     width: 100%; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .card-header { | ||||
|   background-color: #171929; | ||||
| } | ||||
| 
 | ||||
| .flex-container { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   flex-wrap: wrap; | ||||
|   justify-content: center; | ||||
| } | ||||
| 
 | ||||
| .middle-card { | ||||
|   width: 280px; | ||||
|   height: 260px; | ||||
|   margin-top: 40px; | ||||
|   &:hover { | ||||
|     margin-top: 50px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .shiny-border { | ||||
|   background-color: #5058926b; | ||||
|   border: 2px solid #505892; | ||||
|   transform: scale(1.1) translateY(-10px); | ||||
|   margin-top: 70px; | ||||
|   box-shadow: 0px 0px 100px #9858ff52; | ||||
|   .card-header { | ||||
|     background-color: #505892; | ||||
|   } | ||||
| 
 | ||||
|   &.middle-card { | ||||
|     margin-top: 50px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .input-group { | ||||
|   margin: 20px auto; | ||||
| } | ||||
| 
 | ||||
| .donation-confirmed { | ||||
|   h2 { | ||||
|     margin-top: 50px; | ||||
|     span { | ||||
|       display: block; | ||||
|       &:last-child { | ||||
|         color: #9858ff; | ||||
|         font-weight: bold; | ||||
|         font-size: 2rem; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .order-details { | ||||
|     margin-top: 50px; | ||||
|     span { | ||||
|       color: #d81b60; | ||||
|       margin-left: 10px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .card-body { | ||||
|   align-items: center; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   flex-direction: column; | ||||
|   height: 100%; | ||||
| } | ||||
| 
 | ||||
| .wrapper { | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| .input-dark { | ||||
|   background-color: var(--bg); | ||||
|   border-color: var(--active-bg); | ||||
|   color: white; | ||||
| } | ||||
| @ -0,0 +1,94 @@ | ||||
| import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } 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 { retry, switchMap, tap } from 'rxjs/operators'; | ||||
| import { ServicesApiServices } from '../../services/services-api.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-bitcoin-invoice', | ||||
|   templateUrl: './bitcoin-invoice.component.html', | ||||
|   styleUrls: ['./bitcoin-invoice.component.scss'] | ||||
| }) | ||||
| export class BitcoinInvoiceComponent implements OnInit, OnDestroy { | ||||
|   @Input() invoiceId: string; | ||||
|   @Input() redirect = true; | ||||
|   @Output() completed = new EventEmitter(); | ||||
| 
 | ||||
|   paymentForm: FormGroup; | ||||
|   requestSubscription: Subscription | undefined; | ||||
|   paymentStatusSubscription: Subscription | undefined; | ||||
|   invoice: any; | ||||
|   paymentStatus = 1; // 1 - Waiting for invoice | 2 - Pending payment | 3 - Payment completed
 | ||||
|   paramMapSubscription: Subscription | undefined; | ||||
|   invoiceSubscription: Subscription | undefined; | ||||
|   invoiceTimeout; // Wait for angular to load all the things before making a request
 | ||||
| 
 | ||||
|   constructor( | ||||
|     private formBuilder: FormBuilder, | ||||
|     private apiService: ServicesApiServices, | ||||
|     private sanitizer: DomSanitizer, | ||||
|     private activatedRoute: ActivatedRoute | ||||
|   ) { } | ||||
| 
 | ||||
|   ngOnDestroy() { | ||||
|     if (this.requestSubscription) { | ||||
|       this.requestSubscription.unsubscribe(); | ||||
|     } | ||||
|     if (this.paramMapSubscription) { | ||||
|       this.paramMapSubscription.unsubscribe(); | ||||
|     } | ||||
|     if (this.invoiceSubscription) { | ||||
|       this.invoiceSubscription.unsubscribe(); | ||||
|     } | ||||
|     if (this.paymentStatusSubscription) { | ||||
|       this.paymentStatusSubscription.unsubscribe(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.paymentForm = this.formBuilder.group({ | ||||
|       'method': 'lightning' | ||||
|     }); | ||||
| 
 | ||||
|     /** | ||||
|      * If the invoice is passed in the url, fetch it and display btcpay payment | ||||
|      * Otherwise get a new invoice | ||||
|      */ | ||||
|     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; | ||||
|                 this.invoice.amount = invoice.btcDue ?? (invoice.cryptoInfo.length ? parseFloat(invoice.cryptoInfo[0].totalDue) : 0) ?? 0; | ||||
| 
 | ||||
|                 if (this.invoice.amount > 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(); | ||||
|               }), | ||||
|             }); | ||||
|           } | ||||
|         }) | ||||
|       ).subscribe(); | ||||
|   } | ||||
| 
 | ||||
|   bypassSecurityTrustUrl(text: string): SafeUrl { | ||||
|     return this.sanitizer.bypassSecurityTrustUrl(text); | ||||
|   } | ||||
| } | ||||
| @ -75,7 +75,7 @@ | ||||
|                   } @else { | ||||
|                     <app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time> | ||||
|                   } | ||||
|                   @if (!showAccelerationSummary && isMobile && paymentType === 'cashapp' && accelerationEligible && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) { | ||||
|                   @if (!showAccelerationSummary && isMobile && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) { | ||||
|                     <a class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a> | ||||
|                   } | ||||
|                 </span> | ||||
| @ -116,7 +116,7 @@ | ||||
| 
 | ||||
|     <div class="bottom-panel"> | ||||
|       @if (showAccelerationSummary && !accelerationFlowCompleted) { | ||||
|         <app-accelerate-checkout *ngIf="(da$ | async) as da;" [txid]="tx.txid" [eta]="mempoolPosition?.block >= 7 ? null : da.adjustedTimeAvg * (mempoolPosition.block + 1) + now + da.timeOffset" (close)="accelerationFlowCompleted = true" [scrollEvent]="scrollIntoAccelPreview" class="h-100 w-100"></app-accelerate-checkout> | ||||
|         <app-accelerate-checkout *ngIf="(da$ | async) as da;" [cashappEnabled]="accelerationEligible" [txid]="tx.txid" [eta]="mempoolPosition?.block >= 7 ? null : da.adjustedTimeAvg * (mempoolPosition.block + 1) + now + da.timeOffset" (close)="accelerationFlowCompleted = true" [scrollEvent]="scrollIntoAccelPreview" class="h-100 w-100"></app-accelerate-checkout> | ||||
|       } @else { | ||||
|         @if (tx?.acceleration && !tx.status?.confirmed) { | ||||
|           <div class="progress-icon"> | ||||
|  | ||||
| @ -107,7 +107,6 @@ export class TrackerComponent implements OnInit, OnDestroy { | ||||
|   now = Date.now(); | ||||
|   da$: Observable<DifficultyAdjustment>; | ||||
|   isMobile: boolean; | ||||
|   paymentType: 'bitcoin' | 'cashapp' = 'bitcoin'; | ||||
| 
 | ||||
|   trackerStage: TrackerStage = 'waiting'; | ||||
| 
 | ||||
| @ -158,9 +157,6 @@ export class TrackerComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
|     this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === ''; | ||||
| 
 | ||||
|     if (this.acceleratorAvailable && this.stateService.referrer === 'https://cash.app/') { | ||||
|       this.paymentType = 'cashapp'; | ||||
|     } | ||||
|     const urlParams = new URLSearchParams(window.location.search); | ||||
|     if (urlParams.get('cash_request_id')) { | ||||
|       this.showAccelerationSummary = true; | ||||
| @ -390,11 +386,9 @@ export class TrackerComponent implements OnInit, OnDestroy { | ||||
|             this.trackerStage = 'replaced'; | ||||
|           } | ||||
| 
 | ||||
|           this.showAccelerationSummary = true; | ||||
|           if (txPosition.position?.block > 0 && this.tx.weight < 4000) { | ||||
|             this.accelerationEligible = true; | ||||
|             if (this.acceleratorAvailable && this.paymentType === 'cashapp') { | ||||
|               this.showAccelerationSummary = true; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|  | ||||
| @ -167,4 +167,19 @@ export class ServicesApiServices { | ||||
|   requestTestnet4Coins$(address: string, sats: number) { | ||||
|     return this.httpClient.get<{txid: string}>(`${SERVICES_API_PREFIX}/testnet4/faucet/request?address=${address}&sats=${sats}`, { responseType: 'json' }); | ||||
|   } | ||||
| 
 | ||||
|   generateBTCPayAcceleratorInvoice$(txid: string): Observable<any> { | ||||
|     const params = { | ||||
|       product: txid | ||||
|     }; | ||||
|     return this.httpClient.post<any>(`${SERVICES_API_PREFIX}/payments/bitcoin`, params); | ||||
|   } | ||||
| 
 | ||||
|   retreiveInvoice$(invoiceId: string): Observable<any[]> { | ||||
|     return this.httpClient.get<any[]>(`${SERVICES_API_PREFIX}/payments/bitcoin/invoice?id=${invoiceId}`); | ||||
|   } | ||||
| 
 | ||||
|   getPaymentStatus$(orderId: string): Observable<any[]> { | ||||
|     return this.httpClient.get<any[]>(`${SERVICES_API_PREFIX}/payments/bitcoin/check?order_id=${orderId}`); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -115,6 +115,7 @@ import { HttpErrorComponent } from '../shared/components/http-error/http-error.c | ||||
| import { TwitterWidgetComponent } from '../components/twitter-widget/twitter-widget.component'; | ||||
| import { FaucetComponent } from '../components/faucet/faucet.component'; | ||||
| import { TwitterLogin } from '../components/twitter-login/twitter-login.component'; | ||||
| import { BitcoinInvoiceComponent } from '../components/bitcoin-invoice/bitcoin-invoice.component'; | ||||
| 
 | ||||
| import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-directives/weight-directives'; | ||||
| 
 | ||||
| @ -230,6 +231,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | ||||
|     TwitterWidgetComponent, | ||||
|     FaucetComponent, | ||||
|     TwitterLogin, | ||||
|     BitcoinInvoiceComponent, | ||||
|   ], | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
| @ -359,6 +361,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | ||||
|     HttpErrorComponent, | ||||
|     TwitterWidgetComponent, | ||||
|     TwitterLogin, | ||||
|     BitcoinInvoiceComponent, | ||||
| 
 | ||||
|     MempoolBlockOverviewComponent, | ||||
|     ClockchainComponent, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user