Lint html and testing files.

This commit is contained in:
Spencer Ofwiti 2021-06-14 18:26:58 +03:00
parent 7086126386
commit 6c045d1235
29 changed files with 1327 additions and 478 deletions

View File

@ -91,12 +91,14 @@
"src/**/*.{js,ts,scss,md,html,json}": [
"prettier --write",
"git add"
],
"*.scss": [
"stylelint src/**/*.scss"
]
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged && npm run format:lint && lint-staged",
"pre-push": "ng build --prod"
"pre-commit": "npx pretty-quick --staged && npm run format:lint && lint-staged"
}
}
}

View File

@ -8,20 +8,25 @@
<h1 class="text-white">CICADA</h1>
</a>
</mat-card-title>
<div id="one" style="display: block" class="card-body p-4">
<div id="one" style="display: block" class="card-body p-4">
<div class="text-center w-75 m-auto">
<h4 class="text-dark-50 text-center font-weight-bold">Add Private Key</h4>
</div>
<form [formGroup]="keyForm" (ngSubmit)="onSubmit()">
<mat-form-field appearance="outline" class="full-width">
<mat-label>Private Key</mat-label>
<textarea matInput style="height: 30rem" formControlName="key" placeholder="Enter your private key..."
[errorStateMatcher]="matcher"></textarea>
<textarea
matInput
style="height: 30rem"
formControlName="key"
placeholder="Enter your private key..."
[errorStateMatcher]="matcher"
></textarea>
<div *ngIf="submitted && keyFormStub.key.errors" class="invalid-feedback">
<mat-error *ngIf="keyFormStub.key.errors.required">Private Key is required.</mat-error>
<mat-error *ngIf="keyFormStub.key.errors.required"
>Private Key is required.</mat-error
>
</div>
</mat-form-field>
@ -29,20 +34,24 @@
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Add Key
</button>
</form>
</div>
<div id="two" style="display: none" class="card-body p-4 align-items-center">
<div id="two" style="display: none" class="card-body p-4 align-items-center">
<div class="text-center w-75 m-auto">
<h4 id="state" class="text-dark-50 text-center font-weight-bold"></h4>
<button mat-raised-button matRipple color="primary" type="submit" (click)="login()"> Login </button>
<button mat-raised-button matRipple color="primary" type="submit" (click)="login()">
Login
</button>
</div>
<div class="row mt-3">
<div class="col-12 text-center">
<p class="text-muted">Change private key? <a (click)="switchWindows()" class="text-muted ml-1"><b>Enter private key</b></a></p>
</div> <!-- end col-->
<p class="text-muted">
Change private key?
<a (click)="switchWindows()" class="text-muted ml-1"><b>Enter private key</b></a>
</p>
</div>
<!-- end col-->
</div>
<!-- end row -->
</div>

View File

