-
Notifications
You must be signed in to change notification settings - Fork 24.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aio): implement survey notification link (#21371)
- Loading branch information
1 parent
3c6a506
commit 9005a6f
Showing
11 changed files
with
379 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<a href="{{actionUrl}}" class="content" (click)="dismiss()"> | ||
<mat-icon class="icon" [svgIcon]="icon" [attr.aria-label]="iconLabel"></mat-icon> | ||
<span class="message"><ng-content></ng-content></span> | ||
<span class="action-button">{{buttonText}}</span> | ||
</a> | ||
|
||
<button mat-icon-button class="close-button" aria-label="Close" (click)="dismiss()"> | ||
<mat-icon svgIcon="close" aria-label="Dismiss notification"></mat-icon> | ||
</button> |
123 changes: 123 additions & 0 deletions
123
aio/src/app/layout/notification/notification.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; | ||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { By } from '@angular/platform-browser'; | ||
import { CurrentDateToken } from 'app/shared/current-date'; | ||
import { NotificationComponent } from './notification.component'; | ||
import { WindowToken } from 'app/shared/window'; | ||
|
||
describe('NotificationComponent', () => { | ||
let element: HTMLElement; | ||
let component: NotificationComponent; | ||
let fixture: ComponentFixture<TestComponent>; | ||
|
||
function configTestingModule(now = new Date('2018-01-20')) { | ||
TestBed.configureTestingModule({ | ||
declarations: [TestComponent, NotificationComponent], | ||
providers: [ | ||
{ provide: WindowToken, useClass: MockWindow }, | ||
{ provide: CurrentDateToken, useValue: now }, | ||
], | ||
imports: [NoopAnimationsModule], | ||
schemas: [NO_ERRORS_SCHEMA] | ||
}); | ||
} | ||
|
||
function createComponent() { | ||
fixture = TestBed.createComponent(TestComponent); | ||
const debugElement = fixture.debugElement.query(By.directive(NotificationComponent)); | ||
element = debugElement.nativeElement; | ||
component = debugElement.componentInstance; | ||
component.ngOnInit(); | ||
fixture.detectChanges(); | ||
} | ||
|
||
it('should display the message', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
expect(fixture.nativeElement.innerHTML).toContain('Help Angular by taking a <strong>1 minute survey</strong>!'); | ||
}); | ||
|
||
it('should display an icon', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
const iconElement = fixture.debugElement.query(By.css('.icon')); | ||
expect(iconElement.properties['svgIcon']).toEqual('insert_comment'); | ||
expect(iconElement.attributes['aria-label']).toEqual('Survey'); | ||
}); | ||
|
||
it('should display a button', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
const button = fixture.debugElement.query(By.css('.action-button')); | ||
expect(button.nativeElement.textContent).toEqual('Go to survey'); | ||
}); | ||
|
||
it('should call dismiss when the message link is clicked', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
spyOn(component, 'dismiss'); | ||
fixture.debugElement.query(By.css('a')).triggerEventHandler('click', null); | ||
fixture.detectChanges(); | ||
expect(component.dismiss).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should call dismiss when the close button is clicked', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
spyOn(component, 'dismiss'); | ||
fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null); | ||
fixture.detectChanges(); | ||
expect(component.dismiss).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should hide the notification when dismiss is called', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
expect(component.showNotification).toBe('show'); | ||
component.dismiss(); | ||
expect(component.showNotification).toBe('hide'); | ||
}); | ||
|
||
it('should update localStorage key when dismiss is called', () => { | ||
configTestingModule(); | ||
createComponent(); | ||
const setItemSpy: jasmine.Spy = TestBed.get(WindowToken).localStorage.setItem; | ||
component.dismiss(); | ||
expect(setItemSpy).toHaveBeenCalledWith('aio-notification/survey-january-2018', 'hide'); | ||
}); | ||
|
||
it('should not show the notification if the date is after the expiry date', () => { | ||
configTestingModule(new Date('2018-01-23')); | ||
createComponent(); | ||
expect(component.showNotification).toBe('hide'); | ||
}); | ||
|
||
it('should not show the notification if the there is a "hide" flag in localStorage', () => { | ||
configTestingModule(); | ||
const getItemSpy: jasmine.Spy = TestBed.get(WindowToken).localStorage.getItem; | ||
getItemSpy.and.returnValue('hide'); | ||
createComponent(); | ||
expect(getItemSpy).toHaveBeenCalledWith('aio-notification/survey-january-2018'); | ||
expect(component.showNotification).toBe('hide'); | ||
}); | ||
}); | ||
|
||
@Component({ | ||
template: ` | ||
<aio-notification | ||
icon="insert_comment" | ||
iconLabel="Survey" | ||
buttonText="Go to survey" | ||
actionUrl="https://bit.ly/angular-survey-2018" | ||
notificationId="survey-january-2018" | ||
expirationDate="2018-01-22"> | ||
Help Angular by taking a <strong>1 minute survey</strong>! | ||
</aio-notification>` | ||
}) | ||
class TestComponent { | ||
} | ||
|
||
class MockWindow { | ||
localStorage = jasmine.createSpyObj('localStorage', ['getItem', 'setItem']); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { animate, state, style, trigger, transition } from '@angular/animations'; | ||
import { Component, EventEmitter, HostBinding, Inject, Input, OnInit, Output } from '@angular/core'; | ||
import { CurrentDateToken } from 'app/shared/current-date'; | ||
import { WindowToken } from 'app/shared/window'; | ||
|
||
const LOCAL_STORAGE_NAMESPACE = 'aio-notification/'; | ||
|
||
@Component({ | ||
selector: 'aio-notification', | ||
templateUrl: 'notification.component.html', | ||
animations: [ | ||
trigger('hideAnimation', [ | ||
state('show', style({height: '*'})), | ||
state('hide', style({height: 0})), | ||
// this should be kept in sync with the animation durations in: | ||
// - aio/src/styles/2-modules/_notification.scss | ||
// - aio/src/app/app.component.ts : notificationDismissed() | ||
transition('show => hide', animate(250)) | ||
]) | ||
] | ||
}) | ||
export class NotificationComponent implements OnInit { | ||
private get localStorage() { return this.window.localStorage; } | ||
|
||
@Input() icon: string; | ||
@Input() iconLabel: string; | ||
@Input() buttonText: string; | ||
@Input() actionUrl: string; | ||
@Input() notificationId: string; | ||
@Input() expirationDate: string; | ||
@Output() dismissed = new EventEmitter(); | ||
|
||
@HostBinding('@hideAnimation') | ||
showNotification: 'show'|'hide'; | ||
|
||
constructor( | ||
@Inject(WindowToken) private window: Window, | ||
@Inject(CurrentDateToken) private currentDate: Date | ||
) {} | ||
|
||
ngOnInit() { | ||
const previouslyHidden = this.localStorage.getItem(LOCAL_STORAGE_NAMESPACE + this.notificationId) === 'hide'; | ||
const expired = this.currentDate > new Date(this.expirationDate); | ||
this.showNotification = previouslyHidden || expired ? 'hide' : 'show'; | ||
} | ||
|
||
dismiss() { | ||
this.localStorage.setItem(LOCAL_STORAGE_NAMESPACE + this.notificationId, 'hide'); | ||
this.showNotification = 'hide'; | ||
this.dismissed.next(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { InjectionToken } from '@angular/core'; | ||
|
||
export const CurrentDateToken = new InjectionToken('CurrentDate'); | ||
export function currentDateProvider() { return new Date(); } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,3 +29,4 @@ | |
@import 'toc'; | ||
@import 'select-menu'; | ||
@import 'deploy-theme'; | ||
@import 'notification'; |
Oops, something went wrong.