diff --git a/frontend/src/app/components/transaction/transaction-raw.component.html b/frontend/src/app/components/transaction/transaction-raw.component.html index 3bd8ee6d2..35701889b 100644 --- a/frontend/src/app/components/transaction/transaction-raw.component.html +++ b/frontend/src/app/components/transaction/transaction-raw.component.html @@ -30,7 +30,6 @@
-
@@ -40,14 +39,18 @@
-
+
- + This transaction is stored locally in your browser. Broadcast it to add it to the mempool. + + Redirecting to transaction page... + - + +
@if (!hasPrevouts) { diff --git a/frontend/src/app/components/transaction/transaction-raw.component.scss b/frontend/src/app/components/transaction/transaction-raw.component.scss index 5bbe5601e..a4b386cee 100644 --- a/frontend/src/app/components/transaction/transaction-raw.component.scss +++ b/frontend/src/app/components/transaction/transaction-raw.component.scss @@ -191,4 +191,12 @@ .no-cursor { cursor: default !important; pointer-events: none; +} + +.btn-broadcast { + margin-left: 5px; + @media (max-width: 567px) { + margin-left: 0; + margin-top: 5px; + } } \ No newline at end of file diff --git a/frontend/src/app/components/transaction/transaction-raw.component.ts b/frontend/src/app/components/transaction/transaction-raw.component.ts index 5ce170e12..2e4dd4868 100644 --- a/frontend/src/app/components/transaction/transaction-raw.component.ts +++ b/frontend/src/app/components/transaction/transaction-raw.component.ts @@ -3,7 +3,7 @@ import { Transaction, Vout } from '@interfaces/electrs.interface'; import { StateService } from '../../services/state.service'; import { Filter, toFilters } from '../../shared/filters.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 { ActivatedRoute, Router } from '@angular/router'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; @@ -36,6 +36,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy { isLoadingBroadcast: boolean; errorBroadcast: string; successBroadcast: boolean; + broadcastSubscription: Subscription; isMobile: boolean; @ViewChild('graphContainer') @@ -82,7 +83,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy { this.resetState(); this.isLoading = true; 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.fetchCpfpInfo(tx); this.processTransaction(tx, hex); @@ -207,18 +208,22 @@ export class TransactionRawComponent implements OnInit, OnDestroy { }); } - async postTx(): Promise { + postTx(): void { this.isLoadingBroadcast = true; this.errorBroadcast = null; - return new Promise((resolve, reject) => { - this.apiService.postTransaction$(this.rawHexTransaction) - .subscribe((result) => { + + this.broadcastSubscription = this.apiService.postTransaction$(this.rawHexTransaction).pipe( + tap((txid: string) => { this.isLoadingBroadcast = false; this.successBroadcast = true; - this.transaction.txid = result; - resolve(result); - }, - (error) => { + this.transaction.txid = txid; + }), + switchMap((txid: string) => + timer(2000).pipe( + tap(() => this.router.navigate([this.relativeUrlPipe.transform('/tx/' + txid)])), + ) + ), + catchError((error) => { if (typeof error.error === 'string') { const matchText = error.error.replace(/\\/g, '').match('"message":"(.*?)"'); 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.isLoadingBroadcast = false; - reject(this.error); - }); - }); + return throwError(() => error); + }) + ).subscribe(); } resetState() { @@ -253,6 +258,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy { this.missingPrevouts = []; this.stateService.markBlock$.next({}); this.mempoolBlocksSubscription?.unsubscribe(); + this.broadcastSubscription?.unsubscribe(); } resetForm() { @@ -308,6 +314,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy { this.mempoolBlocksSubscription?.unsubscribe(); this.flowPrefSubscription?.unsubscribe(); this.stateService.markBlock$.next({}); + this.broadcastSubscription?.unsubscribe(); } }