Modify components to use behaviour subject.

This commit is contained in:
Spencer Ofwiti 2020-12-05 09:30:30 +03:00
parent 142654ed6d
commit f7f4fe77f6
40 changed files with 1215 additions and 669 deletions

View File

@ -38,8 +38,7 @@
"node_modules/datatables.net/js/jquery.dataTables.js",
"node_modules/bootstrap/dist/js/bootstrap.js",
"node_modules/block-syncer/dist/worker_ondemand.js"
],
"webWorkerTsConfig": "tsconfig.worker.json"
]
},
"configurations": {
"production": {
@ -139,4 +138,4 @@
}
},
"defaultProject": "cic-staff-client"
}
}

34
package-lock.json generated
View File

@ -1647,19 +1647,19 @@
}
},
"@ethereumjs/common": {
"version": "2.0.0-beta.2",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.0.0-beta.2.tgz",
"integrity": "sha512-DdzcV2iTKsfhFihR2boXEdTDqufpbHonPqp7fORsKTv9FRo5dkM8V9SF03RphSsZzYWg+KXd+eX1hYcpUjherw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.0.0.tgz",
"integrity": "sha512-yL0zA7Xwgz8IFHKW0VoXGjdZDVxUJg8BQ/muMHvYPW7zHJNNC80gQmvLH+MpvIg1TCXZkFXxrpYRAyCElSm+aw==",
"requires": {
"crc-32": "^1.2.0"
}
},
"@ethereumjs/tx": {
"version": "3.0.0-beta.2",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.0.0-beta.2.tgz",
"integrity": "sha512-NZLIVXp/OcwkhP4Z4AC742kjInMPwvixKexlQFjAWoughp+/5JZESRb171mvLQAKI4aqY9bYicadtTwCdsMuZQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.0.0.tgz",
"integrity": "sha512-H9tfy6qgYxPXvt1TSObfVmVjlF43OoQqoPQ3PJsG2JiuqaMHj5ettV1pGFEC3FamENDBkl6vD6niQEvIlXv/VQ==",
"requires": {
"@ethereumjs/common": "2.0.0-beta.2",
"@ethereumjs/common": "^2.0.0",
"ethereumjs-util": "^7.0.7"
},
"dependencies": {
@ -4376,16 +4376,16 @@
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg=="
},
"yargs": {
"version": "16.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz",
"integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz",
"integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==",
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.2",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
@ -9877,9 +9877,9 @@
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"requires": {
"ms": "^2.1.1"
}
@ -11111,9 +11111,9 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pg": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.5.0.tgz",
"integrity": "sha512-h+KHEwce67pAQilZhMCpCx1RC7rR1US7mdjwvKzHRaRxKQxbbFtv5UlwjzqILQ1dwhK+RVGqOVcahE/2KOcaeA==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz",
"integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==",
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",

View File

@ -27,7 +27,7 @@
"bootstrap": "^4.5.3",
"chart.js": "^2.9.4",
"cic-client": "^0.0.3",
"cic-client-meta": "^0.0.5",
"cic-client-meta": "0.0.5",
"datatables.net": "^1.10.22",
"datatables.net-dt": "^1.10.22",
"jquery": "^3.5.1",

View File

@ -1,5 +1,6 @@
import {Component, HostListener, OnInit} from '@angular/core';
import {BlockSyncService, TransactionService} from './_services';
import {User} from 'cic-client-meta';
@Component({
selector: 'app-root',
@ -49,6 +50,6 @@ export class AppComponent implements OnInit {
@HostListener('window:cic_convert', ['$event'])
cicConvert(event: CustomEvent): void {
const conversion = event.detail.tx;
this.transactionService.setConversion(conversion);
this.transactionService.setConversion(conversion, 100);
}
}

View File

@ -8,6 +8,7 @@ import {SharedModule} from './shared/shared.module';
import {HttpClientModule} from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {MatTableModule} from '@angular/material/table';
import {MockBackendProvider} from './_helpers';
@NgModule({
declarations: [
@ -22,7 +23,9 @@ import {MatTableModule} from '@angular/material/table';
BrowserAnimationsModule,
MatTableModule
],
providers: [],
providers: [
MockBackendProvider
],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -9,25 +9,42 @@
<div id="content">
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/accounts">Accounts</a></li>
<li class="breadcrumb-item active" aria-current="page">{{account?.name}}</li>
</ol>
</nav>
<div class="card mb-3">
<div class="row card-body">
<h3>
<mat-icon matPrefix>portrait</mat-icon>
<strong> {{account?.name}} </strong>
</h3>
<p class="ml-auto">Balance: {{account?.balance}} RCU</p>
<p class="ml-2">Created: {{account?.created}}</p>
<p class="ml-2">Address: {{account?.address}}</p>
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance}} RCU</span>
<span class="ml-2"><strong>Created:</strong> {{account?.created}}</span>
<span class="ml-2"><strong>Address:</strong> {{account?.address}}</span>
</div>
</div>
<app-disbursement *ngIf="isDisbursing"></app-disbursement>
<div class="card mt-3 mb-3">
<app-disbursement *ngIf="isDisbursing" (cancelDisbursmentEvent)="addTransfer()"></app-disbursement>
<div *ngIf="!account" class="text-center">
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
</div>
<div *ngIf="account" class="card mt-3 mb-3">
<mat-card-title class="card-header">
<div class="row">
DETAILS
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto" (click)="addTransfer()"> NEW TRANSFER </button>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-2"> SAVE </button>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto" (click)="addTransfer()"> NEW TRANSFER </button>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-2" (click)="saveInfo()"> SAVE </button>
</div>
</mat-card-title>
<div class="card-body">
@ -37,26 +54,8 @@
<mat-form-field appearance="outline">
<mat-label> STATUS </mat-label>
<mat-select id="status" [(value)]="account.status">
<mat-option value="false">Unapproved</mat-option>
<mat-option value="true">Approved</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label class="mr-3">Payment Cycle Start Date : </mat-label>
<input matInput type="text" id="startDate" placeholder="{{date}}" value="{{date}}">
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> PAYMENT CYCLE </mat-label>
<mat-select id="paymentCycle">
<mat-option value="weekly">Weekly</mat-option>
<mat-option value="daily">Daily</mat-option>
<mat-option value="monthly">Monthly</mat-option>
<mat-option value="unapproved">Unapproved</mat-option>
<mat-option value="approved">Approved</mat-option>
</mat-select>
</mat-form-field>
</div>
@ -88,6 +87,17 @@
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> USER TOKEN: </mat-label>
<mat-select id="token" [(value)]="account.token">
<mat-option value="RSV"> RESERVE </mat-option>
<mat-option value="ERN"> ERNIE </mat-option>
<mat-option value="BRT"> BERT </mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Failed Pin Attempts: </mat-label>
@ -116,7 +126,7 @@
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> BUSINESS CATEGORY: </mat-label>
<mat-select id="businessCategory">
<mat-select id="businessCategory" [(value)]="account.category">
<mat-option value="food/water">Food/Water</mat-option>
<mat-option value="fuel/energy">Fuel/Energy</mat-option>
<mat-option value="education">Education</mat-option>
@ -126,26 +136,58 @@
<mat-option value="transport">Transport</mat-option>
<mat-option value="farming/labour">Farming/Labour</mat-option>
<mat-option value="savings">Savings Group</mat-option>
<mat-option value="other">Other</mat-option>
<mat-option value="other">Savings Group</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button type="button" class="btn btn btn-outline-primary mb-3"> Add User KYC </button>
<mat-form-field appearance="outline">
<mat-label>User Location: </mat-label>
<input matInput type="text" id="userLocation" placeholder="{{account?.userLocation}}" value="{{account?.userLocation}}">
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button type="button" class="btn btn btn-outline-success mb-3"> Reset Pin </button>
<mat-form-field appearance="outline">
<mat-label> LOCATION: </mat-label>
<mat-select id="location" [(value)]="account.location">
<div *ngFor="let county of locations">
<div *ngFor="let district of county.districts">
<mat-optgroup *ngFor="let location of district.locations" [label]="county.name + ' / ' + district.name + ' / ' + location.name">
<mat-option *ngFor="let village of location.villages" [value]="village">
{{village}}
</mat-option>
</mat-optgroup>
</div>
</div>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button type="button" class="btn btn-outline-danger"> Delete User </button>
<mat-form-field appearance="outline">
<mat-label>Referred By: </mat-label>
<input matInput type="text" id="referredBy" placeholder="{{account?.referrer}}" value="{{account?.referrer}}" readonly>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button color="primary" type="button" class="btn btn btn-outline-primary mb-3"> Add User KYC </button>
</div>
<div *ngIf="account.failedPinAttempts != 0" class="col-md-6 col-lg-4">
<button mat-raised-button color="primary" type="button" class="btn btn btn-outline-success mb-3"> Reset Pin </button>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger"> Delete User </button>
</div>
</div>
</form>
</div>
</div>
<div class="card mb-3">
<mat-card-title class="card-header">
USER
@ -163,96 +205,242 @@
</tr>
</thead>
<tbody>
<tr routerLink='/users/{{account.address}}'>
<td>{{account.name}}</td>
<td>{{account.type}}</td>
<td>{{account.created}}</td>
<td><span class="badge badge-primary badge-pill">{{account.status}}</span></td>
<tr>
<td>{{account?.name}}</td>
<td>{{account?.type}}</td>
<td>{{account?.created}}</td>
<td>
<span *ngIf="account?.status === 'approved'" class="badge badge-success badge-pill"> {{account?.status}} </span>
<span *ngIf="account?.status === 'unapproved'" class="badge badge-danger badge-pill"> {{account?.status}} </span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<app-transaction-details [transaction]="transaction"></app-transaction-details>
<div class="card">
<div class="card-header">
<div class="row">
<mat-form-field appearance="outline">
<mat-label> TRANSACTION TYPE </mat-label>
<mat-select id="transferSelect">
<mat-option value="all" selected>ALL TRANSFERS</mat-option>
<mat-option value="payments">PAYMENTS</mat-option>
<mat-option value="exchange">EXCHANGE</mat-option>
<mat-option value="disbursement">DISBURSEMENT</mat-option>
<mat-option value="reclamation">RECLAMATION</mat-option>>
</mat-select>
</mat-form-field>
<p *ngIf="selection.selected.length > 0" class="ml-auto mr-3"><strong> {{selection.selected.length}} selected </strong></p>
</div>
</div>
<div class="card">
<mat-card-title class="card-header">
History
</mat-card-title>
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
<input matInput type="text" (keyup)="doHistoryFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" matSort matSortActive="sender"
matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="sender">
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.sender?.vcard.fn}} </mat-cell>
<mat-table class="mat-elevation-z10" [dataSource]="historyDataSource" matSort #HistoryTableSort="matSort"
matSortActive="sender" matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="user">
<mat-header-cell *matHeaderCellDef mat-sort-header> User </mat-header-cell>
<mat-cell *matCellDef="let history"> {{history.userName}} </mat-cell>
</ng-container>
<ng-container matColumnDef="recipient">
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.recipient?.vcard.fn}} </mat-cell>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef mat-sort-header> Action </mat-header-cell>
<mat-cell *matCellDef="let history"> {{history.action}} </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 matColumnDef="staff">
<mat-header-cell *matHeaderCellDef mat-sort-header> Staff </mat-header-cell>
<mat-cell *matCellDef="let history"> {{history.staff}} </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 matColumnDef="timestamp">
<mat-header-cell *matHeaderCellDef mat-sort-header> Timestamp </mat-header-cell>
<mat-cell *matCellDef="let history"> {{history.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() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let transaction">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(transaction) : null"
[checked]="selection.isSelected(transaction)">
</mat-checkbox>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: displayedColumns"></mat-row>
<mat-header-row *matHeaderRowDef="historyDisplayedColumns"></mat-header-row>
<mat-row *matRowDef="let history; columns: historyDisplayedColumns" matRipple></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
<mat-paginator #HistoryTablePaginator="matPaginator" [pageSize]="10"
[pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
<mat-tab-group dynamicHeight mat-align-tabs="start">
<mat-tab label="Transactions">
<app-transaction-details [transaction]="transaction"></app-transaction-details>
<div class="card mt-1">
<div class="card-header">
<div class="row">
<mat-form-field appearance="outline">
<mat-label> TRANSACTION TYPE </mat-label>
<mat-select id="transferSelect" [(value)]="transactionsType" (selectionChange)="filterTransactions()">
<mat-option value="all">ALL TRANSFERS</mat-option>
<mat-option value="transaction">PAYMENTS</mat-option>
<mat-option value="conversion">CONVERSION</mat-option>
<mat-option value="disbursements">DISBURSEMENTS</mat-option>
<mat-option value="rewards">REWARDS</mat-option>
<mat-option value="reclamation">RECLAMATION</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doTransactionFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="transactionsDataSource" matSort #TransactionTableSort="matSort"
matSortActive="created" matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="view">
<mat-header-cell *matHeaderCellDef> View </mat-header-cell>
<mat-cell *matCellDef="let transaction" (click)="viewTransaction(transaction)">
<i class="fa fa-eye"></i>
</mat-cell>
</ng-container>
<ng-container matColumnDef="sender">
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.sender?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="senderLocation">
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender Location </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{account.location}} </mat-cell>
</ng-container>
<ng-container matColumnDef="recipient">
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{transaction.recipient?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="recipientLocation">
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient Location </mat-header-cell>
<mat-cell *matCellDef="let transaction"> {{account.location}} </mat-cell>
</ng-container>
<ng-container matColumnDef="token">
<mat-header-cell *matHeaderCellDef mat-sort-header> Token </mat-header-cell>
<mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction.token.name}}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction.destinationToken.name}}</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="value">
<mat-header-cell *matHeaderCellDef mat-sort-header> Value </mat-header-cell>
<mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction.value | tokenRatio}}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction.toValue | tokenRatio}}</span>
</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="type">
<mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </mat-header-cell>
<mat-cell *matCellDef="let transaction">
<span class="badge badge-success badge-pill"> {{transaction.type}} </span>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="transactionsDisplayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: transactionsDisplayedColumns" matRipple (click)="viewTransaction(transaction)"></mat-row>
</mat-table>
<mat-paginator #TransactionTablePaginator="matPaginator" [pageSize]="10"
[pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
</mat-tab>
<mat-tab label="Users">
<div class="card mt-1">
<mat-card-title class="card-header">
Accounts
</mat-card-title>
<div class="card-body">
<div class="row card-header">
<mat-form-field appearance="outline">
<mat-label> ACCOUNT TYPE </mat-label>
<mat-select id="typeSelect" [(value)]="accountsType" (selectionChange)="filterAccounts()">
<mat-option value="all">ALL</mat-option>
<mat-option value="user">USER</mat-option>
<mat-option value="cashier">CASHIER</mat-option>
<mat-option value="vendor">VENDOR</mat-option>
<mat-option value="tokenAgent">TOKENAGENT</mat-option>
<mat-option value="group">GROUPACCOUNT</mat-option>
</mat-select>
</mat-form-field>
</div>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doUserFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="userDataSource" matSort #UserTableSort="matSort"
matSortActive="created" matSortDirection="desc" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header> PHONE NUMBER </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.phone}} </mat-cell>
</ng-container>
<ng-container matColumnDef="created">
<mat-header-cell *matHeaderCellDef mat-sort-header> CREATED </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.created}} </mat-cell>
</ng-container>
<ng-container matColumnDef="balance">
<mat-header-cell *matHeaderCellDef mat-sort-header> BALANCE </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.balance}} </mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.type}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header> STATUS </mat-header-cell>
<mat-cell *matCellDef="let user">
<span *ngIf="user.status === 'approved'" class="badge badge-success badge-pill"> {{user.status}} </span>
<span *ngIf="user.status === 'unapproved'" class="badge badge-danger badge-pill"> {{user.status}} </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="location">
<mat-header-cell *matHeaderCellDef mat-sort-header> LOCATION </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.location}} </mat-cell>
</ng-container>
<ng-container matColumnDef="failedPinAttempts">
<mat-header-cell *matHeaderCellDef mat-sort-header> FAILED PIN ATTEMPTS </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.failedPinAttempts}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef=userDisplayedColumns></mat-header-row>
<mat-row *matRowDef="let account; columns: userDisplayedColumns" (click)="viewAccount(account)" matRipple></mat-row>
</mat-table>
<mat-paginator #UserTablePaginator="matPaginator" [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
</mat-tab>
</mat-tab-group>
</div>
<app-footer appMenuSelection></app-footer>
</div>

