From 87cca9b7d73613ffe388558dd575f99699405193 Mon Sep 17 00:00:00 2001 From: Mike Roberts Date: Wed, 15 Aug 2018 12:25:39 -0400 Subject: [PATCH] Initial Commit --- karma.conf.js | 31 +++++ ng-package.json | 8 ++ ng-package.prod.json | 7 + package.json | 12 ++ src/lib/interfaces.ts | 76 +++++++++++ src/lib/ngx-plaid-link.component.spec.ts | 25 ++++ src/lib/ngx-plaid-link.component.ts | 162 +++++++++++++++++++++++ src/lib/ngx-plaid-link.module.ts | 12 ++ src/lib/ngx-plaid-link.service.spec.ts | 15 +++ src/lib/ngx-plaid-link.service.ts | 8 ++ src/public_api.ts | 7 + src/test.ts | 22 +++ tsconfig.lib.json | 33 +++++ tsconfig.spec.json | 17 +++ tslint.json | 17 +++ 15 files changed, 452 insertions(+) create mode 100644 karma.conf.js create mode 100644 ng-package.json create mode 100644 ng-package.prod.json create mode 100644 package.json create mode 100644 src/lib/interfaces.ts create mode 100644 src/lib/ngx-plaid-link.component.spec.ts create mode 100644 src/lib/ngx-plaid-link.component.ts create mode 100644 src/lib/ngx-plaid-link.module.ts create mode 100644 src/lib/ngx-plaid-link.service.spec.ts create mode 100644 src/lib/ngx-plaid-link.service.ts create mode 100644 src/public_api.ts create mode 100644 src/test.ts create mode 100644 tsconfig.lib.json create mode 100644 tsconfig.spec.json create mode 100644 tslint.json diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..4c5f8d0 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,31 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage'), + reports: ['html', 'lcovonly'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/ng-package.json b/ng-package.json new file mode 100644 index 0000000..d5732a7 --- /dev/null +++ b/ng-package.json @@ -0,0 +1,8 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ngx-plaid-link", + "deleteDestPath": false, + "lib": { + "entryFile": "src/public_api.ts" + } +} \ No newline at end of file diff --git a/ng-package.prod.json b/ng-package.prod.json new file mode 100644 index 0000000..bc084be --- /dev/null +++ b/ng-package.prod.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ngx-plaid-link", + "lib": { + "entryFile": "src/public_api.ts" + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..92dce47 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "ngx-plaid-link", + "version": "0.1.0", + "author": { + "name": "Mike Roberts", + "url": "https://github.com/mike-roberts" + }, + "peerDependencies": { + "@angular/common": "^6.0.0-rc.0 || ^6.0.0", + "@angular/core": "^6.0.0-rc.0 || ^6.0.0" + } +} diff --git a/src/lib/interfaces.ts b/src/lib/interfaces.ts new file mode 100644 index 0000000..3bd4536 --- /dev/null +++ b/src/lib/interfaces.ts @@ -0,0 +1,76 @@ +export interface PlaidSuccessMetadata { + link_session_id: string; + institution: PlaidInstitutionObject; + account: Array; +} + +export interface PlaidOnSuccessArgs { + token: string; + metadata: PlaidSuccessMetadata; +} + +export interface PlaidInstitutionObject { + name: string; + institution_id: string; +} + +export interface PlaidAccountObject { + id: string; + name: string; + mask: string; + type: string; + subtype: string; +} + +export interface PlaidErrorObject { + display_message: string; + error_code: string; + error_message: string; + error_type: string; +} + +export interface PlaidErrorMetadata { + link_session_id: string; + institution: PlaidInstitutionObject; + status: string; +} + +export interface PlaidOnExitArgs { + error: PlaidErrorObject; + metadata: PlaidErrorMetadata; +} + +export interface PlaidOnEventArgs { + eventName: string; + metadata: PlaidEventMetadata; +} + +export interface PlaidEventMetadata { + error_code: string; + error_message: string; + error_type: string; + exit_status: string; + institution_id: string; + institution_name: string; + institution_search_query: string; + request_id: string; + link_session_id: string; + mfa_type: string; + view_name: string; + timestamp: string; +} + +export interface PlaidConfig { + apiVersion?: string; + clientName?: string; + env: string; + forceIframe?: boolean; + key: string; + onLoad?: Function; + onSuccess: Function; + onExit: Function; + onEvent?: Function; + product: Array; + token?: string; + webhook?: string; +} diff --git a/src/lib/ngx-plaid-link.component.spec.ts b/src/lib/ngx-plaid-link.component.spec.ts new file mode 100644 index 0000000..01e4d2c --- /dev/null +++ b/src/lib/ngx-plaid-link.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NgxPlaidLinkComponent } from './ngx-plaid-link.component'; + +describe('NgxPlaidLinkComponent', () => { + let component: NgxPlaidLinkComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NgxPlaidLinkComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NgxPlaidLinkComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/lib/ngx-plaid-link.component.ts b/src/lib/ngx-plaid-link.component.ts new file mode 100644 index 0000000..7edb189 --- /dev/null +++ b/src/lib/ngx-plaid-link.component.ts @@ -0,0 +1,162 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { + PlaidErrorMetadata, + PlaidErrorObject, + PlaidEventMetadata, + PlaidOnEventArgs, + PlaidOnExitArgs, + PlaidOnSuccessArgs, + PlaidSuccessMetadata, + PlaidConfig +} from './interfaces'; + +import { DOCUMENT } from '@angular/platform-browser'; + +export interface ICustomWindow extends Window { + Plaid: { + create: Function; + }; +} + +function getWindow(): any { + return window; +} + +@Component({ + selector: 'mr-ngx-plaid-link', + template: ` + + `, + styles: [] +}) +export class NgxPlaidLinkComponent { + + private defaultProps = { + apiVersion: 'v2', + env: 'sandbox', + institution: null, + token: null, + style: { + 'padding': '6px 4px', + 'outline': 'none', + 'background': '#FFFFFF', + 'border': '2px solid #F1F1F1', + 'border-radius': '4px', + }, + buttonText: 'Link Your Bank Account', + webhook: '', + product: ['auth'], + className: 'plaid-link-button' + }; + + disabledButton: boolean; + linkLoaded: boolean; + + linkHandler: any; + + @Input() apiVersion?: string = this.defaultProps.apiVersion; + @Input() clientName?: string; + @Input() env?: string = this.defaultProps.env; + @Input() institution?: string = this.defaultProps.institution; + @Input() publicKey: string; + @Input() product?: Array = this.defaultProps.product; + @Input() token?: string = this.defaultProps.token; + @Input() webhook?: string = this.defaultProps.webhook; + @Input() style?: any = this.defaultProps.style; + @Input() className?: string = this.defaultProps.className; + @Input() buttonText?: string = this.defaultProps.buttonText; + + @Output() Event: EventEmitter = new EventEmitter(); + @Output() Click: EventEmitter = new EventEmitter(); + @Output() Load: EventEmitter = new EventEmitter(); + @Output() Exit: EventEmitter = new EventEmitter(); + @Output() Success: EventEmitter = new EventEmitter(); + + get nativeWindow(): ICustomWindow { + return getWindow(); + } + + constructor() { + this.disabledButton = false; + this.linkLoaded = false; + } + + onScriptError() { + console.error('There was an issue loading the link-initialize.js script'); + } + + public onExit(error: PlaidErrorObject, metadata: PlaidErrorMetadata) { + this.Exit.emit({ + error: error, + metadata: metadata + }); + } + + public onEvent(eventName: string, metadata: PlaidEventMetadata) { + this.Event.emit({ + eventName: eventName, + metadata: metadata + }); + } + + public onSuccess(public_token: string, metadata: PlaidSuccessMetadata) { + this.Success.emit({ + token: public_token, + metadata: metadata + }); + } + + onClick($event) { + this.Click.emit($event); + const self = this; + const config: PlaidConfig = { + env: self.env, + key: self.publicKey, + product: self.product, + apiVersion: 'v2', + forceIframe: true, + onSuccess: function (public_token, metadata) { + self.onSuccess(public_token, metadata); + }, + onExit: function (err, metadata) { + self.onExit(err, metadata); + }, + onEvent: function (eventName, metadata) { + self.onEvent(eventName, metadata); + }, + onLoad: function () { + self.onLoad(); + } + }; + // Set the optional items. + if (!!self.clientName) { + config.clientName = self.clientName; + } + if (!!self.token) { + config.token = self.token; + } + if (!!self.webhook) { + config.webhook = self.webhook; + } + + this.linkHandler = this.nativeWindow.Plaid.create(config); + + // Open to a specific institution if necessary; + const institution = this.institution || null; + if (this.linkHandler) { + this.linkHandler.open(institution); + } + } + + public onLoad($event = 'link_loaded') { + this.Load.emit($event); + this.linkLoaded = true; + } + +} diff --git a/src/lib/ngx-plaid-link.module.ts b/src/lib/ngx-plaid-link.module.ts new file mode 100644 index 0000000..7bc48d6 --- /dev/null +++ b/src/lib/ngx-plaid-link.module.ts @@ -0,0 +1,12 @@ +import { NgModule, ModuleWithProviders } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { NgxPlaidLinkComponent } from './ngx-plaid-link.component'; + +@NgModule({ + imports: [ + CommonModule + ], + declarations: [NgxPlaidLinkComponent], + exports: [NgxPlaidLinkComponent] +}) +export class NgxPlaidLinkModule { } diff --git a/src/lib/ngx-plaid-link.service.spec.ts b/src/lib/ngx-plaid-link.service.spec.ts new file mode 100644 index 0000000..59140ee --- /dev/null +++ b/src/lib/ngx-plaid-link.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { NgxPlaidLinkService } from './ngx-plaid-link.service'; + +describe('NgxPlaidLinkService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [NgxPlaidLinkService] + }); + }); + + it('should be created', inject([NgxPlaidLinkService], (service: NgxPlaidLinkService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/lib/ngx-plaid-link.service.ts b/src/lib/ngx-plaid-link.service.ts new file mode 100644 index 0000000..dc0ae3b --- /dev/null +++ b/src/lib/ngx-plaid-link.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class NgxPlaidLinkService { + constructor() { } +} diff --git a/src/public_api.ts b/src/public_api.ts new file mode 100644 index 0000000..507f98e --- /dev/null +++ b/src/public_api.ts @@ -0,0 +1,7 @@ +/* + * Public API Surface of ngx-plaid-link + */ + +export * from './lib/ngx-plaid-link.service'; +export * from './lib/ngx-plaid-link.component'; +export * from './lib/ngx-plaid-link.module'; diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..e11ff1c --- /dev/null +++ b/src/test.ts @@ -0,0 +1,22 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/tsconfig.lib.json b/tsconfig.lib.json new file mode 100644 index 0000000..3a2b0b9 --- /dev/null +++ b/tsconfig.lib.json @@ -0,0 +1,33 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "module": "es2015", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "types": [], + "lib": [ + "dom", + "es2015" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "flatModuleId": "AUTOGENERATED", + "flatModuleOutFile": "AUTOGENERATED" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 0000000..16da33d --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..dd92321 --- /dev/null +++ b/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "mr", + "camelCase" + ], + "component-selector": [ + true, + "element", + "mr", + "kebab-case" + ] + } +}