From fb086b5ad5789038e10c6f900c19b95e34fe1610 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 13 Apr 2024 23:07:19 +0900 Subject: [PATCH] [accelerator] polish UI prepaid accel --- .../accelerate-checkout.component.html | 218 +++++++++++------- .../accelerate-checkout.component.ts | 89 ++++--- .../accelerate-preview.component.ts | 1 - .../components/tracker/tracker.component.html | 2 +- .../components/tracker/tracker.component.ts | 5 + .../src/app/services/services-api.service.ts | 4 +- 6 files changed, 192 insertions(+), 127 deletions(-) diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html index 28e0a5832..5a73a48cf 100644 --- a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html @@ -1,103 +1,147 @@
- @if (!showCheckoutPage) { - -
-
-

Accelerate your Bitcoin transaction?

-
-
+ @if (error) { + + } @else { -
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
-
- -
-
-
- } - - @else { - -
-
-

Confirm your payment

-
-
- -
-
-
- Payment to mempool.space for acceleration of txid {{ txid.substr(0, 10) }}..{{ txid.substr(-10) }} -
-
-
- - @if (!loadingCashapp) { -
+ @if (step === 'completed') { +
- Total additional cost
- - Pay - - with - -
+
+
Transaction is now being accelerated!
+
} -
-
-
-
- @if (loadingCashapp) { -
- } + @else if (step === 'cta') { + +
+
+

Accelerate your Bitcoin transaction?

-
-
-
-
- Changed your mind? - +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ } + + @else if (step === 'checkout') { + +
+
+

Confirm your payment

+
-
- } +
+
+
+ Payment to mempool.space for acceleration of txid {{ txid.substr(0, 10) }}..{{ txid.substr(-10) }} +
+
+
+ + @if (!loadingCashapp) { +
+
+
+ Total additional cost
+ + Pay + + with + +
+
+
+
+ } + +
+
+
+
+ @if (loadingCashapp) { +
+ Loading payment method... +
+
+ } +
+
+
+ +
+
+
+ Changed your mind? + +
+
+ } + + @else if (step === 'processing') { +
+
+

Confirm your payment

+
+
+ + +
+ +
+
+
+
+ We are processing your payment... +
+
+
+
+
+ } + + + } +
diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts index 0aef93814..622256461 100644 --- a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts @@ -1,9 +1,10 @@ -import { Component, OnInit, OnDestroy, Output, EventEmitter, Input } from '@angular/core'; +import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef } from '@angular/core'; import { Subscription, tap, of, catchError } from 'rxjs'; import { WebsocketService } from '../../services/websocket.service'; import { ServicesApiServices } from '../../services/services-api.service'; import { nextRoundNumber } from '../../shared/common.utils'; import { StateService } from '../../services/state.service'; +import { AudioService } from '../../services/audio.service'; @Component({ selector: 'app-accelerate-checkout', @@ -13,47 +14,56 @@ import { StateService } from '../../services/state.service'; export class AccelerateCheckout implements OnInit, OnDestroy { @Input() eta: number = Date.now() + 123456789; @Input() txid: string = '70c18d76cdb285a1b5bd87fdaae165880afa189809c30b4083ff7c0e69ee09ad'; + @Output() close = new EventEmitter(); calculating = true; choosenOption: 'wait' | 'accelerate' = 'wait'; - showCheckoutPage = false; error = ''; // accelerator stuff square: { appId: string, locationId: string}; accelerationUUID: string; estimateSubscription: Subscription; + maxBidBoost: number; // sats cost: number; // sats // square + loadingCashapp = false; cashappSubmit: any; payments: any; cashAppPay: any; cashAppSubscription: Subscription; conversionsSubscription: Subscription; - loadingCashapp = true; - processingPayment = true; + step: 'cta' | 'checkout' | 'processing' | 'completed' = 'completed'; constructor( private websocketService: WebsocketService, private servicesApiService: ServicesApiServices, - private stateService: StateService - ) {} + private stateService: StateService, + private audioService: AudioService, + private cd: ChangeDetectorRef + ) { + this.accelerationUUID = window.crypto.randomUUID(); + } ngOnInit() { const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('cash_request_id')) { // Redirected from cashapp - this.processingPayment = true; - window.scrollTo(0, 0); - } else { - this.servicesApiService.setupSquare$().subscribe(ids => { - this.square = { - appId: ids.squareAppId, - locationId: ids.squareLocationId - }; - this.estimate(); - }); + this.insertSquare(); + this.setupSquare(); + this.step = 'processing'; } + + this.servicesApiService.setupSquare$().subscribe(ids => { + this.square = { + appId: ids.squareAppId, + locationId: ids.squareLocationId + }; + if (this.step === 'cta') { + this.estimate(); + } + }); + } ngOnDestroy() { @@ -82,9 +92,10 @@ export class AccelerateCheckout implements OnInit, OnDestroy { return; } // Make min extra fee at least 50% of the current tx fee - const minExtraCost = nextRoundNumber(Math.max(estimation.cost * 2, estimation.txSummary.effectiveFee)); + const minExtraBoost = nextRoundNumber(Math.max(estimation.cost * 2, estimation.txSummary.effectiveFee)); const DEFAULT_BID_RATIO = 2; - this.cost = minExtraCost * DEFAULT_BID_RATIO + estimation.mempoolBaseFee + estimation.vsizeFee; + this.maxBidBoost = minExtraBoost * DEFAULT_BID_RATIO; + this.cost = this.maxBidBoost * DEFAULT_BID_RATIO + estimation.mempoolBaseFee + estimation.vsizeFee; } }), @@ -143,8 +154,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { } } async requestCashAppPayment() { - this.loadingCashapp = true; - if (this.cashAppSubscription) { this.cashAppSubscription.unsubscribe(); } @@ -155,11 +164,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy { this.conversionsSubscription = this.stateService.conversions$.subscribe( async (conversions) => { if (this.cashAppPay) { - this.cashAppPay.destroy(); + await this.cashAppPay.destroy(); } const redirectHostname = document.location.hostname === 'localhost' ? `http://localhost:4200`: `https://${document.location.hostname}`; - const costUSD = this.cost / 100_000_000 * conversions.USD; + const costUSD = this.step === 'processing' ? 69.69 : (this.cost / 100_000_000 * conversions.USD); // When we're redirected to this component, the payment data is already linked to the payment token, so does not matter what amonut we put in there, therefore it's 69.69 const paymentRequest = this.payments.paymentRequest({ countryCode: 'US', currencyCode: 'USD', @@ -172,12 +181,16 @@ export class AccelerateCheckout implements OnInit, OnDestroy { button: { shape: 'semiround', size: 'small', theme: 'light'} }); this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { - redirectURL: `${redirectHostname}/tracker/${this.txid}?acceleration=false`, + redirectURL: `${redirectHostname}/tracker/${this.txid}`, referenceId: `accelerator-${this.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, button: { shape: 'semiround', size: 'small', theme: 'light'} }); - this.cashappSubmit = await this.cashAppPay.CashAppPayInstance.render('#cash-app-pay', { button: { theme: 'light', size: 'small', shape: 'semiround' }, manage: false }); - + + if (this.step === 'checkout') { + await this.cashAppPay.attach(`#cash-app-pay`, { theme: 'light', size: 'small', shape: 'semiround' }) + } + this.loadingCashapp = false; + const that = this; this.cashAppPay.addEventListener('ontokenization', function (event) { const { tokenResult, error } = event.detail; @@ -186,14 +199,17 @@ export class AccelerateCheckout implements OnInit, OnDestroy { } else if (tokenResult.status === 'OK') { that.servicesApiService.accelerateWithCashApp$( that.txid, - that.cost, tokenResult.token, tokenResult.details.cashAppPay.cashtag, tokenResult.details.cashAppPay.referenceId, that.accelerationUUID ).subscribe({ next: () => { - that.estimateSubscription.unsubscribe(); + that.audioService.playSound('ascend-chime-cartoon'); + that.step = 'completed'; + setTimeout(() => { + that.closeModal(); + }, 10000); }, error: (response) => { if (response.status === 403 && response.error === 'not_available') { @@ -205,33 +221,34 @@ export class AccelerateCheckout implements OnInit, OnDestroy { }); } }); - this.loadingCashapp = false; } ); } - submitCashappPay(): void { - if (this.cashappSubmit) { - this.cashappSubmit?.begin(); - this.processingPayment = true; - } - } /** * UI events */ enableCheckoutPage() { - this.showCheckoutPage = true; + this.step = 'checkout'; + this.loadingCashapp = true; this.insertSquare(); this.setupSquare(); } selectedOptionChanged(event) { this.choosenOption = event.target.id; + if (this.choosenOption === 'wait') { + this.restart(); + this.closeModal(); + } } restart() { - this.showCheckoutPage = false + this.step = 'cta'; this.choosenOption = 'wait'; } closeModal(): void { + if (this.cashAppPay) { + this.cashAppPay.destroy(); + } this.close.emit(); } } diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts index ca4e61c06..ec36107a4 100644 --- a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts +++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts @@ -362,7 +362,6 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges that.accelerationSubscription = that.servicesApiService.accelerateWithCashApp$( that.tx.txid, - that.userBid, tokenResult.token, tokenResult.details.cashAppPay.cashtag, tokenResult.details.cashAppPay.referenceId, diff --git a/frontend/src/app/components/tracker/tracker.component.html b/frontend/src/app/components/tracker/tracker.component.html index 3e2eed5d2..9f1388d22 100644 --- a/frontend/src/app/components/tracker/tracker.component.html +++ b/frontend/src/app/components/tracker/tracker.component.html @@ -48,7 +48,7 @@ } @if (isMobile && paymentType === 'cashapp' && accelerationEligible && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) { - Accelerate + Accelerate }
diff --git a/frontend/src/app/components/tracker/tracker.component.ts b/frontend/src/app/components/tracker/tracker.component.ts index 1a33eae66..03f7d3f0c 100644 --- a/frontend/src/app/components/tracker/tracker.component.ts +++ b/frontend/src/app/components/tracker/tracker.component.ts @@ -146,6 +146,11 @@ export class TrackerComponent implements OnInit, OnDestroy { if (this.acceleratorAvailable && this.stateService.ref === 'https://cash.app/') { this.paymentType = 'cashapp'; } + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.get('cash_request_id')) { + this.showAccelerationSummary = true; + } + this.showAccelerationSummary = true; this.enterpriseService.page(); diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts index 44d253efa..89ea9a603 100644 --- a/frontend/src/app/services/services-api.service.ts +++ b/frontend/src/app/services/services-api.service.ts @@ -132,8 +132,8 @@ export class ServicesApiServices { return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/accelerate`, { txInput: txInput, userBid: userBid, accelerationUUID: accelerationUUID }); } - accelerateWithCashApp$(txInput: string, userBid: number, token: string, cashtag: string, referenceId: string, accelerationUUID: string) { - return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/accelerate/cashapp`, { txInput: txInput, userBid: userBid, token: token, cashtag: cashtag, referenceId: referenceId, accelerationUUID: accelerationUUID }); + accelerateWithCashApp$(txInput: string, token: string, cashtag: string, referenceId: string, accelerationUUID: string) { + return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/accelerate/cashapp`, { txInput: txInput, token: token, cashtag: cashtag, referenceId: referenceId, accelerationUUID: accelerationUUID }); } getAccelerations$(): Observable {