# CICADA

### File

`src/app/pages/accounts/account-details/account-details.component.ts`

### Implements

`OnInit`

### Metadata

changeDetection | `ChangeDetectionStrategy.OnPush`
selector | `app-account-details`
styleUrls | `./account-details.component.scss`
templateUrl | `./account-details.component.html`

### Index

###### Properties

- account
- accountAddress
- accountInfoForm
- accounts
- accountStatus
- accountsType
- accountTypes
- area
- areaNames
- areaType
- areaTypes
- bloxbergLink
- categories
- category
- genders
- matcher
- submitted
- tokenSymbol
- transaction
- transactions
- transactionsDataSource
- transactionsDefaultPageSize
- transactionsDisplayedColumns
- transactionsPageSizeOptions
- transactionsType
- transactionsTypes
- transactionTablePaginator
- transactionTableSort
- userDataSource
- userDisplayedColumns
- usersDefaultPageSize
- usersPageSizeOptions
- userTablePaginator
- userTableSort

###### Methods

- copyAddress
- doTransactionFilter
- doUserFilter
- downloadCsv
- filterAccounts
- filterTransactions
- Async ngOnInit
- resetPin
- Async saveInfo
- viewAccount
- viewTransaction

###### Accessors

- accountInfoFormStub

### Constructor

`constructor(formBuilder: FormBuilder, locationService: LocationService, transactionService: TransactionService, userService: UserService, route: ActivatedRoute, router: Router, tokenService: TokenService, loggingService: LoggingService, blockSyncService: BlockSyncService, cdr: ChangeDetectorRef, snackBar: MatSnackBar)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:70

Parameters :

Name | Type | Optional
formBuilder | `FormBuilder` | No
locationService | `LocationService` | No
transactionService | `TransactionService` | No
userService | `UserService` | No
route | `ActivatedRoute` | No
router | `Router` | No
tokenService | `TokenService` | No
loggingService | `LoggingService` | No
blockSyncService | `BlockSyncService` | No
cdr | `ChangeDetectorRef` | No
snackBar | `MatSnackBar` | No

### Methods

copyAddress
`copyAddress()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:287
Returns : `void`

doTransactionFilter
`doTransactionFilter(value: string)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:202

Parameters :

Name | Type | Optional
value | `string` | No

Returns : `void`

doUserFilter
`doUserFilter(value: string)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:206

Parameters :

Name | Type | Optional
value | `string` | No

Returns : `void`

downloadCsv
`downloadCsv(data: any, filename: string)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:283

Parameters :

Name | Type | Optional
data | `any` | No
filename | `string` | No

Returns : `void`

filterAccounts
`filterAccounts()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:245
Returns : `void`

filterTransactions
`filterTransactions()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:258
Returns : `void`

Async ngOnInit
`ngOnInit()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:92
Returns : `Promise<void>`

resetPin
`resetPin()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:271
Returns : `void`

Async saveInfo
`saveInfo()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:224
Returns : `Promise<void>`

viewAccount
`viewAccount(account)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:214

Parameters :

Name | Optional
account | No

Returns : `void`

viewTransaction
`viewTransaction(transaction)`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:210

Parameters :

Name | Optional
transaction | No

Returns : `void`

### Properties

account
Type : `AccountDetails`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:50

accountAddress
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:51

accountInfoForm
Type : `FormGroup`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:49

accounts
Type : `Array<AccountDetails>`
Default value : `[]`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:53

accountStatus
Type : `any`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:52

accountsType
Type : `string`
Default value : `'all'`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:54

accountTypes
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:61

area
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:69

areaNames
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:56

areaType
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:70

areaTypes
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:57

bloxbergLink
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:66

categories
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:55

category
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:68

genders
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:63

matcher
Type : `CustomErrorStateMatcher`
Default value : `new CustomErrorStateMatcher()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:64

submitted
Type : `boolean`
Default value : `false`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:65

tokenSymbol
Type : `string`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:67

transaction
Type : `any`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:58

transactions
Type : `Array<Transaction>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:59

transactionsDataSource
Type : `MatTableDataSource<any>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:35

transactionsDefaultPageSize
Type : `number`
Default value : `10`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:37

transactionsDisplayedColumns
Type : `Array<string>`
Default value : `['sender', 'recipient', 'value', 'created', 'type']`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:36

transactionsPageSizeOptions
Type : `Array<number>`
Default value : `[10, 20, 50, 100]`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:38

transactionsType
Type : `string`
Default value : `'all'`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:60

