diff --git a/goofy-client/libs/historie/src/lib/historie-container/historie-list/historie-item-assign-user-container/historie-item-assign-user/historie-item-assign-user.component.ts b/goofy-client/libs/historie/src/lib/historie-container/historie-list/historie-item-assign-user-container/historie-item-assign-user/historie-item-assign-user.component.ts index 6891496e079d8fd8cd0c80f1852ba662d0202399..6f0f97aa24b276a743195cfa717352b9bbec4a36 100644 --- a/goofy-client/libs/historie/src/lib/historie-container/historie-list/historie-item-assign-user-container/historie-item-assign-user/historie-item-assign-user.component.ts +++ b/goofy-client/libs/historie/src/lib/historie-container/historie-list/historie-item-assign-user-container/historie-item-assign-user/historie-item-assign-user.component.ts @@ -1,7 +1,6 @@ import { Component, Input } from '@angular/core'; import { CommandResource } from '@goofy-client/command-shared'; -import { UserProfileResource } from '@goofy-client/user-profile-shared'; -import { isNil } from 'lodash-es'; +import { getUserName, UserProfileResource } from '@goofy-client/user-profile-shared'; @Component({ selector: 'goofy-client-historie-item-assign-user', @@ -19,10 +18,6 @@ export class HistorieItemAssignUserComponent { headline: string; buildHeadline(userProfile: UserProfileResource): string { - const userName = isNil(userProfile) - ? 'Unbekannter Benutzer' - : `${userProfile.firstName} ${userProfile.lastName}`; - - return `${userName} den Vorgang zugewiesen.`; + return `${getUserName(userProfile)} den Vorgang zugewiesen.`; } } \ No newline at end of file diff --git a/goofy-client/libs/tech-shared/src/lib/tech.util.spec.ts b/goofy-client/libs/tech-shared/src/lib/tech.util.spec.ts index 5fe01d7c8d7f393774b522744b959bf1debed355..4066533c265b9cb9decedf3cb6283429615afbae 100644 --- a/goofy-client/libs/tech-shared/src/lib/tech.util.spec.ts +++ b/goofy-client/libs/tech-shared/src/lib/tech.util.spec.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import { convertForDataTest, EMPTY_STRING, getFirstLetter, hasMinLength, isNotEmpty, isNotNil, isNotNull, replaceAllWhitespaces, replacePlaceholder, replacePlaceholders } from './tech.util'; +import { convertForDataTest, EMPTY_STRING, getFirstLetter, getStringValue, hasMinLength, isNotEmpty, isNotNil, isNotNull, replaceAllWhitespaces, replacePlaceholder, replacePlaceholders } from './tech.util'; describe('TechUtil', () => { @@ -208,5 +208,30 @@ describe('TechUtil', () => { }) }) + describe('get string value', () => { + it('should return empty string on null', () => { + const value: string = null; + + const result: string = getStringValue(value); + + expect(result).toBe(EMPTY_STRING); + }) + + it('should return empty string on undefined', () => { + const value: string = undefined; + + const result: string = getStringValue(value); + + expect(result).toBe(EMPTY_STRING); + }) + + it('should return given value', () => { + const value: string = 'value of this...'; + + const result: string = getStringValue(value); + + expect(result).toBe(value); + }) + }) }) \ No newline at end of file diff --git a/goofy-client/libs/tech-shared/src/lib/tech.util.ts b/goofy-client/libs/tech-shared/src/lib/tech.util.ts index 56d5fa38fead9ed55db25e2452d4a8ee47e97bce..a1a1b3c86fb4ef7d4791f251f0ec43ec9eef5604 100644 --- a/goofy-client/libs/tech-shared/src/lib/tech.util.ts +++ b/goofy-client/libs/tech-shared/src/lib/tech.util.ts @@ -64,4 +64,11 @@ export function hasMinLength(value: any, length: number): boolean { export function convertForDataTest(value: string): string { return replaceAllWhitespaces(value, '_'); +} + +export function getStringValue(value: null | undefined | string): string { + if (isNull(value) || isUndefined(value)) { + return EMPTY_STRING; + } + return value; } \ No newline at end of file diff --git a/goofy-client/libs/user-profile-shared/src/index.ts b/goofy-client/libs/user-profile-shared/src/index.ts index 0eb1a52021f2c3452524aec7c1a99efb32ed2d97..6dfd2b497850df400b00fa5709aa1b9c78a2673c 100644 --- a/goofy-client/libs/user-profile-shared/src/index.ts +++ b/goofy-client/libs/user-profile-shared/src/index.ts @@ -1,5 +1,6 @@ export * from './lib/user-profile-shared.module'; export * from './lib/user-profile.linkrel'; +export * from './lib/user-profile.message'; export * from './lib/user-profile.model'; export * from './lib/user-profile.service'; -export * from './lib/user-profile.message'; +export * from './lib/user-profile.util'; diff --git a/goofy-client/libs/user-profile-shared/src/lib/user-profile.message.ts b/goofy-client/libs/user-profile-shared/src/lib/user-profile.message.ts index 29ce9277a23be10fd2880c0425722831dbc4c6c3..3402c14ea083085f73817561af984560942b3de6 100644 --- a/goofy-client/libs/user-profile-shared/src/lib/user-profile.message.ts +++ b/goofy-client/libs/user-profile-shared/src/lib/user-profile.message.ts @@ -4,5 +4,5 @@ export const userProfileMessage = { [MessageCode.SERVICE_UNAVAILABLE]: 'Die Benutzerdaten konnten nicht geladen werden', [MessageCode.RESOURCE_NOT_FOUND]: 'Der zugewiesene Bearbeiter konnte nicht gefunden werden', UNASSIGNED: 'Kein Bearbeiter zugewiesen', - UNKNOW_ERROR: 'Ein unbekannter Fehler ist aufgetreten', + UNKNOW_ERROR: 'Ein unbekannter Fehler ist aufgetreten' } diff --git a/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.spec.ts b/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae917f16f9f511ccb7370dece2ff6d1ac0902981 --- /dev/null +++ b/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.spec.ts @@ -0,0 +1,104 @@ +import { EMPTY_STRING } from '@goofy-client/tech-shared'; +import { createUserProfileResource } from '../../../user-profile-shared/test/user-profile'; +import { UserProfileResource } from './user-profile.model'; +import { existsName, getUserName, getUserNameInitials, NO_NAME_MESSAGE, UNKNOWN_USER } from './user-profile.util'; + +describe('UserProfileUtil', () => { + + describe('existsName', () => { + + it('should return true if only firstName exists', () => { + const exists: boolean = existsName({ ...createUserProfileResource(), lastName: null }); + + expect(exists).toBeTruthy(); + }) + + it('should return true if only lastName exists', () => { + const exists: boolean = existsName({ ...createUserProfileResource(), firstName: null }); + + expect(exists).toBeTruthy(); + }) + + it('should return false if either firstName nor lastName exists', () => { + const exists: boolean = existsName({ ...createUserProfileResource(), firstName: null, lastName: null }); + + expect(exists).toBeFalsy(); + }) + }) + + describe('get user name', () => { + + it('should return unknown user message on null', () => { + const userName: string = getUserName(null); + + expect(userName).toBe(UNKNOWN_USER); + }) + + it('should return full name', () => { + const userProfile: UserProfileResource = createUserProfileResource(); + + const userName: string = getUserName(userProfile); + + expect(userName).toBe(`${userProfile.firstName} ${userProfile.lastName}`); + }) + + it('should return if only firstName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), lastName: null }; + + const userName: string = getUserName(userProfile); + + expect(userName).toBe(userProfile.firstName); + }) + + it('should return only lastName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), firstName: null }; + + const userName: string = getUserName(userProfile); + + expect(userName).toBe(userProfile.lastName); + }) + + it('should return no name message if either firstName nor lastName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), firstName: null, lastName: null }; + + const userName: string = getUserName(userProfile); + + expect(userName).toBe(NO_NAME_MESSAGE); + }) + }) + + describe('get user name initials', () => { + + it('should return for full name', () => { + const userProfile: UserProfileResource = createUserProfileResource(); + + const userName: string = getUserNameInitials(userProfile); + + expect(userName).toBe(`${userProfile.firstName.substring(0, 1).toLocaleUpperCase()}${userProfile.lastName.substring(0, 1).toLocaleUpperCase()}`); + }) + + it('should return if only firstName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), lastName: EMPTY_STRING }; + + const userName: string = getUserNameInitials(userProfile); + + expect(userName).toBe(`${userProfile.firstName.substring(0, 1).toLocaleUpperCase()}`); + }) + + it('should return only lastName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), firstName: EMPTY_STRING }; + + const userName: string = getUserNameInitials(userProfile); + + expect(userName).toBe(`${userProfile.lastName.substring(0, 1).toLocaleUpperCase()}`); + }) + + it('should return empty string if either firstName nor lastName exists', () => { + const userProfile: UserProfileResource = { ...createUserProfileResource(), firstName: EMPTY_STRING, lastName: EMPTY_STRING }; + + const userName: string = getUserNameInitials(userProfile); + + expect(userName).toBe(EMPTY_STRING); + }) + }) +}) \ No newline at end of file diff --git a/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.ts b/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9c72b2074c642e428fc5c15ed3e72cd62f724ed --- /dev/null +++ b/goofy-client/libs/user-profile-shared/src/lib/user-profile.util.ts @@ -0,0 +1,29 @@ +import { EMPTY_STRING, getFirstLetter, getStringValue, isNotNull } from '@goofy-client/tech-shared'; +import { isNull } from 'lodash-es'; +import { UserProfileResource } from './user-profile.model'; + +export const NO_NAME_MESSAGE: string = 'Benutzer ohne hinterlegtem Namen'; +export const UNKNOWN_USER: string = 'Unbekannter Benutzer'; + +export function existsName(userProfile: UserProfileResource): boolean { + return isNotNull(userProfile.firstName) || isNotNull(userProfile.lastName); +} + +export function getUserName(userProfile: UserProfileResource): string { + if (isNull(userProfile)) { + return UNKNOWN_USER; + } + if (existsName(userProfile)) { + return `${getStringValue(userProfile.firstName)} ${getStringValue(userProfile.lastName)}`.trim(); + } + return NO_NAME_MESSAGE; +} + +export function getUserNameInitials(userProfile: UserProfileResource): string { + return `${getFirstLetterUpperCase(userProfile.firstName)}${getFirstLetterUpperCase(userProfile.lastName)}`; +} + +function getFirstLetterUpperCase(value: string) { + const firstLetter: string = getFirstLetter(value); + return isNull(firstLetter) ? EMPTY_STRING : firstLetter.toUpperCase(); +} diff --git a/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts b/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts index 3c73bc342ba531356cc987e73b0fc35ba54145ea..2ef6ee4004d35fb92de50ca55fd565dd06fe2fc7 100644 --- a/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts +++ b/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts @@ -2,10 +2,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; import { faker } from '@faker-js/faker'; -import { ApiError, createEmptyStateResource, createErrorStateResource, createStateResource, MessageCode } from '@goofy-client/tech-shared'; +import { ApiError, createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_STRING, MessageCode } from '@goofy-client/tech-shared'; import { getElementFromFixture } from '@goofy-client/test-utils'; import { SpinnerComponent } from '@goofy-client/ui'; import { userProfileMessage, UserProfileResource } from '@goofy-client/user-profile-shared'; +import { getDataTestClassOf } from 'libs/tech-shared/test/data-test'; import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile'; import { MockComponent } from 'ng-mocks'; import { createApiError, createIssue } from '../../../../tech-shared/test/error'; @@ -15,10 +16,10 @@ describe('UserIconComponent', () => { let component: UserIconComponent; let fixture: ComponentFixture<UserIconComponent>; - const profileAssignedIcon: string = '[data-test-class="user-profile-assigned"]'; - const profileUnassigned: string = '[data-test-class="user-profile-unassigned"]'; - const profileUserNotFound: string = '[data-test-class="user-profile-user-not-found"]'; - const profileServiceUnavailable: string = '[data-test-class="user-profile-service-unavailable"]'; + const profileAssignedIcon: string = getDataTestClassOf('user-profile-assigned'); + const profileUnassigned: string = getDataTestClassOf('user-profile-unassigned'); + const profileUserNotFound: string = getDataTestClassOf('user-profile-user-not-found'); + const profileServiceUnavailable: string = getDataTestClassOf('user-profile-service-unavailable'); const userProfile: UserProfileResource = createUserProfileResource(); @@ -84,6 +85,7 @@ describe('UserIconComponent', () => { }) describe('tooltip', () => { + it('should return user name', () => { component.userProfileStateResource = createStateResource(userProfile); @@ -108,9 +110,18 @@ describe('UserIconComponent', () => { expect(component.getErrorTooltip).toHaveBeenCalled(); }) + + it('should return empty string on missing name', () => { + component.userProfileStateResource = createStateResource({ ...userProfile, firstName: EMPTY_STRING, lastName: EMPTY_STRING }); + + const tooltip = component.getTooltip(); + + expect(tooltip).toEqual(EMPTY_STRING); + }) }); describe('error tooltip', () => { + it('should return user not found', () => { component.userProfileStateResource = createErrorStateResource(createApiErrorWithMessageCode(MessageCode.RESOURCE_NOT_FOUND)); diff --git a/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts b/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts index c590d46d37c3cda7fa230049b1e7c756b2d30967..92dfc09c658a5ec94edd02854e3dfc9430d5442c 100644 --- a/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts +++ b/goofy-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts @@ -1,7 +1,7 @@ import { Component, Input, SimpleChanges } from '@angular/core'; -import { createEmptyStateResource, getFirstLetter, hasError, MessageCode, StateResource } from '@goofy-client/tech-shared'; -import { userProfileMessage, UserProfileResource } from '@goofy-client/user-profile-shared'; -import { isNull, isUndefined } from 'lodash'; +import { createEmptyStateResource, hasError, MessageCode, StateResource } from '@goofy-client/tech-shared'; +import { getUserName, getUserNameInitials, userProfileMessage, UserProfileResource } from '@goofy-client/user-profile-shared'; +import { isUndefined } from 'lodash'; @Component({ selector: 'goofy-client-user-icon', @@ -34,7 +34,7 @@ export class UserIconComponent { } getUserTooltip(): string { - return `${this.userProfileStateResource.resource.firstName} ${this.userProfileStateResource.resource.lastName}`; + return getUserName(this.userProfileStateResource.resource); } getErrorTooltip(): string { @@ -47,11 +47,6 @@ export class UserIconComponent { } get initials(): string { - return this.getFirstLetterUpperCase(this.userProfileStateResource.resource.firstName) + this.getFirstLetterUpperCase(this.userProfileStateResource.resource.lastName); - } - - private getFirstLetterUpperCase(value: string) { - const firstLetter: string = getFirstLetter(value); - return isNull(firstLetter) ? null : firstLetter.toUpperCase(); + return getUserNameInitials(this.userProfileStateResource.resource); } } diff --git a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.html b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.html index 00f502a294ffddf3c4b95ae6316d0c37f89a687a..b7ed8a8090cab4e03275ae01ceb7c5babe9a39b8 100644 --- a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.html +++ b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.html @@ -1,6 +1,6 @@ -<div *ngIf="userProfileStateResource.resource; else unknownUser"> - <span data-test-class="user-profile-name">{{userProfileStateResource.resource.firstName}} {{userProfileStateResource.resource.lastName}}</span> -</div> -<ng-template #unknownUser> +<div *ngIf="userProfileStateResource.error; else user"> <span data-test-class="user-profile-name-unknown">Unbekannter Benutzer</span> +</div> +<ng-template #user> + <span data-test-class="user-profile-name">{{userName}}</span> </ng-template> \ No newline at end of file diff --git a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.spec.ts b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.spec.ts index d7e1564970ad665960de567be35d963298257bd1..e125baea639f3b8878ba05ac92e735b13fa7d6ef 100644 --- a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.spec.ts +++ b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.spec.ts @@ -13,6 +13,8 @@ describe('UserProfileNameComponent', () => { const userProfileName: string = getDataTestClassOf('user-profile-name'); const userProfileNameUnknown: string = getDataTestClassOf('user-profile-name-unknown'); + const userProfile: UserProfileResource = createUserProfileResource(); + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [UserProfileNameComponent], @@ -32,8 +34,6 @@ describe('UserProfileNameComponent', () => { describe('if user-profile exists', () => { - const userProfile: UserProfileResource = createUserProfileResource(); - beforeEach(() => { component.userProfileStateResource = createStateResource(userProfile); fixture.detectChanges(); @@ -43,22 +43,21 @@ describe('UserProfileNameComponent', () => { const element = fixture.nativeElement.querySelector(userProfileName); expect(element).toBeInstanceOf(HTMLElement); - expect((<HTMLElement>element).innerHTML).toContain(userProfile.firstName + ' ' + userProfile.lastName); }) }) - describe('if user profile NOT exists', () => { + describe('if user profile loading error', () => { beforeEach(() => { component.userProfileStateResource = createErrorStateResource(createApiError()); fixture.detectChanges(); }) - it('show user name unknown as "Unbekannter Benutzer"', () => { + it('should show "Unbekannter Benutzer" as userName', () => { const element = fixture.nativeElement.querySelector(userProfileNameUnknown); expect(element).toBeInstanceOf(HTMLElement); expect((<HTMLElement>element).innerHTML).toContain('Unbekannter Benutzer'); }) }) -}); +}); \ No newline at end of file diff --git a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.ts b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.ts index 3e56ba8781439568dbd43d1dd477523525c21773..83d77773dc8e08577bd8836fa0772978283d4c90 100644 --- a/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.ts +++ b/goofy-client/libs/user-profile/src/lib/user-profile-name/user-profile-name.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { StateResource } from '@goofy-client/tech-shared'; -import { UserProfileResource } from '@goofy-client/user-profile-shared'; +import { getUserName, UserProfileResource } from '@goofy-client/user-profile-shared'; @Component({ selector: 'goofy-client-user-profile-name', @@ -9,5 +9,12 @@ import { UserProfileResource } from '@goofy-client/user-profile-shared'; }) export class UserProfileNameComponent { - @Input() userProfileStateResource: StateResource<UserProfileResource>; + @Input('userProfileStateResource') + public set userProfile(userProfileStateResource: StateResource<UserProfileResource>) { + this.userProfileStateResource = userProfileStateResource; + this.userName = getUserName(userProfileStateResource.resource); + }; + + userProfileStateResource: StateResource<UserProfileResource>; + userName: string; } \ No newline at end of file diff --git a/goofy-client/libs/user-profile/src/test-setup.ts b/goofy-client/libs/user-profile/src/test-setup.ts index 08ef82b5d5efa87cb27257314075f6a16eb7a63e..82178098b34faeb3a94a8268bd072d4db95371a3 100644 --- a/goofy-client/libs/user-profile/src/test-setup.ts +++ b/goofy-client/libs/user-profile/src/test-setup.ts @@ -1,9 +1,10 @@ +import '@testing-library/jest-dom'; import 'jest-preset-angular/setup-jest'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, - platformBrowserDynamicTesting, + platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; getTestBed().resetTestEnvironment();