Merge pull request #5368 from mempool/nymkappa/google-pay
[accelerator] add support for Google Pay payment
This commit is contained in:
		
						commit
						b5d89b83fa
					
				| @ -389,21 +389,29 @@ | |||||||
|                   </div> |                   </div> | ||||||
|                 } |                 } | ||||||
|               </div> |               </div> | ||||||
|               @if (canPayWithCashapp || canPayWithApplePay) { |               @if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay) { | ||||||
|                 <div class="col-sm text-center flex-grow-0  d-flex flex-column justify-content-center align-items-center"> |                 <div class="col-sm text-center flex-grow-0  d-flex flex-column justify-content-center align-items-center"> | ||||||
|                   <p class="text-nowrap">—<span i18n="or">OR</span>—</p> |                   <p class="text-nowrap">—<span i18n="or">OR</span>—</p> | ||||||
|                 </div> |                 </div> | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|             @if (canPayWithCashapp || canPayWithApplePay) { |             @if (canPayWithCashapp || canPayWithApplePay || canPayWithGooglePay) { | ||||||
|               <div class="col-sm text-center d-flex flex-column justify-content-center align-items-center"> |               <div class="col-sm text-center d-flex flex-column justify-content-center align-items-center"> | ||||||
|                 <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container> <app-fiat [value]="cost"></app-fiat> with</p> |                 <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container> <app-fiat [value]="cost"></app-fiat> with</p> | ||||||
|                 @if (canPayWithCashapp) { |                 @if (canPayWithCashapp) { | ||||||
|                   <img class="paymentMethod mx-2" style="width: 200px" src="/resources/cash-app.svg" height=55 (click)="moveToStep('cashapp')"> |                   <img class="paymentMethod mx-2" style="width: 200px" src="/resources/cash-app.svg" height=55 (click)="moveToStep('cashapp')"> | ||||||
|                 } |                 } | ||||||
|                 @if (canPayWithApplePay) { |                 @if (canPayWithApplePay) { | ||||||
|                   @if (canPayWithCashapp) { <hr class="w-25 mt-2 mb-2"> } |                   @if (canPayWithCashapp) { <span class="mt-1 mb-1"></span> } | ||||||
|                   <img style="cursor: pointer;" src="/resources/apple-pay.svg" height=55 (click)="moveToStep('applepay')"> |                   <div class="paymentMethod mx-2" style="width: 200px; height: 55px"> | ||||||
|  |                   <img src="/resources/apple-pay.png" height=37 (click)="moveToStep('applepay')"> | ||||||
|  |                   </div> | ||||||
|  |                 } | ||||||
|  |                 @if (canPayWithGooglePay) { | ||||||
|  |                   @if (canPayWithCashapp || canPayWithApplePay) { <span class="mt-1 mb-1"></span> } | ||||||
|  |                   <div class="paymentMethod mx-2" style="width: 200px; height: 55px"> | ||||||
|  |                     <img src="/resources/google-pay.png" height=37 (click)="moveToStep('googlepay')"> | ||||||
|  |                   </div> | ||||||
|                 } |                 } | ||||||
|               </div> |               </div> | ||||||
|             } |             } | ||||||
| @ -427,7 +435,7 @@ | |||||||
|         <button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button> |         <button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   } @else if (step === 'cashapp' || step === 'applepay') { |   } @else if (step === 'cashapp' || step === 'applepay' || step === 'googlepay') { | ||||||
|     <!-- Show checkout page --> |     <!-- Show checkout page --> | ||||||
|     <div class="row mb-md-1 text-center" id="confirm-title"> |     <div class="row mb-md-1 text-center" id="confirm-title"> | ||||||
|       <div class="col-sm" id="confirm-payment-title"> |       <div class="col-sm" id="confirm-payment-title"> | ||||||
| @ -443,7 +451,7 @@ | |||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     @if (step === 'cashapp' && !loadingCashapp || step === 'applepay' && !loadingApplePay) { |     @if (step === 'cashapp' && !loadingCashapp || step === 'applepay' && !loadingApplePay || step === 'googlepay' && !loadingGooglePay) { | ||||||
|       <div class="row text-center mt-1"> |       <div class="row text-center mt-1"> | ||||||
|         <div class="col-sm"> |         <div class="col-sm"> | ||||||
|           <div class="form-group w-100"> |           <div class="form-group w-100"> | ||||||
| @ -463,11 +471,13 @@ | |||||||
|       <div class="col-sm"> |       <div class="col-sm"> | ||||||
|         <div class="form-group w-100"> |         <div class="form-group w-100"> | ||||||
|           @if (step === 'applepay') { |           @if (step === 'applepay') { | ||||||
|             <div id="apple-pay-button" class="apple-pay-button apple-pay-button-white" [style]="loadingApplePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> |             <div id="apple-pay-button" class="apple-pay-button apple-pay-button-black" style="height: 50px"  [style]="loadingApplePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> | ||||||
|           } @else if (step === 'cashapp') {           |           } @else if (step === 'cashapp') {           | ||||||
|             <div id="cash-app-pay" class="d-inline-block" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> |             <div id="cash-app-pay" class="d-inline-block" style="height: 50px" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> | ||||||
|  |           } @else if (step === 'googlepay') { | ||||||
|  |             <div id="google-pay-button" class="d-inline-block" style="height: 50px" [style]="loadingGooglePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div> | ||||||
|           } |           } | ||||||
|           @if (loadingCashapp || loadingApplePay) { |           @if (loadingCashapp || loadingApplePay || loadingGooglePay) { | ||||||
|           <div display="d-flex flex-row justify-content-center"> |           <div display="d-flex flex-row justify-content-center"> | ||||||
|             <span i18n="accelerator.loading-payment-method">Loading payment method...</span> |             <span i18n="accelerator.loading-payment-method">Loading payment method...</span> | ||||||
|             <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> |             <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> | ||||||
|  | |||||||
| @ -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
 | ||||||
| @ -47,7 +48,7 @@ export const MIN_BID_RATIO = 1; | |||||||
| export const DEFAULT_BID_RATIO = 2; | export const DEFAULT_BID_RATIO = 2; | ||||||
| export const MAX_BID_RATIO = 4; | export const MAX_BID_RATIO = 4; | ||||||
| 
 | 
 | ||||||
| type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'applepay' | 'processing' | 'paid' | 'success'; | type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'applepay' | 'googlepay' | 'processing' | 'paid' | 'success'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-accelerate-checkout', |   selector: 'app-accelerate-checkout', | ||||||
| @ -62,6 +63,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|   @Input() scrollEvent: boolean; |   @Input() scrollEvent: boolean; | ||||||
|   @Input() cashappEnabled: boolean = true; |   @Input() cashappEnabled: boolean = true; | ||||||
|   @Input() applePayEnabled: boolean = false; |   @Input() applePayEnabled: boolean = false; | ||||||
|  |   @Input() googlePayEnabled: boolean = true; | ||||||
|   @Input() advancedEnabled: boolean = false; |   @Input() advancedEnabled: boolean = false; | ||||||
|   @Input() forceMobile: boolean = false; |   @Input() forceMobile: boolean = false; | ||||||
|   @Input() showDetails: boolean = false; |   @Input() showDetails: boolean = false; | ||||||
| @ -83,14 +85,12 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
|   private _step: CheckoutStep = 'summary'; |   private _step: CheckoutStep = 'summary'; | ||||||
|   simpleMode: boolean = true; |   simpleMode: boolean = true; | ||||||
|   paymentMethod: 'cashapp' | 'btcpay'; |  | ||||||
|   timeoutTimer: any; |   timeoutTimer: any; | ||||||
| 
 | 
 | ||||||
|   authSubscription$: Subscription; |   authSubscription$: Subscription; | ||||||
|   auth: IAuth | null = null; |   auth: IAuth | null = null; | ||||||
| 
 | 
 | ||||||
|   // accelerator stuff
 |   // accelerator stuff
 | ||||||
|   square: { appId: string, locationId: string}; |  | ||||||
|   accelerationUUID: string; |   accelerationUUID: string; | ||||||
|   accelerationSubscription: Subscription; |   accelerationSubscription: Subscription; | ||||||
|   difficultySubscription: Subscription; |   difficultySubscription: Subscription; | ||||||
| @ -112,13 +112,13 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|   // square
 |   // square
 | ||||||
|   loadingCashapp = false; |   loadingCashapp = false; | ||||||
|   loadingApplePay = false; |   loadingApplePay = false; | ||||||
|   cashappError = false; |   loadingGooglePay = false; | ||||||
|   cashappSubmit: any; |  | ||||||
|   payments: any; |   payments: any; | ||||||
|   cashAppPay: any; |   cashAppPay: any; | ||||||
|   applePay: any; |   applePay: any; | ||||||
|  |   googlePay: any; | ||||||
|   conversionsSubscription: Subscription; |   conversionsSubscription: Subscription; | ||||||
|   conversions: any; |   conversions: Record<string, number>; | ||||||
| 
 | 
 | ||||||
|   // btcpay
 |   // btcpay
 | ||||||
|   loadingBtcpayInvoice = false; |   loadingBtcpayInvoice = false; | ||||||
| @ -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; | ||||||
| @ -168,13 +168,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|       this.moveToStep('summary'); |       this.moveToStep('summary'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.servicesApiService.setupSquare$().subscribe(ids => { |  | ||||||
|       this.square = { |  | ||||||
|         appId: ids.squareAppId, |  | ||||||
|         locationId: ids.squareLocationId |  | ||||||
|       }; |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     this.conversionsSubscription = this.stateService.conversions$.subscribe( |     this.conversionsSubscription = this.stateService.conversions$.subscribe( | ||||||
|       async (conversions) => { |       async (conversions) => { | ||||||
|         this.conversions = conversions; |         this.conversions = conversions; | ||||||
| @ -182,7 +175,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnDestroy() { |   ngOnDestroy(): void { | ||||||
|     if (this.estimateSubscription) { |     if (this.estimateSubscription) { | ||||||
|       this.estimateSubscription.unsubscribe(); |       this.estimateSubscription.unsubscribe(); | ||||||
|     } |     } | ||||||
| @ -202,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); | ||||||
| @ -228,13 +221,18 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|       this.insertSquare(); |       this.insertSquare(); | ||||||
|       this.setupSquare(); |       this.setupSquare(); | ||||||
|       this.scrollToElementWithTimeout('confirm-title', 'center', 100); |       this.scrollToElementWithTimeout('confirm-title', 'center', 100); | ||||||
|  |     } else if (this._step === 'googlepay' && this.googlePayEnabled) { | ||||||
|  |       this.loadingGooglePay = true; | ||||||
|  |       this.insertSquare(); | ||||||
|  |       this.setupSquare(); | ||||||
|  |       this.scrollToElementWithTimeout('confirm-title', 'center', 100); | ||||||
|     } else if (this._step === 'paid') { |     } else if (this._step === 'paid') { | ||||||
|       this.timePaid = Date.now(); |       this.timePaid = Date.now(); | ||||||
|       this.timeoutTimer = setTimeout(() => { |       this.timeoutTimer = setTimeout(() => { | ||||||
|         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'); | ||||||
|   } |   } | ||||||
| @ -252,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(); | ||||||
| @ -267,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(); | ||||||
|     } |     } | ||||||
| @ -331,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(); | ||||||
| @ -402,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'; | ||||||
| @ -415,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,25 +431,33 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|   } |   } | ||||||
|   async initSquare(): Promise<void> { |   async initSquare(): Promise<void> { | ||||||
|     try { |     try { | ||||||
|       //@ts-ignore
 |       this.servicesApiService.setupSquare$().subscribe({ | ||||||
|       this.payments = window.Square.payments(this.square.appId, this.square.locationId) |         next: async (ids) => { | ||||||
|  |           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(); | ||||||
|           } else if (this._step === 'applepay') { |           } else if (this._step === 'applepay') { | ||||||
|             await this.requestApplePayPayment(); |             await this.requestApplePayPayment(); | ||||||
|  |           } else if (this._step === 'googlepay') { | ||||||
|  |             await this.requestGooglePayPayment(); | ||||||
|           } |           } | ||||||
|  |         }, | ||||||
|  |         error: () => { | ||||||
|  |           console.debug('Error loading Square Payments'); | ||||||
|  |           this.accelerateError = 'cannot_setup_square'; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       console.debug('Error loading Square Payments', e); |       console.debug('Error loading Square Payments', e); | ||||||
|       this.cashappError = true; |       this.accelerateError = 'cannot_setup_square'; | ||||||
|       return; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * APPLE PAY |    * APPLE PAY | ||||||
|    */ |    */ | ||||||
|   async requestApplePayPayment() { |   async requestApplePayPayment(): Promise<void> { | ||||||
|     if (this.conversionsSubscription) { |     if (this.conversionsSubscription) { | ||||||
|       this.conversionsSubscription.unsubscribe(); |       this.conversionsSubscription.unsubscribe(); | ||||||
|     } |     } | ||||||
| @ -505,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(); | ||||||
| @ -541,10 +545,97 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * GOOGLE PAY | ||||||
|  |    */ | ||||||
|  |   async requestGooglePayPayment(): Promise<void> { | ||||||
|  |     if (this.conversionsSubscription) { | ||||||
|  |       this.conversionsSubscription.unsubscribe(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.conversionsSubscription = this.stateService.conversions$.subscribe( | ||||||
|  |       async (conversions) => { | ||||||
|  |         this.conversions = conversions; | ||||||
|  |         if (this.googlePay) { | ||||||
|  |           this.googlePay.destroy(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const costUSD = this.cost / 100_000_000 * conversions.USD; | ||||||
|  |         const paymentRequest = this.payments.paymentRequest({ | ||||||
|  |           countryCode: 'US', | ||||||
|  |           currencyCode: 'USD', | ||||||
|  |           total: { | ||||||
|  |             amount: costUSD.toFixed(2), | ||||||
|  |             label: 'Total' | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         this.googlePay = await this.payments.googlePay(paymentRequest , { | ||||||
|  |           referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         await this.googlePay.attach(`#google-pay-button`, { | ||||||
|  |           buttonType: 'pay', | ||||||
|  |           buttonSizeMode: 'fill', | ||||||
|  |         }); | ||||||
|  |         this.loadingGooglePay = false; | ||||||
|  | 
 | ||||||
|  |         document.getElementById('google-pay-button').addEventListener('click', async event => { | ||||||
|  |           event.preventDefault(); | ||||||
|  |           const tokenResult = await this.googlePay.tokenize(); | ||||||
|  |           if (tokenResult?.status === 'OK') { | ||||||
|  |             const card = tokenResult.details?.card; | ||||||
|  |             if (!card || !card.brand || !card.expMonth || !card.expYear || !card.last4) { | ||||||
|  |               console.error(`Cannot retreive payment card details`); | ||||||
|  |               this.accelerateError = 'apple_pay_no_card_details'; | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  |             const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase()); | ||||||
|  |             this.servicesApiService.accelerateWithGooglePay$( | ||||||
|  |               this.tx.txid, | ||||||
|  |               tokenResult.token, | ||||||
|  |               cardTag, | ||||||
|  |               `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, | ||||||
|  |               this.accelerationUUID | ||||||
|  |             ).subscribe({ | ||||||
|  |               next: () => { | ||||||
|  |                 this.apiService.logAccelerationRequest$(this.tx.txid).subscribe(); | ||||||
|  |                 this.audioService.playSound('ascend-chime-cartoon'); | ||||||
|  |                 if (this.googlePay) { | ||||||
|  |                   this.googlePay.destroy(); | ||||||
|  |                 } | ||||||
|  |                 setTimeout(() => { | ||||||
|  |                   this.moveToStep('paid'); | ||||||
|  |                 }, 1000); | ||||||
|  |               }, | ||||||
|  |               error: (response) => { | ||||||
|  |                 this.accelerateError = response.error; | ||||||
|  |                 if (!(response.status === 403 && response.error === 'not_available')) { | ||||||
|  |                   setTimeout(() => { | ||||||
|  |                     // Reset everything by reloading the page :D, can be improved
 | ||||||
|  |                     const urlParams = new URLSearchParams(window.location.search); | ||||||
|  |                     window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``)); | ||||||
|  |                   }, 3000); | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             }); | ||||||
|  |           } else { | ||||||
|  |             let errorMessage = `Tokenization failed with status: ${tokenResult.status}`; | ||||||
|  |             if (tokenResult.errors) { | ||||||
|  |               errorMessage += ` and errors: ${JSON.stringify( | ||||||
|  |                 tokenResult.errors, | ||||||
|  |               )}`;
 | ||||||
|  |             } | ||||||
|  |             throw new Error(errorMessage); | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** |   /** | ||||||
|    * CASHAPP |    * CASHAPP | ||||||
|    */ |    */ | ||||||
|   async requestCashAppPayment() { |   async requestCashAppPayment(): Promise<void> { | ||||||
|     if (this.conversionsSubscription) { |     if (this.conversionsSubscription) { | ||||||
|       this.conversionsSubscription.unsubscribe(); |       this.conversionsSubscription.unsubscribe(); | ||||||
|     } |     } | ||||||
| @ -566,18 +657,14 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|             label: 'Total', |             label: 'Total', | ||||||
|             pending: true, |             pending: true, | ||||||
|             productUrl: `${redirectHostname}/tracker/${this.tx.txid}`, |             productUrl: `${redirectHostname}/tracker/${this.tx.txid}`, | ||||||
|           }, |           } | ||||||
|           button: { shape: 'semiround', size: 'small', theme: 'light'} |  | ||||||
|         }); |         }); | ||||||
|         this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { |         this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { | ||||||
|           redirectURL: `${redirectHostname}/tracker/${this.tx.txid}`, |           redirectURL: `${redirectHostname}/tracker/${this.tx.txid}`, | ||||||
|           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)}` | ||||||
|           button: { shape: 'semiround', size: 'small', theme: 'light'} |  | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         if (this.step === 'cashapp') { |         await this.cashAppPay.attach(`#cash-app-pay`, { theme: 'dark' }); | ||||||
|           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 => { | ||||||
| @ -626,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); | ||||||
| @ -656,53 +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 couldPayWithBalance() { |   get couldPayWithGooglePay(): boolean { | ||||||
|  |     if (!this.googlePayEnabled) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     return !!this.estimate?.availablePaymentMethods?.googlePay; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   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; | ||||||
|     } |     } | ||||||
| @ -718,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; | ||||||
|     } |     } | ||||||
| @ -734,7 +828,23 @@ export class AccelerateCheckout implements OnInit, OnDestroy { | |||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   get canPayWithBalance() { |   get canPayWithGooglePay(): boolean { | ||||||
|  |     if (!this.googlePayEnabled || !this.conversions) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const paymentMethod = this.estimate?.availablePaymentMethods?.googlePay; | ||||||
|  |     if (paymentMethod) { | ||||||
|  |       const costUSD = (this.cost / 100_000_000 * this.conversions.USD); | ||||||
|  |       if (costUSD >= paymentMethod.min && costUSD <= paymentMethod.max) { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   get canPayWithBalance(): boolean { | ||||||
|     if (!this.hasAccessToBalanceMode) { |     if (!this.hasAccessToBalanceMode) { | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| @ -742,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; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -144,6 +144,10 @@ export class ServicesApiServices { | |||||||
|     return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/applePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID }); |     return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/applePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   accelerateWithGooglePay$(txInput: string, token: string, cardTag: string, referenceId: string, accelerationUUID: string) { | ||||||
|  |     return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/googlePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   getAccelerations$(): Observable<Acceleration[]> { |   getAccelerations$(): Observable<Acceleration[]> { | ||||||
|     return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`); |     return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								frontend/src/resources/apple-pay.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								frontend/src/resources/apple-pay.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 46 KiB | 
| @ -1,84 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> |  | ||||||
| <svg version="1.1" id="Artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" |  | ||||||
| 	 width="165.52107px" height="105.9651px" viewBox="0 0 165.52107 105.9651" enable-background="new 0 0 165.52107 105.9651" |  | ||||||
| 	 xml:space="preserve"> |  | ||||||
| <g> |  | ||||||
| 	<path id="XMLID_4_" d="M150.69807,0H14.82318c-0.5659,0-1.1328,0-1.69769,0.0033c-0.47751,0.0034-0.95391,0.0087-1.43031,0.0217 |  | ||||||
| 		c-1.039,0.0281-2.0869,0.0894-3.1129,0.2738c-1.0424,0.1876-2.0124,0.4936-2.9587,0.9754 |  | ||||||
| 		c-0.9303,0.4731-1.782,1.0919-2.52009,1.8303c-0.73841,0.7384-1.35721,1.5887-1.83021,2.52 |  | ||||||
| 		c-0.4819,0.9463-0.7881,1.9166-0.9744,2.9598c-0.18539,1.0263-0.2471,2.074-0.2751,3.1119 |  | ||||||
| 		c-0.0128,0.4764-0.01829,0.9528-0.0214,1.4291c-0.0033,0.5661-0.0022,1.1318-0.0022,1.6989V91.142 |  | ||||||
| 		c0,0.5671-0.0011,1.13181,0.0022,1.69901c0.00311,0.4763,0.0086,0.9527,0.0214,1.4291 |  | ||||||
| 		c0.028,1.03699,0.08971,2.08469,0.2751,3.11069c0.1863,1.0436,0.4925,2.0135,0.9744,2.9599 |  | ||||||
| 		c0.473,0.9313,1.0918,1.7827,1.83021,2.52c0.73809,0.7396,1.58979,1.3583,2.52009,1.8302 |  | ||||||
| 		c0.9463,0.4831,1.9163,0.7892,2.9587,0.9767c1.026,0.1832,2.0739,0.2456,3.1129,0.2737c0.4764,0.0108,0.9528,0.0172,1.43031,0.0194 |  | ||||||
| 		c0.56489,0.0044,1.13179,0.0044,1.69769,0.0044h135.87489c0.5649,0,1.13181,0,1.69659-0.0044 |  | ||||||
| 		c0.47641-0.0022,0.95282-0.0086,1.4314-0.0194c1.0368-0.0281,2.0845-0.0905,3.11301-0.2737 |  | ||||||
| 		c1.041-0.1875,2.0112-0.4936,2.9576-0.9767c0.9313-0.4719,1.7805-1.0906,2.52011-1.8302c0.7372-0.7373,1.35599-1.5887,1.8302-2.52 |  | ||||||
| 		c0.48299-0.9464,0.78889-1.9163,0.97429-2.9599c0.1855-1.026,0.2457-2.0737,0.2738-3.11069 |  | ||||||
| 		c0.013-0.4764,0.01941-0.9528,0.02161-1.4291c0.00439-0.5672,0.00439-1.1319,0.00439-1.69901V14.8242 |  | ||||||
| 		c0-0.5671,0-1.1328-0.00439-1.6989c-0.0022-0.4763-0.00861-0.9527-0.02161-1.4291c-0.02811-1.0379-0.0883-2.0856-0.2738-3.1119 |  | ||||||
| 		c-0.18539-1.0432-0.4913-2.0135-0.97429-2.9598c-0.47421-0.9313-1.093-1.7816-1.8302-2.52 |  | ||||||
| 		c-0.73961-0.7384-1.58881-1.3572-2.52011-1.8303c-0.9464-0.4818-1.9166-0.7878-2.9576-0.9754 |  | ||||||
| 		c-1.0285-0.1844-2.0762-0.2457-3.11301-0.2738c-0.47858-0.013-0.95499-0.0183-1.4314-0.0217C151.82988,0,151.26297,0,150.69807,0 |  | ||||||
| 		L150.69807,0z"/> |  | ||||||
| 	<path id="XMLID_3_" fill="#FFFFFF" d="M150.69807,3.532l1.67149,0.0032c0.4528,0.0032,0.90561,0.0081,1.36092,0.0205 |  | ||||||
| 		c0.79201,0.0214,1.71849,0.0643,2.58209,0.2191c0.7507,0.1352,1.38029,0.3408,1.9845,0.6484 |  | ||||||
| 		c0.5965,0.3031,1.14301,0.7003,1.62019,1.1768c0.479,0.4797,0.87671,1.0271,1.18381,1.6302 |  | ||||||
| 		c0.30589,0.5995,0.51019,1.2261,0.64459,1.9823c0.1544,0.8542,0.1971,1.7832,0.21881,2.5801 |  | ||||||
| 		c0.01219,0.4498,0.01819,0.8996,0.0204,1.3601c0.00429,0.5569,0.0042,1.1135,0.0042,1.6715V91.142 |  | ||||||
| 		c0,0.558,0.00009,1.1136-0.0043,1.6824c-0.00211,0.4497-0.0081,0.8995-0.0204,1.3501c-0.02161,0.7957-0.0643,1.7242-0.2206,2.5885 |  | ||||||
| 		c-0.13251,0.7458-0.3367,1.3725-0.64429,1.975c-0.30621,0.6016-0.70331,1.1484-1.18022,1.6251 |  | ||||||
| 		c-0.47989,0.48-1.0246,0.876-1.62819,1.1819c-0.5997,0.3061-1.22821,0.51151-1.97151,0.6453 |  | ||||||
| 		c-0.88109,0.157-1.84639,0.2002-2.57339,0.2199c-0.4574,0.0103-0.9126,0.01649-1.37889,0.0187 |  | ||||||
| 		c-0.55571,0.0043-1.1134,0.0042-1.6692,0.0042H14.82318c-0.0074,0-0.0146,0-0.0221,0c-0.5494,0-1.0999,0-1.6593-0.0043 |  | ||||||
| 		c-0.4561-0.00211-0.9112-0.0082-1.3512-0.0182c-0.7436-0.0201-1.7095-0.0632-2.5834-0.2193 |  | ||||||
| 		c-0.74969-0.1348-1.3782-0.3402-1.9858-0.6503c-0.59789-0.3032-1.1422-0.6988-1.6223-1.1797 |  | ||||||
| 		c-0.4764-0.4756-0.8723-1.0207-1.1784-1.6232c-0.3064-0.6019-0.5114-1.2305-0.64619-1.9852 |  | ||||||
| 		c-0.15581-0.8626-0.19861-1.7874-0.22-2.5777c-0.01221-0.4525-0.01731-0.9049-0.02021-1.3547l-0.0022-1.3279l0.0001-0.3506V14.8242 |  | ||||||
| 		l-0.0001-0.3506l0.0021-1.3251c0.003-0.4525,0.0081-0.9049,0.02031-1.357c0.02139-0.7911,0.06419-1.7163,0.22129-2.5861 |  | ||||||
| 		c0.1336-0.7479,0.3385-1.3765,0.6465-1.9814c0.3037-0.5979,0.7003-1.1437,1.17921-1.6225 |  | ||||||
| 		c0.477-0.4772,1.02309-0.8739,1.62479-1.1799c0.6011-0.3061,1.2308-0.5116,1.9805-0.6465c0.8638-0.1552,1.7909-0.198,2.5849-0.2195 |  | ||||||
| 		c0.4526-0.0123,0.9052-0.0172,1.3544-0.0203l1.6771-0.0033H150.69807"/> |  | ||||||
| 	<g> |  | ||||||
| 		<g> |  | ||||||
| 			<path d="M45.1862,35.64053c1.41724-1.77266,2.37897-4.15282,2.12532-6.58506c-2.07464,0.10316-4.60634,1.36871-6.07207,3.14276 |  | ||||||
| 				c-1.31607,1.5192-2.4809,3.99902-2.17723,6.3293C41.39111,38.72954,43.71785,37.36345,45.1862,35.64053"/> |  | ||||||
| 			<path d="M47.28506,38.98252c-3.38211-0.20146-6.25773,1.91951-7.87286,1.91951c-1.61602,0-4.08931-1.81799-6.76438-1.76899 |  | ||||||
| 				c-3.48177,0.05114-6.71245,2.01976-8.4793,5.15079c-3.63411,6.2636-0.95904,15.55471,2.57494,20.65606 |  | ||||||
| 				c1.71618,2.5238,3.78447,5.30269,6.50976,5.20287c2.57494-0.10104,3.58421-1.66732,6.71416-1.66732 |  | ||||||
| 				c3.12765,0,4.03679,1.66732,6.76252,1.61681c2.82665-0.05054,4.59381-2.52506,6.30997-5.05132 |  | ||||||
| 				c1.96878-2.877,2.77473-5.65498,2.82542-5.80748c-0.0507-0.05051-5.45058-2.12204-5.50065-8.33358 |  | ||||||
| 				c-0.05098-5.20101,4.23951-7.6749,4.44144-7.82832C52.3832,39.4881,48.5975,39.08404,47.28506,38.98252"/> |  | ||||||
| 		</g> |  | ||||||
| 		<g> |  | ||||||
| 			<path d="M76.73385,31.94381c7.35096,0,12.4697,5.06708,12.4697,12.44437c0,7.40363-5.22407,12.49704-12.65403,12.49704h-8.13892 |  | ||||||
| 				v12.94318h-5.88037v-37.8846H76.73385z M68.41059,51.9493h6.74732c5.11975,0,8.0336-2.75636,8.0336-7.53479 |  | ||||||
| 				c0-4.77792-2.91385-7.50845-8.00727-7.50845h-6.77365V51.9493z"/> |  | ||||||
| 			<path d="M90.73997,61.97864c0-4.8311,3.70182-7.79761,10.26583-8.16526l7.56061-0.44614v-2.12639 |  | ||||||
| 				c0-3.07185-2.07423-4.90959-5.53905-4.90959c-3.28251,0-5.33041,1.57492-5.82871,4.04313h-5.35574 |  | ||||||
| 				c0.31499-4.98859,4.56777-8.66407,11.3941-8.66407c6.69466,0,10.97377,3.54432,10.97377,9.08388v19.03421h-5.43472v-4.54194 |  | ||||||
| 				h-0.13065c-1.60125,3.07185-5.09341,5.01441-8.71623,5.01441C94.52078,70.30088,90.73997,66.94038,90.73997,61.97864z |  | ||||||
| 				 M108.56641,59.4846v-2.17905l-6.8,0.41981c-3.38683,0.23649-5.30306,1.73291-5.30306,4.09579 |  | ||||||
| 				c0,2.41504,1.99523,3.99046,5.04075,3.99046C105.46823,65.81161,108.56641,63.08108,108.56641,59.4846z"/> |  | ||||||
| 			<path d="M119.34167,79.9889v-4.5946c0.4193,0.10483,1.36425,0.10483,1.83723,0.10483c2.6252,0,4.04313-1.10245,4.90908-3.9378 |  | ||||||
| 				c0-0.05267,0.49931-1.68025,0.49931-1.70658l-9.97616-27.64562h6.14268l6.98432,22.47371h0.10432l6.98433-22.47371h5.9857 |  | ||||||
| 				l-10.34483,29.06304c-2.36186,6.69517-5.0924,8.84789-10.81577,8.84789C121.17891,80.12006,119.76098,80.06739,119.34167,79.9889 |  | ||||||
| 				z"/> |  | ||||||
| 		</g> |  | ||||||
| 	</g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| <g> |  | ||||||
| </g> |  | ||||||
| </svg> |  | ||||||
| Before Width: | Height: | Size: 6.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								frontend/src/resources/google-pay.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								frontend/src/resources/google-pay.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 30 KiB | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user