File

src/app/providers/services/plaid.service.ts

Index

Properties
Methods

Constructor

constructor(httpClient: HttpClient, errorService: ErrorStore, router: Router, sessionStore: SessionStore)
Parameters :
Name Type Optional
httpClient HttpClient No
errorService ErrorStore No
router Router No
sessionStore SessionStore No

Methods

clearAccounts
clearAccounts()
Returns : void
create
create()
Returns : void
getAccounts
getAccounts(publicToken)
Parameters :
Name Optional
publicToken No
getLinkToken
getLinkToken()
Private handleError
handleError(error: any, title: string)
Parameters :
Name Type Optional
error any No
title string No
Returns : any
onAccountsAdded
onAccountsAdded()
Returns : void
onAddAccounts
onAddAccounts()
Returns : void
Private onEvent
onEvent(eventName, metadata)
Parameters :
Name Optional
eventName No
metadata No
Returns : void
Private onExit
onExit(err, metadata)
Parameters :
Name Optional
err No
metadata No
Returns : void
onLoad
onLoad()
Returns : void
Private onSuccess
onSuccess(public_token, metadata)
Parameters :
Name Optional
public_token No
metadata No
Returns : void
open
open()
Returns : void

Properties

Public accounts$
Default value : this.accountsSource.asObservable()
Private accountsSource
Default value : new BehaviorSubject<Array<IPlaidAccount>>(null)
closeOnLoad
Default value : false
Private environment
Type : string
handler
Type : IPlaidHandler
Private headers
Default value : new HttpHeaders()
Public loader$
Default value : this.loaderSource.asObservable()
Private loaderSource
Default value : new BehaviorSubject<IPlaidProgressEvent>(null)
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { filter, first, map } from 'rxjs/operators';
import { catchError } from 'rxjs/operators/catchError';
import { ERROR_MESSAGE, PLAID_API, PLAID_API_LINK_TOKEN } from '../../app.constants';
import { IPlaidAccount } from '../../models/i-plaid-account.model';
import { IPlaidLinkToken } from '../../models/i-plaid-link-token.model';
import { SessionStore } from '../stores';
import { ErrorStore } from '../stores/error.store';

interface IPlaid {
  create(options: any);
}

interface IPlaidHandler {
  open();
  exit();
}

declare var Plaid: IPlaid;

export interface IPlaidProgressEvent {
  header?: string;
  message?: string;
  show: boolean;
}

@Injectable()
export class PlaidService {
  private headers = new HttpHeaders(); // todo move headers to interceptor '../interceptors/auth.interceptor'
  handler: IPlaidHandler;
  private accountsSource = new BehaviorSubject<Array<IPlaidAccount>>(null);
  public accounts$ = this.accountsSource.asObservable();
  private loaderSource = new BehaviorSubject<IPlaidProgressEvent>(null);
  public loader$ = this.loaderSource.asObservable();
  closeOnLoad = false;
  private environment: string;

  constructor(
    private httpClient: HttpClient,
    private errorService: ErrorStore,
    private router: Router,
    private sessionStore: SessionStore
  ) {
    this.headers.append('Cache-control', 'no-cache');
    this.headers.append('Pragma', 'no-cache');
    this.headers.append('Expires', '0');

    sessionStore.session$
      .pipe(
        filter(
          session =>
            session !== null &&
            session !== undefined &&
            session.plaidEnvironment !== null &&
            session.plaidEnvironment !== undefined
        ),
        map(session => session.plaidEnvironment),
        first()
      )
      .subscribe(environment => {
        this.environment = environment.toLowerCase();
        this.create();
      });
  }

  create() {
    console.log(`creating plaid link token`);
    this.getLinkToken().subscribe(data => {
      console.log('plaid link token result', data);
      console.log(`creating plaid for environment ${this.environment}`);
      this.handler = Plaid.create({
        env: this.environment,
        token: data.link_token,
        onLoad: () => {
          this.onLoad();
        },
        onSuccess: (public_token, metadata) => {
          this.onSuccess(public_token, metadata);
        },
        onExit: (err, metadata) => {
          this.onExit(err, metadata);
        },
        onEvent: (eventName, metadata) => {
          this.onEvent(eventName, metadata);
        }
      });
    });
  }

  open() {
    if (!this.handler) {
      this.create();
    }
    this.loaderSource.next({
      header: 'Starting Plaid',
      message: 'Please wait a moment while Plaid starts up',
      show: true
    });
    this.handler.open();
  }

  onLoad() {
    console.log('plaid onLoad');
  }

  onAddAccounts() {
    this.loaderSource.next({
      header: 'Adding Accounts',
      message: 'We are adding your accounts.',
      show: true
    });
  }

  onAccountsAdded() {
    this.loaderSource.next({
      show: false
    });
  }

  clearAccounts() {
    this.accountsSource.next(null);
  }

  private onSuccess(public_token, metadata) {
    this.loaderSource.next({
      header: 'Finding Accounts',
      message: 'Looking for all your accounts.',
      show: true
    });
    this.getAccounts(public_token).subscribe(accounts => {
      console.log('plaid onSuccess', public_token);
      this.accountsSource.next(accounts);
      this.loaderSource.next({
        show: false
      });
    });
  }

  private onExit(err, metadata) {
    this.router.navigate(['/template/create']);
    // function that is called when a user has specifically exited the Link flow
    console.log('plaid onExit', err, metadata);
    if (err != null) {
      // The user encountered a Plaid API error prior to exiting.
    }
  }

  private onEvent(eventName, metadata) {
    // function that is called when a user reaches certain points in the Link flow
    console.log('plaid onEvent', eventName, metadata);
    switch (eventName) {
      case 'OPEN':
        this.loaderSource.next({
          show: false
        });
        break;
      default:
      // noop
    }
  }

  getLinkToken(): Observable<IPlaidLinkToken> {
    return this.httpClient
      .get<IPlaidLinkToken>(`${PLAID_API_LINK_TOKEN}`, {
        headers: this.headers
      })
      .pipe(
        catchError(error => {
          const title = 'Failed to Create Plaid Link Token';
          return this.handleError(error, title);
        })
      );
  }

  getAccounts(publicToken): Observable<Array<IPlaidAccount>> {
    return this.httpClient
      .get<Array<IPlaidAccount>>(`${PLAID_API}?publicToken=${publicToken}`, {
        headers: this.headers
      })
      .pipe(
        map(accounts => {
          return accounts.map(account => {
            account.selected = true;
            return account;
          });
        }),
        catchError(error => {
          const title = 'Failed To Retrieve Plaid Accounts';
          return this.handleError(error, title);
        })
      );
  }

  private handleError(error: any, title: string) {
    this.errorService.showError(title, ERROR_MESSAGE);
    return Observable.of(null);
  }
}

results matching ""

    No results matching ""