transactionsTypes
Type : `Array<string>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:62

transactionTablePaginator
Type : `MatPaginator`
Decorators : `@ViewChild('TransactionTablePaginator', {static: true})`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:39

transactionTableSort
Type : `MatSort`
Decorators : `@ViewChild('TransactionTableSort', {static: true})`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:40

userDataSource
Type : `MatTableDataSource<any>`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:42

userDisplayedColumns
Type : `Array<string>`
Default value : `['name', 'phone', 'created', 'balance', 'location']`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:43

usersDefaultPageSize
Type : `number`
Default value : `10`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:44

usersPageSizeOptions
Type : `Array<number>`
Default value : `[10, 20, 50, 100]`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:45

userTablePaginator
Type : `MatPaginator`
Decorators : `@ViewChild('UserTablePaginator', {static: true})`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:46

userTableSort
Type : `MatSort`
Decorators : `@ViewChild('UserTableSort', {static: true})`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:47

### Accessors

accountInfoFormStub
get `accountInfoFormStub()`
Defined in src/app/pages/accounts/account-details/account-details.component.ts:220

    import {
      ChangeDetectionStrategy,
      ChangeDetectorRef,
      Component,
      OnInit,
      ViewChild,
    } from '@angular/core';
    import { MatTableDataSource } from '@angular/material/table';
    import { MatPaginator } from '@angular/material/paginator';
    import { MatSort } from '@angular/material/sort';
    import {
      BlockSyncService,
      LocationService,
      LoggingService,
      TokenService,
      TransactionService,
      UserService,
    } from '@app/_services';
    import { ActivatedRoute, Params, Router } from '@angular/router';
    import { first } from 'rxjs/operators';
    import { FormBuilder, FormGroup, Validators } from '@angular/forms';
    import { copyToClipboard, CustomErrorStateMatcher, exportCsv } from '@app/_helpers';
    import { MatSnackBar } from '@angular/material/snack-bar';
    import { add0x, strip0x } from '@src/assets/js/ethtx/dist/hex';
    import { environment } from '@src/environments/environment';
    import { AccountDetails, Transaction } from '@app/_models';

    @Component({
      selector: 'app-account-details',
      templateUrl: './account-details.component.html',
      styleUrls: ['./account-details.component.scss'],
      changeDetection: ChangeDetectionStrategy.OnPush,
    })
    export class AccountDetailsComponent implements OnInit {
      transactionsDataSource: MatTableDataSource<any>;
      transactionsDisplayedColumns: Array<string> = ['sender', 'recipient', 'value', 'created', 'type'];
      transactionsDefaultPageSize: number = 10;
      transactionsPageSizeOptions: Array<number> = [10, 20, 50, 100];
      @ViewChild('TransactionTablePaginator', { static: true }) transactionTablePaginator: MatPaginator;
      @ViewChild('TransactionTableSort', { static: true }) transactionTableSort: MatSort;

      userDataSource: MatTableDataSource<any>;
      userDisplayedColumns: Array<string> = ['name', 'phone', 'created', 'balance', 'location'];
      usersDefaultPageSize: number = 10;
      usersPageSizeOptions: Array<number> = [10, 20, 50, 100];
      @ViewChild('UserTablePaginator', { static: true }) userTablePaginator: MatPaginator;
      @ViewChild('UserTableSort', { static: true }) userTableSort: MatSort;

      accountInfoForm: FormGroup;
      account: AccountDetails;
      accountAddress: string;
      accountStatus: any;
      accounts: Array<AccountDetails> = [];
      accountsType: string = 'all';
      categories: Array<string>;
      areaNames: Array<string>;
      areaTypes: Array<string>;
      transaction: any;
      transactions: Array<Transaction>;
      transactionsType: string = 'all';
      accountTypes: Array<string>;
      transactionsTypes: Array<string>;
      genders: Array<string>;
      matcher: CustomErrorStateMatcher = new CustomErrorStateMatcher();
      submitted: boolean = false;
      bloxbergLink: string;
      tokenSymbol: string;
      category: string;
      area: string;
      areaType: string;

      constructor(
        private formBuilder: FormBuilder,
        private locationService: LocationService,
        private transactionService: TransactionService,
        private userService: UserService,
        private route: ActivatedRoute,
        private router: Router,
        private tokenService: TokenService,
        private loggingService: LoggingService,
        private blockSyncService: BlockSyncService,
        private cdr: ChangeDetectorRef,
        private snackBar: MatSnackBar
      ) {
        this.route.paramMap.subscribe((params: Params) => {
          this.accountAddress = add0x(params.get('id'));
          this.bloxbergLink =
            'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
        });
      }

      async ngOnInit(): Promise<void> {
        this.accountInfoForm = this.formBuilder.group({
          firstName: ['', Validators.required],
          lastName: ['', Validators.required],
          phoneNumber: ['', Validators.required],
          age: [''],
          type: ['', Validators.required],
          bio: ['', Validators.required],
          gender: ['', Validators.required],
          businessCategory: ['', Validators.required],
          userLocation: ['', Validators.required],
          location: ['', Validators.required],
          locationType: ['', Validators.required],
        });
        await this.blockSyncService.init();
        await this.tokenService.init();
        await this.transactionService.init();
        await this.userService.init();
        await this.blockSyncService.blockSync(this.accountAddress);
        this.userService.resetAccountsList();
        (await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
          async (res) => {
            if (res !== undefined) {
              this.account = res;
              this.cdr.detectChanges();
              this.loggingService.sendInfoLevelMessage(this.account);
              this.locationService.areaNamesSubject.subscribe((response) => {
                this.area = this.locationService.getAreaNameByLocation(
                  this.account.location.area_name,
                  response
                );
                this.cdr.detectChanges();
                this.locationService.areaTypesSubject.subscribe((result) => {
                  this.areaType = this.locationService.getAreaTypeByArea(this.area, result);
                  this.cdr.detectChanges();
                });
              });
              this.userService.categoriesSubject.subscribe((result) => {
                this.category = this.userService.getCategoryByProduct(this.account.products[0], result);
                this.cdr.detectChanges();
              });
              const fullName = this.account.vcard?.fn[0].value.split(' ');
              this.accountInfoForm.patchValue({
                firstName: fullName[0].split(',')[0],
                lastName: fullName.slice(1).join(' '),
                phoneNumber: this.account.vcard?.tel[0].value,
                age: this.account.age,
                type: this.account.type,
                bio: this.account.products,
                gender: this.account.gender,
                businessCategory: this.account.category || this.category || 'other',
                userLocation: this.account.location.area_name,
                location: this.account.location.area || this.area || 'other',
                locationType: this.account.location.area_type || this.areaType || 'other',
              });
              this.userService
                .getAccountStatus(this.account.vcard?.tel[0].value)
                .pipe(first())
                .subscribe((response) => (this.accountStatus = response.status));
            } else {
              alert('Account not found!');
            }
          }
        );
        this.userService.accountsSubject.subscribe((accounts) => {
          this.userDataSource = new MatTableDataSource<any>(accounts);
          this.userDataSource.paginator = this.userTablePaginator;
          this.userDataSource.sort = this.userTableSort;
          this.accounts = accounts;
          this.cdr.detectChanges();
        });

        this.transactionService.transactionsSubject.subscribe((transactions) => {
          this.transactionsDataSource = new MatTableDataSource<any>(transactions);
          this.transactionsDataSource.paginator = this.transactionTablePaginator;
          this.transactionsDataSource.sort = this.transactionTableSort;
          this.transactions = transactions;
          this.cdr.detectChanges();
        });
        this.userService.getCategories();
        this.userService.categoriesSubject.subscribe((res) => {
          this.categories = Object.keys(res);
        });
        this.locationService.getAreaNames();
        this.locationService.areaNamesSubject.subscribe((res) => {
          this.areaNames = Object.keys(res);
        });
        this.locationService.getAreaTypes();
        this.locationService.areaTypesSubject.subscribe((res) => {
          this.areaTypes = Object.keys(res);
        });
        this.userService
          .getAccountTypes()
          .pipe(first())
          .subscribe((res) => (this.accountTypes = res));
        this.userService
          .getTransactionTypes()
          .pipe(first())
          .subscribe((res) => (this.transactionsTypes = res));
        this.userService
          .getGenders()
          .pipe(first())
          .subscribe((res) => (this.genders = res));
        this.tokenService.load.subscribe(async (status: boolean) => {
          if (status) {
            this.tokenSymbol = await this.tokenService.getTokenSymbol();
          }
        });
      }

      doTransactionFilter(value: string): void {
        this.transactionsDataSource.filter = value.trim().toLocaleLowerCase();
      }

      doUserFilter(value: string): void {
        this.userDataSource.filter = value.trim().toLocaleLowerCase();
      }

      viewTransaction(transaction): void {
        this.transaction = transaction;
      }

      viewAccount(account): void {
        this.router.navigateByUrl(
          `/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
        );
      }

      get accountInfoFormStub(): any {
        return this.accountInfoForm.controls;
      }

      async saveInfo(): Promise<void> {
        this.submitted = true;
        if (this.accountInfoForm.invalid || !confirm(`Change user's profile information?`)) {
          return;
        }
        const accountKey = await this.userService.changeAccountInfo(
          this.accountAddress,
          this.accountInfoFormStub.firstName.value + ', ' + this.accountInfoFormStub.lastName.value,
          this.accountInfoFormStub.phoneNumber.value,
          this.accountInfoFormStub.age.value,
          this.accountInfoFormStub.type.value,
          this.accountInfoFormStub.bio.value,
          this.accountInfoFormStub.gender.value,
          this.accountInfoFormStub.businessCategory.value,
          this.accountInfoFormStub.userLocation.value,
          this.accountInfoFormStub.location.value,
          this.accountInfoFormStub.locationType.value
        );
        this.submitted = false;
      }

      filterAccounts(): void {
        if (this.accountsType === 'all') {
          this.userService.accountsSubject.subscribe((accounts) => {
            this.userDataSource.data = accounts;
            this.accounts = accounts;
          });
        } else {
          this.userDataSource.data = this.accounts.filter(
            (account) => account.type === this.accountsType
          );
        }
      }

      filterTransactions(): void {
        if (this.transactionsType === 'all') {
          this.transactionService.transactionsSubject.subscribe((transactions) => {
            this.transactionsDataSource.data = transactions;
            this.transactions = transactions;
          });
        } else {
          this.transactionsDataSource.data = this.transactions.filter(
            (transaction) => transaction.type + 's' === this.transactionsType
          );
        }
      }

      resetPin(): void {
        if (!confirm(`Reset user's pin?`)) {
          return;
        }
        this.userService
          .resetPin(this.account.vcard.tel[0].value)
          .pipe(first())
          .subscribe((res) => {
            this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
          });
      }

      downloadCsv(data: any, filename: string): void {
        exportCsv(data, filename);
      }

      copyAddress(): void {
        if (copyToClipboard(this.accountAddress)) {
          this.snackBar.open(this.accountAddress + ' copied successfully!', 'Close', {
            duration: 3000,
          });
        }
      }
    }

    <!-- Begin page -->
    <div class="wrapper">
      <app-sidebar></app-sidebar>

      <!-- ============================================================== -->
      <!-- Start Page Content here -->
      <!-- ============================================================== -->

      <div id="content">
        <app-topbar></app-topbar>
        <!-- Start Content-->
        <div class="container-fluid" appMenuSelection>
          <nav aria-label="breadcrumb">
            <ol class="breadcrumb">
              <li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
              <li class="breadcrumb-item"><a routerLink="/accounts">Accounts</a></li>
              <li *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">
              <span class="sr-only">Loading...</span>
            </div>
            <div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem">
              <span class="sr-only">Loading...</span>
            </div>
            <div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem">
              <span class="sr-only">Loading...</span>
            </div>
          </div>
          <div *ngIf="account" class="card mb-3">
            <div class="row card-body">
              <h3>
                <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>
            </div>
          </div>
          <div *ngIf="account" class="card mt-3 mb-3">
            <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
                      >
                    </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
                      >
                    </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
                      >
                    </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-option *ngFor="let accountType of accountTypes" [value]="accountType">
                          {{ accountType | uppercase }}
                        </mat-option>
                      </mat-select>
                      <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> GENDER: </mat-label>
                      <mat-select
                        id="gender"
                        [(value)]="account.gender"
                        formControlName="gender"
                        [errorStateMatcher]="matcher"
                      >
                        <mat-option *ngFor="let gender of genders" [value]="gender">
                          {{ gender | uppercase }}
                        </mat-option>
                      </mat-select>
                      <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>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
                      >
                    </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
                      >
                    </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)]="category"
                        formControlName="businessCategory"
                        [errorStateMatcher]="matcher"
                      >
                        <mat-option *ngFor="let category of categories" [value]="category">
                          {{ category | titlecase }}
                        </mat-option>
                      </mat-select>
                      <mat-error *ngIf="submitted && accountInfoFormStub.businessCategory.errors">
                        Category is required.
                      </mat-error>
                    </mat-form-field>
                  </div>

                  <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"
                      />
                      <mat-error *ngIf="submitted && accountInfoFormStub.userLocation.errors">
                        User 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: </mat-label>
                      <mat-select
                        id="location"
                        [(value)]="area"
                        formControlName="location"
                        [errorStateMatcher]="matcher"
                      >
                        <mat-option *ngFor="let area of areaNames" [value]="area">
                          {{ area | uppercase }}
                        </mat-option>
                      </mat-select>
                      <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)]="areaType"
                        formControlName="locationType"
                        [errorStateMatcher]="matcher"
                      >
                        <mat-option *ngFor="let type of areaTypes" [value]="type">
                          {{ type | uppercase }}
                        </mat-option>
                      </mat-select>
                      <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-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"
                    >
                      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"
                    >
                      SAVE DETAILS
                    </button>
                  </div>
                </div>
              </form>
            </div>
          </div>

          <div class="card mb-3">
            <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>
                  <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>
                  </thead>
                  <tbody>
                    <tr>
                      <td>{{ account?.vcard?.fn[0].value || accountAddress }}</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>
            </div>
          </div>

          <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>
              <div class="card mt-1">
                <div class="card-header">
                  <div class="row">
                    <mat-form-field appearance="outline">
                      <mat-label> TRANSACTION TYPE </mat-label>
                      <mat-select
                        id="transferSelect"
                        [(value)]="transactionsType"
                        (selectionChange)="filterTransactions()"
                      >
                        <mat-option value="all">ALL TRANSFERS</mat-option>
                        <mat-option
                          *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>
                  </div>
                </div>

                <div class="card-body">
                  <mat-form-field appearance="outline">
                    <mat-label> Filter </mat-label>
                    <input
                      matInput
                      type="text"
                      (keyup)="doTransactionFilter($event.target.value)"
                      placeholder="Filter"
                    />
                    <mat-icon matSuffix>search</mat-icon>
                  </mat-form-field>

                  <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>
                    </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>
                    </ng-container>

                    <ng-container matColumnDef="value">
                      <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
                        >
                      </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>
                    </ng-container>

                    <ng-container matColumnDef="type">
                      <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>
                      </td>
                    </ng-container>

                    <tr mat-header-row *matHeaderRowDef="transactionsDisplayedColumns"></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>
                </div>
              </div>
            </mat-tab>

            <mat-tab label="Users">
              <div class="card mt-1">
                <mat-card-title class="card-header"> Accounts </mat-card-title>
                <div class="card-body">
                  <div class="row card-header">
                    <mat-form-field appearance="outline">
                      <mat-label> ACCOUNT TYPE </mat-label>
                      <mat-select
                        id="typeSelect"
                        [(value)]="accountsType"
                        (selectionChange)="filterAccounts()"
                      >
                        <mat-option value="all">ALL</mat-option>
                        <mat-option *ngFor="let accountType of accountTypes" [value]="accountType">
                          {{ 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>
                  </div>

                  <mat-form-field appearance="outline">
                    <mat-label> Filter </mat-label>
                    <input
                      matInput
                      type="text"
                      (keyup)="doUserFilter($event.target.value)"
                      placeholder="Filter"
                    />
                    <mat-icon matSuffix>search</mat-icon>
                  </mat-form-field>

                  <mat-table
                    class="mat-elevation-z10"
                    [dataSource]="userDataSource"
                    matSort
                    #UserTableSort="matSort"
                    matSortActive="created"
                    matSortDirection="desc"
                    matSortDisableClear
                  >
                    <ng-container matColumnDef="name">
                      <mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
                      <mat-cell *matCellDef="let user"> {{ user?.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>
                    </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>
                    </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>
                    </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>
                    </ng-container>

                    <mat-header-row *matHeaderRowDef="userDisplayedColumns"></mat-header-row>
                    <mat-row
                      *matRowDef="let account; columns: userDisplayedColumns"
                      (click)="viewAccount(account)"
                      matRipple
                    ></mat-row>
                  </mat-table>

                  <mat-paginator
                    #UserTablePaginator="matPaginator"
                    [pageSize]="usersDefaultPageSize"
                    [pageSizeOptions]="usersPageSizeOptions"
                    showFirstLastButtons
                  ></mat-paginator>
                </div>
              </div>
            </mat-tab>
          </mat-tab-group>
        </div>
        <app-footer appMenuSelection></app-footer>
      </div>
      <!-- ============================================================== -->
      <!-- End Page content -->
      <!-- ============================================================== -->
    </div>

`./account-details.component.scss`

Legend
Html element
Component
Html element with directive

# result-matching ""

# No results matching ""