View File

@ -1,47 +1,85 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';
import {Transaction} from '../../../_models';
import {Transaction, User} from '../../../_models';
import {SelectionModel} from '@angular/cdk/collections';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {TransactionService, UserService} from '../../../_services';
import {ActivatedRoute, Params} from '@angular/router';
import {LocationService, TransactionService, UserService} from '../../../_services';
import {ActivatedRoute, Params, Router} from '@angular/router';
import {first} from 'rxjs/operators';
@Component({
selector: 'app-account-details',
templateUrl: './account-details.component.html',
styleUrls: ['./account-details.component.scss']
})
export class AccountDetailsComponent implements OnInit, AfterViewInit {
dataSource: MatTableDataSource<Transaction>;
displayedColumns = ['sender', 'recipient', 'token', 'value', 'view', 'select'];
export class AccountDetailsComponent implements OnInit {
transactionsDataSource: MatTableDataSource<any>;
transactionsDisplayedColumns = ['view', 'sender', 'senderLocation', 'recipient', 'recipientLocation', 'token', 'value', 'created', 'type'];
@ViewChild('TransactionTablePaginator', {static: true}) transactionTablePaginator: MatPaginator;
@ViewChild('TransactionTableSort', {static: true}) transactionTableSort: MatSort;
userDataSource: MatTableDataSource<any>;
userDisplayedColumns = ['name', 'phone', 'created', 'balance', 'type', 'status', 'location', 'failedPinAttempts'];
@ViewChild('UserTablePaginator', {static: true}) userTablePaginator: MatPaginator;
@ViewChild('UserTableSort', {static: true}) userTableSort: MatSort;
historyDataSource: MatTableDataSource<any>;
historyDisplayedColumns = ['user', 'action', 'staff', 'timestamp'];
@ViewChild('HistoryTablePaginator', {static: true}) historyTablePaginator: MatPaginator;
@ViewChild('HistoryTableSort', {static: true}) historyTableSort: MatSort;
account: any;
accounts: any[] = [];
accountsType = 'all';
initialSelection = [];
allowMultiSelect = true;
selection: SelectionModel<any>;
date: string;
time: number;
isDisbursing = false;
transaction: Transaction;
account: any;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
locations: any;
transaction: any;
transactions: any[];
transactionsType = 'all';
constructor(
private locationService: LocationService,
private transactionService: TransactionService,
private userService: UserService,
private route: ActivatedRoute
private route: ActivatedRoute,
private router: Router
) {
this.route.paramMap.subscribe((params: Params) => {
this.account = this.userService.getUserById(params.get('id'));
this.userService.getAccountById(params.get('id')).pipe(first()).subscribe(account => {
this.account = account;
this.userService.getHistoryByUser(this.account?.id).pipe(first()).subscribe(history => {
this.historyDataSource = new MatTableDataSource<any>(history);
this.historyDataSource.paginator = this.historyTablePaginator;
this.historyDataSource.sort = this.historyTableSort;
});
});
});
this.userService.getAccounts();
this.locationService.getLocations();
this.locationService.locationsSubject.subscribe(locations => {
this.locations = locations;
});
}
ngOnInit(): void {
this.userService.accountsSubject.subscribe(accounts => {
this.userDataSource = new MatTableDataSource<any>(accounts);
this.userDataSource.paginator = this.userTablePaginator;
this.userDataSource.sort = this.userTableSort;
this.accounts = accounts;
});
this.transactionService.transactionsSubject.subscribe(transactions => {
this.dataSource = new MatTableDataSource<Transaction>(transactions);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
this.transactionsDataSource.paginator = this.transactionTablePaginator;
this.transactionsDataSource.sort = this.transactionTableSort;
this.transactions = transactions;
});
this.selection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
@ -49,30 +87,60 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
this.date = `${d.getDate()}/${d.getMonth()}/${d.getFullYear()}`;
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
addTransfer(): void {
this.isDisbursing = !this.isDisbursing;
}
isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
doTransactionFilter(value: string): void {
this.transactionsDataSource.filter = value.trim().toLocaleLowerCase();
}
masterToggle(): void {
this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach(row => this.selection.select(row));
doUserFilter(value: string): void {
this.userDataSource.filter = value.trim().toLocaleLowerCase();
}
doFilter(value: string): void {
this.dataSource.filter = value.trim().toLocaleLowerCase();
doHistoryFilter(value: string): void {
this.historyDataSource.filter = value.trim().toLocaleLowerCase();
}
viewTransaction(transaction): void {
this.transaction = transaction;
}
viewAccount(account): void {
(function smoothscroll(): void {
const currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
if (currentScroll > 0) {
window.requestAnimationFrame(smoothscroll);
window.scrollTo(0, currentScroll - (currentScroll / 8));
}
})();
window.scrollTo(0, 0);
document.body.scrollTop = document.documentElement.scrollTop = 0;
this.router.navigateByUrl(`/accounts/${account.id}`);
}
saveInfo(): void {}
filterAccounts(): void {
if (this.accountsType === 'all') {
this.userService.accountsSubject.subscribe(accounts => {
this.userDataSource.data = accounts;
this.accounts = accounts;
});
} else {
this.userDataSource.data = this.accounts.filter(account => account.type === this.accountsType);
}
}
filterTransactions(): void {
if (this.transactionsType === 'all') {
this.transactionService.transactionsSubject.subscribe(transactions => {
this.transactionsDataSource.data = transactions;
this.transactions = transactions;
});
} else {
this.transactionsDataSource.data = this.transactions.filter(transaction => transaction.type === this.transactionsType);
}
}
}

View File

@ -10,7 +10,12 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<app-disbursement *ngIf="isDisbursing"></app-disbursement>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Accounts</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Accounts
@ -19,29 +24,24 @@
<div *ngIf="selection.selected.length <= 0" class="row card-header">
<mat-form-field appearance="outline">
<mat-label> ACCOUNT TYPE </mat-label>
<mat-select id="typeSelect">
<mat-option value="all" selected>ALL</mat-option>
<mat-select id="typeSelect" [(value)]="accountsType" (selectionChange)="filterAccounts()">
<mat-option value="all">ALL</mat-option>
<mat-option value="user">USER</mat-option>
<mat-option value="cashier">CASHIER</mat-option>
<mat-option value="vendor">VENDOR</mat-option>
<mat-option value="tokenagent">TOKENAGENT</mat-option>
<mat-option value="groupaccount">GROUPACCOUNT</mat-option>
<mat-option value="tokenAgent">TOKENAGENT</mat-option>
<mat-option value="group">GROUPACCOUNT</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button routerLink="/accounts/create" type="button" class="btn btn-outline-secondary ml-auto">
<button mat-raised-button color="primary" routerLink="/accounts/create" type="button" class="btn btn-outline-primary ml-auto">
<mat-icon>add</mat-icon>
ADD NEW </button>
<button mat-raised-button routerLink="/accounts/export" type="button" class="btn btn-outline-secondary ml-2"> EXPORT </button>
<button mat-raised-button color="primary" routerLink="/accounts/export" type="button" class="btn btn-outline-primary ml-2"> EXPORT </button>
</div>
<div *ngIf="selection.selected.length > 0 && !isDisbursing" class="row card-header">
<div *ngIf="selection.selected.length" class="row card-header">
<p><strong> {{selection.selected.length}} selected </strong></p>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto" (click)="addTransfer()"> NEW TRANSFER </button>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-2"> APPROVE </button>
<button mat-raised-button routerLink="/accounts/export" type="button" class="btn btn-outline-secondary ml-2"> EXPORT </button>
</div>
<div *ngIf="selection.selected.length > 0 && isDisbursing" class="row card-header">
<p><strong> {{selection.selected.length}} selected </strong></p>
<button mat-raised-button routerLink="/accounts/export" type="button" class="btn btn-outline-secondary ml-auto"> EXPORT </button>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto" (click)="approveAccount()"> APPROVE </button>
<button mat-raised-button color="primary" routerLink="/accounts/export" type="button" class="btn btn-outline-primary ml-2"> EXPORT </button>
</div>
<mat-form-field appearance="outline">
@ -72,9 +72,22 @@
<mat-cell *matCellDef="let user"> {{user.balance}} </mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.type}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header> STATUS </mat-header-cell>
<mat-cell *matCellDef="let user"><span class="badge badge-primary badge-pill"> {{user.status}} </span></mat-cell>
<mat-cell *matCellDef="let user">
<span *ngIf="user.status === 'approved'" class="badge badge-success badge-pill"> {{user.status}} </span>
<span *ngIf="user.status === 'unapproved'" class="badge badge-danger badge-pill"> {{user.status}} </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="location">
<mat-header-cell *matHeaderCellDef mat-sort-header> LOCATION </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.location}} </mat-cell>
</ng-container>
<ng-container matColumnDef="failedPinAttempts">
@ -98,7 +111,7 @@
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let account; columns: displayedColumns" (click)="viewAccount(account)"></mat-row>
<mat-row *matRowDef="let account; columns: displayedColumns" (click)="viewAccount(account)" matRipple></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>

View File

@ -1,4 +1,4 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {MatPaginator} from '@angular/material/paginator';
@ -11,13 +11,14 @@ import {Router} from '@angular/router';
templateUrl: './accounts.component.html',
styleUrls: ['./accounts.component.scss']
})
export class AccountsComponent implements OnInit, AfterViewInit{
export class AccountsComponent implements OnInit {
dataSource: MatTableDataSource<any>;
displayedColumns = ['name', 'phone', 'created', 'balance', 'status', 'failedPinAttempts', 'select'];
accounts: any[] = [];
displayedColumns = ['name', 'phone', 'created', 'balance', 'type', 'status', 'location', 'failedPinAttempts', 'select'];
initialSelection = [];
allowMultiSelect = true;
selection: SelectionModel<any>;
isDisbursing = false;
accountsType = 'all';
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ -25,22 +26,20 @@ export class AccountsComponent implements OnInit, AfterViewInit{
constructor(
private userService: UserService,
private router: Router
) { }
) {
this.userService.getAccounts();
}
ngOnInit(): void {
this.dataSource = new MatTableDataSource<any>(this.userService.users);
this.userService.accountsSubject.subscribe(accounts => {
this.dataSource = new MatTableDataSource<any>(accounts);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.accounts = accounts;
});
this.selection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
}
addTransfer(): void {
this.isDisbursing = true;
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
@ -56,6 +55,23 @@ export class AccountsComponent implements OnInit, AfterViewInit{
}
viewAccount(account): void {
this.router.navigateByUrl(`/accounts/${account.id}`);
this.router.navigateByUrl(`/accounts/${account.id}`).then();
}
approveAccount(): void {
for (const account of this.selection.selected) {
account.status = 'approved';
}
}
filterAccounts(): void {
if (this.accountsType === 'all') {
this.userService.accountsSubject.subscribe(accounts => {
this.dataSource.data = accounts;
this.accounts = accounts;
});
} else {
this.dataSource.data = this.accounts.filter(account => account.type === this.accountsType);
}
}
}

View File

@ -20,26 +20,32 @@ import {MatCardModule} from '@angular/material/card';
import {MatIconModule} from '@angular/material/icon';
import {MatSelectModule} from '@angular/material/select';
import {TransactionsModule} from '../transactions/transactions.module';
import {MatTabsModule} from '@angular/material/tabs';
import {MatRippleModule} from '@angular/material/core';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
@NgModule({
declarations: [AccountsComponent, AccountDetailsComponent, CreateAccountComponent, DisbursementComponent, ExportAccountsComponent],
imports: [
CommonModule,
AccountsRoutingModule,
SharedModule,
DataTablesModule,
MatTableModule,
MatSortModule,
MatCheckboxModule,
MatPaginatorModule,
MatInputModule,
MatFormFieldModule,
MatButtonModule,
MatCardModule,
MatIconModule,
MatSelectModule,
TransactionsModule
]
imports: [
CommonModule,
AccountsRoutingModule,
SharedModule,
DataTablesModule,
MatTableModule,
MatSortModule,
MatCheckboxModule,
MatPaginatorModule,
MatInputModule,
MatFormFieldModule,
MatButtonModule,
MatCardModule,
MatIconModule,
MatSelectModule,
TransactionsModule,
MatTabsModule,
MatRippleModule,
MatProgressSpinnerModule
]
})
export class AccountsModule { }

View File

@ -10,6 +10,13 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/accounts">Accounts</a></li>
<li class="breadcrumb-item active" aria-current="page">Create Account</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header text-center">
CREATE A USER ACCOUNT
@ -23,8 +30,8 @@
<mat-option value="user">USER</mat-option>
<mat-option value="cashier">CASHIER</mat-option>
<mat-option value="vendor">VENDOR</mat-option>
<mat-option value="tokenagent">TOKENAGENT</mat-option>
<mat-option value="groupaccount">GROUPACCOUNT</mat-option>
<mat-option value="tokenAgent">TOKENAGENT</mat-option>
<mat-option value="group">GROUPACCOUNT</mat-option>
</mat-select>
</mat-form-field><br>
</div>
@ -107,7 +114,7 @@
</mat-form-field>
</div>
<button mat-raised-button type="submit" class="btn btn-outline-primary ml-3">Submit</button>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-3" (click)="onSubmit()">Submit</button>
</form>
</div>
</div>

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import {Router} from '@angular/router';
@Component({
selector: 'app-create-account',
@ -7,9 +8,14 @@ import { Component, OnInit } from '@angular/core';
})
export class CreateAccountComponent implements OnInit {
constructor() { }
constructor(
private router: Router
) { }
ngOnInit(): void {
}
onSubmit(): void {
this.router.navigateByUrl(`/accounts`);
}
}

View File

@ -1,12 +1,15 @@
<div class="card">
<div class="card-header">
NEW TRANSFER
</div>
<mat-card-title class="card-header">
<div class="row">
NEW TRANSFER
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger ml-auto mr-2" (click)="cancel()"> CANCEL </button>
</div>
</mat-card-title>
<div class="card-body">
<form>
<div class="row">
<div class="row form-inline">
<mat-form-field appearance="outline">
<mat-label> ACCOUNT TYPE </mat-label>
<mat-label> TRANSACTION TYPE </mat-label>
<mat-select id="accountType">
<mat-option value="disbursement">DISBURSEMENT</mat-option>
<mat-option value="transfer">TRANSFER</mat-option>
@ -14,14 +17,13 @@
<mat-option value="reclamation">RECLAMATION</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2"> CANCEL </button>
</div>
<div class="row form-inline">
<mat-form-field appearance="outline">
<mat-form-field appearance="outline" class="ml-3">
<mat-label>Enter Amount: </mat-label>
<input matInput type="text" id="amount" placeholder="Amount">
</mat-form-field>
<button mat-raised-button type="submit" class="btn btn-outline-primary ml-3" >CREATE TRANSFER </button>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-3" style="margin-bottom: 1.2rem;" (click)="createTransfer()">
CREATE TRANSFER
</button>
</div>
</form>
</div>

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit, EventEmitter, Output} from '@angular/core';
@Component({
selector: 'app-disbursement',
@ -6,10 +6,16 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./disbursement.component.scss']
})
export class DisbursementComponent implements OnInit {
@Output() cancelDisbursmentEvent = new EventEmitter();
constructor() { }
ngOnInit(): void {
}
createTransfer(): void {}
cancel(): void {
this.cancelDisbursmentEvent.emit();
}
}

View File

@ -10,6 +10,13 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/accounts">Accounts</a></li>
<li class="breadcrumb-item active" aria-current="page">Export Accounts</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
EXPORT ACCOUNTS
@ -32,7 +39,7 @@
<mat-checkbox id="transfers"></mat-checkbox>
</div>
</div>
<button mat-raised-button type="submit" class="btn btn-outline-primary"> EXPORT </button>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary"> EXPORT </button>
</form>
</div>
</div>

View File

@ -10,6 +10,12 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Admin</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Actions
@ -22,37 +28,65 @@
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" matSort matSortActive="user"
matSortDirection="asc" matSortDisableClear>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" multiTemplateDataRows>
<!-- Expand Column -->
<ng-container matColumnDef="expand">
<mat-header-cell *matHeaderCellDef> Expand </mat-header-cell>
<mat-cell *matCellDef="let element" (click)="expandCollapse(element)">
<span *ngIf="!element.isExpanded" class="signs"> + </span>
<span *ngIf="element.isExpanded" class="signs"> - </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="user">
<mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
<mat-header-cell *matHeaderCellDef> NAME </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.user}} </mat-cell>
</ng-container>
<ng-container matColumnDef="role">
<mat-header-cell *matHeaderCellDef mat-sort-header> ROLE </mat-header-cell>
<mat-header-cell *matHeaderCellDef> ROLE </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.role}} </mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef mat-sort-header> ACTION </mat-header-cell>
<mat-header-cell *matHeaderCellDef> ACTION </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.action}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header> STATUS </mat-header-cell>
<mat-cell *matCellDef="let action"><span class="badge badge-primary badge-pill"> {{approvalStatus(action.approval)}} </span></mat-cell>
<mat-header-cell *matHeaderCellDef> STATUS </mat-header-cell>
<mat-cell *matCellDef="let action">
<span *ngIf="action.approval == true" class="badge badge-success badge-pill"> {{approvalStatus(action.approval)}} </span>
<span *ngIf="action.approval == false" class="badge badge-danger badge-pill"> {{approvalStatus(action.approval)}} </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="approve">
<mat-header-cell *matHeaderCellDef> APPROVE </mat-header-cell>
<mat-cell *matCellDef="let action">
<button mat-raised-button *ngIf="!action.approval" class="btn btn-outline-primary" (click)="approveAction(action)"> Approve </button>
<button mat-raised-button color="primary" *ngIf="!action.approval" class="btn btn-outline-success" (click)="approveAction(action)"> Approve </button>
<button mat-raised-button color="warn" *ngIf="action.approval" class="btn btn-outline-danger" (click)="revertAction(action)"> Revert </button>
</mat-cell>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column -->
<ng-container matColumnDef="expandedDetail">
<mat-cell *matCellDef="let action">
<div>
<span><strong>Staff Name:</strong> {{action.user}}</span><br>
<span><strong>Role:</strong> {{action.role}}</span><br>
<span><strong>Action Details:</strong> {{action.action}}</span><br>
<span><strong>Approval Status:</strong> {{action.approval}}</span><br>
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let action; columns: displayedColumns"></mat-row>
<mat-row *matRowDef="let row; columns: displayedColumns;" matRipple class="element-row"
[class.expanded]="row.isExpanded"></mat-row>
<mat-row *matRowDef="let row; columns: ['expandedDetail'];"
[@detailExpand]="row.isExpanded == true ? 'expanded': 'collapsed'" style="overflow: hidden"></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>

