Simple mode redesign w/ sticky button
This commit is contained in:
parent
aa0c70bd44
commit
48e16e64c2
@ -286,14 +286,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row d-flex justify-content-end align-items-center mr-1" style="height: 48px" *ngIf="!hideCashApp && paymentType === 'cashapp'">
|
@if (!hideCashApp && paymentType === 'cashapp') {
|
||||||
<div [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'" class="p-2">Accelerate with</div>
|
<div #cashappCTA class="cashapp-placeholder {{ stickyCTA }}"></div>
|
||||||
<div id="cash-app-pay" style="max-width: 320px" [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'"></div>
|
<div class="d-flex justify-content-center align-items-center cashapp-cta {{ stickyCTA }}" (click)="submitCashappPay()">
|
||||||
<div *ngIf="showSpinner" class="d-flex align-items-center">
|
<div [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'" class="p-2">Accelerate for <app-fiat [value]="maxCost" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat> with</div>
|
||||||
<span class="mr-2">Loading</span>
|
<div id="cash-app-pay" style="max-width: 320px" [style]="showSpinner ? 'opacity: 0' : 'opacity: 1'"></div>
|
||||||
<div class="spinner-border text-light" style="width: 25px; height: 25px"></div>
|
<div *ngIf="showSpinner" class="d-flex align-items-center">
|
||||||
|
<span class="mr-2">Loading</span>
|
||||||
|
<div class="spinner-border text-light" style="width: 25px; height: 25px"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -109,4 +109,53 @@
|
|||||||
|
|
||||||
.item {
|
.item {
|
||||||
white-space: initial;
|
white-space: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cashapp-cta {
|
||||||
|
width: 100%;
|
||||||
|
height: 54px;
|
||||||
|
background: #653b9c;
|
||||||
|
position: relative;
|
||||||
|
bottom: initial;
|
||||||
|
top: initial;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 4px 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0px 0px 15px 0px #000;
|
||||||
|
|
||||||
|
&.sticky-top {
|
||||||
|
position: fixed;
|
||||||
|
width: calc(100vw - 30px - 1.5rem);
|
||||||
|
margin: auto;
|
||||||
|
z-index: 50;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 102px;
|
||||||
|
@media (min-width: 573px) {
|
||||||
|
top: 62px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.sticky-bottom {
|
||||||
|
position: fixed;
|
||||||
|
width: calc(100vw - 30px - 1.5rem);
|
||||||
|
margin: auto;
|
||||||
|
z-index: 50;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 50px;
|
||||||
|
@media (min-width: 430px) {
|
||||||
|
bottom: 56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cashapp-placeholder {
|
||||||
|
height: 54px;
|
||||||
|
|
||||||
|
&.non-stick {
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, HostListener, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, HostListener, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { Subscription, catchError, of, tap } from 'rxjs';
|
import { Subscription, catchError, of, tap } from 'rxjs';
|
||||||
import { StorageService } from '../../services/storage.service';
|
import { StorageService } from '../../services/storage.service';
|
||||||
import { Transaction } from '../../interfaces/electrs.interface';
|
import { Transaction } from '../../interfaces/electrs.interface';
|
||||||
@ -43,6 +43,9 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
@Input() tx: Transaction | undefined;
|
@Input() tx: Transaction | undefined;
|
||||||
@Input() scrollEvent: boolean;
|
@Input() scrollEvent: boolean;
|
||||||
|
|
||||||
|
@ViewChild('cashappCTA')
|
||||||
|
cashappCTA: ElementRef;
|
||||||
|
|
||||||
math = Math;
|
math = Math;
|
||||||
error = '';
|
error = '';
|
||||||
showSuccess = false;
|
showSuccess = false;
|
||||||
@ -59,6 +62,7 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
selectFeeRateIndex = 1;
|
selectFeeRateIndex = 1;
|
||||||
isMobile: boolean = window.innerWidth <= 767.98;
|
isMobile: boolean = window.innerWidth <= 767.98;
|
||||||
user: any = undefined;
|
user: any = undefined;
|
||||||
|
stickyCTA: string = 'non-stick';
|
||||||
|
|
||||||
maxRateOptions: RateOption[] = [];
|
maxRateOptions: RateOption[] = [];
|
||||||
|
|
||||||
@ -66,6 +70,7 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
paymentType: 'bitcoin' | 'cashapp' = 'bitcoin';
|
paymentType: 'bitcoin' | 'cashapp' = 'bitcoin';
|
||||||
cashAppSubscription: Subscription;
|
cashAppSubscription: Subscription;
|
||||||
conversionsSubscription: Subscription;
|
conversionsSubscription: Subscription;
|
||||||
|
cashappSubmit: any;
|
||||||
payments: any;
|
payments: any;
|
||||||
showSpinner = false;
|
showSpinner = false;
|
||||||
square: any;
|
square: any;
|
||||||
@ -96,14 +101,14 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.stateService.ref === 'https://cash.app/') {
|
if (this.stateService.ref === 'https://cash.app/') {
|
||||||
this.paymentType = 'cashapp';
|
this.paymentType = 'cashapp';
|
||||||
this.stateService.ref = '';
|
|
||||||
} else {
|
} else {
|
||||||
this.paymentType = 'bitcoin';
|
this.paymentType = 'bitcoin';
|
||||||
}
|
}
|
||||||
|
this.onScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes.scrollEvent) {
|
if (changes.scrollEvent && this.paymentType !== 'cashapp') {
|
||||||
this.scrollToPreview('acceleratePreviewAnchor', 'start');
|
this.scrollToPreview('acceleratePreviewAnchor', 'start');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,10 +178,11 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee;
|
this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee;
|
||||||
|
|
||||||
if (!this.error) {
|
if (!this.error) {
|
||||||
this.scrollToPreview('acceleratePreviewAnchor', 'start');
|
|
||||||
if (this.paymentType === 'cashapp') {
|
if (this.paymentType === 'cashapp') {
|
||||||
this.setupSquare();
|
this.setupSquare();
|
||||||
}
|
} else {
|
||||||
|
this.scrollToPreview('acceleratePreviewAnchor', 'start');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@ -310,13 +316,15 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
label: 'Total',
|
label: 'Total',
|
||||||
pending: true,
|
pending: true,
|
||||||
productUrl: `https://mempool.space/tx/${this.tx.txid}`,
|
productUrl: `https://mempool.space/tx/${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: `https://mempool.space/tx/${this.tx.txid}`,
|
redirectURL: `https://mempool.space/tx/${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'}
|
||||||
});
|
});
|
||||||
await this.cashAppPay.attach('#cash-app-pay');
|
const renderPromise = this.cashAppPay.CashAppPayInstance.render('#cash-app-pay', { button: { theme: 'light', size: 'small', shape: 'semiround' }, manage: false });
|
||||||
this.showSpinner = false;
|
this.showSpinner = false;
|
||||||
|
|
||||||
const that = this;
|
const that = this;
|
||||||
@ -351,6 +359,8 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.cashappSubmit = await renderPromise;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -367,4 +377,28 @@ export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s);
|
g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
submitCashappPay(): void {
|
||||||
|
if (this.cashappSubmit) {
|
||||||
|
this.cashappSubmit?.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('window:scroll', ['$event']) // for window scroll events
|
||||||
|
onScroll() {
|
||||||
|
if (!this.cashappCTA?.nativeElement || this.paymentType !== 'cashapp' || !this.isMobile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cta = this.cashappCTA.nativeElement;
|
||||||
|
const rect = cta.getBoundingClientRect();
|
||||||
|
const topOffset = window.innerWidth <= 572 ? 102 : 62;
|
||||||
|
const bottomOffset = window.innerWidth < 430 ? 50 : 56;
|
||||||
|
if (rect.top < topOffset) {
|
||||||
|
this.stickyCTA = 'sticky-top';
|
||||||
|
} else if (rect.top > window.innerHeight - (bottomOffset + 54)) {
|
||||||
|
this.stickyCTA = 'sticky-bottom';
|
||||||
|
} else {
|
||||||
|
this.stickyCTA = 'non-stick';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,9 @@
|
|||||||
<div class="title float-left">
|
<div class="title float-left">
|
||||||
<h2 i18n="transaction.accelerate|Accelerate button label">Accelerate</h2>
|
<h2 i18n="transaction.accelerate|Accelerate button label">Accelerate</h2>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-outline-info accelerator-toggle btn-sm float-right" (click)="showAccelerationSummary = false" i18n="hide-accelerator">Hide accelerator</button>
|
@if (!(isMobile && paymentType === 'cashapp')) {
|
||||||
|
<button type="button" class="btn btn-outline-info accelerator-toggle btn-sm float-right" (click)="showAccelerationSummary = false" i18n="hide-accelerator">Hide accelerator</button>
|
||||||
|
}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -409,9 +411,6 @@
|
|||||||
} @else {
|
} @else {
|
||||||
<ng-container *ngTemplateOutlet="firstSeenRow"></ng-container>
|
<ng-container *ngTemplateOutlet="firstSeenRow"></ng-container>
|
||||||
<ng-container *ngTemplateOutlet="etaRow"></ng-container>
|
<ng-container *ngTemplateOutlet="etaRow"></ng-container>
|
||||||
@if (isMobile) {
|
|
||||||
<ng-container *ngTemplateOutlet="accelerateRow"></ng-container>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
<ng-container *ngTemplateOutlet="featuresRow"></ng-container>
|
<ng-container *ngTemplateOutlet="featuresRow"></ng-container>
|
||||||
@if (tx?.status?.confirmed) {
|
@if (tx?.status?.confirmed) {
|
||||||
@ -533,7 +532,7 @@
|
|||||||
} @else if (this.mempoolPosition.block >= 7) {
|
} @else if (this.mempoolPosition.block >= 7) {
|
||||||
<span [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
<span [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
||||||
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
||||||
@if (!isMobile && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) {
|
@if (!(isMobile && paymentType === 'cashapp') && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) {
|
||||||
<a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
<a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -542,7 +541,7 @@
|
|||||||
} @else {
|
} @else {
|
||||||
<span class="eta justify-content-end" [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'd-flex align-items-center' : ''">
|
<span class="eta justify-content-end" [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'd-flex align-items-center' : ''">
|
||||||
<app-time kind="until" *ngIf="(da$ | async) as da;" [time]="da.adjustedTimeAvg * (this.mempoolPosition.block + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true"></app-time>
|
<app-time kind="until" *ngIf="(da$ | async) as da;" [time]="da.adjustedTimeAvg * (this.mempoolPosition.block + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true"></app-time>
|
||||||
@if (!isMobile && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) {
|
@if (!(isMobile && paymentType === 'cashapp') && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) {
|
||||||
<a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
<a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -555,18 +554,6 @@
|
|||||||
}
|
}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #accelerateRow>
|
|
||||||
@if (!isLoadingTx) {
|
|
||||||
<tr>
|
|
||||||
<td class="td-width align-items-center align-middle p-0" colspan="2">
|
|
||||||
<a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn accelerateFullSize" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
} @else {
|
|
||||||
<ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container>
|
|
||||||
}
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #gogglesRow>
|
<ng-template #gogglesRow>
|
||||||
@if (!isLoadingTx) {
|
@if (!isLoadingTx) {
|
||||||
@if (((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length) {
|
@if (((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length) {
|
||||||
|
@ -117,6 +117,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
flowEnabled: boolean;
|
flowEnabled: boolean;
|
||||||
tooltipPosition: { x: number, y: number };
|
tooltipPosition: { x: number, y: number };
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
|
paymentType: 'bitcoin' | 'cashapp' = 'bitcoin';
|
||||||
|
firstLoad = true;
|
||||||
|
|
||||||
featuresEnabled: boolean;
|
featuresEnabled: boolean;
|
||||||
segwitEnabled: boolean;
|
segwitEnabled: boolean;
|
||||||
@ -154,6 +156,11 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
||||||
|
|
||||||
|
if (this.acceleratorAvailable && this.stateService.ref === 'https://cash.app/') {
|
||||||
|
this.showAccelerationSummary = true;
|
||||||
|
this.paymentType = 'cashapp';
|
||||||
|
}
|
||||||
|
|
||||||
this.enterpriseService.page();
|
this.enterpriseService.page();
|
||||||
|
|
||||||
this.websocketService.want(['blocks', 'mempool-blocks']);
|
this.websocketService.want(['blocks', 'mempool-blocks']);
|
||||||
@ -720,6 +727,11 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetTransaction() {
|
resetTransaction() {
|
||||||
|
if (!this.firstLoad) {
|
||||||
|
this.stateService.ref = '';
|
||||||
|
} else {
|
||||||
|
this.firstLoad = false;
|
||||||
|
}
|
||||||
this.error = undefined;
|
this.error = undefined;
|
||||||
this.tx = null;
|
this.tx = null;
|
||||||
this.setFeatures();
|
this.setFeatures();
|
||||||
@ -814,6 +826,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
this.stateService.ref = '';
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
this.fetchCpfpSubscription.unsubscribe();
|
this.fetchCpfpSubscription.unsubscribe();
|
||||||
this.fetchRbfSubscription.unsubscribe();
|
this.fetchRbfSubscription.unsubscribe();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user