@ -14,30 +14,44 @@
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
<li class="breadcrumb-item"><a routerLink="/accounts">Accounts</a></li>
<li *ngIf="account" class="breadcrumb-item active" aria-current="page">{{account?.vcard?.fn[0].value}}</li>
<li *ngIf="account" class="breadcrumb-item active" aria-current="page">
{{ account?.vcard?.fn[0].value }}
</li>
</ol>
</nav>
<div *ngIf="!account" class="text-center">
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
<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;">
<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;">
<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 mb-3">
<div class="row card-body">
<h3>
<strong> {{account?.vcard?.fn[0].value}} </strong>
<strong> {{ account?.vcard?.fn[0].value }} </strong>
</h3>
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | unixDate}}</span>
<span class="ml-2"><strong>Address:</strong>
<a href="{{bloxbergLink}}" target="_blank"> {{accountAddress}} </a>
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress()" alt="Copy">
<span class="ml-auto"
><strong>Balance:</strong> {{ account?.balance | tokenRatio }}
{{ tokenSymbol | uppercase }}</span
>
<span class="ml-2"
><strong>Created:</strong> {{ account?.date_registered | unixDate }}</span
>
<span class="ml-2"
><strong>Address:</strong>
<a href="{{ bloxbergLink }}" target="_blank"> {{ accountAddress }} </a>
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress()"
alt="Copy"
/>
</span>
</div>
</div>
@ -45,85 +59,145 @@
<div class="card-body">
<form [formGroup]="accountInfoForm" (ngSubmit)="saveInfo()">
<div class="row form-inline">
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>First Name: *</mat-label>
<input matInput type="text" id="firstName" placeholder="{{account?.vcard?.fn[0].value.split(' ')[0]}}"
value="{{account?.vcard?.fn[0].value.split(' ')[0]}}" formControlName="firstName" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && accountInfoFormStub.firstName.errors">First Name is required.</mat-error>
<input
matInput
type="text"
id="firstName"
placeholder="{{ account?.vcard?.fn[0].value.split(' ')[0] }}"
value="{{ account?.vcard?.fn[0].value.split(' ')[0] }}"
formControlName="firstName"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.firstName.errors"
>First Name is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Last Name(s): *</mat-label>
<input matInput type="text" id="lastName" placeholder="{{account?.vcard?.fn[0].value.split(' ').slice(1).join(' ')}}"
value="{{account?.vcard?.fn[0].value.split(' ').slice(1).join(' ')}}" formControlName="lastName" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && accountInfoFormStub.lastName.errors">Last Name is required.</mat-error>
<input
matInput
type="text"
id="lastName"
placeholder="{{ account?.vcard?.fn[0].value.split(' ').slice(1).join(' ') }}"
value="{{ account?.vcard?.fn[0].value.split(' ').slice(1).join(' ') }}"
formControlName="lastName"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.lastName.errors"
>Last Name is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Phone Number: </mat-label>
<input matInput type="text" id="phoneNumber" placeholder="{{account?.vcard?.tel[0].value}}"
value="{{account?.vcard?.tel[0].value}}" formControlName="phoneNumber" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && accountInfoFormStub.phoneNumber.errors">Phone Number is required.</mat-error>
<input
matInput
type="text"
id="phoneNumber"
placeholder="{{ account?.vcard?.tel[0].value }}"
value="{{ account?.vcard?.tel[0].value }}"
formControlName="phoneNumber"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.phoneNumber.errors"
>Phone Number is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Age: </mat-label>
<input matInput type="text" id="age" placeholder="{{account?.age}}"
value="{{account?.age}}" formControlName="age" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && accountInfoFormStub.age.errors">Age is required.</mat-error>
<input
matInput
type="text"
id="age"
placeholder="{{ account?.age }}"
value="{{ account?.age }}"
formControlName="age"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.age.errors"
>Age is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> ACCOUNT TYPE: </mat-label>
<mat-select id="accountType" [(value)]="account.type" formControlName="type"
[errorStateMatcher]="matcher">
<mat-select
id="accountType"
[(value)]="account.type"
formControlName="type"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let accountType of accountTypes" [value]="accountType">
{{accountType | uppercase}}
{{ accountType | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && accountInfoFormStub.type.errors">Type is required.</mat-error>
<mat-error *ngIf="submitted && accountInfoFormStub.type.errors"
>Type is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Bio: </mat-label>
<input matInput type="text" id="bio" placeholder="{{account?.products}}" value="{{account?.products}}"
formControlName="bio" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && accountInfoFormStub.bio.errors">Bio is required.</mat-error>
<input
matInput
type="text"
id="bio"
placeholder="{{ account?.products }}"
value="{{ account?.products }}"
formControlName="bio"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.bio.errors"
>Bio is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> GENDER: </mat-label>
<mat-select id="gender" [(value)]="account.gender" formControlName="gender"
[errorStateMatcher]="matcher">
<mat-select
id="gender"
[(value)]="account.gender"
formControlName="gender"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let gender of genders" [value]="gender">
{{gender | uppercase}}
{{ gender | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && accountInfoFormStub.gender.errors">Gender is required.</mat-error>
<mat-error *ngIf="submitted && accountInfoFormStub.gender.errors"
>Gender is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> BUSINESS CATEGORY: </mat-label>
<mat-select id="businessCategory" [(value)]="account.category" formControlName="businessCategory"
[errorStateMatcher]="matcher">
<mat-select
id="businessCategory"
[(value)]="account.category"
formControlName="businessCategory"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let category of categories" [value]="category">
{{category | titlecase}}
{{ category | titlecase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && accountInfoFormStub.businessCategory.errors">
@ -135,9 +209,15 @@
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>User Location: </mat-label>
<input matInput type="text" id="userLocation" placeholder="{{account?.location.area_name}}"
value="{{account?.location.area_name}}" formControlName="userLocation"
[errorStateMatcher]="matcher">
<input
matInput
type="text"
id="userLocation"
placeholder="{{ account?.location.area_name }}"
value="{{ account?.location.area_name }}"
formControlName="userLocation"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && accountInfoFormStub.userLocation.errors">
User Location is required.
</mat-error>
@ -147,50 +227,82 @@
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> LOCATION: </mat-label>
<mat-select id="location" [(value)]="account.location.area" formControlName="location"
[errorStateMatcher]="matcher">
<mat-select
id="location"
[(value)]="account.location.area"
formControlName="location"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let area of areaNames" [value]="area">
{{area | uppercase}}
{{ area | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && accountInfoFormStub.location.errors">Location is required.</mat-error>
<mat-error *ngIf="submitted && accountInfoFormStub.location.errors"
>Location is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label> LOCATION TYPE: </mat-label>
<mat-select id="locationType" [(value)]="account.location.area_type" formControlName="locationType"
[errorStateMatcher]="matcher">
<mat-select
id="locationType"
[(value)]="account.location.area_type"
formControlName="locationType"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let type of areaTypes" [value]="type">
{{type | uppercase}}
{{ type | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && accountInfoFormStub.locationType.errors">Location Type is required.</mat-error>
<mat-error *ngIf="submitted && accountInfoFormStub.locationType.errors"
>Location Type is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary mb-3">
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary mb-3"
>
Add User KYC
</button>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button color="primary" type="button" class="btn btn-outline-success mb-3"
(click)="resetPin()">
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-success mb-3"
(click)="resetPin()"
>
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 mb-3">
<button
mat-raised-button
color="warn"
type="button"
class="btn btn-outline-danger mb-3"
>
Delete User
</button>
</div>
<div class="col-md-6 col-lg-4">
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary">
<button
mat-raised-button
color="primary"
type="submit"
class="btn btn-outline-primary"
>
SAVE DETAILS
</button>
</div>
@ -200,32 +312,32 @@
</div>
<div class="card mb-3">
<mat-card-title class="card-header">
USER
</mat-card-title>
<mat-card-title class="card-header"> USER </mat-card-title>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover">
<caption> 1 user </caption>
<caption>
1 user
</caption>
<thead class="thead-dark">
<tr>
<th scope="col">NAME</th>
<th scope="col">BALANCE</th>
<th scope="col">CREATED</th>
<th scope="col">STATUS</th>
</tr>
<tr>
<th scope="col">NAME</th>
<th scope="col">BALANCE</th>
<th scope="col">CREATED</th>
<th scope="col">STATUS</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{account?.vcard?.fn[0].value}}</td>
<td>{{account?.balance | tokenRatio}} {{ tokenSymbol | uppercase }}</td>
<td>{{account?.date_registered | unixDate}}</td>
<td>
<span class="badge badge-success badge-pill">
{{accountStatus}}
</span>
</td>
</tr>
<tr>
<td>{{ account?.vcard?.fn[0].value }}</td>
<td>{{ account?.balance | tokenRatio }} {{ tokenSymbol | uppercase }}</td>
<td>{{ account?.date_registered | unixDate }}</td>
<td>
<span class="badge badge-success badge-pill">
{{ accountStatus }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
@ -234,135 +346,216 @@
<mat-tab-group *ngIf="account" dynamicHeight mat-align-tabs="start">
<mat-tab label="Transactions">
<app-transaction-details [transaction]="transaction" (closeWindow)="transaction = $event"></app-transaction-details>
<app-transaction-details
[transaction]="transaction"
(closeWindow)="transaction = $event"
></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-select
id="transferSelect"
[(value)]="transactionsType"
(selectionChange)="filterTransactions()"
>
<mat-option value="all">ALL TRANSFERS</mat-option>
<mat-option *ngFor="let transactionType of transactionsTypes" [value]="transactionType">
{{transactionType | uppercase}}
<mat-option
*ngFor="let transactionType of transactionsTypes"
[value]="transactionType"
>
{{ transactionType | uppercase }}
</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv(transactions, 'transactions')"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv(transactions, 'transactions')"
>
EXPORT
</button>
</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">
<input
matInput
type="text"
(keyup)="doTransactionFilter($event.target.value)"
placeholder="Filter"
/>
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<table mat-table class="mat-elevation-z10" [dataSource]="transactionsDataSource" matSort matSortActive="created"
#TransactionTableSort="matSort" matSortDirection="asc" matSortDisableClear>
<table
mat-table
class="mat-elevation-z10"
[dataSource]="transactionsDataSource"
matSort
matSortActive="created"
#TransactionTableSort="matSort"
matSortDirection="asc"
matSortDisableClear
>
<ng-container matColumnDef="sender">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Sender </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value || transaction.from}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Sender</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.sender?.vcard.fn[0].value || transaction.from }}
</td>
</ng-container>
<ng-container matColumnDef="recipient">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value || transaction.to}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Recipient</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.recipient?.vcard.fn[0].value || transaction.to }}
</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Value </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Value</th>
<td mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction?.value | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction?.toValue | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span *ngIf="transaction.type == 'transaction'"
>{{ transaction?.value | tokenRatio }} {{ tokenSymbol | uppercase }}</span
>
<span *ngIf="transaction.type == 'conversion'"
>{{ transaction?.toValue | tokenRatio }} {{ tokenSymbol | uppercase }}</span
>
</td>
</ng-container>
<ng-container matColumnDef="created">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | unixDate}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Created</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.tx.timestamp | unixDate }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header>TYPE</th>
<td mat-cell *matCellDef="let transaction">
<span class="badge badge-success badge-pill"> {{transaction?.type}} </span>
<span class="badge badge-success badge-pill"> {{ transaction?.type }} </span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="transactionsDisplayedColumns"></tr>
<tr mat-row *matRowDef="let transaction; columns: transactionsDisplayedColumns" matRipple
(click)="viewTransaction(transaction)"></tr>
<tr
mat-row
*matRowDef="let transaction; columns: transactionsDisplayedColumns"
matRipple
(click)="viewTransaction(transaction)"
></tr>
</table>
<mat-paginator #TransactionTablePaginator="matPaginator" [pageSize]="transactionsDefaultPageSize"
[pageSizeOptions]="transactionsPageSizeOptions" showFirstLastButtons></mat-paginator>
<mat-paginator
#TransactionTablePaginator="matPaginator"
[pageSize]="transactionsDefaultPageSize"
[pageSizeOptions]="transactionsPageSizeOptions"
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>
<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-select
id="typeSelect"
[(value)]="accountsType"
(selectionChange)="filterAccounts()"
>
<mat-option value="all">ALL</mat-option>
<mat-option *ngFor="let accountType of accountTypes" [value]="accountType">
{{accountType | uppercase}}
{{ accountType | uppercase }}
</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv(accounts, 'accounts')"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv(accounts, 'accounts')"
>
EXPORT
</button>
</div>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doUserFilter($event.target.value)" placeholder="Filter">
<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>
<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?.vcard.fn[0].value}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.vcard.fn[0].value }} </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?.vcard.tel[0].value}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>
PHONE NUMBER
</mat-header-cell>
<mat-cell *matCellDef="let user"> {{ user?.vcard.tel[0].value }} </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?.date_registered | unixDate}} </mat-cell>
<mat-cell *matCellDef="let user">
{{ user?.date_registered | unixDate }}
</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 | tokenRatio}} {{tokenSymbol | uppercase}} </mat-cell>
<mat-cell *matCellDef="let user">
{{ user?.balance | tokenRatio }} {{ tokenSymbol | uppercase }}
</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.area_name}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.location.area_name }} </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-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]="usersDefaultPageSize"
[pageSizeOptions]="usersPageSizeOptions" showFirstLastButtons></mat-paginator>
<mat-paginator
#UserTablePaginator="matPaginator"
[pageSize]="usersDefaultPageSize"
[pageSizeOptions]="usersPageSizeOptions"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</mat-tab>

