Skip to content
Snippets Groups Projects
Commit ba691b46 authored by OZGCloud's avatar OZGCloud
Browse files

Merge branch 'master' into ozg-2387

parents 8b53cf6d 5ae4b6c6
Branches
Tags
No related merge requests found
Showing
with 139 additions and 202 deletions
...@@ -9,7 +9,6 @@ import { Observable } from 'rxjs'; ...@@ -9,7 +9,6 @@ import { Observable } from 'rxjs';
styleUrls: ['./header-container.component.scss'] styleUrls: ['./header-container.component.scss']
}) })
export class HeaderContainerComponent { export class HeaderContainerComponent {
navigationCollapse$: Observable<boolean>; navigationCollapse$: Observable<boolean>;
constructor( constructor(
......
...@@ -18,4 +18,10 @@ describe('HasLinkPipe', () => { ...@@ -18,4 +18,10 @@ describe('HasLinkPipe', () => {
expect(result).toBe(false); expect(result).toBe(false);
}) })
it('should return false on null resource', () => {
const result: boolean = pipe.transform(null, dummyLink);
expect(result).toBe(false);
})
}) })
...@@ -27,7 +27,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe'; ...@@ -27,7 +27,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
ToTrafficLightTooltipPipe, ToTrafficLightTooltipPipe,
ToEmbeddedResourcesPipe, ToEmbeddedResourcesPipe,
ConvertForDataTestPipe, ConvertForDataTestPipe,
FileSizePipe, FileSizePipe
], ],
exports: [ exports: [
FormatToPrettyDatePipe, FormatToPrettyDatePipe,
......
...@@ -26,3 +26,7 @@ export function dispatchEventFromFixture(fixture: ComponentFixture<any>, element ...@@ -26,3 +26,7 @@ export function dispatchEventFromFixture(fixture: ComponentFixture<any>, element
export function getDebugElementFromFixtureByCss(fixture: ComponentFixture<any>, query: string): DebugElement { export function getDebugElementFromFixtureByCss(fixture: ComponentFixture<any>, query: string): DebugElement {
return fixture.debugElement.query(By.css(query)); return fixture.debugElement.query(By.css(query));
} }
export function getElementFromDomRoot(fixture: ComponentFixture<any>, htmlElement: string): any {
return fixture.nativeElement.parentNode.querySelector(htmlElement);
}
<mat-slide-toggle color="primary"
[disabled]="disabled"
[matTooltip]="toolTip"
[checked]="checked"
(change)="valueChanged.emit($event.checked)">{{label}}
</mat-slide-toggle>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatRippleModule } from '@angular/material/core';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { MatTooltipModule } from '@angular/material/tooltip';
import { SlideToggleComponent } from './slide-toggle.component';
describe('SlideToggleComponent', () => {
let component: SlideToggleComponent;
let fixture: ComponentFixture<SlideToggleComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
MatTooltipModule,
MatRippleModule
],
declarations: [
SlideToggleComponent,
MatSlideToggle
],
}).compileComponents();
fixture = TestBed.createComponent(SlideToggleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
\ No newline at end of file
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { EMPTY_STRING } from '@goofy-client/tech-shared';
@Component({
selector: 'goofy-client-slide-toggle',
templateUrl: './slide-toggle.component.html',
styleUrls: ['./slide-toggle.component.scss'],
})
export class SlideToggleComponent {
@Input() checked: boolean = false;
@Input() label: string = EMPTY_STRING;
@Input() toolTip: string = EMPTY_STRING;
@Input() disabled: boolean = false;
@Output() valueChanged: EventEmitter<boolean> = new EventEmitter();
}
\ No newline at end of file
...@@ -58,6 +58,7 @@ import { ...@@ -58,6 +58,7 @@ import {
} from './mattooltip/mattooltip.directive'; } from './mattooltip/mattooltip.directive';
import { InternalServerErrorDialogComponent } from './notification/internal-server-error-dialog/internal-server-error-dialog.component'; import { InternalServerErrorDialogComponent } from './notification/internal-server-error-dialog/internal-server-error-dialog.component';
import { ProgressBarComponent } from './progress-bar/progress-bar.component'; import { ProgressBarComponent } from './progress-bar/progress-bar.component';
import { SlideToggleComponent } from './slide-toggle/slide-toggle.component';
import { SpinnerComponent } from './spinner/spinner.component'; import { SpinnerComponent } from './spinner/spinner.component';
import { SubnavigationComponent } from './subnavigation/subnavigation.component'; import { SubnavigationComponent } from './subnavigation/subnavigation.component';
import { ValidationErrorComponent } from './validation-error/validation-error.component'; import { ValidationErrorComponent } from './validation-error/validation-error.component';
...@@ -87,7 +88,8 @@ const components = [ ...@@ -87,7 +88,8 @@ const components = [
MattooltipClassDirective, MattooltipClassDirective,
PostfachIconComponent, PostfachIconComponent,
AccordionComponent, AccordionComponent,
AppIconComponent AppIconComponent,
SlideToggleComponent
]; ];
const modules = [ const modules = [
......
export * from './lib/user-settings-container/user-settings-container.component'; export * from './lib/user-settings-container/user-settings-container.component';
export * from './lib/user-settings-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component';
export * from './lib/user-settings.module'; export * from './lib/user-settings.module';
<goofy-client-icon-button-with-spinner icon="settings" toolTip="Einstellungen" <goofy-client-user-settings [apiRoot]="apiRoot$ | async"></goofy-client-user-settings>
[matMenuTriggerFor]="settingsMenu"> \ No newline at end of file
</goofy-client-icon-button-with-spinner>
<mat-menu #settingsMenu="matMenu">
<div class="menu-container" (click)="$event.stopPropagation()">
<goofy-client-user-settings-email-benachrichtigung
[userSettings$]="userSettings$"
(valueChanged)="changeNotificationsSendFor($event)"
></goofy-client-user-settings-email-benachrichtigung>
<goofy-client-user-settings-darkmode
[darkMode$]="darkMode$"
(darkModeEmitter)="changeColorMode($event)"
></goofy-client-user-settings-darkmode>
</div>
</mat-menu>
.menu-container {
margin: 12px 16px;
}
goofy-client-icon-button-with-spinner,
mat-slide-toggle {
display: block;
}
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatMenuModule } from '@angular/material/menu'; import { ApiRootFacade } from '@goofy-client/api-root-shared';
import { AppService } from '@goofy-client/app-shared'; import { Mock, mock } from '@goofy-client/test-utils';
import { mock } from '@goofy-client/test-utils';
import { IconButtonWithSpinnerComponent } from '@goofy-client/ui';
import { UserSettingsService } from '@goofy-client/user-settings-shared';
import { NotificationsSendFor } from 'libs/user-settings-shared/src/lib/user-settings.model';
import { MockComponent } from 'ng-mocks'; import { MockComponent } from 'ng-mocks';
import { BehaviorSubject } from 'rxjs';
import { UserSettingsContainerComponent } from './user-settings-container.component'; import { UserSettingsContainerComponent } from './user-settings-container.component';
import { UserSettingsDarkmodeComponent } from './user-settings-darkmode/user-settings-darkmode.component'; import { UserSettingsComponent } from './user-settings/user-settings.component';
import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component';
describe('UserSettingsContainerComponent', () => { describe('UserSettingsContainerComponent', () => {
let component: UserSettingsContainerComponent; let component: UserSettingsContainerComponent;
let fixture: ComponentFixture<UserSettingsContainerComponent>; let fixture: ComponentFixture<UserSettingsContainerComponent>;
const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false); const apiRootFacade: Mock<ApiRootFacade> = { ...mock(ApiRootFacade), getApiRoot: jest.fn() };
const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj };
const userSettingsService = { ...mock(UserSettingsService), setUserSettings: jest.fn() };
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [MatMenuModule],
declarations: [ declarations: [
UserSettingsContainerComponent, UserSettingsContainerComponent,
MockComponent(UserSettingsDarkmodeComponent), MockComponent(UserSettingsComponent)
MockComponent(UserSettingsEmailBenachrichtigungComponent),
MockComponent(IconButtonWithSpinnerComponent)
], ],
providers: [ providers: [
{ {
provide: AppService, provide: ApiRootFacade,
useValue: appService, useValue: apiRootFacade
},
{
provide: UserSettingsService,
useValue: userSettingsService
} }
], ],
}); });
...@@ -44,34 +29,19 @@ describe('UserSettingsContainerComponent', () => { ...@@ -44,34 +29,19 @@ describe('UserSettingsContainerComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(UserSettingsContainerComponent); fixture = TestBed.createComponent(UserSettingsContainerComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.autoDetectChanges(true);
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
describe('change color mode', () => { describe('ngOnInit', () => {
it('should call app service', () => {
component.changeColorMode(true);
expect(appService.setDarkMode).toHaveBeenCalledWith(true);
})
})
describe('change notifications send for', () => {
it('should call service with ALL', () => {
component.changeNotificationsSendFor(true);
expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.ALL });
})
it('should call service with NONE', () => { it('should call apiRoot facade', () => {
component.changeNotificationsSendFor(false); component.ngOnInit();
expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ notificationsSendFor: NotificationsSendFor.NONE }); expect(apiRootFacade.getApiRoot).toHaveBeenCalled();
}) })
}) })
}); });
import { DOCUMENT } from '@angular/common'; import { Component, OnInit } from '@angular/core';
import { Component, Inject, OnInit, Renderer2 } from '@angular/core'; import { ApiRootFacade, ApiRootResource } from '@goofy-client/api-root-shared';
import { AppService, localStorageDark } from '@goofy-client/app-shared'; import { createEmptyStateResource, StateResource } from '@goofy-client/tech-shared';
import { StateResource } from '@goofy-client/tech-shared';
import { UserSettingsService } from '@goofy-client/user-settings-shared';
import { NotificationsSendFor, UserSettings, UserSettingsResource } from 'libs/user-settings-shared/src/lib/user-settings.model';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
@Component({ @Component({
...@@ -12,50 +9,12 @@ import { Observable, of } from 'rxjs'; ...@@ -12,50 +9,12 @@ import { Observable, of } from 'rxjs';
styleUrls: ['./user-settings-container.component.scss'], styleUrls: ['./user-settings-container.component.scss'],
}) })
export class UserSettingsContainerComponent implements OnInit { export class UserSettingsContainerComponent implements OnInit {
darkMode$: Observable<boolean> = of(true);
userSettings$: Observable<StateResource<UserSettingsResource>>;
constructor( apiRoot$: Observable<StateResource<ApiRootResource>> = of(createEmptyStateResource<ApiRootResource>());
private renderer: Renderer2,
private appService: AppService,
private userSettingsService: UserSettingsService,
@Inject(DOCUMENT) private document: Document
) {
this.darkMode$ = this.appService.getDarkMode();
this.subscribeToDarkMode(); constructor(private apiRootFacade: ApiRootFacade) { }
}
ngOnInit(): void { ngOnInit(): void {
this.userSettings$ = this.userSettingsService.getUserSettings(); this.apiRoot$ = this.apiRootFacade.getApiRoot();
}
private subscribeToDarkMode(): void {
this.darkMode$.subscribe((darkMode) =>
darkMode
? this.addClass(localStorageDark)
: this.removeClass(localStorageDark)
);
}
private addClass(styleClass: string): void {
this.renderer.addClass(this.document.body, styleClass);
}
private removeClass(styleClass: string): void {
this.renderer.removeClass(this.document.body, styleClass);
}
changeColorMode(darkMode: boolean): void {
this.appService.setDarkMode(darkMode);
}
changeNotificationsSendFor(toggleValue: boolean): void {
this.userSettingsService.setUserSettings(this.createUserSettings(toggleValue));
}
private createUserSettings(toggleValue: boolean): UserSettings {
const notificationsSendFor: NotificationsSendFor = toggleValue ? NotificationsSendFor.ALL : NotificationsSendFor.NONE;
return { notificationsSendFor };
} }
} }
\ No newline at end of file
<mat-slide-toggle
color="primary"
[checked]="darkMode$ | async"
(change)="darkModeEmitter.emit($event.checked)"
>Dark Mode
</mat-slide-toggle>
<ng-container *ngIf="(userSettings$ | async)?.resource as userSettings">
<mat-slide-toggle data-test-id="toggle-notifications-send-for"
color="primary"
matTooltip="Benachrichtigung per E-Mail bei Eingang eines Antrags"
[checked]="getToggleStatus(userSettings)"
(change)="valueChanged.emit($event.checked)">Benachrichtigung per E-Mail
</mat-slide-toggle>
</ng-container>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatRippleModule } from '@angular/material/core';
import { MatMenuModule } from '@angular/material/menu';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { createStateResource } from '@goofy-client/tech-shared';
import { dispatchEventFromFixture, mock } from '@goofy-client/test-utils';
import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
import { NotificationsSendFor } from 'libs/user-settings-shared/src/lib/user-settings.model';
import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings';
import { of } from 'rxjs';
import { EventEmitter } from 'stream';
import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung.component';
describe('UserSettingsEmailBenachrichtigungComponent', () => {
let component: UserSettingsEmailBenachrichtigungComponent;
let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungComponent>;
const toggle: string = getDataTestIdOf('toggle-notifications-send-for');
const userSettings = createUserSettings();
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatMenuModule, MatRippleModule],
declarations: [UserSettingsEmailBenachrichtigungComponent, MatSlideToggle],
}).compileComponents();
fixture = TestBed.createComponent(
UserSettingsEmailBenachrichtigungComponent
);
component = fixture.componentInstance;
component.userSettings$ = of(createStateResource(createUserSettingsResource()));
component.valueChanged = { ...<any>mock(EventEmitter), emit: jest.fn() };
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should show toggle', () => {
const element = fixture.nativeElement.querySelector(toggle);
expect(element).toBeInstanceOf(HTMLElement);
})
describe('toggle status', () => {
it('should be set if userSettings.notificationsSendFor is ALL', () => {
userSettings.notificationsSendFor = NotificationsSendFor.ALL;
const result: boolean = component.getToggleStatus(userSettings);
expect(result).toBeTruthy();
})
it('should not be set if userSettings.notificationsSendFor is NONE', () => {
userSettings.notificationsSendFor = NotificationsSendFor.NONE;
const result: boolean = component.getToggleStatus(userSettings);
expect(result).toBeFalsy();
})
it('should emit value if toggled', () => {
dispatchEventFromFixture(fixture, toggle, 'change');
expect(component.valueChanged.emit).toHaveBeenCalled();
})
})
});
<goofy-client-user-settings-darkmode
[darkMode]="darkMode$ | async"
(valueChanged)="changeColorMode($event)">
</goofy-client-user-settings-darkmode>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppService } from '@goofy-client/app-shared';
import { mock } from '@goofy-client/test-utils';
import { MockComponent } from 'ng-mocks';
import { BehaviorSubject } from 'rxjs';
import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container.component';
import { UserSettingsDarkmodeComponent } from './user-settings-darkmode/user-settings-darkmode.component';
describe('UserSettingsDarkmodeContainerComponent', () => {
let component: UserSettingsDarkmodeContainerComponent;
let fixture: ComponentFixture<UserSettingsDarkmodeContainerComponent>;
const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false);
const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj };
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
UserSettingsDarkmodeContainerComponent,
MockComponent(UserSettingsDarkmodeComponent)
],
providers: [
{
provide: AppService,
useValue: appService,
}
]
}).compileComponents();
fixture = TestBed.createComponent(UserSettingsDarkmodeContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('change color mode', () => {
it('should call app service', () => {
component.changeColorMode(true);
expect(appService.setDarkMode).toHaveBeenCalledWith(true);
})
})
});
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment