File

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

Index

Properties

Properties

isFrozen
isFrozen: boolean
Type : boolean
isVerified
isVerified: boolean
Type : boolean
paymentTemplate
paymentTemplate: ITemplate
Type : ITemplate
import { PermissionProvider } from './../../enums/permission-provider';
import { Limits } from './../../models/limits.model';
import { SessionStore } from './../stores/session.store';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { catchError, map, tap, filter, first } from 'rxjs/operators';
import { ERROR_MESSAGE, TEMPLATE_API, PLAID_API } from '../../app.constants';
import { PermissionType } from '../../enums/permission-type';
import { ITemplateUpdate } from '../../models/i-template-update.model';
import { Permission } from '../../models/permission';
import { ITemplate, Template } from '../../models/template.model';
import { VerifyTemplateModel } from '../../models/verify-template.model';
import { ErrorStore } from '../stores/error.store';
import { IPlaidAccount } from '../../models/i-plaid-account.model';
import { AccountCategory } from '../../enums';

const FI_VERIFIED = 'fiverified';
export interface VerificationResponse {
  isVerified: boolean;
  isFrozen: boolean;
  paymentTemplate: ITemplate;
}

@Injectable()
export class TemplateService {
  private templates: Template[];
  private headers = new HttpHeaders();
  private limits: Limits;
  private publisher = new BehaviorSubject<Template[]>(null);
  public templates$ = this.publisher.asObservable();

  private feePublisher = new BehaviorSubject<number>(null);
  public fee$ = this.feePublisher.asObservable();

  constructor(
    private http: HttpClient,
    private errorService: ErrorStore,
    store: SessionStore
  ) {
    this.headers.append('Cache-control', 'no-cache');
    this.headers.append('Pragma', 'no-cache');
    this.headers.append('Expires', '0');
    this.headers.append('Content-Type', 'application/json');
    store.session$.pipe(first((s) => !!s && !!s.limits)).subscribe((session) => {
      this.limits = session.limits;
      console.log('TemplateService -> limits', this.limits);
    });
  }

  private publish() {
    this.publisher.next(this.templates);
  }

  updateTemplate(id: string, payload: ITemplateUpdate): Observable<boolean> {
    const url = `${TEMPLATE_API}/${id}`;
    return this.http.patch(url, payload).pipe(
      map((res) => {
        this.templates = this.templates.map((t) => {
          if (t.id === id) {
            t.displayName = payload.displayName;
          }
          return t;
        });
        this.publish();
        return true;
      }),
      catchError((error) => this.handleError(error, 'Failed To Update Account'))
    );
  }

  addAccounts(accounts: Array<IPlaidAccount>): Observable<boolean> {
    return this.http
      .post<Template[]>(`${PLAID_API}`, accounts, {
        headers: this.headers,
      })
      .pipe(
        catchError((error) => {
          const title = 'Failed To Add Accounts';
          return this.handleError(error, title);
        })
      );
  }

  createTemplate(payload: Template): Observable<Template> {
    const url = `${TEMPLATE_API}/create`;
    return this.http.post<ITemplate>(url, payload).pipe(
      tap((cfg) => {
        const template = new Template(cfg);
        this.templates.unshift(template);
        this.publish();
      }),
      catchError((error) => {
        const title = 'Failed To Add Account';
        return this.handleError(error, title);
      })
    );
  }

  deleteTemplate(id: string): Observable<boolean> {
    const url = `${TEMPLATE_API}/${id}`;
    return this.http.delete(url).pipe(
      map((res) => {
        return true;
      }),
      tap((res) => {
        this.templates = this.templates.filter((t) => t.id !== id);
        this.publish();
      }),
      catchError((error) => {
        const title = 'Failed To Delete Account';
        return this.handleError(error, title);
      })
    );
  }

  loadTemplates(): Observable<boolean> {
    const url = `${TEMPLATE_API}`;
    return this.http
      .get<ITemplate[]>(url, { headers: this.headers })
      .pipe(
        tap((templates) => console.log('templates before permissions filter', templates)),
        map((templates) => {
          if (this.limits.credit.transaction === 0 || this.limits.credit.daily === 0) {
            templates = templates.map((t) => {
              t.permissions = t.permissions.filter(
                (p) =>
                  !(
                    t.accountCategory.toLowerCase() === FI_VERIFIED &&
                    p.type === PermissionType.Credit
                  )
              );
              return t;
            });
          }
          if (this.limits.debit.transaction === 0 || this.limits.debit.daily === 0) {
            templates = templates.map((t) => {
              t.permissions = t.permissions.filter(
                (p) =>
                  !(
                    t.accountCategory.toLowerCase() === FI_VERIFIED &&
                    p.type === PermissionType.Debit
                  )
              );
              return t;
            });
          }
          return templates;
        }),
        tap((templates) => console.log('templates after permissions filter', templates)),
        map((templates) => {
          this.templates = templates.map((t) => new Template(t));
          const customerEntered = templates.filter(
            (t) => t.accountCategory === AccountCategory.CustomerEntered
          );
          this.publish();
          const fee = this.templates && this.templates.length > 0 ? this.templates[0].fee : 0;
          this.feePublisher.next(fee);
          return customerEntered.length > 0;
        }),

        catchError((error) => {
          const title = 'Failed To Retrieve Accounts';
          return this.handleError(error, title);
        })
      );
  }

  getTemplateById(id: string): Observable<Template> {
    try {
      return this.templates$.pipe(
        filter((templates) => templates !== null && templates !== undefined),
        map((templates) => {
          const found = templates.filter((t) => t.id === id);
          const foundTemplate = found.length > 0 ? found[0] : null;
          return foundTemplate;
        })
      );
    } catch (error) {
      const title = 'Failed To Retrieve Account';
      return this.handleError(error, title);
    }
  }

  verify(payload: VerifyTemplateModel): Observable<VerificationResponse> {
    const url = `${TEMPLATE_API}/verify`;
    return this.http.post<VerificationResponse>(url, payload).pipe(
      tap((response) => {
        this.templates = this.templates.map((t) => {
          if (t.id === payload.paymentTemplateId) {
            t.isFrozen = response.isFrozen;
            if (response.isVerified) {
              t.isMicroDepositVerificationPending =
                response.paymentTemplate.isMicroDepositVerificationPending;
              const permissions = response.paymentTemplate.permissions.map(
                (permission) => new Permission(permission)
              );
              t.permissions = permissions;
            }
          }
          return t;
        });
        this.publish();
      }),
      catchError((error) => {
        const title = 'Failed To Verify Account';
        return this.handleError(error, title);
      })
    );
  }

  private handleError(error: HttpErrorResponse, title: string) {
    this.errorService.showError(title, ERROR_MESSAGE);
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.error(`Backend returned code ${error.status}, ` + `body was: ${error.error}`);
    }
    // return an ErrorObservable with a user-facing error message
    return new ErrorObservable('Something bad happened; please try again later.');
  }
}

results matching ""

    No results matching ""