Skip to content

Commit

Permalink
Extract identity card component for use on login screen and (hyperled…
Browse files Browse the repository at this point in the history
…ger-archives#1612)

during identity card import

Contributes to #902

Signed-off-by: James Taylor <[email protected]>
  • Loading branch information
jt-nti authored and Caroline Church committed Aug 18, 2017
1 parent d4ecf74 commit ce5393e
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 135 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<section class="identity-card">
<header>
<button *ngIf="preview" type="button" class="icon dismiss"
(click)="dismiss()">
<svg class="ibm-icon" aria-hidden="true">
<use xlink:href="#icon-close_new"></use>
</svg>
</button>
</header>
<section class="user-details">
<div class="image-placeholder">
<span class="initials">{{getInitials()}}</span>
</div>
<p>{{identity.userId}}</p>
</section>
<section *ngIf="!preview" class="actions">
<button type="button" class="action circular delete"
(click)="delete()">
<svg class="ibm-icon vertical-top" aria-hidden="true">
<use xlink:href="#icon-trash_32"></use>
</svg>
</button>
<button type="button" class="action circular export"
(click)="export()">
<svg class="ibm-icon vertical-top" aria-hidden="true">
<use xlink:href="#icon-download_32"></use>
</svg>
</button>
</section>
<section *ngIf="preview" class="connection-profile-details">
<h3>Connection Profile</h3>
<p>{{identity.profile}}</p>
</section>
<section class="business-network-details">
<h3>Business Network</h3>
<p>{{identity.businessNetwork}}</p>
</section>
<footer>
<button *ngIf="!preview" type="button" class="action connect"
(click)="connect()">
<span>Connect now</span>
<svg class="ibm-icon" aria-hidden="true">
<use xlink:href="#icon-forward_16"></use>
</svg>
</button>
</footer>
</section>
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<IdentityCardComponent>;

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(':)');
});
});
});
Original file line number Diff line number Diff line change
@@ -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<string> = new EventEmitter<string>();

@Output()
onDismiss: EventEmitter<string> = new EventEmitter<string>();

@Output()
onDelete: EventEmitter<string> = new EventEmitter<string>();

@Output()
onExport: EventEmitter<string> = new EventEmitter<string>();

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<String>() {
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 : ':)';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './identity-card.component';
Loading

0 comments on commit ce5393e

Please sign in to comment.