View File

@ -0,0 +1,3 @@
button {
width: 6rem;
}

View File

@ -1,32 +1,43 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {UserService} from '../../_services';
import {animate, state, style, transition, trigger} from '@angular/animations';
import {first} from 'rxjs/operators';
@Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.scss']
styleUrls: ['./admin.component.scss'],
animations: [
trigger('detailExpand', [
state('collapsed', style({height: '0px', minHeight: 0, visibility: 'hidden'})),
state('expanded', style({height: '*', visibility: 'visible'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
])
]
})
export class AdminComponent implements OnInit, AfterViewInit {
export class AdminComponent implements OnInit {
dataSource: MatTableDataSource<any>;
displayedColumns = ['user', 'role', 'action', 'status', 'approve'];
displayedColumns = ['expand', 'user', 'role', 'action', 'status', 'approve'];
action: any;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
private userService: UserService
) { }
ngOnInit(): void {
this.dataSource = new MatTableDataSource<any>(this.userService.actions);
) {
this.userService.getActions();
this.userService.actionsSubject.subscribe(actions => {
this.dataSource = new MatTableDataSource<any>(actions);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
ngOnInit(): void {
}
doFilter(value: string): void {
@ -38,6 +49,16 @@ export class AdminComponent implements OnInit, AfterViewInit {
}
approveAction(action: any): void {
this.userService.approveAction(action.id);
this.userService.approveAction(action.id).pipe(first()).subscribe(res => console.log(res));
this.userService.getActions();
}
revertAction(action: any): void {
this.userService.revokeAction(action.id).pipe(first()).subscribe(res => console.log(res));
this.userService.getActions();
}
expandCollapse(row): void {
row.isExpanded = !row.isExpanded;
}
}

View File

@ -12,22 +12,24 @@ import {MatTableModule} from '@angular/material/table';
import {MatSortModule} from '@angular/material/sort';
import {MatPaginatorModule} from '@angular/material/paginator';
import {MatButtonModule} from '@angular/material/button';
import {MatRippleModule} from '@angular/material/core';
@NgModule({
declarations: [AdminComponent],
imports: [
CommonModule,
AdminRoutingModule,
SharedModule,
MatCardModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatPaginatorModule,
MatButtonModule
]
imports: [
CommonModule,
AdminRoutingModule,
SharedModule,
MatCardModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatPaginatorModule,
MatButtonModule,
MatRippleModule
]
})
export class AdminModule { }

View File

@ -6,7 +6,6 @@ import { PagesComponent } from './pages.component';
const routes: Routes = [
{ path: 'home', component: PagesComponent },
{ path: 'tx', loadChildren: () => import('./transactions/transactions.module').then(m => m.TransactionsModule) },
{ path: 'users', loadChildren: () => import('./users/users.module').then(m => m.UsersModule) },
{ path: 'settings', loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule) },
{ path: 'accounts', loadChildren: () => import('./accounts/accounts.module').then(m => m.AccountsModule) },
{ path: 'tokens', loadChildren: () => import('./tokens/tokens.module').then(m => m.TokensModule) },

View File

@ -10,83 +10,99 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<div class="card col-12">
<div class="card-header">
<form class="form-inline">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page">Home</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
CICADA DASHBOARD
</mat-card-title>
<div class="col-12">
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label>Filter by user : </mat-label>
<mat-label>Filter by location : </mat-label>
<mat-select class="ml-2" id="filterUser">
<mat-option value="default">SELECT ATTRIBUTE</mat-option>
<mat-option value="2">2</mat-option>
<mat-option value="3">3</mat-option>
<mat-option value="4">4</mat-option>
<mat-option value="5">5</mat-option>
<div *ngFor="let county of locations">
<div *ngFor="let district of county.districts">
<mat-optgroup *ngFor="let location of district.locations" [label]="county.name + ' / ' + district.name + ' / ' + location.name">
<mat-option *ngFor="let village of location.villages" [value]="village">
{{village}}
</mat-option>
</mat-optgroup>
</div>
</div>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="ml-auto">
<mat-label>Filter by Date</mat-label>
<input matInput type="text" id="filterDate" placeholder="Date">
</mat-form-field>
<button mat-raised-button type="submit" class="btn btn-outline-secondary ml-3"> FILTER </button>
</form>
</div>
<div class="row">
<div class="card col-md-8">
<div class="card-body">
<div style="display: block">
<canvas baseChart
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[colors]="lineChartColors"
[legend]="lineChartLegend"
[chartType]="lineChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)">
</canvas>
</div>
</div>
<hr>
<div class="card-body row">
<div class="col-md-3 text-center">
<h4>MASTER WALLET BALANCE</h4>
<p>{{10000000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL DISTRIBUTED</h4>
<p>{{disbursements * 1000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL SPENT</h4>
<p>{{transactions * 100000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL USERS</h4>
<p>{{users * 10 | number}} users</p>
</div>
</div>
<hr>
<div class="card-body">
<div style="display: block">
<canvas baseChart
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[legend]="barChartLegend"
[chartType]="barChartType">
</canvas>
</div>
</div>
</div>
<div class="card col-md-4">
<div class="card-body text-center">
<h4>TRANSFER USAGES</h4>
<p>Transfer Usages Will Appear Here</p>
<div class="row">
<div class="card col-md-8">
<div class="card-body">
<div style="display: block">
<canvas baseChart
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[colors]="lineChartColors"
[legend]="lineChartLegend"
[chartType]="lineChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)">
</canvas>
</div>
</div>
<hr>
<div class="card-body row">
<div class="col-md-3 text-center">
<h4>MASTER WALLET BALANCE</h4>
<p>{{10000000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL DISTRIBUTED</h4>
<p>{{disbursements * 1000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL SPENT</h4>
<p>{{transactions * 100000 | number}} RCU</p>
</div>
<div class="col-md-3 text-center">
<h4>TOTAL USERS</h4>
<p>{{users * 10 | number}} users</p>
</div>
</div>
<hr>
<div class="card-body">
<div style="display: block">
<canvas baseChart
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[legend]="barChartLegend"
[chartType]="barChartType">
</canvas>
</div>
</div>
</div>
<hr>
<div class="card-body">
<h4 class="text-center">PARTNER LIVE FEED</h4>
<div class="card col-md-4">
<div class="card-body text-center">
<h4>TRANSFER USAGES</h4>
<div style="display: block">
<canvas baseChart
[data]="transferUsagesChartData"
[labels]="transferUsagesChartLabels"
[options]="transferUsagesChartOptions"
[colors]="transferUsagesChartColors"
[legend]="transferUsagesChartLegend"
[chartType]="transferUsagesChartType">
</canvas>
</div>
</div>
<hr>
<div class="card-body">
<h4 class="text-center">PARTNER LIVE FEED</h4>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core';
import {Color, Label} from 'ng2-charts';
import {ChartDataSets, ChartOptions, ChartType} from 'chart.js';
import {LocationService, UserService} from '../_services';
import { ArraySum } from '../_helpers';
@Component({
selector: 'app-pages',
@ -9,7 +11,8 @@ import {ChartDataSets, ChartOptions, ChartType} from 'chart.js';
})
export class PagesComponent implements OnInit {
disbursements: number = 0;
users: number = 0;
users: any;
locations: any;
transactions: number = 0;
public lineChartData: ChartDataSets[] = [
{ data: [65, 59, 80, 81, 56, 55, 40], label: 'User Registration'},
@ -109,16 +112,57 @@ export class PagesComponent implements OnInit {
{ data: [28, 48, 40, 19, 86, 27, 90], label: 'Recurrent Users'}
];
constructor() { }
public transferUsagesChartLabels: Label[] = ['Food/Water', 'Fuel/Energy', 'Education', 'Health', 'Shop', 'Environment', 'Transport',
'Farming/Labour', 'Savings Group', 'Savings Group'];
public transferUsagesChartData: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
public transferUsagesChartType: ChartType = 'pie';
public transferUsagesChartOptions: ChartOptions = {
responsive: true,
legend: {
position: 'top',
},
plugins: {
datalabels: {
formatter: (value, ctx) => {
const label = ctx.chart.data.labels[ctx.dataIndex];
return label;
},
},
}
};
public transferUsagesChartLegend = true;
public transferUsagesChartColors = [
{
backgroundColor: [
'rgba(0,0,255,0.3)',
'rgba(255,0,0,0.3)',
'rgba(0,255,0,0.3)',
'rgba(255,0,255,0.3)',
'rgba(255,255,0,0.3)',
'rgba(0,255,255,0.3)',
'rgba(255,255,255,0.3)',
'rgba(255,100,0,0.3)',
'rgba(0,255,100,0.3)',
'rgba(100,0,255,0.3)'],
},
];
constructor(
private userService: UserService,
private locationService: LocationService
) {
this.locationService.getLocations();
this.locationService.locationsSubject.subscribe(locations => {
this.locations = locations;
});
}
ngOnInit(): void {
this.newDataPoint([50, 80], 'August');
// this.disbursements = this.lineChartData.find(data => data.label === 'Token Disbursements')
// .data.reduce((accumulator, current) => accumulator + current, 0);
// this.users = this.barChartData.find(data => data.label === 'New Users')
// .data.reduce((accumulator, current) => accumulator + current, 0);
// this.transactions = this.lineChartData.find(data => data.label === 'Transaction Volumes')
// .data.reduce((accumulator, current) => accumulator + current, 0);
this.transferUsagesChartData = [18, 12, 10, 8, 6, 5, 5, 3, 2, 1];
this.disbursements = ArraySum.arraySum(this.lineChartData.find(data => data.label === 'Token Disbursements').data);
this.users = ArraySum.arraySum(this.barChartData.find(data => data.label === 'New Users').data);
this.transactions = ArraySum.arraySum(this.lineChartData.find(data => data.label === 'Transaction Volumes').data);
}
newDataPoint(dataArr: any[], label: string): void {

View File

@ -9,19 +9,21 @@ import {MatButtonModule} from '@angular/material/button';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatInputModule} from '@angular/material/input';
import {MatCardModule} from '@angular/material/card';
@NgModule({
declarations: [PagesComponent],
imports: [
CommonModule,
PagesRoutingModule,
SharedModule,
ChartsModule,
MatButtonModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule
]
imports: [
CommonModule,
PagesRoutingModule,
SharedModule,
ChartsModule,
MatButtonModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
MatCardModule
]
})
export class PagesModule { }

View File

@ -10,6 +10,13 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/settings">Settings</a></li>
<li class="breadcrumb-item active" aria-current="page">Invite User</li>
</ol>
</nav>
<div class="col-md-6">
<div class="card">
<mat-card-title class="card-header text-center">
@ -27,7 +34,7 @@
<mat-radio-button value="Subadmin">Subadmin</mat-radio-button><br>
<mat-radio-button value="View">View</mat-radio-button><br>
</mat-radio-group>
<button mat-raised-button type="submit" class="btn btn-outline-primary">INVITE</button>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary">INVITE</button>
</form>
</div>
</div>

View File

@ -10,7 +10,14 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<div class="col-md-6">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/settings">Settings</a></li>
<li class="breadcrumb-item active" aria-current="page">Organization Settings</li>
</ol>
</nav>
<div class="col-md-6 center-body">
<div class="card">
<mat-card-title class="card-header text-center">
DEFAULT ORGANISATION SETTINGS
@ -35,7 +42,7 @@
<mat-option value="UG">UG Uganda</mat-option>
</mat-select>
</mat-form-field><br>
<button mat-raised-button type="submit" class="btn btn-primary">Submit</button>
<button mat-raised-button color="primary" type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>

View File

@ -10,114 +10,112 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Settings</li>
</ol>
</nav>
<div class="row">
<div class="col-md-6 mb-2">
<div class="card">
<div class="card-header text-center">
<mat-card-title class="card-header text-center">
SETTINGS
</div>
</mat-card-title>
<div class="card-body">
<h4>Kobo Toolbox Credentials</h4>
<p><strong>Username: </strong> admin_reserve </p>
<p><strong>Password: </strong> p@55w0rd </p>
</div>
<hr>
<div class="card-body">
<h4>Account Status: </h4>
<span><i class="fa fa-check-circle"></i> Please contact support.</span>
</div>
<hr>
<div class="card-body">
<h4>Support</h4>
<span><i class="fa fa-commenting"></i> Chat</span><br>
<span><i class="fa fa-book"></i> Help Center</span>
<span><strong>Username: </strong> admin_reserve </span><br>
<span><strong>Password: </strong> ******** </span>
</div>
<hr>
<div class="card-body">
<h4>Organization Settings</h4>
<p routerLink="/settings/organization"><i>Update your organization settings</i></p>
<a routerLink="/settings/organization"><i>Update your organization settings</i></a>
</div>
</div>
</div>
<div class="col-md-6 mb-2">
<div class="card">
<div class="card-header text-center">
<mat-card-title class="card-header text-center">
ACCOUNT MANAGEMENT
</div>
</mat-card-title>
<div class="card-body">
<h4>Change Password</h4>
<p><i>Change your account password</i></p>
<a routerLink="/settings"><i>Change your account password</i></a>
</div>
<hr>
<div class="card-body">
<h4>Two-step authentication</h4>
<p><i>Secure your account with two step verification</i></p>
<a routerLink="/settings"><i>Secure your account with two step verification</i></a>
</div>
<hr>
<div class="card-body">
<button mat-raised-button type="button" class="btn btn-outline-primary"> LOGOUT ADMIN </button>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary"> LOGOUT ADMIN </button>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="card mb-3">
<div class="card-header">
<div class="row">
USERS
<button mat-raised-button routerLink="/settings/invite" type="button" class="btn btn-outline-primary ml-auto"><i class="fa fa-plus"> NEW USER </i></button>
<div class="col-12">
<div class="card mb-3">
<mat-card-title class="card-header">
<div class="row">
USERS
<button mat-raised-button color="primary" routerLink="/settings/invite" type="button" class="btn btn-outline-primary ml-auto"><i class="fa fa-plus"> NEW USER </i></button>
</div>
</mat-card-title>
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" matSort matSortActive="name"
matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="accountType">
<mat-header-cell *matHeaderCellDef mat-sort-header> ACCOUNT TYPE </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.accountType}} </mat-cell>
</ng-container>
<ng-container matColumnDef="created">
<mat-header-cell *matHeaderCellDef mat-sort-header> CREATED </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.created}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header> STATUS </mat-header-cell>
<mat-cell *matCellDef="let user">
<span *ngIf="user.status === 'activated'" class="badge badge-success badge-pill"> {{user.status}} </span>
<span *ngIf="user.status === 'deactivated'" class="badge badge-danger badge-pill"> {{user.status}} </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="options">
<mat-header-cell *matHeaderCellDef> OPTIONS </mat-header-cell>
<mat-cell *matCellDef="let user" class="dropdown">
<button mat-raised-button color="warn" [matMenuTriggerFor]="menu" class="btn btn-outline-danger ml-1"><i class="fa fa-ellipsis-h"></i></button>
<mat-menu #menu='matMenu'>
<button mat-menu-item (click)="changeStaffType(user.id, 'SuperAdmin')">Change to Super Admin</button>
<button mat-menu-item (click)="changeStaffType(user.id, 'Admin')">Change to Admin</button>
<button mat-menu-item (click)="changeStaffType(user.id, 'Enroller')">Change to Enroller</button>
<button mat-menu-item (click)="changeStaffType(user.id, 'View')">Change to View Only</button>
<button *ngIf="user.status === 'activated'" mat-menu-item (click)="deactivateStaff(user.id)">Deactivate User</button>
<button *ngIf="user.status === 'deactivated'" mat-menu-item (click)="activateStaff(user.id)">Activate User</button>
</mat-menu>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator [pageSize]="5" [pageSizeOptions]="[5, 10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" matSort matSortActive="name"
matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="accountType">
<mat-header-cell *matHeaderCellDef mat-sort-header> ACCOUNT TYPE </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.accountType}} </mat-cell>
</ng-container>
<ng-container matColumnDef="created">
<mat-header-cell *matHeaderCellDef mat-sort-header> CREATED </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.created}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header> STATUS </mat-header-cell>
<mat-cell *matCellDef="let user"><span class="badge badge-primary badge-pill"> {{user.status}} </span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="options">
<mat-header-cell *matHeaderCellDef> </mat-header-cell>
<mat-cell *matCellDef="let user" class="dropdown">
<button mat-raised-button [matMenuTriggerFor]="menu" class="btn btn-outline-danger ml-1"><i class="fa fa-ellipsis-h"></i></button>
<mat-menu #menu='matMenu'>
<button mat-menu-item>Change to Super Admin</button>
<button mat-menu-item>Change to Admin</button>
<button mat-menu-item>Change to Enroller</button>
<button mat-menu-item>Change to View Only</button>
<button mat-menu-item>Disable User</button>
</mat-menu>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator [pageSize]="5" [pageSizeOptions]="[5, 10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
</div>
</div>

View File

@ -1,17 +1,16 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {UserService} from '../../_services';
import {first} from 'rxjs/operators';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit, AfterViewInit {
data = [
{ name: 'admin@acme.org', accountType: 'Admin', created: '17/11/2020', status: 'activated'}
];
export class SettingsComponent implements OnInit {
date: string;
dataSource: MatTableDataSource<any>;
displayedColumns = ['name', 'accountType', 'created', 'status', 'options'];
@ -19,20 +18,38 @@ export class SettingsComponent implements OnInit, AfterViewInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor() { }
ngOnInit(): void {
this.dataSource = new MatTableDataSource<any>(this.data);
const d = new Date();
this.date = `${d.getDate()}/${d.getMonth()}/${d.getFullYear()}`;
constructor(
private userService: UserService
) {
this.userService.getStaff();
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
ngOnInit(): void {
this.userService.staffSubject.subscribe(staff => {
this.dataSource = new MatTableDataSource<any>(staff);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
const d = new Date();
this.date = `${d.getDate()}/${d.getMonth()}/${d.getFullYear()}`;
}
doFilter(value: string): void {
this.dataSource.filter = value.trim().toLocaleLowerCase();
}
activateStaff(id: string): void {
this.userService.activateStaff(id).pipe(first()).subscribe(res => console.log(res));
this.userService.getStaff();
}
deactivateStaff(id: string): void {
this.userService.deactivateStaff(id).pipe(first()).subscribe(res => console.log(res));
this.userService.getStaff();
}
changeStaffType(id: string, type: string): void {
this.userService.changeStaffType(id, type).pipe(first()).subscribe(res => console.log(res));
this.userService.getStaff();
}
}

View File

@ -9,19 +9,43 @@
<div id="content">
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<div class="col-md-4">
<div class="container-fluid text-center" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/tokens">Tokens</a></li>
<li class="breadcrumb-item active" aria-current="page">{{token.name}}</li>
</ol>
</nav>
<div class="col-md-6 center-body">
<div class="card">
<mat-card-title class="card-header">
Token
</mat-card-title>
<div class="card-body">
<div>
<p>Name: {{token.name}}</p>
<p>Symbol: {{token.symbol}}</p>
<p>Details: A community inclusive currency for trading among lower to middle income societies.</p>
<p>Supply: 100000000</p>
<p>Circulation: 57000000</p>
<span><strong>Name:</strong> {{token.name}}</span>
</div>
<div>
<span><strong>Symbol:</strong> {{token.symbol}}</span>
</div>
<div>
<span><strong>Address:</strong> {{token.address}}</span>
</div>
<div>
<span><strong>Details:</strong> A community inclusive currency for trading among lower to middle income societies.</span>
</div>
<div>
<span><strong>Supply:</strong> {{token.supply | tokenRatio}}</span>
</div><br>
<div>
<h2>Reserve</h2>
<div>
<span><strong>Weight:</strong> {{token.reserveRatio}}</span>
</div>
<div>
<span><strong>Owner:</strong> {{token.owner}}</span>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute, Params} from '@angular/router';
import {TokenService} from '../../../_services';
import {first} from 'rxjs/operators';
@Component({
selector: 'app-token-details',
@ -15,7 +16,9 @@ export class TokenDetailsComponent implements OnInit {
private tokenService: TokenService
) {
this.route.paramMap.subscribe((params: Params) => {
this.token = this.tokenService.getBySymbol(params.get('id'));
this.tokenService.getTokenBySymbol(params.get('id')).pipe(first()).subscribe(token => {
this.token = token;
});
});
}

View File

@ -10,42 +10,51 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="dataSource" matSort matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.name}} </mat-cell>
</ng-container>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Tokens</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Tokens
</mat-card-title>
<div class="card-body">
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<ng-container matColumnDef="symbol">
<mat-header-cell *matHeaderCellDef mat-sort-header> Symbol </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.symbol}} </mat-cell>
</ng-container>
<mat-table class="mat-elevation-z10 table-responsive" [dataSource]="dataSource" matSort matSortDirection="asc" matSortDisableClear>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="select">
<mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected">
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let token">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(token) : null"
[checked]="selection.isSelected(token)">
</mat-checkbox>
</mat-cell>
</ng-container>
<ng-container matColumnDef="symbol">
<mat-header-cell *matHeaderCellDef mat-sort-header> Symbol </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.symbol}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columnsToDisplay"></mat-header-row>
<mat-row *matRowDef="let token; columns: columnsToDisplay" (click)="viewToken(token)"></mat-row>
</mat-table>
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef mat-sort-header> Address </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.address}} </mat-cell>
</ng-container>
<mat-paginator [pageSize]="3" [pageSizeOptions]="[3, 5, 10]" showFirstLastButtons></mat-paginator>
<ng-container matColumnDef="supply">
<mat-header-cell *matHeaderCellDef mat-sort-header> Supply </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.supply | tokenRatio}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columnsToDisplay"></mat-header-row>
<mat-row *matRowDef="let token; columns: columnsToDisplay" (click)="viewToken(token)" matRipple></mat-row>
</mat-table>
<mat-paginator [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
</div>
<app-footer appMenuSelection></app-footer>
</div>

View File

@ -1,9 +1,8 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {TokenService} from '../../_services';
import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {Router} from '@angular/router';
@Component({
@ -11,39 +10,25 @@ import {Router} from '@angular/router';
templateUrl: './tokens.component.html',
styleUrls: ['./tokens.component.scss']
})
export class TokensComponent implements OnInit, AfterViewInit {
export class TokensComponent implements OnInit {
dataSource: MatTableDataSource<any>;
columnsToDisplay = ['name', 'symbol', 'select'];
initialSelection = [];
allowMultiSelect = true;
selection: SelectionModel<any>;
columnsToDisplay = ['name', 'symbol', 'address', 'supply'];
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
private tokenService: TokenService,
private router: Router
) { }
) {
tokenService.getTokens();
}
ngOnInit(): void {
this.dataSource = new MatTableDataSource(this.tokenService.data);
this.selection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
}
masterToggle(): void {
this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach(row => this.selection.select(row));
this.tokenService.tokensSubject.subscribe(tokens => {
this.dataSource = new MatTableDataSource(tokens);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
doFilter(value: string): void {

View File

@ -8,7 +8,7 @@ import {SharedModule} from '../../shared/shared.module';
import {MatTableModule} from '@angular/material/table';
import {MatPaginatorModule} from '@angular/material/paginator';
import {MatSortModule} from '@angular/material/sort';
import {MatPseudoCheckboxModule} from '@angular/material/core';
import {MatPseudoCheckboxModule, MatRippleModule} from '@angular/material/core';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
@ -21,22 +21,23 @@ import {MatCardModule} from '@angular/material/card';
@NgModule({
declarations: [TokensComponent, TokenDetailsComponent],
imports: [
CommonModule,
TokensRoutingModule,
SharedModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatPseudoCheckboxModule,
MatCheckboxModule,
MatInputModule,
MatFormFieldModule,
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatToolbarModule,
MatCardModule
]
imports: [
CommonModule,
TokensRoutingModule,
SharedModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatPseudoCheckboxModule,
MatCheckboxModule,
MatInputModule,
MatFormFieldModule,
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatToolbarModule,
MatCardModule,
MatRippleModule
]
})
export class TokensModule { }

View File

@ -1,37 +1,40 @@
<div *ngIf="transaction" class="mb-5">
<div *ngIf="transaction" class="mb-3 mt-1">
<div class="card text-center">
<div class="card-header bg-dark text-white">
<strong>TRANSACTION DETAILS</strong>
</div>
<div class="card-body">
<mat-card-title class="card-header">
<div class="row">
TRANSACTION DETAILS
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2" (click)="transaction = null"> CLOSE </button>
</div>
</mat-card-title>
<div *ngIf="transaction.type == 'transaction'" class="card-body">
<div class="row">
<div class="col-md-6">
<h4>Exchange: </h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<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>
<span>Sender: {{transaction.sender?.vcard.fn}}</span><br><br>
<span>Sender Address: {{transaction.from}}</span><br><br>
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Sender</button>
</li>
<li class="list-group-item">
<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>
<span>Recipient: {{transaction.recipient?.vcard.fn}}</span><br><br>
<span>Recipient Address: {{transaction.to}}</span><br><br>
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Recipient</button>
</li>
<li class="list-group-item">
<p>Amount: {{transaction.token.symbol + ' ' + transaction.value}}</p>
<span>Amount: {{transaction.token.symbol + ' ' + transaction.value}}</span>
</li>
</ul>
<h4 class="mt-2">Token: </h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<p>Address: {{transaction.token.address}}</p>
<span>Address: {{transaction.token.address}}</span>
</li>
<li class="list-group-item">
<p>Name: {{transaction.token.name}}</p>
<span>Name: {{transaction.token.name}}</span>
</li>
<li class="list-group-item">
<p>Symbol: {{transaction.token.symbol}}</p>
<span>Symbol: {{transaction.token.symbol}}</span>
</li>
</ul>
</div>
@ -39,29 +42,84 @@
<h4>Transaction: </h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<p>Block: {{transaction.tx.block}}</p>
<span>Block: {{transaction.tx.block}}</span>
</li>
<li class="list-group-item">
<p>Index: {{transaction.tx.txIndex}}</p>
<span>Index: {{transaction.tx.txIndex}}</span>
</li>
<li class="list-group-item">
<p>Hash: {{transaction.tx.txHash}}</p>
<span>Hash: {{transaction.tx.txHash}}</span>
</li>
<li class="list-group-item">
<p>Success: {{transaction.tx.success}}</p>
<span>Success: {{transaction.tx.success}}</span>
</li>
<li class="list-group-item">
<p>Timestamp: {{transaction.tx.timestamp | date}}</p>
<span>Timestamp: {{transaction.tx.timestamp | date}}</span>
</li>
</ul>
</ul><br>
<div class="mb-3">
<button mat-raised-button type="button" class="btn btn-outline-success">Resend SMS</button>
<button mat-raised-button color="primary" 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>
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger">Reverse Transaction</button>
</div>
</div>
</div>
</div>
<div *ngIf="transaction.type == 'conversion'" class="card-body">
<h3>Exchange: </h3>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span><strong>Trader: {{transaction.sender?.vcard.fn}}</strong></span>
</li>
<li class="list-group-item">
<span>Trader Address: {{transaction.trader}}</span>
</li>
</ul>
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Trader</button>
<br><br>
<div class="row">
<div class="col-md-6">
<h4>Source Token: </h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>Address: {{transaction.sourceToken.address}}</span>
</li>
<li class="list-group-item">
<span>Name: {{transaction.sourceToken.name}}</span>
</li>
<li class="list-group-item">
<span>Symbol: {{transaction.sourceToken.symbol}}</span>
</li>
<li class="list-group-item">
<span>Amount: {{transaction.sourceToken.symbol + ' ' + transaction.fromValue}}</span>
</li>
</ul>
</div>
<div class="col-md-6">
<h4>Destination Token: </h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>Address: {{transaction.destinationToken.address}}</span>
</li>
<li class="list-group-item">
<span>Name: {{transaction.destinationToken.name}}</span>
</li>
<li class="list-group-item">
<span>Symbol: {{transaction.destinationToken.symbol}}</span>
</li>
<li class="list-group-item">
<span>Amount: {{transaction.destinationToken.symbol + ' ' + transaction.toValue}}</span>
</li>
</ul>
</div>
<div class="col-md-6">
<button mat-raised-button color="primary" type="button" class="btn btn-outline-success">Resend SMS</button>
</div>
<div class="col-md-6">
<button mat-raised-button color="warn" type="button" class="btn btn-outline-danger ml-2">Reverse Transaction</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import {Component, Input, OnInit} from '@angular/core';
import {Component, Input, OnInit, Output} from '@angular/core';
import {Transaction} from '../../../_models';
@Component({
@ -7,7 +7,7 @@ import {Transaction} from '../../../_models';
styleUrls: ['./transaction-details.component.scss']
})
export class TransactionDetailsComponent implements OnInit {
@Input() transaction: Transaction;
@Input() transaction;
constructor() { }

View File

@ -10,6 +10,12 @@
<app-topbar></app-topbar>
<!-- Start Content-->
<div class="container-fluid" appMenuSelection>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Transactions</li>
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Transfers
@ -21,22 +27,20 @@
<div *ngIf="transactionSelection.selected.length <=0" class="row card-header">
<mat-form-field appearance="outline">
<mat-label> TRANSFER TYPE </mat-label>
<mat-select id="typeSelect">
<mat-option value="all" selected>ALL TRANSFERS</mat-option>
<mat-option value="payments">PAYMENTS</mat-option>
<mat-option value="exchange">EXCHANGE</mat-option>
<mat-select id="typeSelect" [(value)]="transactionsType" (selectionChange)="filterTransactions()">
<mat-option value="all">ALL TRANSFERS</mat-option>
<mat-option value="transaction">PAYMENTS</mat-option>
<mat-option value="conversion">CONVERSION</mat-option>
<mat-option value="disbursements">DISBURSEMENTS</mat-option>
<mat-option value="rewards">REWARDS</mat-option>
<mat-option value="reclamation">RECLAMATION</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto"><i class="fa fa-plus"></i> ADD NEW </button>
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-2"> EXPORT </button>
</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-form-field appearance="outline" class="ml-auto">
<mat-label> TRANSACTION STATUS </mat-label>
<mat-select id="statusSelect">
<mat-option selected disabled> -- SELECT -- </mat-option>
@ -54,24 +58,48 @@
<mat-table class="mat-elevation-z10" [dataSource]="transactionDataSource" matSort matSortActive="created"
matSortDirection="desc" matSortDisableClear>
<ng-container matColumnDef="view">
<mat-header-cell *matHeaderCellDef> View </mat-header-cell>
<mat-cell *matCellDef="let transaction" (click)="viewTransaction(transaction)">
<i class="fa fa-eye"></i>
</mat-cell>
</ng-container>
<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>
<mat-cell *matCellDef="let transaction"> {{transaction.sender?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="senderLocation">
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender Location </mat-header-cell>
<mat-cell *matCellDef="let transaction"> Miyani </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>
<mat-cell *matCellDef="let transaction"> {{transaction.recipient?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="recipientLocation">
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient Location </mat-header-cell>
<mat-cell *matCellDef="let transaction"> Kayaba </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>
<mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction.token.name}}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction.destinationToken.name}}</span>
</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>
<mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction.value | tokenRatio}}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction.toValue | tokenRatio}}</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="created">
@ -79,12 +107,10 @@
<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>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </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>
<span class="badge badge-success badge-pill"> {{transaction.type}} </span>
</mat-cell>
</ng-container>
@ -104,88 +130,13 @@
</ng-container>
<mat-header-row *matHeaderRowDef="transactionDisplayedColumns"></mat-header-row>
<mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns"></mat-row>
<mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns" (click)="viewTransaction(transaction)"></mat-row>
</mat-table>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
<div class="card">
<mat-card-title class="card-header">
Conversions
</mat-card-title>
<div class="card-body">
<app-conversion-details [conversion]="conversion"></app-conversion-details>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value, conversionDataSource)" placeholder="Filter">
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10" [dataSource]="conversionDataSource" matSort matSortActive="created"
matSortDirection="desc" matSortDisableClear>
<ng-container matColumnDef="initialToken">
<mat-header-cell *matHeaderCellDef mat-sort-header> Initial Token </mat-header-cell>
<mat-cell *matCellDef="let conversion"> {{conversion.sourceToken.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="initialValue">
<mat-header-cell *matHeaderCellDef mat-sort-header> Initial Value </mat-header-cell>
<mat-cell *matCellDef="let conversion"> {{conversion.sourceToken.symbol + ' ' + conversion.fromValue}} </mat-cell>
</ng-container>
<ng-container matColumnDef="finalToken">
<mat-header-cell *matHeaderCellDef mat-sort-header> Final Token </mat-header-cell>
<mat-cell *matCellDef="let conversion"> {{conversion.destinationToken.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="finalValue">
<mat-header-cell *matHeaderCellDef mat-sort-header> Final Value </mat-header-cell>
<mat-cell *matCellDef="let conversion"> {{conversion.destinationToken.symbol + ' ' + conversion.toValue}} </mat-cell>
</ng-container>
<ng-container matColumnDef="trader">
<mat-header-cell *matHeaderCellDef mat-sort-header> Trader </mat-header-cell>
<mat-cell *matCellDef="let conversion" routerLink="/users/{{conversion.trader}}"> {{conversion.user?.vcard.fn}} </mat-cell>
</ng-container>
<ng-container matColumnDef="created">
<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>
<app-footer appMenuSelection></app-footer>
</div>

View File

@ -1,6 +1,5 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {BlockSyncService, TransactionService} from '../../_services';
import {Conversion, Transaction} from '../../_models';
import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {MatPaginator} from '@angular/material/paginator';
@ -12,16 +11,14 @@ import {MatSort} from '@angular/material/sort';
styleUrls: ['./transactions.component.scss']
})
export class TransactionsComponent implements OnInit, AfterViewInit {
transactionDataSource: MatTableDataSource<Transaction>;
conversionDataSource: MatTableDataSource<any>;
transactionDisplayedColumns = ['sender', 'recipient', 'token', 'value', 'created', 'view', 'select'];
conversionDisplayedColumns = ['initialToken', 'initialValue', 'finalToken', 'finalValue', 'trader', 'created', 'view', 'select'];
transactionDataSource: MatTableDataSource<any>;
transactionDisplayedColumns = ['view', 'sender', 'senderLocation', 'recipient', 'recipientLocation', 'token', 'value', 'created', 'type', 'select'];
initialSelection = [];
allowMultiSelect = true;
transactionSelection: SelectionModel<any>;
conversionSelection: SelectionModel<any>;
transaction: Transaction;
conversion: Conversion;
transactions: any[];
transaction: any;
transactionsType = 'all';
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ -31,38 +28,22 @@ export class TransactionsComponent implements OnInit, AfterViewInit {
private blockSyncService: BlockSyncService
) {
this.blockSyncService.blockSync();
}
}
ngOnInit(): void {
this.transactionService.transactionsSubject.subscribe(transactions => {
this.transactionDataSource = new MatTableDataSource<Transaction>(transactions);
this.transactionDataSource = new MatTableDataSource<any>(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.transactions = transactions;
});
this.transactionSelection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
this.conversionSelection = new SelectionModel<any>(this.allowMultiSelect, this.initialSelection);
}
viewTransaction(transaction): void {
this.transaction = transaction;
}
viewConversion(conversion): void {
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;
@ -76,4 +57,20 @@ export class TransactionsComponent implements OnInit, AfterViewInit {
doFilter(value: string, dataSource): void {
dataSource.filter = value.trim().toLocaleLowerCase();
}
filterTransactions(): void {
if (this.transactionsType === 'all') {
this.transactionService.transactionsSubject.subscribe(transactions => {
this.transactionDataSource.data = transactions;
this.transactions = transactions;
});
} else {
this.transactionDataSource.data = this.transactions.filter(transaction => transaction.type === this.transactionsType);
}
}
ngAfterViewInit(): void {
this.transactionDataSource.paginator = this.paginator;
this.transactionDataSource.sort = this.sort;
}
}

View File

@ -6,7 +6,6 @@ import { TransactionsComponent } from './transactions.component';
import { TransactionDetailsComponent } from './transaction-details/transaction-details.component';
import {DataTablesModule} from 'angular-datatables';
import {SharedModule} from '../../shared/shared.module';
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';
@ -20,7 +19,7 @@ import {MatCardModule} from '@angular/material/card';
@NgModule({
declarations: [TransactionsComponent, TransactionDetailsComponent, ConversionDetailsComponent],
declarations: [TransactionsComponent, TransactionDetailsComponent],
exports: [
TransactionDetailsComponent
],

View File

@ -7,6 +7,7 @@ import { MenuSelectionDirective } from './_directives/menu-selection.directive';
import { MenuToggleDirective } from './_directives/menu-toggle.directive';
import {RouterModule} from '@angular/router';
import {MatIconModule} from '@angular/material/icon';
import {TokenRatioPipe} from './_pipes/token-ratio.pipe';
@ -16,13 +17,15 @@ import {MatIconModule} from '@angular/material/icon';
FooterComponent,
SidebarComponent,
MenuSelectionDirective,
MenuToggleDirective
MenuToggleDirective,
TokenRatioPipe
],
exports: [
TopbarComponent,
FooterComponent,
SidebarComponent,
MenuSelectionDirective
MenuSelectionDirective,
TokenRatioPipe
],
imports: [
CommonModule,

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>CIC-Staff-Client</title>
<title>CICADA</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta content="A fully featured admin client for managing users and transactions in the CIC network." name="description" />

View File

@ -211,6 +211,50 @@ a[data-toggle="collapse"] {
overflow: initial;
}
button {
height: 2.5rem;
}
.badge-pill {
width: 5rem;
}
.mat-column {
word-wrap: break-word !important;
white-space: unset !important;
overflow-wrap: break-word;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
.mat-column-address {
flex: 0 0 30% !important;
width: 30% !important;
}
.mat-column-supply {
flex: 0 0 25% !important;
width: 25% !important;
}
.mat-column-select {
flex: 0 0 10% !important;
width: 10% !important;
}
.mat-column-view {
flex: 0 0 5% !important;
width: 5% !important;
}
.center-body {
float: none;
margin: 0 auto 10px;
}
@media (max-width: 768px) {
#sidebar {
margin-left: 0;