Add material design datatables to transaction list.

This commit is contained in:
Spencer Ofwiti 2020-11-25 10:55:27 +03:00
parent db4d713532
commit 9836476c3a
6 changed files with 291 additions and 100 deletions

View File

@ -4,8 +4,11 @@
<strong>CONVERSION DETAILS</strong> <strong>CONVERSION DETAILS</strong>
</div> </div>
<div class="card-body"> <div class="card-body">
<h4>Exchange: </h4> <h3>Exchange: </h3>
<h6>Trader Address: {{conversion.trader}}</h6><br> <p><strong>Trader: {{conversion.user?.vcard.fn}}</strong></p>
<p>Trader Address: {{conversion.trader}}</p>
<button mat-raised-button class="btn btn-dark" routerLink="/accounts/1">View Trader</button>
<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>
@ -20,7 +23,7 @@
<p>Symbol: {{conversion.sourceToken.symbol}}</p> <p>Symbol: {{conversion.sourceToken.symbol}}</p>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<p>Amount: {{conversion.fromValue | currency: conversion.sourceToken.name + ' ' }}</p> <p>Amount: {{conversion.sourceToken.symbol + ' ' + conversion.fromValue}}</p>
</li> </li>
</ul> </ul>
</div> </div>
@ -37,9 +40,15 @@
<p>Symbol: {{conversion.destinationToken.symbol}}</p> <p>Symbol: {{conversion.destinationToken.symbol}}</p>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<p>Amount: {{conversion.toValue | currency: conversion.destinationToken.name + ' ' }}</p> <p>Amount: {{conversion.destinationToken.symbol + ' ' + conversion.toValue}}</p>
</li> </li>
</ul> </ul>
<div class="mb-3">
<button mat-raised-button type="button" class="btn btn-outline-success">Resend SMS</button>
</div>
<div>
<button mat-raised-button type="button" class="btn btn-outline-danger">Reverse Transaction</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,13 +9,17 @@
<h4>Exchange: </h4> <h4>Exchange: </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">
<p>Sender: {{transaction.from}}</p> <p>Sender: {{transaction.sender?.vcard.fn}}</p>
<p>Sender Address: {{transaction.from}}</p>
<button mat-raised-button class="btn btn-outline-dark" routerLink="/accounts/1">View Sender</button>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<p>Recipient: {{transaction.to}}</p> <p>Recipient: {{transaction.recipient?.vcard.fn}}</p>
<p>Recipient Address: {{transaction.to}}</p>
<button mat-raised-button class="btn btn-outline-dark" routerLink="/accounts/1">View Recipient</button>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<p>Amount: {{transaction.value | currency: transaction.token.name + ' ' }}</p> <p>Amount: {{transaction.token.symbol + ' ' + transaction.value}}</p>
</li> </li>
</ul> </ul>
<h4 class="mt-2">Token: </h4> <h4 class="mt-2">Token: </h4>
@ -47,9 +51,15 @@
<p>Success: {{transaction.tx.success}}</p> <p>Success: {{transaction.tx.success}}</p>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<p>Timestamp: {{transaction.tx.timestamp}}</p> <p>Timestamp: {{transaction.tx.timestamp | date}}</p>
</li> </li>
</ul> </ul>
<div class="mb-3">
<button mat-raised-button type="button" class="btn btn-outline-success">Resend SMS</button>
</div>
<div>
<button mat-raised-button type="button" class="btn btn-outline-danger">Reverse Transaction</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,83 +11,179 @@
<!-- Start Content--> <!-- Start Content-->
<div class="container-fluid" appMenuSelection> <div class="container-fluid" appMenuSelection>
<div class="card"> <div class="card">
<div class="card-header"> <mat-card-title class="card-header">
Transfers Transfers
</div> </mat-card-title>
<div class="card-body"> <div class="card-body">
<app-transaction-details [transaction]="transaction"></app-transaction-details> <app-transaction-details [transaction]="transaction"></app-transaction-details>
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover table-sm row-border hover" datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger"> <div *ngIf="transactionSelection.selected.length <=0" class="row card-header">
<thead class="thead-dark"> <mat-form-field appearance="outline">
<tr> <mat-label> TRANSFER TYPE </mat-label>
<th scope="col">Sender</th> <mat-select id="typeSelect">
<th scope="col">Recipient</th> <mat-option value="all" selected>ALL TRANSFERS</mat-option>
<th scope="col">Value</th> <mat-option value="payments">PAYMENTS</mat-option>
<th scope="col"></th> <mat-option value="exchange">EXCHANGE</mat-option>
</tr> <mat-option value="disbursements">DISBURSEMENTS</mat-option>
</thead> <mat-option value="reclamation">RECLAMATION</mat-option>
<tbody> </mat-select>
<tr *ngFor="let transaction of transactions"> </mat-form-field>
<td>{{transaction.from}}</td> <button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto"><i class="fa fa-plus"></i> ADD NEW </button>
<td>{{transaction.to}}</td> <button mat-raised-button type="button" class="btn btn-outline-secondary ml-2"> EXPORT </button>
<td>{{transaction.value | currency: transaction.token.name + ' '}}</td>
<td>
<button type="button" class="btn btn-outline-primary" (click)="viewTransaction(transaction)"><i class="fa fa-eye"> VIEW </i></button></td>
</tr>
</tbody>
<tfoot class="thead-dark">
<tr>
<th scope="col">Sender</th>
<th scope="col">Recipient</th>
<th scope="col">Value</th>
<th scope="col"></th>
</tr>
</tfoot>
</table>
</div> </div>
<div *ngIf="transactionSelection.selected.length > 0" class="row card-header">
<p><strong> {{transactionSelection.selected.length}} selected </strong></p>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto"> NEXT </button>
<mat-form-field appearance="outline" class="ml-3">
<mat-label> TRANSACTION STATUS </mat-label>
<mat-select id="statusSelect">
<mat-option selected disabled> -- SELECT -- </mat-option>
<mat-option value="complete">COMPLETE</mat-option>
<mat-option value="reject">REJECT</mat-option>
</mat-select>
</mat-form-field>
</div>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value, transactionDataSource)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="transactionDataSource" matSort matSortActive="created"
matSortDirection="desc" matSortDisableClear>
<ng-container matColumnDef="sender">
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender </mat-header-cell>
<mat-cell *matCellDef="let transaction" routerLink="/users/{{transaction.from}}"> {{transaction.sender?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="recipient">
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </mat-header-cell>
<mat-cell *matCellDef="let transaction" routerLink="/users/{{transaction.to}}"> {{transaction.recipient?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="token">
<mat-header-cell *matHeaderCellDef mat-sort-header> Token </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.token.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="value">
<mat-header-cell *matHeaderCellDef mat-sort-header> Value </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.token.symbol + ' ' + transaction.value}} </mat-cell>
</ng-container>
<ng-container matColumnDef="created">
<mat-header-cell *matHeaderCellDef mat-sort-header> Created </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.tx.timestamp | date}} </mat-cell>
</ng-container>
<ng-container matColumnDef="view">
<mat-header-cell *matHeaderCellDef> View Transaction </mat-header-cell>
<mat-cell *matCellDef="let transaction">
<button mat-raised-button type="button" class="btn btn-outline-primary" (click)="viewTransaction(transaction)">
<i class="fa fa-eye"> VIEW </i>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="select">
<mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle(transactionSelection, transactionDataSource) : null"
[checked]="transactionSelection.hasValue() && isAllSelected(transactionSelection, transactionDataSource)"
[indeterminate]="transactionSelection.hasValue() && !isAllSelected(transactionSelection, transactionDataSource)">
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let transaction">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? transactionSelection.toggle(transaction) : null"
[checked]="transactionSelection.isSelected(transaction)">
</mat-checkbox>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="transactionDisplayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns"></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <mat-card-title class="card-header">
Conversions Conversions
</div> </mat-card-title>
<div class="card-body"> <div class="card-body">
<app-conversion-details [conversion]="conversion"></app-conversion-details> <app-conversion-details [conversion]="conversion"></app-conversion-details>
<div class="table-responsive"> <mat-form-field appearance="outline">
<table class="table table-striped table-bordered table-hover table-sm row-border hover" datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger"> <mat-label> Filter </mat-label>
<thead class="thead-dark"> <input matInput type="text" (keyup)="doFilter($event.target.value, conversionDataSource)" placeholder="Filter">
<tr> <mat-icon matSuffix>search</mat-icon>
<th scope="col">Initial Token</th> </mat-form-field>
<th scope="col">Initial Value</th>
<th scope="col">Final Token</th> <mat-table class="mat-elevation-z10" [dataSource]="conversionDataSource" matSort matSortActive="created"
<th scope="col">Final Value</th> matSortDirection="desc" matSortDisableClear>
<th scope="col">Trader</th> <ng-container matColumnDef="initialToken">
<th scope="col"></th> <mat-header-cell *matHeaderCellDef mat-sort-header> Initial Token </mat-header-cell>
</tr> <mat-cell *matCellDef="let conversion"> {{conversion.sourceToken.name}} </mat-cell>
</thead> </ng-container>
<tbody>
<tr *ngFor="let conversion of conversions"> <ng-container matColumnDef="initialValue">
<td>{{conversion.sourceToken.symbol}}</td> <mat-header-cell *matHeaderCellDef mat-sort-header> Initial Value </mat-header-cell>
<td>{{conversion.fromValue | currency: conversion.sourceToken.name + ' '}}</td> <mat-cell *matCellDef="let conversion"> {{conversion.sourceToken.symbol + ' ' + conversion.fromValue}} </mat-cell>
<td>{{conversion.destinationToken.symbol}}</td> </ng-container>
<td>{{conversion.toValue | currency: conversion.destinationToken.name + ' '}}</td>
<td>{{conversion.trader}}</td> <ng-container matColumnDef="finalToken">
<td> <mat-header-cell *matHeaderCellDef mat-sort-header> Final Token </mat-header-cell>
<button type="button" class="btn btn-outline-primary" (click)="viewConversion(conversion)"><i class="fa fa-eye"> VIEW </i></button></td> <mat-cell *matCellDef="let conversion"> {{conversion.destinationToken.name}} </mat-cell>
</tr> </ng-container>
</tbody>
<tfoot class="thead-dark"> <ng-container matColumnDef="finalValue">
<tr> <mat-header-cell *matHeaderCellDef mat-sort-header> Final Value </mat-header-cell>
<th scope="col">Initial Token</th> <mat-cell *matCellDef="let conversion"> {{conversion.destinationToken.symbol + ' ' + conversion.toValue}} </mat-cell>
<th scope="col">Initial Value</th> </ng-container>
<th scope="col">Final Token</th>
<th scope="col">Final Value</th> <ng-container matColumnDef="trader">
<th scope="col">Trader</th> <mat-header-cell *matHeaderCellDef mat-sort-header> Trader </mat-header-cell>
<th scope="col"></th> <mat-cell *matCellDef="let conversion" routerLink="/users/{{conversion.trader}}"> {{conversion.user?.vcard.fn}} </mat-cell>
</tr> </ng-container>
</tfoot>
</table> <ng-container matColumnDef="created">
</div> <mat-header-cell *matHeaderCellDef mat-sort-header> Created </mat-header-cell>
<mat-cell *matCellDef="let conversion"> {{conversion.tx.timestamp | date}} </mat-cell>
</ng-container>
<ng-container matColumnDef="view">
<mat-header-cell *matHeaderCellDef> View Conversion </mat-header-cell>
<mat-cell *matCellDef="let conversion">
<button mat-raised-button type="button" class="btn btn-outline-primary" (click)="viewConversion(conversion)">
<i class="fa fa-eye"> VIEW </i>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="select">
<mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle(conversionSelection, conversionDataSource) : null"
[checked]="conversionSelection.hasValue() && isAllSelected(conversionSelection, conversionDataSource)"
[indeterminate]="conversionSelection.hasValue() && !isAllSelected(conversionSelection, conversionDataSource)">
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let conversion">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? conversionSelection.toggle(conversion) : null"
[checked]="conversionSelection.isSelected(conversion)">
</mat-checkbox>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="conversionDisplayedColumns"></mat-header-row>
<mat-row *matRowDef="let conversion; columns: conversionDisplayedColumns"></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,16 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TransactionsComponent } from './transactions.component'; import { TransactionsComponent } from './transactions.component';
import {HttpClient} from '@angular/common/http';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {FooterStubComponent, SidebarStubComponent, TopbarStubComponent} from '../../../testing';
import {TransactionsModule} from './transactions.module';
import {AppModule} from '../../app.module';
describe('TransactionsComponent', () => { describe('TransactionsComponent', () => {
let component: TransactionsComponent; let component: TransactionsComponent;
let fixture: ComponentFixture<TransactionsComponent>; let fixture: ComponentFixture<TransactionsComponent>;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ TransactionsComponent ] declarations: [
TransactionsComponent,
FooterStubComponent,
SidebarStubComponent,
TopbarStubComponent
],
imports: [
AppModule,
HttpClientTestingModule,
TransactionsModule
]
}) })
.compileComponents(); .compileComponents();
httpClient = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
}); });
beforeEach(() => { beforeEach(() => {

View File

@ -1,38 +1,51 @@
import {Component, OnDestroy, OnInit} from '@angular/core'; import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {TransactionService} from '../../_services/transaction.service'; import {BlockSyncService, TransactionService} from '../../_services';
import {Conversion, Transaction} from '../../_models'; import {Conversion, Transaction} from '../../_models';
import {Subject} from 'rxjs'; import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
@Component({ @Component({
selector: 'app-transactions', selector: 'app-transactions',
templateUrl: './transactions.component.html', templateUrl: './transactions.component.html',
styleUrls: ['./transactions.component.scss'] styleUrls: ['./transactions.component.scss']
}) })
export class TransactionsComponent implements OnInit, OnDestroy { export class TransactionsComponent implements OnInit, AfterViewInit {
dtOptions: DataTables.Settings = {}; transactionDataSource: MatTableDataSource<Transaction>;
dtTrigger: Subject<any> = new Subject(); conversionDataSource: MatTableDataSource<any>;
transactions: Transaction[] = []; transactionDisplayedColumns = ['sender', 'recipient', 'token', 'value', 'created', 'view', 'select'];
conversions: Conversion[] = []; conversionDisplayedColumns = ['initialToken', 'initialValue', 'finalToken', 'finalValue', 'trader', 'created', 'view', 'select'];
initialSelection = [];
allowMultiSelect = true;
transactionSelection: SelectionModel<any>;
conversionSelection: SelectionModel<any>;
transaction: Transaction; transaction: Transaction;
conversion: Conversion; conversion: Conversion;
constructor(private transactionService: TransactionService) { } @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
ngOnInit(): void { constructor(
this.dtOptions = { private transactionService: TransactionService,
pagingType: 'full_numbers', private blockSyncService: BlockSyncService
pageLength: 5, ) {
lengthMenu: [5, 10, 25, 50, 100], this.blockSyncService.blockSync();
processing: true
};
this.transactions = this.transactionService.transactions;
this.conversions = this.transactionService.conversions;
this.dtTrigger.next();
} }
ngOnDestroy(): void { ngOnInit(): void {
this.dtTrigger.unsubscribe(); this.transactionService.transactionsSubject.subscribe(transactions => {
this.transactionDataSource = new MatTableDataSource<Transaction>(transactions);
this.transactionDataSource.paginator = this.paginator;
this.transactionDataSource.sort = this.sort;
});
this.transactionService.conversionsSubject.subscribe(conversions => {
this.conversionDataSource = new MatTableDataSource<any>(this.transactionService.conversions);
this.conversionDataSource.paginator = this.paginator;
this.conversionDataSource.sort = this.sort;
});
this.transactionSelection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
this.conversionSelection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
} }
viewTransaction(transaction): void { viewTransaction(transaction): void {
@ -42,4 +55,25 @@ export class TransactionsComponent implements OnInit, OnDestroy {
viewConversion(conversion): void { viewConversion(conversion): void {
this.conversion = conversion; this.conversion = conversion;
} }
ngAfterViewInit(): void {
this.transactionDataSource.paginator = this.paginator;
this.transactionDataSource.sort = this.sort;
this.conversionDataSource.paginator = this.paginator;
this.conversionDataSource.sort = this.sort;
}
isAllSelected(selection, dataSource): boolean {
const numSelected = selection.selected.length;
const numRows = dataSource.data.length;
return numSelected === numRows;
}
masterToggle(selection, dataSource): void {
this.isAllSelected(selection, dataSource) ? selection.clear() : dataSource.data.forEach(row => selection.select(row));
}
doFilter(value: string, dataSource): void {
dataSource.filter = value.trim().toLocaleLowerCase();
}
} }

View File

@ -7,15 +7,38 @@ import { TransactionDetailsComponent } from './transaction-details/transaction-d
import {DataTablesModule} from 'angular-datatables'; import {DataTablesModule} from 'angular-datatables';
import {SharedModule} from '../../shared/shared.module'; import {SharedModule} from '../../shared/shared.module';
import { ConversionDetailsComponent } from './conversion-details/conversion-details.component'; import { ConversionDetailsComponent } from './conversion-details/conversion-details.component';
import {MatTableModule} from '@angular/material/table';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatPaginatorModule} from '@angular/material/paginator';
import {MatSortModule} from '@angular/material/sort';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatInputModule} from '@angular/material/input';
import {MatButtonModule} from '@angular/material/button';
import {MatIconModule} from '@angular/material/icon';
import {MatSelectModule} from '@angular/material/select';
import {MatCardModule} from '@angular/material/card';
@NgModule({ @NgModule({
declarations: [TransactionsComponent, TransactionDetailsComponent, ConversionDetailsComponent], declarations: [TransactionsComponent, TransactionDetailsComponent, ConversionDetailsComponent],
exports: [
TransactionDetailsComponent
],
imports: [ imports: [
CommonModule, CommonModule,
TransactionsRoutingModule, TransactionsRoutingModule,
DataTablesModule, DataTablesModule,
SharedModule SharedModule,
MatTableModule,
MatCheckboxModule,
MatPaginatorModule,
MatSortModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
MatIconModule,
MatSelectModule,
MatCardModule
] ]
}) })
export class TransactionsModule { } export class TransactionsModule { }