diff --git a/.gitignore b/.gitignore index 14fe5b7..4c55524 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /dist /tmp /out-tsc +/tests # Only exists if Bazel was run /bazel-out diff --git a/docs/compodoc/interceptors/ConnectionInterceptor.html b/docs/compodoc/interceptors/ConnectionInterceptor.html new file mode 100644 index 0000000..ec12b46 --- /dev/null +++ b/docs/compodoc/interceptors/ConnectionInterceptor.html @@ -0,0 +1,371 @@ + + + + + + CICADA + + + + + + + + + + + + +
+
+ + +
+
+ + + + + + + + + + + + +
+
+

+

File

+

+

+ src/app/_interceptors/connection.interceptor.ts +

+ +

+

Description

+

+

+

Intercepts and handles of events from outgoing HTTP request.

+ +

+ + +
+

Index

+ + + + + + + + + + + + + + + +
+
Methods
+
+ +
+
+ +
+

Constructor

+ + + + + + + + + + + + + +
+constructor(loggingService: LoggingService) +
+ +
+

Initialization of the connection interceptor.

+
+
+ Parameters : + + + + + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
loggingService + LoggingService + + No + +
    +
  • A service that provides logging capabilities.
  • +
+
+
+
+
+
+ +
+ +

+ Methods +

+ + + + + + + + + + + + + + + + + + + +
+ + + + intercept + + + +
+intercept(request: HttpRequest, next: HttpHandler) +
+ +
+

Intercepts HTTP requests.

+
+ +
+ Parameters : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
request + HttpRequest<unknown> + + No + +
    +
  • An outgoing HTTP request with an optional typed body.
  • +
+ +
next + HttpHandler + + No + +
    +
  • The next HTTP handler or the outgoing request dispatcher.
  • +
+ +
+
+
+
+
+ Returns : Observable<HttpEvent<unknown>> + +
+
+

The forwarded request.

+ +
+
+
+ +
+ + +
+
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+
+// Third party imports
+import { Observable } from 'rxjs';
+
+// Application imports
+import { LoggingService } from '@app/_services/logging.service';
+import { checkOnlineStatus } from '@app/_helpers';
+
+/** Intercepts and handles of events from outgoing HTTP request. */
+@Injectable()
+export class ConnectionInterceptor implements HttpInterceptor {
+  /**
+   * Initialization of the connection interceptor.
+   *
+   * @param loggingService - A service that provides logging capabilities.
+   */
+  constructor(private loggingService: LoggingService) {}
+
+  /**
+   * Intercepts HTTP requests.
+   *
+   * @param request - An outgoing HTTP request with an optional typed body.
+   * @param next - The next HTTP handler or the outgoing request dispatcher.
+   * @returns The forwarded request.
+   */
+  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
+    checkOnlineStatus().then((online) => {
+      if (!online) {
+        this.loggingService.sendErrorLevelMessage('No internet connection on device!', this, {
+          error: `NetworkError when attempting to fetch resource ${request.url}.`,
+        });
+        return;
+      } else {
+        return next.handle(request);
+      }
+    });
+    return next.handle(request);
+  }
+}
+
+
+
+ + + + + + + + + + + +
+
+

result-matching ""

