Merge pull request #5372 from mempool/mononaut/google-play-minor-fixes

minor accelerator checkout fixes
This commit is contained in:
nymkappa 2024-07-26 11:37:54 +02:00 committed by GitHub
commit b719b76999
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 57 deletions

View File

@ -1,7 +1,8 @@
/* eslint-disable no-console */
import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core'; import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core';
import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs'; import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs';
import { ServicesApiServices } from '../../services/services-api.service'; import { ServicesApiServices } from '../../services/services-api.service';
import { md5, nextRoundNumber, insecureRandomUUID } from '../../shared/common.utils'; import { md5, insecureRandomUUID } from '../../shared/common.utils';
import { StateService } from '../../services/state.service'; import { StateService } from '../../services/state.service';
import { AudioService } from '../../services/audio.service'; import { AudioService } from '../../services/audio.service';
import { ETA, EtaService } from '../../services/eta.service'; import { ETA, EtaService } from '../../services/eta.service';
@ -11,7 +12,7 @@ import { IAuth, AuthServiceMempool } from '../../services/auth.service';
import { EnterpriseService } from '../../services/enterprise.service'; import { EnterpriseService } from '../../services/enterprise.service';
import { ApiService } from '../../services/api.service'; import { ApiService } from '../../services/api.service';
export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp'; export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp' | 'applePay' | 'googlePay';
export type AccelerationEstimate = { export type AccelerationEstimate = {
hasAccess: boolean; hasAccess: boolean;
@ -24,7 +25,7 @@ export type AccelerationEstimate = {
mempoolBaseFee: number; mempoolBaseFee: number;
vsizeFee: number; vsizeFee: number;
pools: number[]; pools: number[];
availablePaymentMethods: {[method: string]: {min: number, max: number}}; availablePaymentMethods: Record<PaymentMethod, {min: number, max: number}>;
unavailable?: boolean; unavailable?: boolean;
options: { // recommended bid options options: { // recommended bid options
fee: number; // recommended userBid in sats fee: number; // recommended userBid in sats
@ -112,14 +113,13 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
loadingCashapp = false; loadingCashapp = false;
loadingApplePay = false; loadingApplePay = false;
loadingGooglePay = false; loadingGooglePay = false;
cashappSubmit: any;
payments: any; payments: any;
cashAppPay: any; cashAppPay: any;
applePay: any; applePay: any;
googlePay: any; googlePay: any;
conversionsSubscription: Subscription; conversionsSubscription: Subscription;
conversions: any; conversions: Record<string, number>;
// btcpay // btcpay
loadingBtcpayInvoice = false; loadingBtcpayInvoice = false;
invoice = undefined; invoice = undefined;
@ -137,13 +137,13 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.accelerationUUID = insecureRandomUUID(); this.accelerationUUID = insecureRandomUUID();
// Check if Apple Pay available // Check if Apple Pay available
// @ts-ignore https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/checking_for_apple_pay_availability#overview // https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/checking_for_apple_pay_availability#overview
if (window.ApplePaySession) { if (window['ApplePaySession']) {
this.applePayEnabled = true; this.applePayEnabled = true;
} }
} }
ngOnInit() { ngOnInit(): void {
this.authSubscription$ = this.authService.getAuth$().subscribe((auth) => { this.authSubscription$ = this.authService.getAuth$().subscribe((auth) => {
if (this.auth?.user?.userId !== auth?.user?.userId) { if (this.auth?.user?.userId !== auth?.user?.userId) {
this.auth = auth; this.auth = auth;
@ -175,7 +175,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
); );
} }
ngOnDestroy() { ngOnDestroy(): void {
if (this.estimateSubscription) { if (this.estimateSubscription) {
this.estimateSubscription.unsubscribe(); this.estimateSubscription.unsubscribe();
} }
@ -195,7 +195,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
} }
moveToStep(step: CheckoutStep) { moveToStep(step: CheckoutStep): void {
this._step = step; this._step = step;
if (this.timeoutTimer) { if (this.timeoutTimer) {
clearTimeout(this.timeoutTimer); clearTimeout(this.timeoutTimer);
@ -232,7 +232,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
if (this.step === 'paid') { if (this.step === 'paid') {
this.accelerateError = 'internal_server_error'; this.accelerateError = 'internal_server_error';
} }
}, 120000) }, 120000);
} }
this.hasDetails.emit(this._step === 'quote'); this.hasDetails.emit(this._step === 'quote');
} }
@ -250,7 +250,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.scrollToElement(id, position); this.scrollToElement(id, position);
}, timeout); }, timeout);
} }
scrollToElement(id: string, position: ScrollLogicalPosition) { scrollToElement(id: string, position: ScrollLogicalPosition): void {
const acceleratePreviewAnchor = document.getElementById(id); const acceleratePreviewAnchor = document.getElementById(id);
if (acceleratePreviewAnchor) { if (acceleratePreviewAnchor) {
this.cd.markForCheck(); this.cd.markForCheck();
@ -265,7 +265,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* Accelerator * Accelerator
*/ */
fetchEstimate() { fetchEstimate(): void {
if (this.estimateSubscription) { if (this.estimateSubscription) {
this.estimateSubscription.unsubscribe(); this.estimateSubscription.unsubscribe();
} }
@ -329,7 +329,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
}), }),
catchError((response) => { catchError(() => {
this.estimate = undefined; this.estimate = undefined;
this.quoteError = `cannot_accelerate_tx`; this.quoteError = `cannot_accelerate_tx`;
this.estimateSubscription.unsubscribe(); this.estimateSubscription.unsubscribe();
@ -400,8 +400,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
* Square * Square
*/ */
insertSquare(): void { insertSquare(): void {
//@ts-ignore if (window['Square']) {
if (window.Square) {
return; return;
} }
let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js'; let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js';
@ -413,19 +412,17 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
statsUrl = 'https://web.squarecdn.com/v1/square.js'; statsUrl = 'https://web.squarecdn.com/v1/square.js';
} }
(function() { (function(): void {
const d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; 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); g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s);
})(); })();
} }
setupSquare() { setupSquare(): void {
const init = () => { const init = (): void => {
this.initSquare(); this.initSquare();
}; };
//@ts-ignore if (!window['Square']) {
if (!window.Square) {
console.debug('Square.js failed to load properly. Retrying in 1 second.'); console.debug('Square.js failed to load properly. Retrying in 1 second.');
setTimeout(init, 1000); setTimeout(init, 1000);
} else { } else {
@ -436,8 +433,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
try { try {
this.servicesApiService.setupSquare$().subscribe({ this.servicesApiService.setupSquare$().subscribe({
next: async (ids) => { next: async (ids) => {
//@ts-ignore this.payments = window['Square'].payments(ids.squareAppId, ids.squareLocationId);
this.payments = window.Square.payments(ids.squareAppId, ids.squareLocationId)
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
if (this._step === 'cashapp' || urlParams.get('cash_request_id')) { if (this._step === 'cashapp' || urlParams.get('cash_request_id')) {
await this.requestCashAppPayment(); await this.requestCashAppPayment();
@ -451,7 +447,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
console.debug('Error loading Square Payments'); console.debug('Error loading Square Payments');
this.accelerateError = 'cannot_setup_square'; this.accelerateError = 'cannot_setup_square';
} }
}); });
} catch (e) { } catch (e) {
console.debug('Error loading Square Payments', e); console.debug('Error loading Square Payments', e);
this.accelerateError = 'cannot_setup_square'; this.accelerateError = 'cannot_setup_square';
@ -461,11 +457,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* APPLE PAY * APPLE PAY
*/ */
async requestApplePayPayment() { async requestApplePayPayment(): Promise<void> {
if (this.conversionsSubscription) { if (this.conversionsSubscription) {
this.conversionsSubscription.unsubscribe(); this.conversionsSubscription.unsubscribe();
} }
this.conversionsSubscription = this.stateService.conversions$.subscribe( this.conversionsSubscription = this.stateService.conversions$.subscribe(
async (conversions) => { async (conversions) => {
this.conversions = conversions; this.conversions = conversions;
@ -512,6 +508,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.accelerationUUID this.accelerationUUID
).subscribe({ ).subscribe({
next: () => { next: () => {
this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
this.audioService.playSound('ascend-chime-cartoon'); this.audioService.playSound('ascend-chime-cartoon');
if (this.applePay) { if (this.applePay) {
this.applePay.destroy(); this.applePay.destroy();
@ -551,11 +548,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* GOOGLE PAY * GOOGLE PAY
*/ */
async requestGooglePayPayment() { async requestGooglePayPayment(): Promise<void> {
if (this.conversionsSubscription) { if (this.conversionsSubscription) {
this.conversionsSubscription.unsubscribe(); this.conversionsSubscription.unsubscribe();
} }
this.conversionsSubscription = this.stateService.conversions$.subscribe( this.conversionsSubscription = this.stateService.conversions$.subscribe(
async (conversions) => { async (conversions) => {
this.conversions = conversions; this.conversions = conversions;
@ -578,7 +575,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
await this.googlePay.attach(`#google-pay-button`, { await this.googlePay.attach(`#google-pay-button`, {
buttonType: 'pay', buttonType: 'pay',
onClick: (e) => { console.log(e, 'hi') } onClick: (e) => { console.log(e); }
}); });
this.loadingGooglePay = false; this.loadingGooglePay = false;
@ -601,6 +598,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.accelerationUUID this.accelerationUUID
).subscribe({ ).subscribe({
next: () => { next: () => {
this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
this.audioService.playSound('ascend-chime-cartoon'); this.audioService.playSound('ascend-chime-cartoon');
if (this.googlePay) { if (this.googlePay) {
this.googlePay.destroy(); this.googlePay.destroy();
@ -628,7 +626,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
)}`; )}`;
} }
throw new Error(errorMessage); throw new Error(errorMessage);
} }
}); });
} }
); );
@ -637,11 +635,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* CASHAPP * CASHAPP
*/ */
async requestCashAppPayment() { async requestCashAppPayment(): Promise<void> {
if (this.conversionsSubscription) { if (this.conversionsSubscription) {
this.conversionsSubscription.unsubscribe(); this.conversionsSubscription.unsubscribe();
} }
this.conversionsSubscription = this.stateService.conversions$.subscribe( this.conversionsSubscription = this.stateService.conversions$.subscribe(
async (conversions) => { async (conversions) => {
this.conversions = conversions; this.conversions = conversions;
@ -666,7 +664,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}` referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`
}); });
await this.cashAppPay.attach(`#cash-app-pay`, { theme: 'light', size: 'small', shape: 'semiround' }) await this.cashAppPay.attach(`#cash-app-pay`, { theme: 'light', size: 'small', shape: 'semiround' });
this.loadingCashapp = false; this.loadingCashapp = false;
this.cashAppPay.addEventListener('ontokenization', event => { this.cashAppPay.addEventListener('ontokenization', event => {
@ -715,7 +713,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* BTCPay * BTCPay
*/ */
async requestBTCPayInvoice() { async requestBTCPayInvoice(): Promise<void> {
this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.tx.txid, this.userBid).pipe( this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.tx.txid, this.userBid).pipe(
switchMap(response => { switchMap(response => {
return this.servicesApiService.retreiveInvoice$(response.btcpayInvoiceId); return this.servicesApiService.retreiveInvoice$(response.btcpayInvoiceId);
@ -745,60 +743,60 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
/** /**
* UI events * UI events
*/ */
selectedOptionChanged(event) { selectedOptionChanged(event): void {
this.selectedOption = event.target.id; this.selectedOption = event.target.id;
} }
get step() { get step(): CheckoutStep {
return this._step; return this._step;
} }
get paymentMethods() { get paymentMethods(): PaymentMethod[] {
return Object.keys(this.estimate?.availablePaymentMethods || {}); return Object.keys(this.estimate?.availablePaymentMethods || {}) as PaymentMethod[];
} }
get couldPayWithBitcoin() { get couldPayWithBitcoin(): boolean {
return !!this.estimate?.availablePaymentMethods?.bitcoin; return !!this.estimate?.availablePaymentMethods?.bitcoin;
} }
get couldPayWithCashapp() { get couldPayWithCashapp(): boolean {
if (!this.cashappEnabled) { if (!this.cashappEnabled) {
return false; return false;
} }
return !!this.estimate?.availablePaymentMethods?.cashapp; return !!this.estimate?.availablePaymentMethods?.cashapp;
} }
get couldPayWithApplePay() { get couldPayWithApplePay(): boolean {
if (!this.applePayEnabled) { if (!this.applePayEnabled) {
return false; return false;
} }
return !!this.estimate?.availablePaymentMethods?.applePay; return !!this.estimate?.availablePaymentMethods?.applePay;
} }
get couldPayWithGooglePay() { get couldPayWithGooglePay(): boolean {
if (!this.googlePayEnabled) { if (!this.googlePayEnabled) {
return false; return false;
} }
return !!this.estimate?.availablePaymentMethods?.googlePay; return !!this.estimate?.availablePaymentMethods?.googlePay;
} }
get couldPayWithBalance() { get couldPayWithBalance(): boolean {
if (!this.hasAccessToBalanceMode) { if (!this.hasAccessToBalanceMode) {
return false; return false;
} }
return !!this.estimate?.availablePaymentMethods?.balance; return !!this.estimate?.availablePaymentMethods?.balance;
} }
get couldPay() { get couldPay(): boolean {
return this.couldPayWithBalance || this.couldPayWithBitcoin || this.couldPayWithCashapp || this.couldPayWithApplePay; return this.couldPayWithBalance || this.couldPayWithBitcoin || this.couldPayWithCashapp || this.couldPayWithApplePay || this.couldPayWithGooglePay;
} }
get canPayWithBitcoin() { get canPayWithBitcoin(): boolean {
const paymentMethod = this.estimate?.availablePaymentMethods?.bitcoin; const paymentMethod = this.estimate?.availablePaymentMethods?.bitcoin;
return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max; return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max;
} }
get canPayWithCashapp() { get canPayWithCashapp(): boolean {
if (!this.cashappEnabled || !this.conversions) { if (!this.cashappEnabled || !this.conversions) {
return false; return false;
} }
@ -814,7 +812,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return false; return false;
} }
get canPayWithApplePay() { get canPayWithApplePay(): boolean {
if (!this.applePayEnabled || !this.conversions) { if (!this.applePayEnabled || !this.conversions) {
return false; return false;
} }
@ -830,7 +828,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return false; return false;
} }
get canPayWithGooglePay() { get canPayWithGooglePay(): boolean {
if (!this.googlePayEnabled || !this.conversions) { if (!this.googlePayEnabled || !this.conversions) {
return false; return false;
} }
@ -846,7 +844,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return false; return false;
} }
get canPayWithBalance() { get canPayWithBalance(): boolean {
if (!this.hasAccessToBalanceMode) { if (!this.hasAccessToBalanceMode) {
return false; return false;
} }
@ -854,11 +852,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max && this.cost <= this.estimate?.userBalance; return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max && this.cost <= this.estimate?.userBalance;
} }
get canPay() { get canPay(): boolean {
return this.canPayWithBalance || this.canPayWithBitcoin || this.canPayWithCashapp || this.canPayWithApplePay; return this.canPayWithBalance || this.canPayWithBitcoin || this.canPayWithCashapp || this.canPayWithApplePay || this.canPayWithGooglePay;
} }
get hasAccessToBalanceMode() { get hasAccessToBalanceMode(): boolean {
return this.isLoggedIn() && this.estimate?.hasAccess; return this.isLoggedIn() && this.estimate?.hasAccess;
} }

View File

@ -7,7 +7,7 @@ export interface WebsocketResponse {
backend?: 'esplora' | 'electrum' | 'none'; backend?: 'esplora' | 'electrum' | 'none';
block?: BlockExtended; block?: BlockExtended;
blocks?: BlockExtended[]; blocks?: BlockExtended[];
conversions?: any; conversions?: Record<string, number>;
txConfirmed?: string; txConfirmed?: string;
historicalDate?: string; historicalDate?: string;
mempoolInfo?: MempoolInfo; mempoolInfo?: MempoolInfo;

View File

@ -138,7 +138,7 @@ export class StateService {
blocksSubject$ = new BehaviorSubject<BlockExtended[]>([]); blocksSubject$ = new BehaviorSubject<BlockExtended[]>([]);
blocks$: Observable<BlockExtended[]>; blocks$: Observable<BlockExtended[]>;
transactions$ = new BehaviorSubject<TransactionStripped[]>(null); transactions$ = new BehaviorSubject<TransactionStripped[]>(null);
conversions$ = new ReplaySubject<any>(1); conversions$ = new ReplaySubject<Record<string, number>>(1);
bsqPrice$ = new ReplaySubject<number>(1); bsqPrice$ = new ReplaySubject<number>(1);
mempoolInfo$ = new ReplaySubject<MempoolInfo>(1); mempoolInfo$ = new ReplaySubject<MempoolInfo>(1);
mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1); mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);