Add copy to clipboard functionality to addresses.

This commit is contained in:
Spencer Ofwiti 2021-04-26 13:14:36 +03:00
parent a2e320d923
commit 4030f709fc
9 changed files with 129 additions and 16 deletions

View 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
};

View File

@ -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';

View File

@ -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>

View File

@ -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 });
}
}
} }

View File

@ -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 { }

View File

@ -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>

View File

@ -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,16 +14,22 @@ 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 {
if (this.transaction.type === 'conversion') {
this.traderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions';
} else {
this.senderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions'; this.senderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions';
this.recipientBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions'; this.recipientBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions';
} }
}
async viewSender(): Promise<void> { async viewSender(): Promise<void> {
await this.router.navigateByUrl(`/accounts/${this.transaction.from}`); await this.router.navigateByUrl(`/accounts/${this.transaction.from}`);
@ -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 });
}
}
} }

View File

@ -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 { }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.8 KiB