View File

@ -18,33 +18,61 @@
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Accounts
</mat-card-title>
<mat-card-title class="card-header"> Accounts </mat-card-title>
<div class="card-body">
<mat-tab-group>
<mat-tab label="Phone Number">
<form [formGroup]="phoneSearchForm" (ngSubmit)="onPhoneSearch()">
<mat-form-field appearance="outline">
<mat-label> Search </mat-label>
<input matInput type="text" placeholder="Search by phone number" formControlName="phoneNumber" [errorStateMatcher]="matcher">
<mat-error *ngIf="phoneSearchSubmitted && phoneSearchFormStub.phoneNumber.errors">Phone Number is required.</mat-error>
<input
matInput
type="text"
placeholder="Search by phone number"
formControlName="phoneNumber"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="phoneSearchSubmitted && phoneSearchFormStub.phoneNumber.errors"
>Phone Number is required.</mat-error
>
<mat-icon matSuffix>phone</mat-icon>
<mat-hint>Phone Number</mat-hint>
</mat-form-field>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-3"> SEARCH </button>
<button
mat-raised-button
color="primary"
type="submit"
class="btn btn-outline-primary ml-3"
>
SEARCH
</button>
</form>
</mat-tab>
<mat-tab label="Account Address">
<form [formGroup]="addressSearchForm" (ngSubmit)="onAddressSearch()">
<mat-form-field appearance="outline">
<mat-label> Search </mat-label>
<input matInput type="text" placeholder="Search by account address" formControlName="address" [errorStateMatcher]="matcher">
<mat-error *ngIf="addressSearchSubmitted && addressSearchFormStub.address.errors">Account Address is required.</mat-error>
<input
matInput
type="text"
placeholder="Search by account address"
formControlName="address"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="addressSearchSubmitted && addressSearchFormStub.address.errors"
>Account Address is required.</mat-error
>
<mat-icon matSuffix>view_in_ar</mat-icon>
<mat-hint>Account Address</mat-hint>
</mat-form-field>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-3"> SEARCH </button>
<button
mat-raised-button
color="primary"
type="submit"
class="btn btn-outline-primary ml-3"
>
SEARCH
</button>
</form>
</mat-tab>
</mat-tab-group>

View File

@ -17,63 +17,99 @@
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Accounts
</mat-card-title>
<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-select
id="typeSelect"
[(value)]="accountsType"
(selectionChange)="filterAccounts()"
>
<mat-option value="all">ALL</mat-option>
<mat-option *ngFor="let accountType of accountTypes" [value]="accountType">
{{accountType | uppercase}}
{{ accountType | uppercase }}
</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" routerLink="/accounts/search"> SEARCH </button>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary mr-2" (click)="downloadCsv()"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
routerLink="/accounts/search"
>
SEARCH
</button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary mr-2"
(click)="downloadCsv()"
>
EXPORT
</button>
</div>
<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)="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="created"
matSortDirection="desc" matSortDisableClear>
<mat-table
class="mat-elevation-z10"
[dataSource]="dataSource"
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?.vcard.fn[0].value}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.vcard.fn[0].value }} </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?.vcard.tel[0].value}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.vcard.tel[0].value }} </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?.date_registered | unixDate}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.date_registered | unixDate }} </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 | tokenRatio}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.balance | tokenRatio }} </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.area_name}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user?.location.area_name }} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let account; columns: displayedColumns" (click)="viewAccount(account)" matRipple></mat-row>
<mat-row
*matRowDef="let account; columns: displayedColumns"
(click)="viewAccount(account)"
matRipple
></mat-row>
</mat-table>
<mat-paginator [pageSize]="defaultPageSize" [pageSizeOptions]="pageSizeOptions" showFirstLastButtons></mat-paginator>
<mat-paginator
[pageSize]="defaultPageSize"
[pageSizeOptions]="pageSizeOptions"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</div>

View File

@ -18,61 +18,110 @@
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header text-center">
CREATE A USER ACCOUNT
</mat-card-title>
<mat-card-title class="card-header text-center"> CREATE A USER ACCOUNT </mat-card-title>
<div class="card-body">
<form class="row form-inline" [formGroup]="createForm" (ngSubmit)="onSubmit()">
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Account Type: </mat-label>
<mat-select id="accountType" formControlName="accountType" [errorStateMatcher]="matcher">
<mat-select
id="accountType"
formControlName="accountType"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let accountType of accountTypes" [value]="accountType">
{{accountType | uppercase}}
{{ accountType | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && createFormStub.accountType.errors">Account type is required.</mat-error>
</mat-form-field><br>
<mat-error *ngIf="submitted && createFormStub.accountType.errors"
>Account type is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>ID Number: </mat-label>
<input matInput type="text" id="idNumber" placeholder="ID Number" formControlName="idNumber" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.idNumber.errors">ID Number is required.</mat-error>
<input
matInput
type="text"
id="idNumber"
placeholder="ID Number"
formControlName="idNumber"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.idNumber.errors"
>ID Number is required.</mat-error
>
</mat-form-field>
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Phone Number: </mat-label>
<input matInput type="text" id="phoneNumber" placeholder="Phone Number" formControlName="phoneNumber" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.phoneNumber.errors">Phone Number is required.</mat-error>
</mat-form-field><br>
<input
matInput
type="text"
id="phoneNumber"
placeholder="Phone Number"
formControlName="phoneNumber"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.phoneNumber.errors"
>Phone Number is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Given Name(s):* </mat-label>
<input matInput type="text" id="givenNames" placeholder="Given Names" formControlName="givenName" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.givenName.errors">Given Names are required.</mat-error>
</mat-form-field><br>
<input
matInput
type="text"
id="givenNames"
placeholder="Given Names"
formControlName="givenName"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.givenName.errors"
>Given Names are required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Family/Surname: </mat-label>
<input matInput type="text" id="surname" placeholder="Surname" formControlName="surname" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.surname.errors">Surname is required.</mat-error>
</mat-form-field><br>
<input
matInput
type="text"
id="surname"
placeholder="Surname"
formControlName="surname"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.surname.errors"
>Surname is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Directory Entry: </mat-label>
<input matInput type="text" id="directoryEntry" placeholder="Directory Entry" formControlName="directoryEntry" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.directoryEntry.errors">Directory Entry is required.</mat-error>
</mat-form-field><br>
<input
matInput
type="text"
id="directoryEntry"
placeholder="Directory Entry"
formControlName="directoryEntry"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.directoryEntry.errors"
>Directory Entry is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
@ -80,11 +129,13 @@
<mat-label>Location: </mat-label>
<mat-select id="location" formControlName="location" [errorStateMatcher]="matcher">
<mat-option *ngFor="let area of areaNames" [value]="area">
{{area | uppercase}}
{{ area | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && createFormStub.location.errors">Location is required.</mat-error>
</mat-form-field><br>
<mat-error *ngIf="submitted && createFormStub.location.errors"
>Location is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
@ -92,34 +143,59 @@
<mat-label>Gender: </mat-label>
<mat-select id="gender" formControlName="gender" [errorStateMatcher]="matcher">
<mat-option *ngFor="let gender of genders" [value]="gender">
{{gender | uppercase}}
{{ gender | uppercase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && createFormStub.gender.errors">Gender is required.</mat-error>
</mat-form-field><br>
<mat-error *ngIf="submitted && createFormStub.gender.errors"
>Gender is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Referrer Phone Number: </mat-label>
<input matInput type="text" id="referredBy" placeholder="Reffered By" formControlName="referrer" [errorStateMatcher]="matcher">
<mat-error *ngIf="submitted && createFormStub.referrer.errors">Referrer is required.</mat-error>
</mat-form-field><br>
<input
matInput
type="text"
id="referredBy"
placeholder="Reffered By"
formControlName="referrer"
[errorStateMatcher]="matcher"
/>
<mat-error *ngIf="submitted && createFormStub.referrer.errors"
>Referrer is required.</mat-error
> </mat-form-field
><br />
</div>
<div class="col-md-6 col-lg-4">
<mat-form-field appearance="outline">
<mat-label>Business Category: </mat-label>
<mat-select id="businessCategory" formControlName="businessCategory" [errorStateMatcher]="matcher">
<mat-select
id="businessCategory"
formControlName="businessCategory"
[errorStateMatcher]="matcher"
>
<mat-option *ngFor="let category of categories" [value]="category">
{{category | titlecase}}
{{ category | titlecase }}
</mat-option>
</mat-select>
<mat-error *ngIf="submitted && createFormStub.businessCategory.errors">Business Category is required.</mat-error>
<mat-error *ngIf="submitted && createFormStub.businessCategory.errors"
>Business Category is required.</mat-error
>
</mat-form-field>
</div>
<button mat-raised-button color="primary" type="submit" class="btn btn-outline-primary ml-3" (click)="onSubmit()">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

@ -20,19 +20,30 @@
<mat-card-title class="card-header">
<div class="row">
Actions
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv()"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv()"
>
EXPORT
</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">
<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" multiTemplateDataRows>
<!-- Expand Column -->
<ng-container matColumnDef="expand">
<mat-header-cell *matHeaderCellDef> Expand </mat-header-cell>
@ -44,32 +55,52 @@
<ng-container matColumnDef="user">
<mat-header-cell *matHeaderCellDef> NAME </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.user}} </mat-cell>
<mat-cell *matCellDef="let action"> {{ action.user }} </mat-cell>
</ng-container>
<ng-container matColumnDef="role">
<mat-header-cell *matHeaderCellDef> ROLE </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.role}} </mat-cell>
<mat-cell *matCellDef="let action"> {{ action.role }} </mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef> ACTION </mat-header-cell>
<mat-cell *matCellDef="let action"> {{action.action}} </mat-cell>
<mat-cell *matCellDef="let action"> {{ action.action }} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<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>
<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 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)="disapproveAction(action)"> Disapprove </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)="disapproveAction(action)"
>
Disapprove
</button>
</mat-cell>
</ng-container>
@ -77,22 +108,37 @@
<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>
<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 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-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>
<mat-paginator
[pageSize]="10"
[pageSizeOptions]="[10, 20, 50, 100]"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</div>
@ -102,4 +148,3 @@
<!-- End Page content -->
<!-- ============================================================== -->
</div>

