235 lines
7.4 KiB
TypeScript
235 lines
7.4 KiB
TypeScript
import { Component, OnInit, OnDestroy, Input } 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';
|
|
|
|
@Component({
|
|
selector: 'app-accelerate-checkout',
|
|
templateUrl: './accelerate-checkout.component.html',
|
|
styleUrls: ['./accelerate-checkout.component.scss']
|
|
})
|
|
export class AccelerateCheckout implements OnInit, OnDestroy {
|
|
@Input() eta: number = Date.now() + 123456789;
|
|
@Input() txid: string = '70c18d76cdb285a1b5bd87fdaae165880afa189809c30b4083ff7c0e69ee09ad';
|
|
|
|
calculating = true;
|
|
choosenOption: 'wait' | 'accelerate' = 'wait';
|
|
showCheckoutPage = false;
|
|
error = '';
|
|
|
|
// accelerator stuff
|
|
square: { appId: string, locationId: string};
|
|
accelerationUUID: string;
|
|
estimateSubscription: Subscription;
|
|
cost: number; // sats
|
|
|
|
// square
|
|
cashappSubmit: any;
|
|
payments: any;
|
|
cashAppPay: any;
|
|
cashAppSubscription: Subscription;
|
|
conversionsSubscription: Subscription;
|
|
loadingCashapp = true;
|
|
processingPayment = true;
|
|
|
|
constructor(
|
|
private websocketService: WebsocketService,
|
|
private servicesApiService: ServicesApiServices,
|
|
private stateService: StateService
|
|
) {}
|
|
|
|
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();
|
|
});
|
|
}
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
if (this.estimateSubscription) {
|
|
this.estimateSubscription.unsubscribe();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Accelerator
|
|
*/
|
|
estimate() {
|
|
if (this.estimateSubscription) {
|
|
this.estimateSubscription.unsubscribe();
|
|
}
|
|
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 {
|
|
const estimation = response.body;
|
|
if (!estimation) {
|
|
this.error = `cannot_accelerate_tx`;
|
|
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 DEFAULT_BID_RATIO = 2;
|
|
this.cost = minExtraCost * DEFAULT_BID_RATIO + estimation.mempoolBaseFee + estimation.vsizeFee;
|
|
}
|
|
}),
|
|
|
|
catchError((response) => {
|
|
this.error = `cannot_accelerate_tx`;
|
|
return of(null);
|
|
})
|
|
).subscribe();
|
|
}
|
|
|
|
/**
|
|
* Square
|
|
*/
|
|
insertSquare(): void {
|
|
//@ts-ignore
|
|
if (window.Square) {
|
|
return;
|
|
}
|
|
let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js';
|
|
if (document.location.hostname === 'mempool-staging.fmt.mempool.space' ||
|
|
document.location.hostname === 'mempool-staging.va1.mempool.space' ||
|
|
document.location.hostname === 'mempool-staging.fra.mempool.space' ||
|
|
document.location.hostname === 'mempool-staging.tk7.mempool.space' ||
|
|
document.location.hostname === 'mempool.space') {
|
|
statsUrl = 'https://web.squarecdn.com/v1/square.js';
|
|
}
|
|
|
|
(function() {
|
|
const d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
|
// @ts-ignore
|
|
g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s);
|
|
})();
|
|
}
|
|
setupSquare() {
|
|
const init = () => {
|
|
this.initSquare();
|
|
};
|
|
|
|
//@ts-ignore
|
|
if (!window.Square) {
|
|
console.debug('Square.js failed to load properly. Retrying in 1 second.');
|
|
setTimeout(init, 1000);
|
|
} else {
|
|
init();
|
|
}
|
|
}
|
|
async initSquare(): Promise<void> {
|
|
try {
|
|
//@ts-ignore
|
|
this.payments = window.Square.payments(this.square.appId, this.square.locationId)
|
|
await this.requestCashAppPayment();
|
|
} catch (e) {
|
|
console.error(e);
|
|
this.error = 'Error loading Square Payments';
|
|
return;
|
|
}
|
|
}
|
|
async requestCashAppPayment() {
|
|
this.loadingCashapp = true;
|
|
|
|
if (this.cashAppSubscription) {
|
|
this.cashAppSubscription.unsubscribe();
|
|
}
|
|
if (this.conversionsSubscription) {
|
|
this.conversionsSubscription.unsubscribe();
|
|
}
|
|
|
|
this.conversionsSubscription = this.stateService.conversions$.subscribe(
|
|
async (conversions) => {
|
|
if (this.cashAppPay) {
|
|
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 paymentRequest = this.payments.paymentRequest({
|
|
countryCode: 'US',
|
|
currencyCode: 'USD',
|
|
total: {
|
|
amount: costUSD.toString(),
|
|
label: 'Total',
|
|
pending: true,
|
|
productUrl: `${redirectHostname}/tracker/${this.txid}`,
|
|
},
|
|
button: { shape: 'semiround', size: 'small', theme: 'light'}
|
|
});
|
|
this.cashAppPay = await this.payments.cashAppPay(paymentRequest, {
|
|
redirectURL: `${redirectHostname}/tracker/${this.txid}?acceleration=false`,
|
|
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 });
|
|
|
|
const that = this;
|
|
this.cashAppPay.addEventListener('ontokenization', function (event) {
|
|
const { tokenResult, error } = event.detail;
|
|
if (error) {
|
|
this.error = error;
|
|
} 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();
|
|
},
|
|
error: (response) => {
|
|
if (response.status === 403 && response.error === 'not_available') {
|
|
that.error = 'waitlisted';
|
|
} else {
|
|
that.error = response.error;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
this.loadingCashapp = false;
|
|
}
|
|
);
|
|
}
|
|
submitCashappPay(): void {
|
|
if (this.cashappSubmit) {
|
|
this.cashappSubmit?.begin();
|
|
this.processingPayment = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UI events
|
|
*/
|
|
enableCheckoutPage() {
|
|
this.showCheckoutPage = true;
|
|
this.insertSquare();
|
|
this.setupSquare();
|
|
}
|
|
selectedOptionChanged(event) {
|
|
this.choosenOption = event.target.id;
|
|
}
|
|
restart() {
|
|
this.showCheckoutPage = false
|
|
this.choosenOption = 'wait';
|
|
}
|
|
}
|