From ce5393e0a115290971897b56e94b0bf84ff19e6c Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 20 Jul 2017 15:16:47 +0100 Subject: [PATCH] Extract identity card component for use on login screen and (#1612) during identity card import Contributes to #902 Signed-off-by: James Taylor --- .../identity-card.component.html | 47 ++++++ .../identity-card.component.scss | 117 +++++++++++++ .../identity-card.component.spec.ts | 154 ++++++++++++++++++ .../identity-card/identity-card.component.ts | 59 +++++++ .../src/app/login/identity-card/index.ts | 1 + .../src/app/login/login.component.html | 39 +---- .../src/app/login/login.component.scss | 110 ++----------- .../src/app/login/login.component.spec.ts | 11 +- .../src/app/login/login.module.ts | 4 +- 9 files changed, 407 insertions(+), 135 deletions(-) create mode 100644 packages/composer-playground/src/app/login/identity-card/identity-card.component.html create mode 100644 packages/composer-playground/src/app/login/identity-card/identity-card.component.scss create mode 100644 packages/composer-playground/src/app/login/identity-card/identity-card.component.spec.ts create mode 100644 packages/composer-playground/src/app/login/identity-card/identity-card.component.ts create mode 100644 packages/composer-playground/src/app/login/identity-card/index.ts diff --git a/packages/composer-playground/src/app/login/identity-card/identity-card.component.html b/packages/composer-playground/src/app/login/identity-card/identity-card.component.html new file mode 100644 index 0000000000..c224261983 --- /dev/null +++ b/packages/composer-playground/src/app/login/identity-card/identity-card.component.html @@ -0,0 +1,47 @@ +
+
+ +
+
+
+ {{getInitials()}} +
+

{{identity.userId}}

+
+
+ + +
+
+

Connection Profile

+

{{identity.profile}}

+
+
+

Business Network

+

{{identity.businessNetwork}}

+
+
+ +
+
diff --git a/packages/composer-playground/src/app/login/identity-card/identity-card.component.scss b/packages/composer-playground/src/app/login/identity-card/identity-card.component.scss new file mode 100644 index 0000000000..b27e0d822b --- /dev/null +++ b/packages/composer-playground/src/app/login/identity-card/identity-card.component.scss @@ -0,0 +1,117 @@ +@import '../../../assets/styles/base/_colors.scss'; +@import '../../../assets/styles/base/_variables.scss'; + +.composer { + .identity-card { + position: relative; + background-color: $white; + box-shadow: 3px 6px 15px 0 rgba(0, 0, 0, 0.20); + margin-left: $space-large; + margin-bottom: $space-large; + width: 275px; + + section, footer { + padding: 0 $space-large; + } + + p { + text-align: center; + } + + h3 { + text-align: center; + text-transform: uppercase; + color: $secondary-text; + font-family: $font-stack; + font-weight: 400; + font-size: 0.9rem; + font-size: x-small; + } + + header { + button.dismiss { + position: absolute; + top: 0; + right: $space-smedium; + + svg { + fill: $second-highlight; + } + } + } + + footer { + display: flex; + justify-content: space-around; + background-color: $white; + border-top: 1px solid $fourth-highlight; + + button { + display: flex; + align-items: center; + + span { + color: $second-highlight; + margin-right: $space-smedium; + } + + svg { + // why is the align-self required for Safari?! + align-self: center; + fill: $second-highlight; + } + } + } + + .user-details { + padding-top: $space-large; + + p { + font-weight: 600; + } + + .image-placeholder { + display: flex; + align-items: center; + justify-content: space-around; + background-color: $fourth-highlight; + border: 1px solid $fourth-highlight; + border-radius: 50%; + width: 75px; + height: 75px; + margin: 0 auto; + position: relative; + + .initials { + color: $second-highlight; + font-weight: 600; + font-size: xx-large; + text-transform: uppercase; + } + } + } + + .actions { + display: flex; + justify-content: center; + padding-bottom: $space-smedium; + + button.delete { + border-color: transparent; + } + + button:first-child { + margin-right: $space-large; + } + + svg { + fill: $second-highlight; + } + } + + .connection-profile-details, .business-network-details { + padding-top: $space-medium; + border-top: 1px solid $fourth-highlight; + } + } +} diff --git a/packages/composer-playground/src/app/login/identity-card/identity-card.component.spec.ts b/packages/composer-playground/src/app/login/identity-card/identity-card.component.spec.ts new file mode 100644 index 0000000000..8eedd74aba --- /dev/null +++ b/packages/composer-playground/src/app/login/identity-card/identity-card.component.spec.ts @@ -0,0 +1,154 @@ +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { IdentityCardComponent } from './identity-card.component'; + +import * as chai from 'chai'; +import * as sinon from 'sinon'; + +let should = chai.should(); + +describe(`IdentityCardComponent`, () => { + + let component: IdentityCardComponent; + let fixture: ComponentFixture; + + let mockAdminService; + let mockIdentityService; + let mockClientService; + let mockConnectionProfileService; + let mockInitializationService; + let routerStub; + let mockAlertService; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [IdentityCardComponent] + }); + + fixture = TestBed.createComponent(IdentityCardComponent); + + component = fixture.componentInstance; + }); + + describe('#connect', () => { + it('should emit connect event', (done) => { + component.identity = { + userId: 'pedantic-owl' + }; + + component.onConnect.subscribe((e) => { + e.should.equal('pedantic-owl'); + done(); + }); + + fixture.detectChanges(); + let button = fixture.debugElement.query(By.css('button.connect')); + button.nativeElement.click(); + }); + }); + + describe('#dismiss', () => { + it('should emit dismiss event', (done) => { + component.preview = true; + component.identity = { + userId: 'pedantic-owl' + }; + + component.onDismiss.subscribe((e) => { + e.should.equal('pedantic-owl'); + done(); + }); + + fixture.detectChanges(); + let button = fixture.debugElement.query(By.css('button.dismiss')); + button.nativeElement.click(); + }); + }); + + describe('#delete', () => { + it('should emit delete event', (done) => { + component.identity = { + userId: 'pedantic-owl' + }; + + component.onDelete.subscribe((e) => { + e.should.equal('pedantic-owl'); + done(); + }); + + fixture.detectChanges(); + let button = fixture.debugElement.query(By.css('button.delete')); + button.nativeElement.click(); + }); + }); + + describe('#export', () => { + it('should emit export event', (done) => { + component.identity = { + userId: 'pedantic-owl' + }; + + component.onExport.subscribe((e) => { + e.should.equal('pedantic-owl'); + done(); + }); + + fixture.detectChanges(); + let button = fixture.debugElement.query(By.css('button.export')); + button.nativeElement.click(); + }); + }); + + describe('#getInitials', () => { + it('should get one initial', () => { + component.identity = { + userId: 'admin' + }; + + let result = component.getInitials(); + + result.should.equal('a'); + }); + + it('should get two initials', () => { + component.identity = { + userId: 'pedantic owl' + }; + + let result = component.getInitials(); + + result.should.equal('po'); + }); + + it('should get maximum of two initials', () => { + component.identity = { + userId: 'eat conga repeat' + }; + + let result = component.getInitials(); + + result.should.equal('ec'); + }); + + it('should get non-ascii \'initials\'', () => { + component.identity = { + userId: '黄 丽' + }; + + let result = component.getInitials(); + + result.should.equal('黄丽'); + }); + + it('should smile if there are no initials', () => { + component.identity = { + userId: ' ' + }; + + let result = component.getInitials(); + + result.should.equal(':)'); + }); + }); +}); diff --git a/packages/composer-playground/src/app/login/identity-card/identity-card.component.ts b/packages/composer-playground/src/app/login/identity-card/identity-card.component.ts new file mode 100644 index 0000000000..41c8a4abf7 --- /dev/null +++ b/packages/composer-playground/src/app/login/identity-card/identity-card.component.ts @@ -0,0 +1,59 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'identity-card', + templateUrl: './identity-card.component.html', + styleUrls: [ + './identity-card.component.scss'.toString() + ] +}) + +export class IdentityCardComponent { + + @Input() + identity: any; + + @Input() + preview: boolean = false; + + @Output() + onConnect: EventEmitter = new EventEmitter(); + + @Output() + onDismiss: EventEmitter = new EventEmitter(); + + @Output() + onDelete: EventEmitter = new EventEmitter(); + + @Output() + onExport: EventEmitter = new EventEmitter(); + + connect() { + this.onConnect.emit(this.identity.userId); + } + + dismiss() { + this.onDismiss.emit(this.identity.userId); + } + + delete() { + this.onDelete.emit(this.identity.userId); + } + + export() { + this.onExport.emit(this.identity.userId); + } + + getInitials() { + let result; + let userId = this.identity.userId; + let regexp = /^(\S)\S*\s*(\S?)/i; + let matches = regexp.exec(userId); + + if (matches) { + result = matches.slice(1, 3).join(''); + } + + return result ? result : ':)'; + } +} diff --git a/packages/composer-playground/src/app/login/identity-card/index.ts b/packages/composer-playground/src/app/login/identity-card/index.ts new file mode 100644 index 0000000000..141b887ba5 --- /dev/null +++ b/packages/composer-playground/src/app/login/identity-card/index.ts @@ -0,0 +1 @@ +export * from './identity-card.component'; diff --git a/packages/composer-playground/src/app/login/login.component.html b/packages/composer-playground/src/app/login/login.component.html index 0b14dc3787..2f246b49d1 100644 --- a/packages/composer-playground/src/app/login/login.component.html +++ b/packages/composer-playground/src/app/login/login.component.html @@ -19,41 +19,10 @@

Identities for {{connectionProfile.name === '$default' ? 'Web Browser' : con

-
-
-
- {{identity.userId.substring(0,2)}} -
-
- {{identity.userId}} -
-
- - -
-
-
-

BUSINESS NETWORK

-

{{identity.businessNetwork}}

-
- -
-
-
+ +
diff --git a/packages/composer-playground/src/app/login/login.component.scss b/packages/composer-playground/src/app/login/login.component.scss index d56b88b8aa..db3b45660c 100644 --- a/packages/composer-playground/src/app/login/login.component.scss +++ b/packages/composer-playground/src/app/login/login.component.scss @@ -14,110 +14,24 @@ app-login { height: calc(100vh - 63px - 70px); padding: $space-medium $space-large; - div.connection-profile:first-child { - margin-top: 0; - } - - div.connection-profile { - margin-top: $space-large; - - .connection-profile-buttons { - display: inline-block; - margin-left: $space-medium; + div.connection-profile:first-child { + margin-top: 0; } - .identities { - display: flex; - flex-wrap: wrap; - - .identity { - background-color: $white; - padding: $space-large 0 $space-smedium 0; - box-shadow: 3px 6px 15px 0 rgba(0, 0, 0, 0.20); - margin-left: $space-large; - margin-bottom: $space-large; - width: 275px; - - .top-section { - - padding: 0 $space-large; - - & > * { - margin-top: $space-medium; - } - - .userId-image { - background-color: $fourth-highlight; - border: 1px solid $fourth-highlight; - border-radius: 50%; - width: 75px; - height: 75px; - margin: 0 auto; - position: relative; - - span { - position: absolute; - top: 26px; - right: 26px; - color: $second-highlight; - text-transform: uppercase; - } - } - - .userId { - text-align: center; - } - - .action-buttons { - display: flex; - justify-content: center; + div.connection-profile { + margin-top: $space-large; - button:first-child { - margin-right: $space-large; - } - - svg { - fill: $second-highlight; - } - } - } - - .bottom-section { - - & > * { - padding: 0 $space-large; - text-align: center; - } - - .business-network { - border-top: 1px solid $fourth-highlight; - text-align: center; - color: $secondary-text; - font-size: x-small; - padding-top: $space-medium; - } - - .connect { - margin-top: $space-medium; - border-top: 1px solid $fourth-highlight; - text-align: center; - padding-top: $space-small; + .connection-profile-buttons { + display: inline-block; + margin-left: $space-medium; + } - button { - span { - color: $second-highlight; - margin-right: $space-smedium; - } - svg { - fill: $second-highlight; - } - } - } - } + .identities { + display: flex; + flex-wrap: wrap; } - } - } + } } section.edit-connection-profile { diff --git a/packages/composer-playground/src/app/login/login.component.spec.ts b/packages/composer-playground/src/app/login/login.component.spec.ts index a2f05f5c75..367dc718ba 100644 --- a/packages/composer-playground/src/app/login/login.component.spec.ts +++ b/packages/composer-playground/src/app/login/login.component.spec.ts @@ -76,6 +76,14 @@ class MockConnectionProfileComponent { public profileUpdated: EventEmitter = new EventEmitter(); } +@Component({ + selector: 'identity-card', + template: '' +}) +class MockIdentityCardComponent { + @Input() identity: any; +} + describe(`LoginComponent`, () => { let component: LoginComponent; @@ -113,7 +121,8 @@ describe(`LoginComponent`, () => { TestBed.configureTestingModule({ declarations: [ LoginComponent, - MockConnectionProfileComponent + MockConnectionProfileComponent, + MockIdentityCardComponent ], providers: [ {provide: IdentityService, useValue: mockIdentityService}, diff --git a/packages/composer-playground/src/app/login/login.module.ts b/packages/composer-playground/src/app/login/login.module.ts index 3dc47ac983..ac6d6f3af5 100644 --- a/packages/composer-playground/src/app/login/login.module.ts +++ b/packages/composer-playground/src/app/login/login.module.ts @@ -6,11 +6,13 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { LoginComponent } from './login.component'; import { LoginRoutingModule } from './login-routing.module'; +import { IdentityCardComponent } from './identity-card'; import { ConnectionProfileModule } from '../connection-profile/connection-profile.module'; @NgModule({ imports: [CommonModule, FormsModule, NgbModule, LoginRoutingModule, ConnectionProfileModule], - declarations: [LoginComponent], + entryComponents: [IdentityCardComponent], + declarations: [LoginComponent, IdentityCardComponent], }) export class LoginModule {