View File

@ -16,10 +16,16 @@
</ol>
</nav>
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" [src]="url | safe" allow="fullscreen" loading="lazy"
title="Community inclusion currencies dashboard" referrerpolicy="no-referrer">
<iframe
class="embed-responsive-item"
[src]="url | safe"
allow="fullscreen"
loading="lazy"
title="Community inclusion currencies dashboard"
referrerpolicy="no-referrer"
>
<p>
<a href="{{url}}"> Your browser does not support iframes. </a>
<a href="{{ url }}"> Your browser does not support iframes. </a>
</p>
</iframe>
</div>

View File

@ -26,19 +26,31 @@
<form [formGroup]="organizationForm" (ngSubmit)="onSubmit()">
<mat-form-field appearance="outline">
<mat-label>Default Disbursement *</mat-label>
<input matInput type="text" id="amount" placeholder="Amount" formControlName="disbursement"
[errorStateMatcher]="matcher">
<input
matInput
type="text"
id="amount"
placeholder="Amount"
formControlName="disbursement"
[errorStateMatcher]="matcher"
/>
<span matSuffix>RCU</span>
<mat-error *ngIf="submitted && organizationFormStub.disbursement.errors">
Default Disbursement is required.
</mat-error>
</mat-form-field>
<div class="form-group form-check">
<mat-checkbox id="transferCard" formControlName="transfer">Require Transfer Card *</mat-checkbox>
<mat-checkbox id="transferCard" formControlName="transfer"
>Require Transfer Card *</mat-checkbox
>
</div>
<mat-form-field appearance="outline">
<mat-label>Default Country Code *</mat-label>
<mat-select id="countryCode" formControlName="countryCode" [errorStateMatcher]="matcher">
<mat-select
id="countryCode"
formControlName="countryCode"
[errorStateMatcher]="matcher"
>
<mat-option value="KE">KE Kenya</mat-option>
<mat-option value="US">US United States</mat-option>
<mat-option value="ETH">ETH Ethiopia</mat-option>
@ -47,9 +59,11 @@
</mat-select>
<mat-error *ngIf="submitted && organizationFormStub.countryCode.errors">
Country Code is required.
</mat-error>
</mat-form-field><br>
<button mat-raised-button color="primary" type="submit" class="btn btn-primary">Submit</button>
</mat-error> </mat-form-field
><br />
<button mat-raised-button color="primary" type="submit" class="btn btn-primary">
Submit
</button>
</form>
</div>
</div>

View File

@ -19,16 +19,14 @@
<div class="row">
<div class="col-md-6 mb-2">
<div class="card">
<mat-card-title class="card-header text-center">
SETTINGS
</mat-card-title>
<mat-card-title class="card-header text-center"> SETTINGS </mat-card-title>
<div class="card-body">
<h4>CICADA Admin Credentials</h4>
<span><strong>UserId: </strong> {{ userInfo?.userid }} </span><br>
<span><strong>Username: </strong> {{ userInfo?.name }} </span><br>
<span><strong>UserId: </strong> {{ userInfo?.userid }} </span><br />
<span><strong>Username: </strong> {{ userInfo?.name }} </span><br />
<span><strong>Email: </strong> {{ userInfo?.email }} </span>
</div>
<hr>
<hr />
<div class="card-body">
<h4>Organization Settings</h4>
<a routerLink="/settings/organization"><i>Update your organization settings</i></a>
@ -37,21 +35,27 @@
</div>
<div class="col-md-6 mb-2">
<div class="card">
<mat-card-title class="card-header text-center">
ACCOUNT MANAGEMENT
</mat-card-title>
<mat-card-title class="card-header text-center"> ACCOUNT MANAGEMENT </mat-card-title>
<div class="card-body">
<h4>Change Password</h4>
<a routerLink="/settings"><i>Change your account password</i></a>
</div>
<hr>
<hr />
<div class="card-body">
<h4>Two-step authentication</h4>
<a routerLink="/settings"><i>Secure your account with two step verification</i></a>
</div>
<hr>
<hr />
<div class="card-body">
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary" (click)="logout()"> LOGOUT ADMIN </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary"
(click)="logout()"
>
LOGOUT ADMIN
</button>
</div>
</div>
</div>
@ -60,39 +64,60 @@
<mat-card-title class="card-header">
<div class="row">
TRUSTED USERS
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv()"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv()"
>
EXPORT
</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">
<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>
<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>
<mat-cell *matCellDef="let user"> {{ user.name }} </mat-cell>
</ng-container>
<ng-container matColumnDef="email">
<mat-header-cell *matHeaderCellDef mat-sort-header> EMAIL </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.email}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user.email }} </mat-cell>
</ng-container>
<ng-container matColumnDef="userId">
<mat-header-cell *matHeaderCellDef mat-sort-header> USER ID </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.userid}} </mat-cell>
<mat-cell *matCellDef="let user"> {{ user.userid }} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let user; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator [pageSize]="5" [pageSizeOptions]="[5, 10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
<mat-paginator
[pageSize]="5"
[pageSizeOptions]="[5, 10, 20, 50, 100]"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</div>

