Add copy to clipboard functionality to addresses.
This commit is contained in:
parent
a2e320d923
commit
4030f709fc
54
src/app/_helpers/clipboard-copy.ts
Normal file
54
src/app/_helpers/clipboard-copy.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
function copyToClipboard(text: any): boolean {
|
||||||
|
// create our hidden div element
|
||||||
|
const hiddenCopy = document.createElement('div');
|
||||||
|
// set the innerHTML of the div
|
||||||
|
hiddenCopy.innerHTML = text;
|
||||||
|
// set the position to be absolute and off the screen
|
||||||
|
hiddenCopy.style.position = 'absolute';
|
||||||
|
hiddenCopy.style.left = '-9999px';
|
||||||
|
|
||||||
|
// check and see if the user had a text selection range
|
||||||
|
let currentRange;
|
||||||
|
if (document.getSelection().rangeCount > 0) {
|
||||||
|
// the user has a text selection range, store it
|
||||||
|
currentRange = document.getSelection().getRangeAt(0);
|
||||||
|
// remove the current selection
|
||||||
|
window.getSelection().removeRange(currentRange);
|
||||||
|
} else {
|
||||||
|
// they didn't have anything selected
|
||||||
|
currentRange = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the div to the body
|
||||||
|
document.body.appendChild(hiddenCopy);
|
||||||
|
// create a selection range
|
||||||
|
const copyRange = document.createRange();
|
||||||
|
// set the copy range to be the hidden div
|
||||||
|
copyRange.selectNode(hiddenCopy);
|
||||||
|
// add the copy range
|
||||||
|
window.getSelection().addRange(copyRange);
|
||||||
|
|
||||||
|
// since not all browsers support this, use a try block
|
||||||
|
try {
|
||||||
|
// copy the text
|
||||||
|
document.execCommand('copy');
|
||||||
|
} catch (err) {
|
||||||
|
window.alert('Your Browser Doesn\'t support this! Error : ' + err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// remove the selection range (Chrome throws a warning if we don't.)
|
||||||
|
window.getSelection().removeRange(copyRange);
|
||||||
|
// remove the hidden div
|
||||||
|
document.body.removeChild(hiddenCopy);
|
||||||
|
|
||||||
|
// return the old selection range
|
||||||
|
if (currentRange) {
|
||||||
|
window.getSelection().addRange(currentRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
copyToClipboard
|
||||||
|
};
|
@ -6,3 +6,4 @@ export * from '@app/_helpers/http-getter';
|
|||||||
export * from '@app/_helpers/global-error-handler';
|
export * from '@app/_helpers/global-error-handler';
|
||||||
export * from '@app/_helpers/export-csv';
|
export * from '@app/_helpers/export-csv';
|
||||||
export * from '@app/_helpers/read-csv';
|
export * from '@app/_helpers/read-csv';
|
||||||
|
export * from '@app/_helpers/clipboard-copy';
|
||||||
|
@ -35,7 +35,10 @@
|
|||||||
</h3>
|
</h3>
|
||||||
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance | tokenRatio}} SRF</span>
|
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance | tokenRatio}} SRF</span>
|
||||||
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | date}}</span>
|
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | date}}</span>
|
||||||
<span class="ml-2"><strong>Address:</strong><a href="{{bloxbergLink}}" target="_blank"> {{account?.identities.evm['bloxberg:8996']}} </a></span>
|
<span class="ml-2"><strong>Address:</strong>
|
||||||
|
<a href="{{bloxbergLink}}" target="_blank"> {{accountAddress}} </a>
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress()" alt="Copy">
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="account" class="card mt-3 mb-3">
|
<div *ngIf="account" class="card mt-3 mb-3">
|
||||||
@ -176,13 +179,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<button mat-raised-button color="primary" type="button" class="btn btn btn-outline-primary mb-3">
|
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary mb-3">
|
||||||
Add User KYC
|
Add User KYC
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<button mat-raised-button color="primary" type="button" class="btn btn btn-outline-success mb-3"
|
<button mat-raised-button color="primary" type="button" class="btn btn-outline-success mb-3"
|
||||||
(click)="resetPin()">
|
(click)="resetPin()">
|
||||||
Reset Pin
|
Reset Pin
|
||||||
</button>
|
</button>
|
||||||
|
@ -6,7 +6,8 @@ import {BlockSyncService, LocationService, LoggingService, TokenService, Transac
|
|||||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||||
import {first} from 'rxjs/operators';
|
import {first} from 'rxjs/operators';
|
||||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
import {CustomErrorStateMatcher, exportCsv} from '@app/_helpers';
|
import {copyToClipboard, CustomErrorStateMatcher, exportCsv} from '@app/_helpers';
|
||||||
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-account-details',
|
selector: 'app-account-details',
|
||||||
@ -54,6 +55,7 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private blockSyncService: BlockSyncService,
|
private blockSyncService: BlockSyncService,
|
||||||
private cdr: ChangeDetectorRef,
|
private cdr: ChangeDetectorRef,
|
||||||
|
private snackBar: MatSnackBar,
|
||||||
) {
|
) {
|
||||||
this.accountInfoForm = this.formBuilder.group({
|
this.accountInfoForm = this.formBuilder.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
@ -190,4 +192,10 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
downloadCsv(data: any, filename: string): void {
|
downloadCsv(data: any, filename: string): void {
|
||||||
exportCsv(data, filename);
|
exportCsv(data, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyAddress(): void {
|
||||||
|
if (copyToClipboard(this.accountAddress)) {
|
||||||
|
this.snackBar.open(this.accountAddress + ' copied successfully!', 'Close', { duration: 3000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import {MatRippleModule} from '@angular/material/core';
|
|||||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||||
import {ReactiveFormsModule} from '@angular/forms';
|
import {ReactiveFormsModule} from '@angular/forms';
|
||||||
import { AccountSearchComponent } from './account-search/account-search.component';
|
import { AccountSearchComponent } from './account-search/account-search.component';
|
||||||
|
import {MatSnackBarModule} from '@angular/material/snack-bar';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -55,7 +56,8 @@ import { AccountSearchComponent } from './account-search/account-search.componen
|
|||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatRippleModule,
|
MatRippleModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule,
|
||||||
|
MatSnackBarModule,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AccountsModule { }
|
export class AccountsModule { }
|
||||||
|
@ -13,12 +13,20 @@
|
|||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Sender: {{transaction.sender?.vcard.fn[0].value}}</span><br><br>
|
<span>Sender: {{transaction.sender?.vcard.fn[0].value}}</span><br><br>
|
||||||
<span>Sender Address: <a href="{{senderBloxbergLink}}" target="_blank"> {{transaction.from}} </a></span><br><br>
|
<span>
|
||||||
|
Sender Address:
|
||||||
|
<a href="{{senderBloxbergLink}}" target="_blank"> {{transaction.from}} </a>
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.from)" alt="Copy">
|
||||||
|
</span><br><br>
|
||||||
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewSender()">View Sender</button>
|
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewSender()">View Sender</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Recipient: {{transaction.recipient?.vcard.fn[0].value}}</span><br><br>
|
<span>Recipient: {{transaction.recipient?.vcard.fn[0].value}}</span><br><br>
|
||||||
<span>Recipient Address: <a href="{{recipientBloxbergLink}}" target="_blank"> {{transaction.to}} </a></span><br><br>
|
<span>
|
||||||
|
Recipient Address:
|
||||||
|
<a href="{{recipientBloxbergLink}}" target="_blank"> {{transaction.to}} </a>
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.to)" alt="Copy">
|
||||||
|
</span><br><br>
|
||||||
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewRecipient()">View Recipient</button>
|
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewRecipient()">View Recipient</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
@ -28,7 +36,11 @@
|
|||||||
<h4 class="mt-2">Token: </h4>
|
<h4 class="mt-2">Token: </h4>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Address: {{transaction.token._address}}</span>
|
<span>
|
||||||
|
Address:
|
||||||
|
{{transaction.token._address}}
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.token._address)" alt="Copy">
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Name: Sarafu Token</span>
|
<span>Name: Sarafu Token</span>
|
||||||
@ -73,17 +85,25 @@
|
|||||||
<span><strong>Trader: {{transaction.sender?.vcard.fn[0].value}}</strong></span>
|
<span><strong>Trader: {{transaction.sender?.vcard.fn[0].value}}</strong></span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Trader Address: {{transaction.trader}}</span>
|
<span>
|
||||||
|
Trader Address:
|
||||||
|
<a href="{{traderBloxbergLink}}" target="_blank"> {{transaction.trader}} </a>
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.trader)" alt="Copy">
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Trader</button>
|
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewTrader()">View Trader</button>
|
||||||
<br><br>
|
<br><br>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h4>Source Token: </h4>
|
<h4>Source Token: </h4>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Address: {{transaction.sourceToken.address}}</span>
|
<span>
|
||||||
|
Address:
|
||||||
|
{{transaction.sourceToken.address}}
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.sourceToken.address)" alt="Copy">
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Name: {{transaction.sourceToken.name}}</span>
|
<span>Name: {{transaction.sourceToken.name}}</span>
|
||||||
@ -100,7 +120,11 @@
|
|||||||
<h4>Destination Token: </h4>
|
<h4>Destination Token: </h4>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Address: {{transaction.destinationToken.address}}</span>
|
<span>
|
||||||
|
Address:
|
||||||
|
{{transaction.destinationToken.address}}
|
||||||
|
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.destinationToken.address)" alt="Copy">
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Name: {{transaction.destinationToken.name}}</span>
|
<span>Name: {{transaction.destinationToken.name}}</span>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
import {TransactionService} from '@app/_services';
|
import {TransactionService} from '@app/_services';
|
||||||
|
import {copyToClipboard} from '../../../_helpers';
|
||||||
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transaction-details',
|
selector: 'app-transaction-details',
|
||||||
@ -12,15 +14,21 @@ export class TransactionDetailsComponent implements OnInit {
|
|||||||
@Input() transaction;
|
@Input() transaction;
|
||||||
senderBloxbergLink: string;
|
senderBloxbergLink: string;
|
||||||
recipientBloxbergLink: string;
|
recipientBloxbergLink: string;
|
||||||
|
traderBloxbergLink: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private transactionService: TransactionService
|
private transactionService: TransactionService,
|
||||||
|
private snackBar: MatSnackBar,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.senderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions';
|
if (this.transaction.type === 'conversion') {
|
||||||
this.recipientBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions';
|
this.traderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions';
|
||||||
|
} else {
|
||||||
|
this.senderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions';
|
||||||
|
this.recipientBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async viewSender(): Promise<void> {
|
async viewSender(): Promise<void> {
|
||||||
@ -31,6 +39,10 @@ export class TransactionDetailsComponent implements OnInit {
|
|||||||
await this.router.navigateByUrl(`/accounts/${this.transaction.to}`);
|
await this.router.navigateByUrl(`/accounts/${this.transaction.to}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async viewTrader(): Promise<void> {
|
||||||
|
await this.router.navigateByUrl(`/accounts/${this.transaction.trader}`);
|
||||||
|
}
|
||||||
|
|
||||||
async reverseTransaction(): Promise<void> {
|
async reverseTransaction(): Promise<void> {
|
||||||
await this.transactionService.transferRequest(
|
await this.transactionService.transferRequest(
|
||||||
this.transaction.token.address,
|
this.transaction.token.address,
|
||||||
@ -39,4 +51,10 @@ export class TransactionDetailsComponent implements OnInit {
|
|||||||
this.transaction.value
|
this.transaction.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyAddress(address: string): void {
|
||||||
|
if (copyToClipboard(address)) {
|
||||||
|
this.snackBar.open(address + ' copied successfully!', 'Close', { duration: 3000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import {MatIconModule} from '@angular/material/icon';
|
|||||||
import {MatSelectModule} from '@angular/material/select';
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
import {MatCardModule} from '@angular/material/card';
|
import {MatCardModule} from '@angular/material/card';
|
||||||
import {MatRippleModule} from '@angular/material/core';
|
import {MatRippleModule} from '@angular/material/core';
|
||||||
|
import {MatSnackBarModule} from '@angular/material/snack-bar';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -39,7 +40,8 @@ import {MatRippleModule} from '@angular/material/core';
|
|||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatRippleModule
|
MatRippleModule,
|
||||||
|
MatSnackBarModule,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class TransactionsModule { }
|
export class TransactionsModule { }
|
||||||
|
1
src/assets/images/checklist.svg
Normal file
1
src/assets/images/checklist.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.8 KiB |
Loading…
Reference in New Issue
Block a user