mirror of
https://github.com/mempool/mempool.git
synced 2025-10-09 23:02:58 +02:00
Merge pull request #5815 from mempool/natsoni/tx-preview-feedback
Tx preview: trim input and redirect to tx page
This commit is contained in:
@@ -30,7 +30,6 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="container-buttons">
|
<div class="container-buttons">
|
||||||
<button *ngIf="successBroadcast" type="button" class="btn btn-sm btn-success no-cursor" i18n="transaction.broadcasted|Broadcasted">Broadcasted</button>
|
|
||||||
<button class="btn btn-sm" style="margin-left: 10px; padding: 0;" (click)="resetForm()">✕</button>
|
<button class="btn btn-sm" style="margin-left: 10px; padding: 0;" (click)="resetForm()">✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,14 +39,18 @@
|
|||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
<div *ngIf="!successBroadcast" class="alert alert-mempool" style="align-items: center;">
|
<div class="alert alert-mempool" style="align-items: center;">
|
||||||
<span>
|
<span>
|
||||||
<fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon>
|
||||||
<ng-container i18n="transaction.local-tx|This transaction is stored locally in your browser.">
|
<ng-container *ngIf="!successBroadcast" i18n="transaction.local-tx|This transaction is stored locally in your browser.">
|
||||||
This transaction is stored locally in your browser. Broadcast it to add it to the mempool.
|
This transaction is stored locally in your browser. Broadcast it to add it to the mempool.
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<ng-container *ngIf="successBroadcast" i18n="transaction.redirecting|Redirecting to transaction page...">
|
||||||
|
Redirecting to transaction page...
|
||||||
|
</ng-container>
|
||||||
</span>
|
</span>
|
||||||
<button [disabled]="isLoadingBroadcast" type="button" class="btn btn-sm btn-primary" i18n="transaction.broadcast|Broadcast" (click)="postTx()">Broadcast</button>
|
<button *ngIf="!successBroadcast" [disabled]="isLoadingBroadcast" type="button" class="btn btn-sm btn-primary btn-broadcast" i18n="transaction.broadcast|Broadcast" (click)="postTx()">Broadcast</button>
|
||||||
|
<button *ngIf="successBroadcast" type="button" class="btn btn-sm btn-success no-cursor btn-broadcast" i18n="transaction.broadcasted|Broadcasted">Broadcasted</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (!hasPrevouts) {
|
@if (!hasPrevouts) {
|
||||||
|
@@ -192,3 +192,11 @@
|
|||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-broadcast {
|
||||||
|
margin-left: 5px;
|
||||||
|
@media (max-width: 567px) {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@ import { Transaction, Vout } from '@interfaces/electrs.interface';
|
|||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { Filter, toFilters } from '../../shared/filters.utils';
|
import { Filter, toFilters } from '../../shared/filters.utils';
|
||||||
import { decodeRawTransaction, getTransactionFlags, addInnerScriptsToVin, countSigops } from '../../shared/transaction.utils';
|
import { decodeRawTransaction, getTransactionFlags, addInnerScriptsToVin, countSigops } from '../../shared/transaction.utils';
|
||||||
import { firstValueFrom, Subscription } from 'rxjs';
|
import { catchError, firstValueFrom, Subscription, switchMap, tap, throwError, timer } from 'rxjs';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
@@ -36,6 +36,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
isLoadingBroadcast: boolean;
|
isLoadingBroadcast: boolean;
|
||||||
errorBroadcast: string;
|
errorBroadcast: string;
|
||||||
successBroadcast: boolean;
|
successBroadcast: boolean;
|
||||||
|
broadcastSubscription: Subscription;
|
||||||
|
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
@ViewChild('graphContainer')
|
@ViewChild('graphContainer')
|
||||||
@@ -82,7 +83,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
this.resetState();
|
this.resetState();
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
try {
|
try {
|
||||||
const { tx, hex } = decodeRawTransaction(this.pushTxForm.get('txRaw').value, this.stateService.network);
|
const { tx, hex } = decodeRawTransaction(this.pushTxForm.get('txRaw').value.trim(), this.stateService.network);
|
||||||
await this.fetchPrevouts(tx);
|
await this.fetchPrevouts(tx);
|
||||||
await this.fetchCpfpInfo(tx);
|
await this.fetchCpfpInfo(tx);
|
||||||
this.processTransaction(tx, hex);
|
this.processTransaction(tx, hex);
|
||||||
@@ -207,18 +208,22 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async postTx(): Promise<string> {
|
postTx(): void {
|
||||||
this.isLoadingBroadcast = true;
|
this.isLoadingBroadcast = true;
|
||||||
this.errorBroadcast = null;
|
this.errorBroadcast = null;
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.apiService.postTransaction$(this.rawHexTransaction)
|
this.broadcastSubscription = this.apiService.postTransaction$(this.rawHexTransaction).pipe(
|
||||||
.subscribe((result) => {
|
tap((txid: string) => {
|
||||||
this.isLoadingBroadcast = false;
|
this.isLoadingBroadcast = false;
|
||||||
this.successBroadcast = true;
|
this.successBroadcast = true;
|
||||||
this.transaction.txid = result;
|
this.transaction.txid = txid;
|
||||||
resolve(result);
|
}),
|
||||||
},
|
switchMap((txid: string) =>
|
||||||
(error) => {
|
timer(2000).pipe(
|
||||||
|
tap(() => this.router.navigate([this.relativeUrlPipe.transform('/tx/' + txid)])),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
catchError((error) => {
|
||||||
if (typeof error.error === 'string') {
|
if (typeof error.error === 'string') {
|
||||||
const matchText = error.error.replace(/\\/g, '').match('"message":"(.*?)"');
|
const matchText = error.error.replace(/\\/g, '').match('"message":"(.*?)"');
|
||||||
this.errorBroadcast = 'Failed to broadcast transaction, reason: ' + (matchText && matchText[1] || error.error);
|
this.errorBroadcast = 'Failed to broadcast transaction, reason: ' + (matchText && matchText[1] || error.error);
|
||||||
@@ -226,9 +231,9 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
this.errorBroadcast = 'Failed to broadcast transaction, reason: ' + error.message;
|
this.errorBroadcast = 'Failed to broadcast transaction, reason: ' + error.message;
|
||||||
}
|
}
|
||||||
this.isLoadingBroadcast = false;
|
this.isLoadingBroadcast = false;
|
||||||
reject(this.error);
|
return throwError(() => error);
|
||||||
});
|
})
|
||||||
});
|
).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
resetState() {
|
resetState() {
|
||||||
@@ -253,6 +258,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
this.missingPrevouts = [];
|
this.missingPrevouts = [];
|
||||||
this.stateService.markBlock$.next({});
|
this.stateService.markBlock$.next({});
|
||||||
this.mempoolBlocksSubscription?.unsubscribe();
|
this.mempoolBlocksSubscription?.unsubscribe();
|
||||||
|
this.broadcastSubscription?.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
resetForm() {
|
resetForm() {
|
||||||
@@ -308,6 +314,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
|
|||||||
this.mempoolBlocksSubscription?.unsubscribe();
|
this.mempoolBlocksSubscription?.unsubscribe();
|
||||||
this.flowPrefSubscription?.unsubscribe();
|
this.flowPrefSubscription?.unsubscribe();
|
||||||
this.stateService.markBlock$.next({});
|
this.stateService.markBlock$.next({});
|
||||||
|
this.broadcastSubscription?.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user