View File

@ -3,32 +3,43 @@
<mat-card-title class="card-header">
<div class="row">
TOKEN DETAILS
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2" (click)="close()"> CLOSE </button>
<button
mat-raised-button
type="button"
class="btn btn-outline-secondary ml-auto mr-2"
(click)="close()"
>
CLOSE
</button>
</div>
</mat-card-title>
<div class="card-body">
<div>
<span><strong>Name:</strong> {{token?.name}}</span>
<span><strong>Name:</strong> {{ token?.name }}</span>
</div>
<div>
<span><strong>Symbol:</strong> {{token?.symbol}}</span>
<span><strong>Symbol:</strong> {{ token?.symbol }}</span>
</div>
<div>
<span><strong>Address:</strong> {{token?.address}}</span>
<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>
<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>
<span><strong>Supply:</strong> {{ token?.supply | tokenRatio }}</span>
</div>
<br />
<div>
<h2>Reserve</h2>
<div>
<span><strong>Weight:</strong> {{token?.reserveRatio}}</span>
<span><strong>Weight:</strong> {{ token?.reserveRatio }}</span>
</div>
<div>
<span><strong>Owner:</strong> {{token?.owner}}</span>
<span><strong>Owner:</strong> {{ token?.owner }}</span>
</div>
</div>
</div>

View File

@ -20,45 +20,71 @@
<mat-card-title class="card-header">
<div class="row">
Tokens
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv()"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv()"
>
EXPORT
</button>
</div>
</mat-card-title>
<div class="card-body">
<app-token-details [token]="token" (closeWindow)="token = $event"></app-token-details>
<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)="doFilter($event.target.value)"
placeholder="Filter"
/>
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<mat-table class="mat-elevation-z10 table-responsive" [dataSource]="dataSource" matSort matSortDirection="asc" matSortDisableClear>
<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>
<mat-cell *matCellDef="let token"> {{ token.name }} </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>
<mat-cell *matCellDef="let token"> {{ token.symbol }} </mat-cell>
</ng-container>
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef mat-sort-header> Address </mat-header-cell>
<mat-cell *matCellDef="let token"> {{token.address}} </mat-cell>
<mat-cell *matCellDef="let token"> {{ token.address }} </mat-cell>
</ng-container>
<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>
<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-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>
<mat-paginator
[pageSize]="5"
[pageSizeOptions]="[5, 10, 25, 100]"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</div>
@ -68,4 +94,3 @@
<!-- End Page content -->
<!-- ============================================================== -->
</div>

View File

@ -3,43 +3,86 @@
<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)="close()"> CLOSE </button>
<button
mat-raised-button
type="button"
class="btn btn-outline-secondary ml-auto mr-2"
(click)="close()"
>
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>
<h4>Exchange:</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>Sender: {{transaction.sender?.vcard.fn[0].value}}</span><br><br>
<span>Sender: {{ transaction.sender?.vcard.fn[0].value }}</span
><br /><br />
<span>
Sender Address:
<a href="{{senderBloxbergLink}}" target="_blank"> {{transaction.from}} </a>
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.from)" alt="Copy">
</span><br><br>
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewSender()">View Sender</button>
<a href="{{ senderBloxbergLink }}" target="_blank"> {{ transaction.from }} </a>
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.from)"
alt="Copy"
/> </span
><br /><br />
<button
mat-raised-button
color="primary"
class="btn btn-outline-info"
(click)="viewSender()"
>
View Sender
</button>
</li>
<li class="list-group-item">
<span>Recipient: {{transaction.recipient?.vcard.fn[0].value}}</span><br><br>
<span>Recipient: {{ transaction.recipient?.vcard.fn[0].value }}</span
><br /><br />
<span>
Recipient Address:
<a href="{{recipientBloxbergLink}}" target="_blank"> {{transaction.to}} </a>
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.to)" alt="Copy">
</span><br><br>
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewRecipient()">View Recipient</button>
<a href="{{ recipientBloxbergLink }}" target="_blank"> {{ transaction.to }} </a>
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.to)"
alt="Copy"
/> </span
><br /><br />
<button
mat-raised-button
color="primary"
class="btn btn-outline-info"
(click)="viewRecipient()"
>
View Recipient
</button>
</li>
<li class="list-group-item">
<span>Amount: {{transaction.value | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span
>Amount: {{ transaction.value | tokenRatio }} {{ tokenSymbol | uppercase }}</span
>
</li>
</ul>
<h4 class="mt-2">Token: </h4>
<h4 class="mt-2">Token:</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>
Address:
{{transaction.token._address}}
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.token._address)" alt="Copy">
{{ transaction.token._address }}
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.token._address)"
alt="Copy"
/>
</span>
</li>
<li class="list-group-item">
@ -51,97 +94,140 @@
</ul>
</div>
<div class="col-md-6">
<h4>Transaction: </h4>
<h4>Transaction:</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>Block: {{transaction.tx.block}}</span>
<span>Block: {{ transaction.tx.block }}</span>
</li>
<li class="list-group-item">
<span>Index: {{transaction.tx.txIndex}}</span>
<span>Index: {{ transaction.tx.txIndex }}</span>
</li>
<li class="list-group-item">
<span>Hash: {{transaction.tx.txHash}}</span>
<span>Hash: {{ transaction.tx.txHash }}</span>
</li>
<li class="list-group-item">
<span>Success: {{transaction.tx.success}}</span>
<span>Success: {{ transaction.tx.success }}</span>
</li>
<li class="list-group-item">
<span>Timestamp: {{transaction.tx.timestamp | unixDate}}</span>
<span>Timestamp: {{ transaction.tx.timestamp | unixDate }}</span>
</li>
</ul><br>
</ul>
<br />
<div class="mb-3">
<button mat-raised-button color="primary" 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 color="warn" 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>
<h3>Exchange:</h3>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span><strong>Trader: {{transaction.sender?.vcard.fn[0].value}}</strong></span>
<span
><strong>Trader: {{ transaction.sender?.vcard.fn[0].value }}</strong></span
>
</li>
<li class="list-group-item">
<span>
Trader Address:
<a href="{{traderBloxbergLink}}" target="_blank"> {{transaction.trader}} </a>
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.trader)" alt="Copy">
<a href="{{ traderBloxbergLink }}" target="_blank"> {{ transaction.trader }} </a>
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.trader)"
alt="Copy"
/>
</span>
</li>
</ul>
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewTrader()">View Trader</button>
<br><br>
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewTrader()">
View Trader
</button>
<br /><br />
<div class="row">
<div class="col-md-6">
<h4>Source Token: </h4>
<h4>Source Token:</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>
Address:
{{transaction.sourceToken.address}}
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.sourceToken.address)" alt="Copy">
{{ transaction.sourceToken.address }}
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.sourceToken.address)"
alt="Copy"
/>
</span>
</li>
<li class="list-group-item">
<span>Name: {{transaction.sourceToken.name}}</span>
<span>Name: {{ transaction.sourceToken.name }}</span>
</li>
<li class="list-group-item">
<span>Symbol: {{transaction.sourceToken.symbol | uppercase}}</span>
<span>Symbol: {{ transaction.sourceToken.symbol | uppercase }}</span>
</li>
<li class="list-group-item">
<span>Amount: {{transaction.fromValue}} {{transaction.sourceToken.symbol | uppercase}}</span>
<span
>Amount: {{ transaction.fromValue }}
{{ transaction.sourceToken.symbol | uppercase }}</span
>
</li>
</ul>
</div>
<div class="col-md-6">
<h4>Destination Token: </h4>
<h4>Destination Token:</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<span>
Address:
{{transaction.destinationToken.address}}
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress(transaction.destinationToken.address)" alt="Copy">
{{ transaction.destinationToken.address }}
<img
src="assets/images/checklist.svg"
class="ml-2"
height="20rem"
(click)="copyAddress(transaction.destinationToken.address)"
alt="Copy"
/>
</span>
</li>
<li class="list-group-item">
<span>Name: {{transaction.destinationToken.name}}</span>
<span>Name: {{ transaction.destinationToken.name }}</span>
</li>
<li class="list-group-item">
<span>Symbol: {{transaction.destinationToken.symbol | uppercase}}</span>
<span>Symbol: {{ transaction.destinationToken.symbol | uppercase }}</span>
</li>
<li class="list-group-item">
<span>Amount: {{transaction.toValue}} {{transaction.destinationToken.symbol | uppercase}}</span>
<span
>Amount: {{ transaction.toValue }}
{{ transaction.destinationToken.symbol | uppercase }}</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>
<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" (click)="reverseTransaction()">Reverse Transaction</button>
<button
mat-raised-button
color="warn"
type="button"
class="btn btn-outline-danger ml-2"
(click)="reverseTransaction()"
>
Reverse Transaction
</button>
</div>
</div>
</div>