+
    +
    +
    +

    No results matching ""

    +
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typedoc/classes/app__interceptors_connection_interceptor.connectioninterceptor.html b/docs/typedoc/classes/app__interceptors_connection_interceptor.connectioninterceptor.html new file mode 100644 index 0000000..3eef76d --- /dev/null +++ b/docs/typedoc/classes/app__interceptors_connection_interceptor.connectioninterceptor.html @@ -0,0 +1,246 @@ + + + + + + ConnectionInterceptor | CICADA + + + + + + +
    +
    +
    +
    + +
    +
    + Options +
    +
    + All +
      +
    • Public
    • +
    • Public/Protected
    • +
    • All
    • +
    +
    + + + + +
    +
    + Menu +
    +
    +
    +
    +
    +
    + +

    Class ConnectionInterceptor

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Intercepts and handles of events from outgoing HTTP request.

    +
    +
    +
    +
    +

    Hierarchy

    +
      +
    • + ConnectionInterceptor +
    • +
    +
    +
    +

    Implements

    +
      +
    • HttpInterceptor
    • +
    +
    +
    +

    Index

    +
    +
    +
    +

    Constructors

    + +
    +
    +

    Methods

    + +
    +
    +
    +
    +
    +

    Constructors

    +
    + +

    constructor

    + +
      +
    • + +
      +
      +

      Initialization of the connection interceptor.

      +
      +
      +

      Parameters

      +
        +
      • +
        loggingService: LoggingService
        +
        +

        A service that provides logging capabilities.

        +
        +
      • +
      +

      Returns ConnectionInterceptor

      +
    • +
    +
    +
    +
    +

    Methods

    +
    + +

    intercept

    +
      +
    • intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>>
    • +
    +
      +
    • + +
      +
      +

      Intercepts HTTP requests.

      +
      +
      +

      Parameters

      +
        +
      • +
        request: HttpRequest<unknown>
        +
        +

        An outgoing HTTP request with an optional typed body.

        +
        +
      • +
      • +
        next: HttpHandler
        +
        +

        The next HTTP handler or the outgoing request dispatcher.

        +
        +
      • +
      +

      Returns Observable<HttpEvent<unknown>>

      +

      The forwarded request.

      +
    • +
    +
    +
    +
    + +
    +
    + +
    +

    Generated using TypeDoc

    +
    +
    + + + \ No newline at end of file diff --git a/docs/typedoc/modules/app__helpers_online_status.html b/docs/typedoc/modules/app__helpers_online_status.html new file mode 100644 index 0000000..e876cae --- /dev/null +++ b/docs/typedoc/modules/app__helpers_online_status.html @@ -0,0 +1,146 @@ + + + + + + app/_helpers/online-status | CICADA + + + + + + +
    +
    +
    +
    + +
    +
    + Options +
    +
    + All +
      +
    • Public
    • +
    • Public/Protected
    • +
    • All
    • +
    +
    + + + + +
    +
    + Menu +
    +
    +
    +
    +
    +
    + +

    Module app/_helpers/online-status

    +
    +
    +
    +
    +
    +
    +
    +

    Index

    +
    +
    +
    +

    Functions

    + +
    +
    +
    +
    +
    +

    Functions

    +
    + +

    checkOnlineStatus

    +
      +
    • checkOnlineStatus(): Promise<boolean>
    • +
    +
      +
    • + +

      Returns Promise<boolean>

      +
    • +
    +
    +
    +
    + +
    +
    + +
    +

    Generated using TypeDoc

    +
    +
    + + + \ No newline at end of file diff --git a/docs/typedoc/modules/app__interceptors_connection_interceptor.html b/docs/typedoc/modules/app__interceptors_connection_interceptor.html new file mode 100644 index 0000000..5097c4d --- /dev/null +++ b/docs/typedoc/modules/app__interceptors_connection_interceptor.html @@ -0,0 +1,126 @@ + + + + + + app/_interceptors/connection.interceptor | CICADA + + + + + + +
    +
    +
    +
    + +
    +
    + Options +
    +
    + All +
      +
    • Public
    • +
    • Public/Protected
    • +
    • All
    • +
    +
    + + + + +
    +
    + Menu +
    +
    +
    +
    +
    +
    + +

    Module app/_interceptors/connection.interceptor

    +
    +
    +
    +
    +
    +
    +
    +

    Index

    +
    +
    +
    +

    Classes

    + +
    +
    +
    +
    +
    + +
    +
    + +
    +

    Generated using TypeDoc

    +
    +
    + + + \ No newline at end of file diff --git a/src/app/_helpers/index.ts b/src/app/_helpers/index.ts index 82fdb87..c1f744b 100644 --- a/src/app/_helpers/index.ts +++ b/src/app/_helpers/index.ts @@ -9,3 +9,4 @@ export * from '@app/_helpers/mock-backend'; export * from '@app/_helpers/read-csv'; export * from '@app/_helpers/schema-validation'; export * from '@app/_helpers/sync'; +export * from '@app/_helpers/online-status'; diff --git a/src/app/_helpers/online-status.ts b/src/app/_helpers/online-status.ts new file mode 100644 index 0000000..2655e23 --- /dev/null +++ b/src/app/_helpers/online-status.ts @@ -0,0 +1,15 @@ +const apiUrls = [ + 'https://api.coindesk.com/v1/bpi/currentprice.json', + 'https://dog.ceo/api/breeds/image/random', +]; + +async function checkOnlineStatus(): Promise { + try { + const online = await fetch(apiUrls[Math.floor(Math.random() * apiUrls.length)]); + return online.status >= 200 && online.status < 300; + } catch (error) { + return false; + } +} + +export { checkOnlineStatus }; diff --git a/src/app/_interceptors/connection.interceptor.spec.ts b/src/app/_interceptors/connection.interceptor.spec.ts new file mode 100644 index 0000000..465d252 --- /dev/null +++ b/src/app/_interceptors/connection.interceptor.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ConnectionInterceptor } from './connection.interceptor'; + +describe('ConnectionInterceptor', () => { + beforeEach(() => + TestBed.configureTestingModule({ + providers: [ConnectionInterceptor], + }) + ); + + it('should be created', () => { + const interceptor: ConnectionInterceptor = TestBed.inject(ConnectionInterceptor); + expect(interceptor).toBeTruthy(); + }); +}); diff --git a/src/app/_interceptors/connection.interceptor.ts b/src/app/_interceptors/connection.interceptor.ts new file mode 100644 index 0000000..2116add --- /dev/null +++ b/src/app/_interceptors/connection.interceptor.ts @@ -0,0 +1,42 @@ +// Core imports +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +// Third party imports +import { Observable } from 'rxjs'; + +// Application imports +import { LoggingService } from '@app/_services/logging.service'; +import { checkOnlineStatus } from '@app/_helpers'; + +/** Intercepts and handles of events from outgoing HTTP request. */ +@Injectable() +export class ConnectionInterceptor implements HttpInterceptor { + /** + * Initialization of the connection interceptor. + * + * @param loggingService - A service that provides logging capabilities. + */ + constructor(private loggingService: LoggingService) {} + + /** + * Intercepts HTTP requests. + * + * @param request - An outgoing HTTP request with an optional typed body. + * @param next - The next HTTP handler or the outgoing request dispatcher. + * @returns The forwarded request. + */ + intercept(request: HttpRequest, next: HttpHandler): Observable> { + checkOnlineStatus().then((online) => { + if (!online) { + this.loggingService.sendErrorLevelMessage('No internet connection on device!', this, { + error: `NetworkError when attempting to fetch resource ${request.url}.`, + }); + return; + } else { + return next.handle(request); + } + }); + return next.handle(request); + } +} diff --git a/src/app/_interceptors/error.interceptor.ts b/src/app/_interceptors/error.interceptor.ts index e189d9b..4e2deea 100644 --- a/src/app/_interceptors/error.interceptor.ts +++ b/src/app/_interceptors/error.interceptor.ts @@ -59,9 +59,10 @@ export class ErrorInterceptor implements HttpInterceptor { this.router.navigateByUrl('/auth').then(); break; case 403: // forbidden - this.errorDialogService.openDialog( - { message: 'Access to resource is not allowed (Error 403)'}) - //alert('Access to resource is not allowed!'); + this.errorDialogService.openDialog({ + message: 'Access to resource is not allowed (Error 403)', + }); + // alert('Access to resource is not allowed!'); break; } // Return an observable with a user-facing error message. diff --git a/src/app/_interceptors/index.ts b/src/app/_interceptors/index.ts index a9ce065..a3fb1f1 100644 --- a/src/app/_interceptors/index.ts +++ b/src/app/_interceptors/index.ts @@ -1,3 +1,4 @@ +export * from '@app/_interceptors/connection.interceptor'; export * from '@app/_interceptors/error.interceptor'; export * from '@app/_interceptors/http-config.interceptor'; export * from '@app/_interceptors/logging.interceptor'; diff --git a/src/app/_services/auth.service.ts b/src/app/_services/auth.service.ts index 53e3d13..9342b11 100644 --- a/src/app/_services/auth.service.ts +++ b/src/app/_services/auth.service.ts @@ -5,7 +5,6 @@ import { environment } from '@src/environments/environment'; import { LoggingService } from '@app/_services/logging.service'; import { MutableKeyStore } from '@app/_pgp'; import { ErrorDialogService } from '@app/_services/error-dialog.service'; -import { HttpClient } from '@angular/common/http'; import { HttpError, rejectBody } from '@app/_helpers/global-error-handler'; import { Staff } from '@app/_models'; import { BehaviorSubject, Observable } from 'rxjs'; @@ -23,7 +22,6 @@ export class AuthService { trustedUsersSubject: Observable> = this.trustedUsersList.asObservable(); constructor( - private httpClient: HttpClient, private loggingService: LoggingService, private errorDialogService: ErrorDialogService ) {} @@ -48,7 +46,7 @@ export class AuthService { } getWithToken(): Promise { - const sessionToken = this.getSessionToken() + const sessionToken = this.getSessionToken(); const headers = { Authorization: 'Bearer ' + sessionToken, 'Content-Type': 'application/json;charset=utf-8', @@ -94,33 +92,32 @@ export class AuthService { async login(): Promise { if (this.getSessionToken()) { sessionStorage.removeItem(btoa('CICADA_SESSION_TOKEN')); - } + } const o = await this.getChallenge(); const r = await signChallenge( - o.challenge, - o.realm, - environment.cicMetaUrl, - this.mutableKeyStore + o.challenge, + o.realm, + environment.cicMetaUrl, + this.mutableKeyStore ); - const tokenResponse = await this.sendSignedChallenge(r) - .then((response) => { - const token = response.headers.get('Token'); - if (token) { - return token; - } - if (response.status === 401) { - throw new HttpError('You are not authorized to use this system', response.status); - } - if (!response.ok) { - throw new HttpError('Unknown error from authentication server', response.status); - } + const tokenResponse = await this.sendSignedChallenge(r).then((response) => { + const token = response.headers.get('Token'); + if (token) { + return token; + } + if (response.status === 401) { + throw new HttpError('You are not authorized to use this system', response.status); + } + if (!response.ok) { + throw new HttpError('Unknown error from authentication server', response.status); + } }); if (tokenResponse) { this.setSessionToken(tokenResponse); - //this.setState('Click button to log in'); + // this.setState('Click button to log in'); return true; } return false; diff --git a/src/app/_services/block-sync.service.ts b/src/app/_services/block-sync.service.ts index 785d452..0435ec1 100644 --- a/src/app/_services/block-sync.service.ts +++ b/src/app/_services/block-sync.service.ts @@ -4,7 +4,6 @@ import { TransactionHelper } from '@cicnet/cic-client'; import { first } from 'rxjs/operators'; import { TransactionService } from '@app/_services/transaction.service'; import { environment } from '@src/environments/environment'; -import { LoggingService } from '@app/_services/logging.service'; import { RegistryService } from '@app/_services/registry.service'; import { Web3Service } from '@app/_services/web3.service'; @@ -15,17 +14,9 @@ export class BlockSyncService { readyStateTarget: number = 2; readyState: number = 0; - constructor( - private transactionService: TransactionService, - private loggingService: LoggingService - ) {} - - async init(): Promise { - await this.transactionService.init(); - } + constructor(private transactionService: TransactionService) {} async blockSync(address: string = null, offset: number = 0, limit: number = 100): Promise { - this.transactionService.resetTransactionsList(); const settings: Settings = new Settings(this.scan); const readyStateElements: { network: number } = { network: 2 }; settings.w3.provider = environment.web3Provider; diff --git a/src/app/_services/location.service.ts b/src/app/_services/location.service.ts index 562952f..740cc5e 100644 --- a/src/app/_services/location.service.ts +++ b/src/app/_services/location.service.ts @@ -35,6 +35,7 @@ export class LocationService { return queriedAreaName; } } + return 'other'; } getAreaTypes(): void { @@ -54,5 +55,6 @@ export class LocationService { return queriedAreaType; } } + return 'other'; } } diff --git a/src/app/_services/logging.service.ts b/src/app/_services/logging.service.ts index 0865e88..d7e38a1 100644 --- a/src/app/_services/logging.service.ts +++ b/src/app/_services/logging.service.ts @@ -5,9 +5,6 @@ import { NGXLogger } from 'ngx-logger'; providedIn: 'root', }) export class LoggingService { - env: string; - canDebug: boolean; - constructor(private logger: NGXLogger) { // TRACE|DEBUG|INFO|LOG|WARN|ERROR|FATAL|OFF if (isDevMode()) { diff --git a/src/app/_services/token.service.ts b/src/app/_services/token.service.ts index a572729..120bcc7 100644 --- a/src/app/_services/token.service.ts +++ b/src/app/_services/token.service.ts @@ -22,9 +22,7 @@ export class TokenService { async init(): Promise { this.registry = await RegistryService.getRegistry(); - this.tokenRegistry = new TokenRegistry( - await this.registry.getContractAddressByName('TokenRegistry') - ); + this.tokenRegistry = await RegistryService.getTokenRegistry(); this.load.next(true); } diff --git a/src/app/_services/transaction.service.ts b/src/app/_services/transaction.service.ts index 1977c3e..4a46e73 100644 --- a/src/app/_services/transaction.service.ts +++ b/src/app/_services/transaction.service.ts @@ -10,7 +10,6 @@ import { add0x, fromHex, strip0x, toHex } from '@src/assets/js/ethtx/dist/hex'; import { Tx } from '@src/assets/js/ethtx/dist'; import { toValue } from '@src/assets/js/ethtx/dist/tx'; import * as secp256k1 from 'secp256k1'; -import { AuthService } from '@app/_services/auth.service'; import { defaultAccount } from '@app/_models'; import { LoggingService } from '@app/_services/logging.service'; import { HttpClient } from '@angular/common/http'; @@ -28,13 +27,11 @@ export class TransactionService { transactions: any[] = []; private transactionList = new BehaviorSubject(this.transactions); transactionsSubject = this.transactionList.asObservable(); - userInfo: any; web3: Web3; registry: CICRegistry; constructor( private httpClient: HttpClient, - private authService: AuthService, private userService: UserService, private loggingService: LoggingService ) { @@ -42,8 +39,6 @@ export class TransactionService { } async init(): Promise { - await this.authService.init(); - await this.userService.init(); this.registry = await RegistryService.getRegistry(); } diff --git a/src/app/_services/user.service.ts b/src/app/_services/user.service.ts index 975dd72..d6d95a6 100644 --- a/src/app/_services/user.service.ts +++ b/src/app/_services/user.service.ts @@ -7,11 +7,9 @@ import { ArgPair, Envelope, Phone, Syncable, User } from 'cic-client-meta'; import { AccountDetails } from '@app/_models'; import { LoggingService } from '@app/_services/logging.service'; import { TokenService } from '@app/_services/token.service'; -import { AccountIndex } from '@app/_eth'; import { MutableKeyStore, PGPSigner, Signer } from '@app/_pgp'; import { RegistryService } from '@app/_services/registry.service'; import { CICRegistry } from '@cicnet/cic-client'; -import { AuthService } from '@app/_services/auth.service'; import { personValidation, updateSyncable, vcardValidation } from '@app/_helpers'; import { add0x } from '@src/assets/js/ethtx/dist/hex'; import { KeystoreService } from '@app/_services/keystore.service'; @@ -43,13 +41,10 @@ export class UserService { constructor( private httpClient: HttpClient, private loggingService: LoggingService, - private tokenService: TokenService, - private authService: AuthService + private tokenService: TokenService ) {} async init(): Promise { - await this.authService.init(); - await this.tokenService.init(); this.keystore = await KeystoreService.getKeystore(); this.signer = new PGPSigner(this.keystore); this.registry = await RegistryService.getRegistry(); @@ -203,12 +198,6 @@ export class UserService { } async loadAccounts(limit: number = 100, offset: number = 0): Promise { - this.resetAccountsList(); - // const accountIndexAddress: string = await this.registry.getContractAddressByName( - // 'AccountRegistry' - // ); - // const accountIndexQuery = new AccountIndex(accountIndexAddress); - // const accountAddresses: Array = await accountIndexQuery.last(limit); try { const accountRegistry = await RegistryService.getAccountRegistry(); const accountAddresses: Array = await accountRegistry.last(limit); @@ -271,10 +260,6 @@ export class UserService { this.accountsList.next(this.accounts); } - searchAccountByName(name: string): any { - return; - } - getCategories(): void { this.httpClient .get(`${environment.cicMetaUrl}/categories`) @@ -292,6 +277,7 @@ export class UserService { return queriedCategory; } } + return 'other'; } getAccountTypes(): Observable { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d9e4a2e..96c0507 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,12 +1,16 @@ import { ChangeDetectionStrategy, Component, HostListener, OnInit } from '@angular/core'; import { AuthService, + BlockSyncService, ErrorDialogService, LoggingService, + TokenService, TransactionService, + UserService, } from '@app/_services'; -import { catchError } from 'rxjs/operators'; import { SwUpdate } from '@angular/service-worker'; +import { NavigationEnd, Router } from '@angular/router'; +import { filter } from 'rxjs/operators'; @Component({ selector: 'app-root', @@ -16,16 +20,20 @@ import { SwUpdate } from '@angular/service-worker'; }) export class AppComponent implements OnInit { title = 'CICADA'; - readyStateTarget: number = 3; - readyState: number = 0; mediaQuery: MediaQueryList = window.matchMedia('(max-width: 768px)'); + url: string; + accountDetailsRegex = '/accounts/[a-z,A-Z,0-9]{40}'; constructor( private authService: AuthService, - private transactionService: TransactionService, - private loggingService: LoggingService, + private blockSyncService: BlockSyncService, private errorDialogService: ErrorDialogService, - private swUpdate: SwUpdate + private loggingService: LoggingService, + private tokenService: TokenService, + private transactionService: TransactionService, + private userService: UserService, + private swUpdate: SwUpdate, + private router: Router ) { this.mediaQuery.addEventListener('change', this.onResize); this.onResize(this.mediaQuery); @@ -33,7 +41,34 @@ export class AppComponent implements OnInit { async ngOnInit(): Promise { await this.authService.init(); + await this.tokenService.init(); + await this.userService.init(); await this.transactionService.init(); + await this.router.events + .pipe(filter((e) => e instanceof NavigationEnd)) + .forEach(async (routeInfo) => { + if (routeInfo instanceof NavigationEnd) { + this.url = routeInfo.url; + if (!this.url.match(this.accountDetailsRegex) || !this.url.includes('tx')) { + await this.blockSyncService.blockSync(); + } + if (!this.url.includes('accounts')) { + try { + // TODO it feels like this should be in the onInit handler + await this.userService.loadAccounts(100); + } catch (error) { + this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error }); + } + } + if (!this.url.includes('tokens')) { + this.tokenService.load.subscribe(async (status: boolean) => { + if (status) { + await this.tokenService.getTokens(); + } + }); + } + } + }); try { const publicKeys = await this.authService.getPublicKeys(); await this.authService.mutableKeyStore.importPublicKey(publicKeys); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9c0c7b3..01ce07e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,7 +11,12 @@ import { MatTableModule } from '@angular/material/table'; import { AuthGuard } from '@app/_guards'; import { LoggerModule } from 'ngx-logger'; import { environment } from '@src/environments/environment'; -import { ErrorInterceptor, HttpConfigInterceptor, LoggingInterceptor } from '@app/_interceptors'; +import { + ConnectionInterceptor, + ErrorInterceptor, + HttpConfigInterceptor, + LoggingInterceptor, +} from '@app/_interceptors'; import { MutablePgpKeyStore } from '@app/_pgp'; import { ServiceWorkerModule } from '@angular/service-worker'; @@ -38,6 +43,7 @@ import { ServiceWorkerModule } from '@angular/service-worker'; MockBackendProvider, GlobalErrorHandler, { provide: ErrorHandler, useClass: GlobalErrorHandler }, + { provide: HTTP_INTERCEPTORS, useClass: ConnectionInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }, diff --git a/src/app/auth/auth.component.ts b/src/app/auth/auth.component.ts index d715fd4..cf72b96 100644 --- a/src/app/auth/auth.component.ts +++ b/src/app/auth/auth.component.ts @@ -3,7 +3,6 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { CustomErrorStateMatcher } from '@app/_helpers'; import { AuthService } from '@app/_services'; import { ErrorDialogService } from '@app/_services/error-dialog.service'; -import { LoggingService } from '@app/_services/logging.service'; import { Router } from '@angular/router'; @Component({ @@ -25,7 +24,7 @@ export class AuthComponent implements OnInit { private errorDialogService: ErrorDialogService ) {} - async ngOnInit(): Promise { + ngOnInit(): void { this.keyForm = this.formBuilder.group({ key: ['', Validators.required], }); @@ -58,7 +57,7 @@ export class AuthComponent implements OnInit { } } catch (HttpError) { this.errorDialogService.openDialog({ - message: "Failed to login please try again.", + message: 'Failed to login please try again.', }); } } diff --git a/src/app/pages/accounts/account-details/account-details.component.html b/src/app/pages/accounts/account-details/account-details.component.html index 4378beb..672da8a 100644 --- a/src/app/pages/accounts/account-details/account-details.component.html +++ b/src/app/pages/accounts/account-details/account-details.component.html @@ -382,6 +382,11 @@ search +
    +

    Loading Transactions!

    + +
    + search +
    +

    Loading Accounts!

    + +
    + ; transactionsDisplayedColumns: Array = ['sender', 'recipient', 'value', 'created', 'type']; transactionsDefaultPageSize: number = 10; @@ -68,6 +69,8 @@ export class AccountDetailsComponent implements OnInit { category: string; area: string; areaType: string; + accountsLoading: boolean = true; + transactionsLoading: boolean = true; constructor( private formBuilder: FormBuilder, @@ -103,10 +106,7 @@ export class AccountDetailsComponent implements OnInit { location: ['', Validators.required], locationType: ['', Validators.required], }); - await this.blockSyncService.init(); - await this.tokenService.init(); - await this.transactionService.init(); - await this.userService.init(); + this.transactionService.resetTransactionsList(); await this.blockSyncService.blockSync(this.accountAddress); this.userService.resetAccountsList(); (await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe( @@ -114,7 +114,6 @@ export class AccountDetailsComponent implements OnInit { 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, @@ -158,6 +157,9 @@ export class AccountDetailsComponent implements OnInit { this.userDataSource.paginator = this.userTablePaginator; this.userDataSource.sort = this.userTableSort; this.accounts = accounts; + if (accounts.length > 0) { + this.accountsLoading = false; + } this.cdr.detectChanges(); }); @@ -166,6 +168,9 @@ export class AccountDetailsComponent implements OnInit { this.transactionsDataSource.paginator = this.transactionTablePaginator; this.transactionsDataSource.sort = this.transactionTableSort; this.transactions = transactions; + if (transactions.length > 0) { + this.transactionsLoading = false; + } this.cdr.detectChanges(); }); this.userService.getCategories(); @@ -199,6 +204,17 @@ export class AccountDetailsComponent implements OnInit { }); } + ngAfterViewInit(): void { + if (this.userDataSource) { + this.userDataSource.paginator = this.userTablePaginator; + this.userDataSource.sort = this.userTableSort; + } + if (this.transactionsDataSource) { + this.transactionsDataSource.paginator = this.transactionTablePaginator; + this.transactionsDataSource.sort = this.transactionTableSort; + } + } + doTransactionFilter(value: string): void { this.transactionsDataSource.filter = value.trim().toLocaleLowerCase(); } diff --git a/src/app/pages/accounts/account-search/account-search.component.ts b/src/app/pages/accounts/account-search/account-search.component.ts index f0ea97d..a24708a 100644 --- a/src/app/pages/accounts/account-search/account-search.component.ts +++ b/src/app/pages/accounts/account-search/account-search.component.ts @@ -13,9 +13,6 @@ import { environment } from '@src/environments/environment'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class AccountSearchComponent implements OnInit { - nameSearchForm: FormGroup; - nameSearchSubmitted: boolean = false; - nameSearchLoading: boolean = false; phoneSearchForm: FormGroup; phoneSearchSubmitted: boolean = false; phoneSearchLoading: boolean = false; @@ -29,9 +26,6 @@ export class AccountSearchComponent implements OnInit { private userService: UserService, private router: Router ) { - this.nameSearchForm = this.formBuilder.group({ - name: ['', Validators.required], - }); this.phoneSearchForm = this.formBuilder.group({ phoneNumber: ['', Validators.required], }); @@ -40,13 +34,8 @@ export class AccountSearchComponent implements OnInit { }); } - async ngOnInit(): Promise { - await this.userService.init(); - } + ngOnInit(): void {} - get nameSearchFormStub(): any { - return this.nameSearchForm.controls; - } get phoneSearchFormStub(): any { return this.phoneSearchForm.controls; } @@ -54,16 +43,6 @@ export class AccountSearchComponent implements OnInit { return this.addressSearchForm.controls; } - onNameSearch(): void { - this.nameSearchSubmitted = true; - if (this.nameSearchForm.invalid) { - return; - } - this.nameSearchLoading = true; - this.userService.searchAccountByName(this.nameSearchFormStub.name.value); - this.nameSearchLoading = false; - } - async onPhoneSearch(): Promise { this.phoneSearchSubmitted = true; if (this.phoneSearchForm.invalid) { diff --git a/src/app/pages/accounts/accounts.component.html b/src/app/pages/accounts/accounts.component.html index 62bc39f..5831b2a 100644 --- a/src/app/pages/accounts/accounts.component.html +++ b/src/app/pages/accounts/accounts.component.html @@ -64,6 +64,11 @@ search +
    +

    Loading Accounts!

    + +
    + ; accounts: Array = []; displayedColumns: Array = ['name', 'phone', 'created', 'balance', 'location']; @@ -25,32 +31,34 @@ export class AccountsComponent implements OnInit { accountsType: string = 'all'; accountTypes: Array; tokenSymbol: string; + loading: boolean = true; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; constructor( - private userService: UserService, private loggingService: LoggingService, + private userService: UserService, private router: Router, private tokenService: TokenService ) {} async ngOnInit(): Promise { - await this.userService.init(); - await this.tokenService.init(); + this.userService.accountsSubject.subscribe((accounts) => { + this.dataSource = new MatTableDataSource(accounts); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + this.accounts = accounts; + if (accounts.length > 0) { + this.loading = false; + } + }); try { // TODO it feels like this should be in the onInit handler await this.userService.loadAccounts(100); } catch (error) { this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error }); } - this.userService.accountsSubject.subscribe((accounts) => { - this.dataSource = new MatTableDataSource(accounts); - this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; - this.accounts = accounts; - }); this.userService .getAccountTypes() .pipe(first()) @@ -62,6 +70,13 @@ export class AccountsComponent implements OnInit { }); } + ngAfterViewInit(): void { + if (this.dataSource) { + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + } + } + doFilter(value: string): void { this.dataSource.filter = value.trim().toLocaleLowerCase(); } diff --git a/src/app/pages/accounts/accounts.module.ts b/src/app/pages/accounts/accounts.module.ts index 2d3cf37..fde59b1 100644 --- a/src/app/pages/accounts/accounts.module.ts +++ b/src/app/pages/accounts/accounts.module.ts @@ -23,6 +23,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { ReactiveFormsModule } from '@angular/forms'; import { AccountSearchComponent } from './account-search/account-search.component'; import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; @NgModule({ declarations: [ @@ -51,6 +52,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; MatProgressSpinnerModule, ReactiveFormsModule, MatSnackBarModule, + MatProgressBarModule, ], }) export class AccountsModule {} diff --git a/src/app/pages/accounts/create-account/create-account.component.ts b/src/app/pages/accounts/create-account/create-account.component.ts index ab6dfbc..c29d714 100644 --- a/src/app/pages/accounts/create-account/create-account.component.ts +++ b/src/app/pages/accounts/create-account/create-account.component.ts @@ -25,8 +25,7 @@ export class CreateAccountComponent implements OnInit { private userService: UserService ) {} - async ngOnInit(): Promise { - await this.userService.init(); + ngOnInit(): void { this.createForm = this.formBuilder.group({ accountType: ['', Validators.required], idNumber: ['', Validators.required], diff --git a/src/app/pages/admin/admin.component.html b/src/app/pages/admin/admin.component.html index b933f3e..950057d 100644 --- a/src/app/pages/admin/admin.component.html +++ b/src/app/pages/admin/admin.component.html @@ -43,6 +43,11 @@ search +
    +

    Loading Actions!

    + +
    + diff --git a/src/app/pages/admin/admin.component.ts b/src/app/pages/admin/admin.component.ts index d33be3c..c505c80 100644 --- a/src/app/pages/admin/admin.component.ts +++ b/src/app/pages/admin/admin.component.ts @@ -6,7 +6,7 @@ import { LoggingService, UserService } from '@app/_services'; import { animate, state, style, transition, trigger } from '@angular/animations'; import { first } from 'rxjs/operators'; import { exportCsv } from '@app/_helpers'; -import { Action } from '../../_models'; +import { Action } from '@app/_models'; @Component({ selector: 'app-admin', @@ -26,20 +26,23 @@ export class AdminComponent implements OnInit { displayedColumns: Array = ['expand', 'user', 'role', 'action', 'status', 'approve']; action: Action; actions: Array; + loading: boolean = true; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; constructor(private userService: UserService, private loggingService: LoggingService) {} - async ngOnInit(): Promise { - await this.userService.init(); + ngOnInit(): void { this.userService.getActions(); this.userService.actionsSubject.subscribe((actions) => { this.dataSource = new MatTableDataSource(actions); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; this.actions = actions; + if (actions.length > 0) { + this.loading = false; + } }); } diff --git a/src/app/pages/admin/admin.module.ts b/src/app/pages/admin/admin.module.ts index 7e50ba1..d29f774 100644 --- a/src/app/pages/admin/admin.module.ts +++ b/src/app/pages/admin/admin.module.ts @@ -13,6 +13,7 @@ import { MatSortModule } from '@angular/material/sort'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatButtonModule } from '@angular/material/button'; import { MatRippleModule } from '@angular/material/core'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; @NgModule({ declarations: [AdminComponent], @@ -29,6 +30,7 @@ import { MatRippleModule } from '@angular/material/core'; MatPaginatorModule, MatButtonModule, MatRippleModule, + MatProgressBarModule, ], }) export class AdminModule {} diff --git a/src/app/pages/pages-routing.module.ts b/src/app/pages/pages-routing.module.ts index 94ee6c9..02fe0a1 100644 --- a/src/app/pages/pages-routing.module.ts +++ b/src/app/pages/pages-routing.module.ts @@ -22,10 +22,10 @@ const routes: Routes = [ path: 'tokens', loadChildren: () => import('@pages/tokens/tokens.module').then((m) => m.TokensModule), }, - { - path: 'admin', - loadChildren: () => import('@pages/admin/admin.module').then((m) => m.AdminModule), - }, + // { + // path: 'admin', + // loadChildren: () => import('@pages/admin/admin.module').then((m) => m.AdminModule), + // }, { path: '**', redirectTo: 'home', pathMatch: 'full' }, ]; diff --git a/src/app/pages/settings/settings.component.html b/src/app/pages/settings/settings.component.html index 2ed99a0..24fc878 100644 --- a/src/app/pages/settings/settings.component.html +++ b/src/app/pages/settings/settings.component.html @@ -40,6 +40,7 @@ +
    @@ -67,6 +68,12 @@ /> search + +
    +

    Loading Trusted Users!

    + +
    + ; displayedColumns: Array = ['name', 'email', 'userId']; trustedUsers: Array; userInfo: Staff; + loading: boolean = true; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; constructor(private authService: AuthService) {} - async ngOnInit(): Promise { - await this.authService.init(); + ngOnInit(): void { this.authService.trustedUsersSubject.subscribe((users) => { this.dataSource = new MatTableDataSource(users); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; this.trustedUsers = users; + if (users.length > 0) { + this.loading = false; + } }); this.userInfo = this.authService.getPrivateKeyInfo(); } diff --git a/src/app/pages/settings/settings.module.ts b/src/app/pages/settings/settings.module.ts index 139feae..0eb5648 100644 --- a/src/app/pages/settings/settings.module.ts +++ b/src/app/pages/settings/settings.module.ts @@ -18,6 +18,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatSelectModule } from '@angular/material/select'; import { MatMenuModule } from '@angular/material/menu'; import { ReactiveFormsModule } from '@angular/forms'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; @NgModule({ declarations: [SettingsComponent, OrganizationComponent], @@ -38,6 +39,7 @@ import { ReactiveFormsModule } from '@angular/forms'; MatSelectModule, MatMenuModule, ReactiveFormsModule, + MatProgressBarModule, ], }) export class SettingsModule {} diff --git a/src/app/pages/tokens/tokens.component.html b/src/app/pages/tokens/tokens.component.html index 56d843b..bebf178 100644 --- a/src/app/pages/tokens/tokens.component.html +++ b/src/app/pages/tokens/tokens.component.html @@ -45,6 +45,11 @@ search +
    +

    Loading Tokens!

    + +
    + ; columnsToDisplay: Array = ['name', 'symbol', 'address', 'supply']; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; tokens: Array; token: Token; + loading: boolean = true; - constructor( - private tokenService: TokenService, - private loggingService: LoggingService, - private router: Router - ) {} + constructor(private tokenService: TokenService) {} - async ngOnInit(): Promise { - await this.tokenService.init(); + ngOnInit(): void { this.tokenService.load.subscribe(async (status: boolean) => { if (status) { await this.tokenService.getTokens(); } }); this.tokenService.tokensSubject.subscribe((tokens) => { - this.loggingService.sendInfoLevelMessage(tokens); this.dataSource = new MatTableDataSource(tokens); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; this.tokens = tokens; + if (tokens.length > 0) { + this.loading = false; + } }); } + ngAfterViewInit(): void { + if (this.dataSource) { + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + } + } + doFilter(value: string): void { this.dataSource.filter = value.trim().toLocaleLowerCase(); } diff --git a/src/app/pages/tokens/tokens.module.ts b/src/app/pages/tokens/tokens.module.ts index 938d4fb..b3a6332 100644 --- a/src/app/pages/tokens/tokens.module.ts +++ b/src/app/pages/tokens/tokens.module.ts @@ -17,6 +17,7 @@ import { MatSidenavModule } from '@angular/material/sidenav'; import { MatButtonModule } from '@angular/material/button'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatCardModule } from '@angular/material/card'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; @NgModule({ declarations: [TokensComponent, TokenDetailsComponent], @@ -37,6 +38,7 @@ import { MatCardModule } from '@angular/material/card'; MatToolbarModule, MatCardModule, MatRippleModule, + MatProgressBarModule, ], }) export class TokensModule {} diff --git a/src/app/pages/transactions/transaction-details/transaction-details.component.ts b/src/app/pages/transactions/transaction-details/transaction-details.component.ts index 29322bb..ca324e1 100644 --- a/src/app/pages/transactions/transaction-details/transaction-details.component.ts +++ b/src/app/pages/transactions/transaction-details/transaction-details.component.ts @@ -36,9 +36,7 @@ export class TransactionDetailsComponent implements OnInit { private tokenService: TokenService ) {} - async ngOnInit(): Promise { - await this.transactionService.init(); - await this.tokenService.init(); + ngOnInit(): void { if (this.transaction?.type === 'conversion') { this.traderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions'; diff --git a/src/app/pages/transactions/transactions.component.html b/src/app/pages/transactions/transactions.component.html index 96cfcc9..cfceae0 100644 --- a/src/app/pages/transactions/transactions.component.html +++ b/src/app/pages/transactions/transactions.component.html @@ -63,6 +63,11 @@ search +
    +

    Loading Transactions!

    + +
    +
    ; tokenSymbol: string; + loading: boolean = true; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -41,17 +42,16 @@ export class TransactionsComponent implements OnInit, AfterViewInit { ) {} async ngOnInit(): Promise { + await this.blockSyncService.blockSync(); this.transactionService.transactionsSubject.subscribe((transactions) => { this.transactionDataSource = new MatTableDataSource(transactions); this.transactionDataSource.paginator = this.paginator; this.transactionDataSource.sort = this.sort; this.transactions = transactions; + if (transactions.length > 0) { + this.loading = false; + } }); - await this.blockSyncService.init(); - await this.tokenService.init(); - await this.transactionService.init(); - await this.userService.init(); - await this.blockSyncService.blockSync(); this.userService .getTransactionTypes() .pipe(first()) @@ -85,8 +85,10 @@ export class TransactionsComponent implements OnInit, AfterViewInit { } ngAfterViewInit(): void { - this.transactionDataSource.paginator = this.paginator; - this.transactionDataSource.sort = this.sort; + if (this.transactionDataSource) { + this.transactionDataSource.paginator = this.paginator; + this.transactionDataSource.sort = this.sort; + } } downloadCsv(): void { diff --git a/src/app/pages/transactions/transactions.module.ts b/src/app/pages/transactions/transactions.module.ts index 4a5b044..e71342b 100644 --- a/src/app/pages/transactions/transactions.module.ts +++ b/src/app/pages/transactions/transactions.module.ts @@ -17,6 +17,7 @@ import { MatSelectModule } from '@angular/material/select'; import { MatCardModule } from '@angular/material/card'; import { MatRippleModule } from '@angular/material/core'; import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; @NgModule({ declarations: [TransactionsComponent, TransactionDetailsComponent], @@ -37,6 +38,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; MatCardModule, MatRippleModule, MatSnackBarModule, + MatProgressBarModule, ], }) export class TransactionsModule {} diff --git a/src/app/shared/network-status/network-status.component.html b/src/app/shared/network-status/network-status.component.html index 54d821a..92b9802 100644 --- a/src/app/shared/network-status/network-status.component.html +++ b/src/app/shared/network-status/network-status.component.html @@ -1,6 +1,6 @@