diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html index 064289aa47b5e6ff3e9e37656407d30cd0d52c8d..c38b3871bcc6324394b118055c18a363c9fb56b9 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.html @@ -1,6 +1,5 @@ <ods-button-with-spinner [stateResource]="submitStateResource$ | async" - (clickEmitter)="submit()" text="Speichern" dataTestId="save-button" /> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.spec.ts index dcd4e3712eb848de5eea8e563c60987b2c310429..1ab28ef6080559135f61a47b975e96a1af384011 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.spec.ts @@ -2,9 +2,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { User } from '@admin-client/user-shared'; import { createStateResource, StateResource } from '@alfa-client/tech-shared'; -import { dispatchEventFromFixture, getDebugElementFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils'; +import { getDebugElementFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils'; import { ButtonWithSpinnerComponent } from '@ods/component'; -import { cold } from 'jest-marbles'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; import { getDataTestIdAttributeOf } from '../../../../../../tech-shared/test/data-test'; @@ -40,28 +39,6 @@ describe('UserFormSaveButtonComponent', () => { expect(component).toBeTruthy(); }); - describe('component', () => { - describe('submit', () => { - const userStateResource: StateResource<User> = createStateResource(createUser()); - - beforeEach(() => { - formService.submit.mockReturnValue(of(userStateResource)); - }); - - it('should call formService submit', () => { - component.submit(); - - expect(formService.submit).toHaveBeenCalled(); - }); - - it('should set submitState$', () => { - component.submit(); - - expect(component.submitStateResource$).toBeObservable(cold('(a|)', { a: userStateResource })); - }); - }); - }); - describe('template', () => { describe('button save', () => { describe('input', () => { @@ -74,16 +51,6 @@ describe('UserFormSaveButtonComponent', () => { expect(getDebugElementFromFixtureByCss(fixture, saveButton).componentInstance.stateResource).toEqual(stateResource); }); }); - - describe('output', () => { - it('should call submit', () => { - component.submit = jest.fn(); - - dispatchEventFromFixture(fixture, saveButton, 'clickEmitter'); - - expect(component.submit).toHaveBeenCalled(); - }); - }); }); }); }); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.ts index 941904eb8d84b9c72b9483cabcfdb354026fd48e..a575d872a11a5a82623e4409832168b3f5d13e6b 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-save-button/user-form-save-button.component.ts @@ -1,10 +1,9 @@ import { User } from '@admin-client/user-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { AsyncPipe } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { Observable } from 'rxjs'; -import { UserFormService } from '../user.formservice'; @Component({ selector: 'admin-user-form-save-button', @@ -13,11 +12,5 @@ import { UserFormService } from '../user.formservice'; templateUrl: './user-form-save-button.component.html', }) export class UserFormSaveButtonComponent { - public readonly formService = inject(UserFormService); - - public submitStateResource$: Observable<StateResource<User>>; - - public submit(): void { - this.submitStateResource$ = this.formService.submit(); - } + @Input() submitStateResource$: Observable<StateResource<User>>; } diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html index 132dc6ba2c8eb40cfc12c0f163ba94092afca6a2..e147b63cf7d7ccc42a1e4cf4cae5b6da103d31e8 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.html @@ -23,20 +23,22 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<ods-spinner [stateResource]="userStateResource$ | async"> - <div class="max-w-[960px]" data-test-id="user-content"> - <admin-user-form-headline [isPatch]="isPatch" /> - <admin-user-form-data [formGroupParent]="formService.form" [isPatch]="isPatch" [userName]="userName" /> - <admin-user-form-roles [formGroupParent]="formService.form" /> - <admin-user-form-organisations-einheit-list - [formGroupParent]="formService.form" - [formGroupOrganisationsEinheiten]="formService.getOrganisationsEinheitenGroup()" - /> - <div class="mb-6 flex justify-between"> - <admin-user-form-save-button /> - @if (isPatch) { - <admin-delete-open-dialog-button data-test-id="delete-button-container" /> - } +<form [formGroup]="formService.form" (ngSubmit)="submit()"> + <ods-spinner [stateResource]="userStateResource$ | async"> + <div class="max-w-[960px]" data-test-id="user-content"> + <admin-user-form-headline [isPatch]="isPatch" /> + <admin-user-form-data [formGroupParent]="formService.form" [isPatch]="isPatch" [userName]="userName" /> + <admin-user-form-roles [formGroupParent]="formService.form" /> + <admin-user-form-organisations-einheit-list + [formGroupParent]="formService.form" + [formGroupOrganisationsEinheiten]="formService.getOrganisationsEinheitenGroup()" + /> + <div class="mb-6 flex justify-between"> + <admin-user-form-save-button [submitStateResource$]="submitStateResource$"/> + @if (isPatch) { + <admin-delete-open-dialog-button data-test-id="delete-button-container" /> + } + </div> </div> - </div> -</ods-spinner> + </ods-spinner> +</form> \ No newline at end of file diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts index bbaa75605aa2bc1071ceba8302892ee5088be620..632bab5c79d13c028fd0c6d76589215007b5ab86 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.spec.ts @@ -29,16 +29,18 @@ import { DIALOG_COMPONENT } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { expect } from '@jest/globals'; import { ButtonWithSpinnerComponent, SpinnerComponent } from '@ods/component'; import { cold } from 'jest-marbles'; import { createUser } from 'libs/admin/user-shared/test/user'; import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; import { UserFormDataComponent } from './user-form-data/user-form-data.component'; import { UserFormHeadlineComponent } from './user-form-headline/user-form-headline.component'; import { UserFormOrganisationsEinheitListComponent } from './user-form-organisations-einheit-list/user-form-organisations-einheit-list.component'; import { UserFormRolesComponent } from './user-form-roles/user-form-roles.component'; +import { UserFormSaveButtonComponent } from './user-form-save-button/user-form-save-button.component'; import { UserFormComponent } from './user-form.component'; import { UserFormService } from './user.formservice'; @@ -60,6 +62,7 @@ describe('UserFormComponent', () => { isInvalid: jest.fn(), form: new FormGroup({}), isPatch: jest.fn(), + submit: jest.fn(), }; await TestBed.configureTestingModule({ @@ -145,6 +148,22 @@ describe('UserFormComponent', () => { expect(component.userName).toBe(userName); }); }); + describe('submit', () => { + it('should call formservice submit', () => { + component.submit(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should set submit state resource', () => { + const stateResource$: Observable<StateResource<User>> = of(createStateResource(createUser())); + formService.submit.mockReturnValue(stateResource$); + + component.submit(); + + expect(component.submitStateResource$).toBe(stateResource$); + }); + }); }); describe('template', () => { @@ -204,23 +223,34 @@ describe('UserFormComponent', () => { notExistsAsHtmlElement(fixture, userContent); }); - }); - describe('admin delete button container', () => { - it('should exist', () => { - component.isPatch = true; + describe('admin save button', () => { + it('should exist with input', () => { + component.submitStateResource$ = of(createStateResource<User>(createUser())); - fixture.detectChanges(); + fixture.detectChanges(); - existsAsHtmlElement(fixture, deleteButtonContainer); + const saveButtonComponent: UserFormSaveButtonComponent = getMockComponent(fixture, UserFormSaveButtonComponent); + expect(saveButtonComponent.submitStateResource$).toBe(component.submitStateResource$); + }); }); - it('should not exist', () => { - component.isPatch = false; + describe('admin delete button container', () => { + it('should exist', () => { + component.isPatch = true; - fixture.detectChanges(); + fixture.detectChanges(); + + existsAsHtmlElement(fixture, deleteButtonContainer); + }); + + it('should not exist', () => { + component.isPatch = false; - notExistsAsHtmlElement(fixture, deleteButtonContainer); + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, deleteButtonContainer); + }); }); }); }); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts index f60e03692eed409a960bdeb3b27caa64b12d1ef9..9874532168270ed3ae8558d24949fe15c9032131 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form.component.ts @@ -62,6 +62,7 @@ export class UserFormComponent implements OnInit { public userStateResource$: Observable<StateResource<User>>; public isPatch: boolean; public userName: string; + public submitStateResource$: Observable<StateResource<User>>; ngOnInit(): void { this.userStateResource$ = this.formService.get().pipe( @@ -71,4 +72,8 @@ export class UserFormComponent implements OnInit { }), ); } + + public submit(): void { + this.submitStateResource$ = this.formService.submit(); + } } diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts index b0cb7867c9cd8330c274fd9ee944d16f9a5507bb..d97dee1e2b586f2a1bf01ed02059bcc31f687afd 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts @@ -100,34 +100,37 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest } _initForm(): UntypedFormGroup { - return this.formBuilder.group({ - [UserFormService.FIRST_NAME]: new FormControl(EMPTY_STRING, fieldEmptyValidator(UserFormService.FIRST_NAME)), - [UserFormService.LAST_NAME]: new FormControl(EMPTY_STRING, fieldEmptyValidator(UserFormService.LAST_NAME)), - [UserFormService.USERNAME]: new FormControl(EMPTY_STRING, [fieldLengthValidator(UserFormService.USERNAME, 3, 255)]), - [UserFormService.EMAIL]: new FormControl(EMPTY_STRING, [ - fieldInvalidValidator(UserFormService.EMAIL, /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/), - ]), - [UserFormService.CLIENT_ROLES]: this.formBuilder.group( - { - [UserFormService.ADMINISTRATION_GROUP]: this.formBuilder.group({ - [UserFormService.ADMIN]: new FormControl(false), - [UserFormService.DATENBEAUFTRAGUNG]: new FormControl(false), - }), - [UserFormService.ALFA_GROUP]: this.formBuilder.group({ - [UserFormService.LOESCHEN]: new FormControl(false), - [UserFormService.USER]: new FormControl(false), - [UserFormService.POSTSTELLE]: new FormControl(false), - }), - }, - { - validators: checkBoxGroupsEmptyValidator(UserFormService.CLIENT_ROLES, [ - UserFormService.ADMINISTRATION_GROUP, - UserFormService.ALFA_GROUP, - ]), - }, - ), - [UserFormService.GROUPS]: this.formBuilder.group({}), - }); + return this.formBuilder.group( + { + [UserFormService.FIRST_NAME]: new FormControl(EMPTY_STRING, fieldEmptyValidator(UserFormService.FIRST_NAME)), + [UserFormService.LAST_NAME]: new FormControl(EMPTY_STRING, fieldEmptyValidator(UserFormService.LAST_NAME)), + [UserFormService.USERNAME]: new FormControl(EMPTY_STRING, [fieldLengthValidator(UserFormService.USERNAME, 3, 255)]), + [UserFormService.EMAIL]: new FormControl(EMPTY_STRING, [ + fieldInvalidValidator(UserFormService.EMAIL, /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/), + ]), + [UserFormService.CLIENT_ROLES]: this.formBuilder.group( + { + [UserFormService.ADMINISTRATION_GROUP]: this.formBuilder.group({ + [UserFormService.ADMIN]: new FormControl(false), + [UserFormService.DATENBEAUFTRAGUNG]: new FormControl(false), + }), + [UserFormService.ALFA_GROUP]: this.formBuilder.group({ + [UserFormService.LOESCHEN]: new FormControl(false), + [UserFormService.USER]: new FormControl(false), + [UserFormService.POSTSTELLE]: new FormControl(false), + }), + }, + { + validators: checkBoxGroupsEmptyValidator(UserFormService.CLIENT_ROLES, [ + UserFormService.ADMINISTRATION_GROUP, + UserFormService.ALFA_GROUP, + ]), + }, + ), + [UserFormService.GROUPS]: this.formBuilder.group({}), + }, + { updateOn: 'submit' }, + ); } _initOrganisationsEinheiten(): Observable<AdminOrganisationsEinheit[]> {