View File

@ -17,71 +17,114 @@
</ol>
</nav>
<div class="card">
<mat-card-title class="card-header">
Transfers
</mat-card-title>
<mat-card-title class="card-header"> Transfers </mat-card-title>
<div class="card-body">
<app-transaction-details [transaction]="transaction" (closeWindow)="transaction = $event"></app-transaction-details>
<app-transaction-details
[transaction]="transaction"
(closeWindow)="transaction = $event"
></app-transaction-details>
<div class="row card-header">
<mat-form-field appearance="outline">
<mat-label> TRANSFER TYPE </mat-label>
<mat-select id="typeSelect" [(value)]="transactionsType" (selectionChange)="filterTransactions()">
<mat-select
id="typeSelect"
[(value)]="transactionsType"
(selectionChange)="filterTransactions()"
>
<mat-option value="all">ALL TRANSFERS</mat-option>
<mat-option *ngFor="let transactionType of transactionsTypes" [value]="transactionType">
{{transactionType | uppercase}}
<mat-option
*ngFor="let transactionType of transactionsTypes"
[value]="transactionType"
>
{{ transactionType | uppercase }}
</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button color="primary" type="button" class="btn btn-outline-primary ml-auto mr-2" (click)="downloadCsv()"> EXPORT </button>
<button
mat-raised-button
color="primary"
type="button"
class="btn btn-outline-primary ml-auto mr-2"
(click)="downloadCsv()"
>
EXPORT
</button>
</div>
<mat-form-field appearance="outline">
<mat-label> Filter </mat-label>
<input matInput type="text" (keyup)="doFilter($event.target.value, transactionDataSource)" placeholder="Filter">
<input
matInput
type="text"
(keyup)="doFilter($event.target.value, transactionDataSource)"
placeholder="Filter"
/>
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<table mat-table class="mat-elevation-z10" [dataSource]="transactionDataSource" matSort matSortActive="created"
matSortDirection="desc" matSortDisableClear>
<table
mat-table
class="mat-elevation-z10"
[dataSource]="transactionDataSource"
matSort
matSortActive="created"
matSortDirection="desc"
matSortDisableClear
>
<ng-container matColumnDef="sender">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Sender </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value || transaction.from}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Sender</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.sender?.vcard.fn[0].value || transaction.from }}
</td>
</ng-container>
<ng-container matColumnDef="recipient">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value || transaction.to}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Recipient</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.recipient?.vcard.fn[0].value || transaction.to }}
</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Value </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Value</th>
<td mat-cell *matCellDef="let transaction">
<span *ngIf="transaction.type == 'transaction'">{{transaction?.value | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span *ngIf="transaction.type == 'conversion'">{{transaction?.toValue | tokenRatio}} {{ tokenSymbol | uppercase }}</span>
<span *ngIf="transaction.type == 'transaction'"
>{{ transaction?.value | tokenRatio }} {{ tokenSymbol | uppercase }}</span
>
<span *ngIf="transaction.type == 'conversion'"
>{{ transaction?.toValue | tokenRatio }} {{ tokenSymbol | uppercase }}</span
>
</td>
</ng-container>
<ng-container matColumnDef="created">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created </th>
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | unixDate}} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Created</th>
<td mat-cell *matCellDef="let transaction">
{{ transaction?.tx.timestamp | unixDate }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header>TYPE</th>
<td mat-cell *matCellDef="let transaction">
<span class="badge badge-success badge-pill"> {{transaction?.type}} </span>
<span class="badge badge-success badge-pill"> {{ transaction?.type }} </span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="transactionDisplayedColumns"></tr>
<tr mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns;" (click)="viewTransaction(transaction)"></tr>
<tr
mat-row
*matRowDef="let transaction; columns: transactionDisplayedColumns"
(click)="viewTransaction(transaction)"
></tr>
</table>
<mat-paginator [pageSize]="defaultPageSize" [pageSizeOptions]="pageSizeOptions" showFirstLastButtons></mat-paginator>
<mat-paginator
[pageSize]="defaultPageSize"
[pageSizeOptions]="pageSizeOptions"
showFirstLastButtons
></mat-paginator>
</div>
</div>
</div>
@ -91,5 +134,3 @@
<!-- End Page content -->
<!-- ============================================================== -->
</div>

View File

@ -1,10 +1,6 @@
<div>
<div>
<p>
Message: {{ data.message }}
</p>
<p *ngIf="data.status">
Status: {{ data?.status }}
</p>
<p>Message: {{ data.message }}</p>
<p *ngIf="data.status">Status: {{ data?.status }}</p>
</div>
</div>

View File

@ -1,8 +1,10 @@
<!-- Footer Start -->
<footer class="footer">
<a target="blank" title="GPL-3" href="https://www.gnu.org/licenses/gpl-3.0.en.html"> Copyleft </a> 🄯.
<a target="blank" title="GPL-3" href="https://www.gnu.org/licenses/gpl-3.0.en.html"> Copyleft </a>
🄯.
{{ currentYear }}
<a target="blank" title="Gitlab@GrassrootsEconomics" href="https://gitlab.com/grassrootseconomics"><u> Grassroots Economics </u></a>
<a target="blank" title="Gitlab@GrassrootsEconomics" href="https://gitlab.com/grassrootseconomics"
><u> Grassroots Economics </u></a
>
</footer>
<!-- end Footer -->

View File

@ -1,13 +1,13 @@
<nav class="navbar navbar-dark background-dark">
<h1 class="navbar-brand">
<div *ngIf="noInternetConnection; then offlineBlock else onlineBlock"></div>
<div *ngIf="noInternetConnection; then offlineBlock; else onlineBlock"></div>
<ng-template #offlineBlock>
<strong style="color: red;">OFFLINE </strong>
<img width="20rem" src="assets/images/no-wifi.svg" alt="Internet Disconnected">
<strong style="color: red">OFFLINE </strong>
<img width="20rem" src="assets/images/no-wifi.svg" alt="Internet Disconnected" />
</ng-template>
<ng-template #onlineBlock>
<strong style="color: lawngreen;">ONLINE </strong>
<img width="20rem" src="assets/images/wifi.svg" alt="Internet Connected">
<strong style="color: lawngreen">ONLINE </strong>
<img width="20rem" src="assets/images/wifi.svg" alt="Internet Connected" />
</ng-template>
</h1>
</nav>

View File

@ -2,10 +2,9 @@
<div id="sidebar">
<app-network-status></app-network-status>
<nav>
<div class="sidebar-header">
<h3>
<img class="full-width" src="assets/images/CIC-Logo-white.png" alt="CIC Admin Dashboard">
<img class="full-width" src="assets/images/CIC-Logo-white.png" alt="CIC Admin Dashboard" />
</h3>
<strong>CICADA</strong>
</div>

View File

@ -1,7 +1,13 @@
<!-- Topbar Start -->
<nav class="navbar navbar-expand-lg navbar-light bg-light sticky-top">
<div class="container-fluid">
<button type="button" id="sidebarCollapse" class="navbar-btn menutoggle" aria-label="Sidebar toggle" appMenuToggle>
<button
type="button"
id="sidebarCollapse"
class="navbar-btn menutoggle"
aria-label="Sidebar toggle"
appMenuToggle
>
<span></span>
<span></span>
<span></span>

View File

@ -1,52 +1,187 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<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"/>
<meta content="Spencer Ofwiti" name="author"/>
<link rel="icon" type="image/x-icon" href="assets/icons/manifest-icon-512.png">
<link rel="apple-touch-icon" href="assets/icons/apple-icon-180.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2048-2732.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2732-2048.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1668-2388.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2388-1668.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1536-2048.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2048-1536.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1668-2224.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2224-1668.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1620-2160.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2160-1620.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1284-2778.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2778-1284.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1170-2532.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2532-1170.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1125-2436.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2436-1125.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1242-2688.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2688-1242.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-828-1792.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1792-828.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1242-2208.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-2208-1242.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-750-1334.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1334-750.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-640-1136.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="assets/icons/apple-splash-1136-640.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&amp;display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#313a46">
</head>
<body class="mat-typography">
<app-root></app-root>
<script async src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script async src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script async src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
</body>
<head>
<meta charset="utf-8" />
<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"
/>
<meta content="Spencer Ofwiti" name="author" />
<link rel="icon" type="image/x-icon" href="assets/icons/manifest-icon-512.png" />
<link rel="apple-touch-icon" href="assets/icons/apple-icon-180.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2048-2732.jpg"
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2732-2048.jpg"
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1668-2388.jpg"
media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2388-1668.jpg"
media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1536-2048.jpg"
media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2048-1536.jpg"
media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1668-2224.jpg"
media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2224-1668.jpg"
media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1620-2160.jpg"
media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2160-1620.jpg"
media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1284-2778.jpg"
media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2778-1284.jpg"
media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1170-2532.jpg"
media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2532-1170.jpg"
media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1125-2436.jpg"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2436-1125.jpg"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1242-2688.jpg"
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2688-1242.jpg"
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-828-1792.jpg"
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1792-828.jpg"
media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1242-2208.jpg"
media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-2208-1242.jpg"
media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-750-1334.jpg"
media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1334-750.jpg"
media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-640-1136.jpg"
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="assets/icons/apple-splash-1136-640.jpg"
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
crossorigin="anonymous"
/>
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&amp;display=swap"
rel="stylesheet"
/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link rel="manifest" href="manifest.webmanifest" />
<meta name="theme-color" content="#313a46" />
</head>
<body class="mat-typography">
<app-root></app-root>
<script
async
src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"
></script>
<script
async
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
crossorigin="anonymous"
></script>
<script
async
src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"
integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s"
crossorigin="anonymous"
></script>
</body>
</html>

View File

@ -8,5 +8,6 @@ if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));

