-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add and edit B2B users in organization-management
Closes #260 Co-authored-by: Silke Grüber <S.Grueber@intershop.de> Co-authored-by: Danilo Hoffmann <d.hoffmann@intershop.de>
- Loading branch information
1 parent
e9f845c
commit 5b4a0c0
Showing
35 changed files
with
1,211 additions
and
121 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
e2e/cypress/integration/pages/organizationmanagement/users-detail.page.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
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
39 changes: 39 additions & 0 deletions
39
...ion-management/src/app/components/user/user-profile-form/user-profile-form.component.html
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,39 @@ | ||
<div> | ||
<div *ngIf="error" role="alert" class="alert alert-danger"> | ||
<span>{{ error.headers['error-key'] | translate }}</span> | ||
</div> | ||
<p class="indicates-required"><span class="required">*</span>{{ 'account.required_field.message' | translate }}</p> | ||
<fieldset> | ||
<ish-select-title [form]="form" controlName="title" [titles]="titles"></ish-select-title> | ||
<ish-input | ||
[form]="form" | ||
controlName="firstName" | ||
label="account.address.firstname.label" | ||
[errorMessages]="{ | ||
required: 'account.user.new.firstname.error.required' | ||
}" | ||
></ish-input> | ||
<ish-input | ||
[form]="form" | ||
controlName="lastName" | ||
label="account.address.lastname.label" | ||
[errorMessages]="{ | ||
required: 'account.user.new.lastname.error.required' | ||
}" | ||
></ish-input> | ||
</fieldset> | ||
<fieldset *ngIf="form.value.email !== undefined"> | ||
<ish-input | ||
[form]="form" | ||
controlName="email" | ||
label="account.user.email.label" | ||
[errorMessages]="{ | ||
required: 'account.update_email.email.error.notempty', | ||
email: 'account.update_email.email.error.email' | ||
}" | ||
></ish-input> | ||
</fieldset> | ||
<fieldset> | ||
<ish-input [form]="form" controlName="phone" label="account.profile.phone.label"></ish-input> | ||
</fieldset> | ||
</div> |
65 changes: 65 additions & 0 deletions
65
...-management/src/app/components/user/user-profile-form/user-profile-form.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,65 @@ | ||
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; | ||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; | ||
import { RouterTestingModule } from '@angular/router/testing'; | ||
import { TranslateModule } from '@ngx-translate/core'; | ||
import { MockComponent } from 'ng-mocks'; | ||
import { CustomValidators } from 'ngx-custom-validators'; | ||
import { of } from 'rxjs'; | ||
import { instance, mock, when } from 'ts-mockito'; | ||
|
||
import { AppFacade } from 'ish-core/facades/app.facade'; | ||
import { Locale } from 'ish-core/models/locale/locale.model'; | ||
import { ErrorMessageComponent } from 'ish-shared/components/common/error-message/error-message.component'; | ||
import { InputComponent } from 'ish-shared/forms/components/input/input.component'; | ||
import { SelectTitleComponent } from 'ish-shared/forms/components/select-title/select-title.component'; | ||
|
||
import { UserProfileFormComponent } from './user-profile-form.component'; | ||
|
||
describe('User Profile Form Component', () => { | ||
let component: UserProfileFormComponent; | ||
let fixture: ComponentFixture<UserProfileFormComponent>; | ||
let element: HTMLElement; | ||
let fb: FormBuilder; | ||
let appFacade: AppFacade; | ||
|
||
beforeEach(async(() => { | ||
appFacade = mock(AppFacade); | ||
|
||
TestBed.configureTestingModule({ | ||
imports: [ReactiveFormsModule, RouterTestingModule, TranslateModule.forRoot()], | ||
declarations: [ | ||
MockComponent(ErrorMessageComponent), | ||
MockComponent(InputComponent), | ||
MockComponent(SelectTitleComponent), | ||
UserProfileFormComponent, | ||
], | ||
providers: [{ provide: AppFacade, useFactory: () => instance(appFacade) }], | ||
}).compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(UserProfileFormComponent); | ||
component = fixture.componentInstance; | ||
element = fixture.nativeElement; | ||
fb = TestBed.inject(FormBuilder); | ||
when(appFacade.currentLocale$).thenReturn(of({ lang: 'en_US' } as Locale)); | ||
|
||
component.form = fb.group({ | ||
email: ['', [Validators.required, CustomValidators.email]], | ||
}); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(component).toBeTruthy(); | ||
expect(element).toBeTruthy(); | ||
expect(() => fixture.detectChanges()).not.toThrow(); | ||
}); | ||
|
||
it('should display form input fields on creation', () => { | ||
fixture.detectChanges(); | ||
|
||
expect(element.querySelector('[controlname=firstName]')).toBeTruthy(); | ||
expect(element.querySelector('[controlname=lastName]')).toBeTruthy(); | ||
expect(element.querySelector('[controlname=phone]')).toBeTruthy(); | ||
}); | ||
}); |
41 changes: 41 additions & 0 deletions
41
...ation-management/src/app/components/user/user-profile-form/user-profile-form.component.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,41 @@ | ||
import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core'; | ||
import { FormGroup } from '@angular/forms'; | ||
import { Observable, Subject } from 'rxjs'; | ||
import { takeUntil } from 'rxjs/operators'; | ||
|
||
import { AppFacade } from 'ish-core/facades/app.facade'; | ||
import { HttpError } from 'ish-core/models/http-error/http-error.model'; | ||
import { Locale } from 'ish-core/models/locale/locale.model'; | ||
import { whenTruthy } from 'ish-core/utils/operators'; | ||
import { determineSalutations } from 'ish-shared/forms/utils/form-utils'; | ||
|
||
@Component({ | ||
selector: 'ish-user-profile-form', | ||
templateUrl: './user-profile-form.component.html', | ||
changeDetection: ChangeDetectionStrategy.Default, | ||
}) | ||
export class UserProfileFormComponent implements OnInit, OnDestroy { | ||
@Input() form: FormGroup; | ||
@Input() error: HttpError; | ||
|
||
currentLocale$: Observable<Locale>; | ||
private destroy$ = new Subject(); | ||
|
||
titles = []; | ||
|
||
constructor(private appFacade: AppFacade) {} | ||
|
||
ngOnInit() { | ||
this.currentLocale$ = this.appFacade.currentLocale$; | ||
|
||
// determine default language from session and available locales | ||
this.currentLocale$.pipe(whenTruthy(), takeUntil(this.destroy$)).subscribe(locale => { | ||
this.titles = locale?.lang ? determineSalutations(locale.lang.slice(3)) : undefined; | ||
}); | ||
} | ||
|
||
ngOnDestroy() { | ||
this.destroy$.next(); | ||
this.destroy$.complete(); | ||
} | ||
} |
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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// tslint:disable: no-barrel-files | ||
|
||
export { OrganizationManagementModule } from '../organization-management.module'; | ||
|
||
export { OrganizationManagementBreadcrumbService } from '../services/organization-management-breadcrumb/organization-management-breadcrumb.service'; |
34 changes: 30 additions & 4 deletions
34
projects/organization-management/src/app/facades/organization-management.facade.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 |
---|---|---|
@@ -1,18 +1,44 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { Store, select } from '@ngrx/store'; | ||
|
||
import { getSelectedUser, getUsers, getUsersError, getUsersLoading, loadUsers } from '../store/users'; | ||
import { B2bUser } from '../models/b2b-user/b2b-user.model'; | ||
import { | ||
addUser, | ||
getSelectedUser, | ||
getUsers, | ||
getUsersError, | ||
getUsersLoading, | ||
loadUsers, | ||
updateUser, | ||
} from '../store/users'; | ||
|
||
// tslint:disable:member-ordering | ||
@Injectable({ providedIn: 'root' }) | ||
export class OrganizationManagementFacade { | ||
constructor(private store: Store) {} | ||
|
||
usersError$ = this.store.pipe(select(getUsersError)); | ||
usersLoading$ = this.store.pipe(select(getUsersLoading)); | ||
selectedUser$ = this.store.pipe(select(getSelectedUser)); | ||
|
||
users$() { | ||
this.store.dispatch(loadUsers()); | ||
return this.store.pipe(select(getUsers)); | ||
} | ||
usersError$ = this.store.pipe(select(getUsersError)); | ||
usersLoading$ = this.store.pipe(select(getUsersLoading)); | ||
selectedUser$ = this.store.pipe(select(getSelectedUser)); | ||
|
||
addUser(user: B2bUser) { | ||
this.store.dispatch( | ||
addUser({ | ||
user, | ||
}) | ||
); | ||
} | ||
|
||
updateUser(user: B2bUser) { | ||
this.store.dispatch( | ||
updateUser({ | ||
user, | ||
}) | ||
); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
projects/organization-management/src/app/models/b2b-user/b2b-user.model.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 |
---|---|---|
@@ -1,5 +1,11 @@ | ||
import { Customer } from 'ish-core/models/customer/customer.model'; | ||
import { User } from 'ish-core/models/user/user.model'; | ||
|
||
export interface CustomerB2bUserType { | ||
customer: Customer; | ||
user: B2bUser; | ||
} | ||
|
||
export interface B2bUser extends Partial<User> { | ||
name?: string; // list call only | ||
} |
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
23 changes: 18 additions & 5 deletions
23
projects/organization-management/src/app/pages/organization-management-routing.module.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
17 changes: 17 additions & 0 deletions
17
projects/organization-management/src/app/pages/user-create/user-create-page.component.html
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,17 @@ | ||
<div class="row"> | ||
<div class="col-md-12"> | ||
<h1>{{ 'account.user.new.heading' | translate }}</h1> | ||
<form *ngIf="form" [formGroup]="form" (ngSubmit)="submitForm()" class="form-horizontal" novalidate="novalidate"> | ||
<ish-user-profile-form [form]="profile" [error]="userError$ | async"></ish-user-profile-form> | ||
<div class="row"> | ||
<div class="offset-md-4 col-md-8"> | ||
<button type="submit" class="btn btn-primary" [disabled]="formDisabled"> | ||
{{ 'account.user.new.button.create.label' | translate }} | ||
</button> | ||
<a routerLink="../../" class="btn btn-secondary">{{ 'account.cancel.link' | translate }}</a> | ||
</div> | ||
</div> | ||
</form> | ||
</div> | ||
<ish-loading *ngIf="loading$ | async"></ish-loading> | ||
</div> |
69 changes: 69 additions & 0 deletions
69
...ects/organization-management/src/app/pages/user-create/user-create-page.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,69 @@ | ||
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; | ||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; | ||
import { RouterTestingModule } from '@angular/router/testing'; | ||
import { TranslateModule } from '@ngx-translate/core'; | ||
import { MockComponent } from 'ng-mocks'; | ||
import { CustomValidators } from 'ngx-custom-validators'; | ||
import { instance, mock } from 'ts-mockito'; | ||
|
||
import { LoadingComponent } from 'ish-shared/components/common/loading/loading.component'; | ||
|
||
import { UserProfileFormComponent } from '../../components/user/user-profile-form/user-profile-form.component'; | ||
import { OrganizationManagementFacade } from '../../facades/organization-management.facade'; | ||
|
||
import { UserCreatePageComponent } from './user-create-page.component'; | ||
|
||
describe('User Create Page Component', () => { | ||
let component: UserCreatePageComponent; | ||
let fixture: ComponentFixture<UserCreatePageComponent>; | ||
let element: HTMLElement; | ||
let organizationManagementFacade: OrganizationManagementFacade; | ||
let fb: FormBuilder; | ||
|
||
beforeEach(async(() => { | ||
organizationManagementFacade = mock(OrganizationManagementFacade); | ||
TestBed.configureTestingModule({ | ||
imports: [ReactiveFormsModule, RouterTestingModule, TranslateModule.forRoot()], | ||
declarations: [MockComponent(LoadingComponent), MockComponent(UserProfileFormComponent), UserCreatePageComponent], | ||
providers: [{ provide: OrganizationManagementFacade, useFactory: () => instance(organizationManagementFacade) }], | ||
}).compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(UserCreatePageComponent); | ||
component = fixture.componentInstance; | ||
element = fixture.nativeElement; | ||
fb = TestBed.inject(FormBuilder); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(component).toBeTruthy(); | ||
expect(element).toBeTruthy(); | ||
expect(() => fixture.detectChanges()).not.toThrow(); | ||
}); | ||
|
||
it('should submit a valid form when the user fills all required fields', () => { | ||
fixture.detectChanges(); | ||
|
||
component.form = fb.group({ | ||
profile: fb.group({ | ||
firstName: ['Bernhard', [Validators.required]], | ||
lastName: ['Boldner', [Validators.required]], | ||
email: ['test@gmail.com', [Validators.required, CustomValidators.email]], | ||
preferredLanguage: ['en_US', [Validators.required]], | ||
}), | ||
}); | ||
|
||
expect(component.formDisabled).toBeFalse(); | ||
component.submitForm(); | ||
expect(component.formDisabled).toBeFalse(); | ||
}); | ||
|
||
it('should disable submit button when the user submits an invalid form', () => { | ||
fixture.detectChanges(); | ||
|
||
expect(component.formDisabled).toBeFalse(); | ||
component.submitForm(); | ||
expect(component.formDisabled).toBeTrue(); | ||
}); | ||
}); |
Oops, something went wrong.