View File

@ -55,8 +55,7 @@
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS

View File

@ -6,11 +6,13 @@
/* Visual */
/* Misc */
}
@import "~bootstrap/dist/css/bootstrap.css";
@import "https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap";
@import '~bootstrap/dist/css/bootstrap.css';
@import 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap';
html,
body { height: 100%; }
body {
height: 100%;
}
body {
margin: 0;
@ -35,7 +37,7 @@ a:hover,
a:focus {
text-decoration: none;
color: inherit;
transition: all .3s;
transition: all 0.3s;
}
.wrapper {
@ -50,15 +52,19 @@ a:focus {
ul ul a {
padding-left: 30px;
font-size: .9em;
font-size: 0.9em;
background: #6d7fcc;
}
.full-width,
table { width: 100%; }
table {
width: 100%;
}
li.breadcrumb-item.active,
footer.footer { color: black; }
footer.footer {
color: black;
}
.clipboard {
position: absolute;
@ -91,9 +97,13 @@ footer.footer { color: black; }
}
#sidebar .sidebar-header strong,
#sidebar.active .sidebar-header h3 { display: none; }
#sidebar.active .sidebar-header h3 {
display: none;
}
#sidebar.active .sidebar-header strong { display: block; }
#sidebar.active .sidebar-header strong {
display: block;
}
#sidebar ul li a {
display: block;
@ -104,11 +114,13 @@ footer.footer { color: black; }
}
#sidebar ul li a.active,
#sidebar.active ul li a.active { background: #000; }
#sidebar.active ul li a.active {
background: #000;
}
#sidebar.active ul li a {
padding: 20px 10px;
font-size: .85em;
font-size: 0.85em;
text-align: center;
}
@ -119,7 +131,9 @@ footer.footer { color: black; }
font-size: 1.8em;
}
#sidebar.active ul li a { padding: 10px; }
#sidebar.active ul li a {
padding: 10px;
}
#sidebar.active .dropdown-toggle::after {
top: auto;
@ -146,12 +160,14 @@ footer.footer { color: black; }
}
#sidebar ul li.active > a,
a[aria-expanded="true"] {
a[aria-expanded='true'] {
color: #fff;
background: #313a46;
}
a[data-toggle="collapse"] { position: relative; }
a[data-toggle='collapse'] {
position: relative;
}
.dropdown-toggle::after {
position: absolute;
@ -170,7 +186,9 @@ a[data-toggle="collapse"] { position: relative; }
#sidebar,
#sidebar.active,
#content,
#content.active { transition: all .3s cubic-bezier(.945, .020, .270, .665); }
#content.active {
transition: all 0.3s cubic-bezier(0.945, 0.02, 0.27, 0.665);
}
#sidebarCollapse {
width: 40px;
@ -184,14 +202,20 @@ a[data-toggle="collapse"] { position: relative; }
height: 2px;
margin: 0 auto;
background: #555;
transition: all .8s cubic-bezier(.810, -.330, .345, 1.375);
transition: all 0.8s cubic-bezier(0.81, -0.33, 0.345, 1.375);
}
#sidebarCollapse span:first-of-type { transform: rotate(45deg) translate(2px, 2px); }
#sidebarCollapse span:first-of-type {
transform: rotate(45deg) translate(2px, 2px);
}
#sidebarCollapse span:nth-of-type(2) { opacity: 0; }
#sidebarCollapse span:nth-of-type(2) {
opacity: 0;
}
#sidebarCollapse span:last-of-type { transform: rotate(-45deg) translate(1px, -1px); }
#sidebarCollapse span:last-of-type {
transform: rotate(-45deg) translate(1px, -1px);
}
#sidebarCollapse.active span {
margin: 5px auto;
@ -205,11 +229,17 @@ a[data-toggle="collapse"] { position: relative; }
color: #98a6ad;
}
.mat-column-select { overflow: initial; }
.mat-column-select {
overflow: initial;
}
button { height: 2.5rem; }
button {
height: 2.5rem;
}
.badge-pill { width: 5rem; }
.badge-pill {
width: 5rem;
}
.mat-column {
word-wrap: break-word;
@ -246,14 +276,18 @@ button { height: 2.5rem; }
}
#sidebar .sidebar-header strong,
#sidebar.active .sidebar-header h3 { display: none; }
#sidebar.active .sidebar-header h3 {
display: none;
}
#sidebar.active .sidebar-header strong,
#sidebar.active ul li a i { display: block; }
#sidebar.active ul li a i {
display: block;
}
#sidebar.active ul li a {
padding: 20px 10px;
font-size: .85em;
font-size: 0.85em;
}
#sidebar.active ul li a i {
@ -262,7 +296,9 @@ button { height: 2.5rem; }
font-size: 1.8em;
}
#sidebar.active ul ul a { padding: 10px; }
#sidebar.active ul ul a {
padding: 10px;
}
.dropdown-toggle::after {
top: auto;
@ -279,15 +315,21 @@ button { height: 2.5rem; }
height: 100vh;
}
#content .menutoggle { margin-left: 250px; }
#content .menutoggle {
margin-left: 250px;
}
#sidebar,
#content,
#content.active,
#content.active .menutoggle { margin-left: 0; }
#content.active .menutoggle {
margin-left: 0;
}
#content .menutoggle,
#content.active .menutoggle { transition: all .3s cubic-bezier(.945, .020, .270, .665); }
#content.active .menutoggle {
transition: all 0.3s cubic-bezier(0.945, 0.02, 0.27, 0.665);
}
#sidebarCollapse span:first-of-type,
#sidebarCollapse span:nth-of-type(2),
@ -297,11 +339,19 @@ button { height: 2.5rem; }
opacity: 1;
}
#sidebarCollapse.active span { margin: 0 auto; }
#sidebarCollapse.active span {
margin: 0 auto;
}
#sidebarCollapse.active span:first-of-type { transform: rotate(45deg) translate(2px, 2px); }
#sidebarCollapse.active span:first-of-type {
transform: rotate(45deg) translate(2px, 2px);
}
#sidebarCollapse.active span:nth-of-type(2) { opacity: 0; }
#sidebarCollapse.active span:nth-of-type(2) {
opacity: 0;
}
#sidebarCollapse.active span:last-of-type { transform: rotate(-45deg) translate(1px, -1px); }
#sidebarCollapse.active span:last-of-type {
transform: rotate(-45deg) translate(1px, -1px);
}
}

View File

@ -4,21 +4,22 @@ import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.

View File

@ -1,7 +1,7 @@
import {Directive, HostListener, Input} from '@angular/core';
import { Directive, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appRouterLink]'
selector: '[appRouterLink]',
})
// tslint:disable-next-line:directive-class-suffix
export class RouterLinkDirectiveStub {

View File

@ -1,10 +1,10 @@
import {Component} from '@angular/core';
import { Component } from '@angular/core';
@Component({selector: 'app-sidebar', template: ''})
@Component({ selector: 'app-sidebar', template: '' })
export class SidebarStubComponent {}
@Component({selector: 'app-topbar', template: ''})
@Component({ selector: 'app-topbar', template: '' })
export class TopbarStubComponent {}
@Component({selector: 'app-footer', template: ''})
@Component({ selector: 'app-footer', template: '' })
export class FooterStubComponent {}

View File

@ -2,7 +2,7 @@ export class TokenServiceStub {
getBySymbol(symbol: string): any {
return {
name: 'Reserve',
symbol: 'RSV'
symbol: 'RSV',
};
}
}

View File

@ -1,4 +1,4 @@
import {Observable, of} from 'rxjs';
import { Observable, of } from 'rxjs';
export class TransactionServiceStub {
setTransaction(transaction: any, cacheSize: number): void {}

View File

@ -1,12 +1,72 @@
import {Observable, of} from 'rxjs';
import { Observable, of } from 'rxjs';
export class UserServiceStub {
users = [
{id: 1, name: 'John Doe', phone: '+25412345678', address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865', type: 'user', created: '08/16/2020', balance: '12987', failedPinAttempts: 1, status: 'approved', bio: 'Bodaboda', gender: 'male'},
{id: 2, name: 'Jane Buck', phone: '+25412341234', address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865', type: 'vendor', created: '04/02/2020', balance: '56281', failedPinAttempts: 0, status: 'approved', bio: 'Groceries', gender: 'female'},
{id: 3, name: 'Mc Donald', phone: '+25498765432', address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865', type: 'group', created: '11/16/2020', balance: '450', failedPinAttempts: 2, status: 'unapproved', bio: 'Food', gender: 'male'},
{id: 4, name: 'Hera Cles', phone: '+25498769876', address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865', type: 'user', created: '05/28/2020', balance: '5621', failedPinAttempts: 3, status: 'approved', bio: 'Shop', gender: 'female'},
{id: 5, name: 'Silver Fia', phone: '+25462518374', address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865', type: 'token agent', created: '10/10/2020', balance: '817', failedPinAttempts: 0, status: 'unapproved', bio: 'Electronics', gender: 'male'},
{
id: 1,
name: 'John Doe',
phone: '+25412345678',
address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865',
type: 'user',
created: '08/16/2020',
balance: '12987',
failedPinAttempts: 1,
status: 'approved',
bio: 'Bodaboda',
gender: 'male',
},
{
id: 2,
name: 'Jane Buck',
phone: '+25412341234',
address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865',
type: 'vendor',
created: '04/02/2020',
balance: '56281',
failedPinAttempts: 0,
status: 'approved',
bio: 'Groceries',
gender: 'female',
},
{
id: 3,
name: 'Mc Donald',
phone: '+25498765432',
address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865',
type: 'group',
created: '11/16/2020',
balance: '450',
failedPinAttempts: 2,
status: 'unapproved',
bio: 'Food',
gender: 'male',
},
{
id: 4,
name: 'Hera Cles',
phone: '+25498769876',
address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865',
type: 'user',
created: '05/28/2020',
balance: '5621',
failedPinAttempts: 3,
status: 'approved',
bio: 'Shop',
gender: 'female',
},
{
id: 5,
name: 'Silver Fia',
phone: '+25462518374',
address: '0xc86ff893ac40d3950b4d5f94a9b837258b0a9865',
type: 'token agent',
created: '10/10/2020',
balance: '817',
failedPinAttempts: 0,
status: 'unapproved',
bio: 'Electronics',
gender: 'male',
},
];
actions = [
@ -15,7 +75,13 @@ export class UserServiceStub {
{ id: 3, user: 'Will', role: 'superadmin', action: 'Reclaim RSV 1000', approval: true },
{ id: 4, user: 'Vivian', role: 'enroller', action: 'Complete user profile', approval: true },
{ id: 5, user: 'Jack', role: 'enroller', action: 'Reclaim RSV 200', approval: false },
{ id: 6, user: 'Patience', role: 'enroller', action: 'Change user information', approval: false }
{
id: 6,
user: 'Patience',
role: 'enroller',
action: 'Change user information',
approval: false,
},
];
getUserById(id: string): any {
@ -30,7 +96,7 @@ export class UserServiceStub {
failedPinAttempts: 1,
status: 'approved',
bio: 'Bodaboda',
gender: 'male'
gender: 'male',
};
}
@ -41,20 +107,17 @@ export class UserServiceStub {
key: {
ethereum: [
'0x51d3c8e2e421604e2b644117a362d589c5434739',
'0x9D7c284907acbd4a0cE2dDD0AA69147A921a573D'
]
'0x9D7c284907acbd4a0cE2dDD0AA69147A921a573D',
],
},
location: {
external: {},
latitude: '22.430670',
longitude: '151.002995'
longitude: '151.002995',
},
selling: [
'environment',
'health',
'transport'
],
vcard: 'QkVHSU46VkNBUkQNClZFUlNJT046My4wDQpFTUFJTDphYXJuZXNlbkBob3RtYWlsLmNvbQ0KRk46S3VydMKgS3JhbmpjDQpOOktyYW5qYztLdXJ0Ozs7DQpURUw7VFlQPUNFTEw6NjkyNTAzMzQ5ODE5Ng0KRU5EOlZDQVJEDQo='
selling: ['environment', 'health', 'transport'],
vcard:
'QkVHSU46VkNBUkQNClZFUlNJT046My4wDQpFTUFJTDphYXJuZXNlbkBob3RtYWlsLmNvbQ0KRk46S3VydMKgS3JhbmpjDQpOOktyYW5qYztLdXJ0Ozs7DQpURUw7VFlQPUNFTEw6NjkyNTAzMzQ5ODE5Ng0KRU5EOlZDQVJEDQo=',
});
}
@ -64,7 +127,7 @@ export class UserServiceStub {
user: 'Tom',
role: 'enroller',
action: 'Disburse RSV 100',
approval: false
approval: false,
};
}
@ -74,7 +137,7 @@ export class UserServiceStub {
user: 'Tom',
role: 'enroller',
action: 'Disburse RSV 100',
approval: true
approval: true,
};
}
}