diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts index 0c4fd5127eaa8546579fdd4268244081b370da46..350fef2058a41e30e107d9cc3d691f98e8a5269f 100644 --- a/alfa-client/apps/admin/src/app/app.module.ts +++ b/alfa-client/apps/admin/src/app/app.module.ts @@ -15,13 +15,13 @@ import { StoreModule } from '@ngrx/store'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { AdminLogoIconComponent, + DropdownMenuButtonComponent, + DropdownMenuComponent, LogoutIconComponent, MailboxIconComponent, NavItemComponent, NavbarComponent, OrgaUnitIconComponent, - PopupComponent, - PopupListItemComponent, } from '@ods/system'; import { OAuthModule } from 'angular-oauth2-oidc'; import { HttpUnauthorizedInterceptor } from 'libs/authentication/src/lib/http-unauthorized.interceptor'; @@ -44,8 +44,8 @@ import { appRoutes } from './app.routes'; imports: [ CommonModule, AdminLogoIconComponent, - PopupComponent, - PopupListItemComponent, + DropdownMenuComponent, + DropdownMenuButtonComponent, NavItemComponent, NavbarComponent, OrgaUnitIconComponent, diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html index 436ac2a76728c0b0b9b9da7d5e67d8bc0765a98d..7e40d215fa180350f111fabda9499e174119cab1 100644 --- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html +++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html @@ -1,4 +1,4 @@ -<ods-popup buttonClass="rounded-full"> +<ods-dropdown-menu buttonClass="rounded-full"> <div button-content role="img" @@ -8,11 +8,11 @@ {{ currentUserInitials }} </p> </div> - <ods-popup-list-item + <ods-dropdown-menu-button caption="Abmelden" (itemClicked)="authenticationService.logout()" data-test-id="popup-logout-button" > <ods-logout-icon icon /> - </ods-popup-list-item> -</ods-popup> + </ods-dropdown-menu-button> +</ods-dropdown-menu> diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts index 70c324948070f3e79d92bf51dca0f8f8f577d821..cc8b3f4838a8628642837db808ba47fbde89053b 100644 --- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts +++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts @@ -6,7 +6,11 @@ import { } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { LogoutIconComponent, PopupComponent, PopupListItemComponent } from '@ods/system'; +import { + DropdownMenuButtonComponent, + DropdownMenuComponent, + LogoutIconComponent, +} from '@ods/system'; import { AuthenticationService } from 'authentication'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; @@ -26,8 +30,8 @@ describe('UserProfileButtonContainerComponent', () => { declarations: [UserProfileButtonContainerComponent], imports: [ RouterTestingModule, - MockComponent(PopupComponent), - MockComponent(PopupListItemComponent), + MockComponent(DropdownMenuComponent), + MockComponent(DropdownMenuButtonComponent), MockComponent(LogoutIconComponent), ], providers: [ diff --git a/alfa-client/apps/alfa-e2e/src/components/user-settings/user-settings.component.e2e.ts b/alfa-client/apps/alfa-e2e/src/components/user-settings/user-settings.component.e2e.ts index 0ff6578edbce33cb3da9392fe3a1d41716352a71..ad90c1c60619c7124c00ce359a0a9a036d917cc7 100644 --- a/alfa-client/apps/alfa-e2e/src/components/user-settings/user-settings.component.e2e.ts +++ b/alfa-client/apps/alfa-e2e/src/components/user-settings/user-settings.component.e2e.ts @@ -25,16 +25,32 @@ import { TOGGLE_ELEMENT } from '../../support/angular.util'; export class UserSettingsE2EComponent { private readonly rootLocator: string = 'user-settings'; - private readonly emailBenachrichtigungLocator: string = 'email-benachrichtigung'; + private readonly emailBenachrichtigungNewVorgangLocator: string = 'email-benachrichtigung-neuer-Vorgang'; + private readonly emailBenachrichtigungVorgangAssignedToUserLocator: string = 'email-benachrichtigung-neuer-Vorgang-Assigned'; + private readonly emailBenachrichtigungPostfachNachrichtFromAntragsteller: string = + 'email-benachrichtigung-neue-Nachricht-Antragsteller'; + private readonly emailBenachrichtigungWiedervorlageDueToday: string = 'email-benachrichtigung-Faellige-Wiedervorlage'; private readonly darkModeLocator: string = 'dark-mode'; - private readonly buttonLocator: string = 'icon-button'; + private readonly buttonLocator: string = 'user-settings-button'; public getRoot() { return cy.getTestElementWithOid(this.rootLocator); } - public getEmailBenachrichtigung(): ToggleE2EComponent { - return new ToggleE2EComponent(this.emailBenachrichtigungLocator); + public getEmailBenachrichtigungForNewVorgang(): ToggleE2EComponent { + return new ToggleE2EComponent(this.emailBenachrichtigungNewVorgangLocator); + } + + public getEmailBenachrichtigungForVorgangAssignedToUser(): ToggleE2EComponent { + return new ToggleE2EComponent(this.emailBenachrichtigungVorgangAssignedToUserLocator); + } + + public getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller(): ToggleE2EComponent { + return new ToggleE2EComponent(this.emailBenachrichtigungPostfachNachrichtFromAntragsteller); + } + + public getEmailBenachrichtigungForWiedervorlageDueToday(): ToggleE2EComponent { + return new ToggleE2EComponent(this.emailBenachrichtigungWiedervorlageDueToday); } public getDarkMode(): ToggleE2EComponent { @@ -42,7 +58,7 @@ export class UserSettingsE2EComponent { } public getButton() { - return this.getRoot().findTestElementWithClass(this.buttonLocator); + return this.getRoot().getTestElementWithOid(this.buttonLocator); } } diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts index 2afd947dca54b689a373fde801350d3c5d0a53f1..49a14de53bcbd06b28c8e17fac05b789557d6c7c 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts @@ -4,7 +4,7 @@ import { VorgangSearchE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/ import { VorgangViewsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component'; import { HeaderE2EComponent } from 'apps/alfa-e2e/src/page-objects/header.po'; import { MainPage, waitForSpinnerToDisappear } from 'apps/alfa-e2e/src/page-objects/main.po'; -import { isKeyboardFocused } from 'apps/alfa-e2e/src/support/angular.util'; +import { isKeyboardFocused, isOdsFocused } from 'apps/alfa-e2e/src/support/angular.util'; import { dropCollections, pressTab } from 'apps/alfa-e2e/src/support/cypress-helper'; import { exist, haveFocus } from 'apps/alfa-e2e/src/support/cypress.util'; import { initUsermanagerUsers, loginAsSabine } from 'apps/alfa-e2e/src/support/user-util'; @@ -63,7 +63,7 @@ describe('VorgangList Page', () => { it('should focus settings icon', () => { pressTab(); - isKeyboardFocused(header.getUserSettings().getButton()); + isOdsFocused(header.getUserSettings().getButton()); }); it('should focus user icon', () => { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts index cd0b66b1f0310c27f6406ef071acdddabb5acd2f..2ba36a2468e8cf3c13653885f476e7d047da1d59 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/user-settings/user-settings.cy.ts @@ -58,8 +58,20 @@ describe('User Settings', () => { userSettings.getRoot().click(); }); - it('should show notificationsSendsFor toggle', () => { - exist(userSettings.getEmailBenachrichtigung().getRoot()); + it('should show benachrichtigung neuer Vorgang toggle', () => { + exist(userSettings.getEmailBenachrichtigungForNewVorgang().getRoot()); + }); + + it('should show benachrichtigung neue nachricht antragsteller toggle', () => { + exist(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getRoot()); + }); + + it('should show benachrichtigung vorgang mir zugewiesen toggle', () => { + exist(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getRoot()); + }); + + it('should show benachrichtigung faellige wiedervorlage toggle', () => { + exist(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getRoot()); }); it('should show darkMode toggle', () => { @@ -67,22 +79,79 @@ describe('User Settings', () => { }); }); - describe('click on notificationSendsFor toggle', () => { + describe('click on neuer Vorgang toggle', () => { + it('should have initial unchecked toggle', () => { + isNotChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + }); + + it('should switch toggle status', () => { + userSettings.getEmailBenachrichtigungForNewVorgang().getToggle().click(); + + isChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + }); + + it('should be loaded after page reload', () => { + reload(); + + userSettings.getRoot().click(); + isChecked(userSettings.getEmailBenachrichtigungForNewVorgang().getToggle()); + }); + }); + + describe('click on neue nachricht antragsteller toggle', () => { + it('should have initial unchecked toggle', () => { + isNotChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + }); + + it('should switch toggle status', () => { + userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle().click(); + + isChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + }); + + it('should be loaded after page reload', () => { + reload(); + + userSettings.getRoot().click(); + isChecked(userSettings.getEmailBenachrichtigungForPostfachNachrichtFromAntragsteller().getToggle()); + }); + }); + + describe('click on vorgang mir zugewiesen toggle', () => { + it('should have initial unchecked toggle', () => { + isNotChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + }); + + it('should switch toggle status', () => { + userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle().click(); + + isChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + }); + + it('should be loaded after page reload', () => { + reload(); + + userSettings.getRoot().click(); + isChecked(userSettings.getEmailBenachrichtigungForVorgangAssignedToUser().getToggle()); + }); + }); + + describe('click on faellige wiedervorlage toggle', () => { it('should have initial unchecked toggle', () => { - isNotChecked(userSettings.getEmailBenachrichtigung().getToggle()); + isNotChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); it('should switch toggle status', () => { - userSettings.getEmailBenachrichtigung().getToggle().click(); + userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle().click(); - isChecked(userSettings.getEmailBenachrichtigung().getToggle()); + isChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); it('should be loaded after page reload', () => { reload(); userSettings.getRoot().click(); - isChecked(userSettings.getEmailBenachrichtigung().getToggle()); + isChecked(userSettings.getEmailBenachrichtigungForWiedervorlageDueToday().getToggle()); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json index a05a798da3d435c1bfb2315e889a3d15a9163ea6..814e061ad715953b45342a9fde9a3dab6f7b17c3 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_ariane.json @@ -1,12 +1,12 @@ { "_id": { - "$oid": "645e6fa20cfafc0fbbe6bf73" + "$oid": "66fbace8d001317c611681ed" }, "createdAt": { "$date": "2024-09-03T10:25:17.001Z" }, "deleted": false, - "keycloakUserId": "2ccf0c13-da74-4516-ae3d-f46d30e8ec0c", + "keycloakUserId": "625718b7-61ea-43e9-841b-0b01438f6cbc", "firstName": "Ariane", "fullName": "Ariane Admin", "lastName": "Admin", diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json index 7f9b6d80eccbfbf7f0461cffc434adea04320f09..9bc95422fb2c6d99c6ea408d684e73b13fde1e08 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_peter.json @@ -1,6 +1,6 @@ { "_id": { - "$oid": "63284e55c39b316b2ad02e2c" + "$oid": "66fbb761bdbeecbd2b1681ed" }, "createdAt": { "$date": "2022-02-18T09:21:24.340Z" diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json index c04113e617497d444949fd17a4a287c9cc35e9a7..013cd251b1f3d1e20c6b775c61c1f0a11471b50f 100644 --- a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json +++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json @@ -1,12 +1,12 @@ { "_id": { - "$oid": "645e6fa20cfafc0fbbe6bf73" + "$oid": "66fbacfdd001317c611681ee" }, "createdAt": { "$date": "2024-08-14T13:11:56.489Z" }, "deleted": false, - "keycloakUserId": "2ccf0c13-da74-4516-ae3d-f46d30e8ec0c", + "keycloakUserId": "2320657a-dc97-4b9f-ae24-abec842e23ef", "firstName": "Zelda", "fullName": "Zelda Zusammen", "lastName": "Zusammen", diff --git a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts index c2a2187e14ea6dab14577d723fafb49f8f0b85cb..fd6bec7557050fb42fd8687b6b7582d23367ba71 100644 --- a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts +++ b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts @@ -30,6 +30,7 @@ enum AngularClassesE2E { MAT_BUTTONG_TOGGLE_CHECKED = 'mat-button-toggle-checked', MAT_FOCUSED = 'mat-focused', CDK_KEYBOARD_FOCUSED = 'cdk-keyboard-focused', + ODS_FOCUSED = 'ods-focused', MAT_BADGE_HIDDEN = 'mat-badge-hidden', } @@ -71,6 +72,10 @@ export function isKeyboardFocused(element: any) { containClass(element, AngularClassesE2E.CDK_KEYBOARD_FOCUSED); } +export function isOdsFocused(element: any) { + containClass(element, AngularClassesE2E.ODS_FOCUSED); +} + export function expectIconWithoutBadge(element: any): void { containClass(element, AngularClassesE2E.MAT_BADGE_HIDDEN); } diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index e3b231848785cf80bd379be9748b58e9dbd4fdd1..9e23463ad6c6fd0d96953de7adb1b71075150ca2 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -5,6 +5,8 @@ export * from './lib/bescheid-status-text/bescheid-status-text.component'; export * from './lib/bescheid-wrapper/bescheid-wrapper.component'; export * from './lib/button-card/button-card.component'; export * from './lib/button/button.component'; +export * from './lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component'; +export * from './lib/dropdown-menu/dropdown-menu/dropdown-menu.component'; export * from './lib/form/checkbox/checkbox.component'; export * from './lib/form/error-message/error-message.component'; export * from './lib/form/fieldset/fieldset.component'; @@ -34,6 +36,4 @@ export * from './lib/instant-search/instant-search/instant-search.component'; export * from './lib/instant-search/instant-search/instant-search.model'; export * from './lib/navbar/nav-item/nav-item.component'; export * from './lib/navbar/navbar/navbar.component'; -export * from './lib/popup/popup-list-item/popup-list-item.component'; -export * from './lib/popup/popup/popup.component'; export * from './lib/testbtn/testbtn.component'; diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.spec.ts similarity index 65% rename from alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts rename to alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.spec.ts index 3d624f9674b26a1f03a2e024f0139f9eb8230746..2bcb6edef656dfbd88ae821211e204eeae9c1917 100644 --- a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.spec.ts @@ -1,17 +1,17 @@ import { dispatchEventFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { PopupListItemComponent } from './popup-list-item.component'; +import { DropdownMenuButtonComponent } from './dropdown-menu-button.component'; -describe('PopupListItemComponent', () => { - let component: PopupListItemComponent; - let fixture: ComponentFixture<PopupListItemComponent>; +describe('DropdownMenuButtonComponent', () => { + let component: DropdownMenuButtonComponent; + let fixture: ComponentFixture<DropdownMenuButtonComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PopupListItemComponent], + imports: [DropdownMenuButtonComponent], }).compileComponents(); - fixture = TestBed.createComponent(PopupListItemComponent); + fixture = TestBed.createComponent(DropdownMenuButtonComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.ts similarity index 71% rename from alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts rename to alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.ts index 3bc88c4c30db6091ccf72a4e3658972fe4f117b6..ca2f522f5e5a4afb408f97635d84afef1e25f5ee 100644 --- a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button/dropdown-menu-button.component.ts @@ -2,19 +2,20 @@ import { CommonModule } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ - selector: 'ods-popup-list-item', + selector: 'ods-dropdown-menu-button', standalone: true, imports: [CommonModule], template: `<button - class="flex min-h-12 w-full items-center gap-4 border-2 border-transparent bg-whitetext px-4 py-3 text-start outline-none hover:border-primary focus-visible:border-focus" - role="listitem" + class="flex min-h-12 w-full items-center gap-4 border-2 border-transparent px-4 py-3 + text-start outline-none hover:border-primary focus-visible:border-focus" + role="menuitem" (click)="itemClicked.emit()" > <ng-content select="[icon]" /> <p class="text-text">{{ caption }}</p> </button>`, }) -export class PopupListItemComponent { +export class DropdownMenuButtonComponent { @Input({ required: true }) caption!: string; @Output() itemClicked: EventEmitter<MouseEvent> = new EventEmitter(); diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.spec.ts similarity index 80% rename from alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts rename to alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.spec.ts index fe6160acf32b4e63623ac2996b32f6222e377188..4848c4005e5493630f498836b2807519da953cbe 100644 --- a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.spec.ts @@ -1,19 +1,19 @@ import { getElementFromFixture } from '@alfa-client/test-utils'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; -import { PopupComponent } from './popup.component'; +import { DropdownMenuComponent } from './dropdown-menu.component'; -describe('PopupComponent', () => { - let component: PopupComponent; - let fixture: ComponentFixture<PopupComponent>; - const popupButton: string = getDataTestIdOf('popup-button'); +describe('DropdownMenuComponent', () => { + let component: DropdownMenuComponent; + let fixture: ComponentFixture<DropdownMenuComponent>; + const dropdownButton: string = getDataTestIdOf('dropdown-button'); beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PopupComponent], + imports: [DropdownMenuComponent], }).compileComponents(); - fixture = TestBed.createComponent(PopupComponent); + fixture = TestBed.createComponent(DropdownMenuComponent); component = fixture.componentInstance; fixture.detectChanges(); }); @@ -40,6 +40,24 @@ describe('PopupComponent', () => { }); }); + describe('toggleFocusedButton', () => { + it('should change false to true', () => { + component.isButtonFocused = false; + + component.toggleFocusedButton(); + + expect(component.isButtonFocused).toBe(true); + }); + + it('should change true to false', () => { + component.isButtonFocused = true; + + component.toggleFocusedButton(); + + expect(component.isButtonFocused).toBe(false); + }); + }); + describe('handleButtonClick', () => { beforeEach(() => { component.togglePopup = jest.fn(); @@ -80,12 +98,34 @@ describe('PopupComponent', () => { })); }); + describe('on focus button', () => { + it('should toggle focused button', () => { + component.toggleFocusedButton = jest.fn(); + const buttonElement: HTMLElement = getElementFromFixture(fixture, dropdownButton); + + buttonElement.focus(); + + expect(component.toggleFocusedButton).toHaveBeenCalled(); + }); + }); + + describe('on blur button', () => { + it('should toggle focused button', () => { + component.toggleFocusedButton = jest.fn(); + const buttonElement: HTMLElement = getElementFromFixture(fixture, dropdownButton); + + buttonElement.dispatchEvent(new Event('blur')); + + expect(component.toggleFocusedButton).toHaveBeenCalled(); + }); + }); + describe('aria-expanded', () => { it('should be true if popup is open', () => { component.isPopupOpen = true; fixture.detectChanges(); - const buttonElement: HTMLElement = getElementFromFixture(fixture, popupButton); + const buttonElement: HTMLElement = getElementFromFixture(fixture, dropdownButton); expect(buttonElement.getAttribute('aria-expanded')).toBe('true'); }); @@ -94,7 +134,7 @@ describe('PopupComponent', () => { component.isPopupOpen = false; fixture.detectChanges(); - const buttonElement: HTMLElement = getElementFromFixture(fixture, popupButton); + const buttonElement: HTMLElement = getElementFromFixture(fixture, dropdownButton); expect(buttonElement.getAttribute('aria-expanded')).toBe('false'); }); diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts similarity index 75% rename from alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts rename to alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts index 60adf093640b07510296fab35c0a6e4fbb3650e9..35cc64b06437d36745806052b651115d4d307b99 100644 --- a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts @@ -4,24 +4,28 @@ import { Component, ElementRef, HostListener, Input, ViewChild } from '@angular/ import { twMerge } from 'tailwind-merge'; @Component({ - selector: 'ods-popup', + selector: 'ods-dropdown-menu', standalone: true, imports: [CommonModule, CdkTrapFocus], template: `<div class="relative w-fit"> <button - [ngClass]="[twMerge('w-fit outline-2 outline-offset-2 outline-focus', buttonClass)]" + [ngClass]="[twMerge('block w-fit outline-2 outline-offset-2 outline-focus', buttonClass)]" (click)="handleButtonClick()" [attr.aria-expanded]="isPopupOpen" aria-haspopup="true" [attr.aria-label]="label" - data-test-id="popup-button" + [attr.data-test-id]="buttonTestId" + [class.ods-focused]="isButtonFocused" + (focus)="toggleFocusedButton()" + (blur)="toggleFocusedButton()" #button > <ng-content select="[button-content]" /> </button> - <ul + <div *ngIf="isPopupOpen" - class="absolute max-h-120 min-w-44 max-w-80 animate-fadeIn overflow-y-auto rounded shadow-lg shadow-grayborder focus:outline-none" + class="bg-dropdownBg absolute max-h-120 min-w-44 max-w-80 + animate-fadeIn overflow-y-auto rounded shadow-md focus:outline-none" [ngClass]="alignTo === 'left' ? 'right-0' : 'left-0'" role="menu" aria-modal="true" @@ -30,15 +34,17 @@ import { twMerge } from 'tailwind-merge'; #popupList > <ng-content /> - </ul> + </div> </div>`, }) -export class PopupComponent { +export class DropdownMenuComponent { @Input() alignTo: 'left' | 'right' = 'left'; @Input() label: string = ''; @Input() buttonClass: string = ''; + @Input() buttonTestId: string = 'dropdown-button'; isPopupOpen: boolean = false; + isButtonFocused: boolean = false; readonly twMerge = twMerge; @ViewChild('button') buttonRef: ElementRef<HTMLButtonElement>; @@ -71,6 +77,10 @@ export class PopupComponent { this.isPopupOpen = !this.isPopupOpen; } + toggleFocusedButton(): void { + this.isButtonFocused = !this.isButtonFocused; + } + closePopupAndFocusButton(): void { this.isPopupOpen = false; this.buttonRef.nativeElement.focus(); diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.stories.ts similarity index 52% rename from alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts rename to alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.stories.ts index 015112aabc92eee9b30ec4ab36ab84cce8da850c..c5b38d806a4af5e404f4c8f189fb33c383c9a113 100644 --- a/alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts +++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.stories.ts @@ -8,15 +8,20 @@ import { import { SaveIconComponent } from '../../icons/save-icon/save-icon.component'; import { UserIconComponent } from '../../icons/user-icon/user-icon.component'; -import { PopupListItemComponent } from '../popup-list-item/popup-list-item.component'; -import { PopupComponent } from './popup.component'; +import { DropdownMenuButtonComponent } from '../dropdown-menu-button/dropdown-menu-button.component'; +import { DropdownMenuComponent } from './dropdown-menu.component'; -const meta: Meta<PopupComponent> = { - title: 'Popup/Popup', - component: PopupComponent, +const meta: Meta<DropdownMenuComponent> = { + title: 'Dropdown menu/Dropdown menu', + component: DropdownMenuComponent, decorators: [ moduleMetadata({ - imports: [PopupComponent, PopupListItemComponent, SaveIconComponent, UserIconComponent], + imports: [ + DropdownMenuComponent, + DropdownMenuButtonComponent, + SaveIconComponent, + UserIconComponent, + ], }), componentWrapperDecorator((story) => `<div class="flex justify-center mb-32">${story}</div>`), ], @@ -25,7 +30,7 @@ const meta: Meta<PopupComponent> = { }; export default meta; -type Story = StoryObj<PopupComponent>; +type Story = StoryObj<DropdownMenuComponent>; export const Default: Story = { args: { alignTo: 'left', label: '', buttonClass: '' }, @@ -42,37 +47,37 @@ export const Default: Story = { }, render: (args) => ({ props: args, - template: `<ods-popup ${argsToTemplate(args)}> + template: `<ods-dropdown-menu ${argsToTemplate(args)}> <ods-user-icon button-content /> - <ods-popup-list-item caption="Lorem" /> - <ods-popup-list-item caption="Ipsum" /> - <ods-popup-list-item caption="Dolor" /> - </ods-popup>`, + <ods-dropdown-menu-button caption="Lorem" /> + <ods-dropdown-menu-button caption="Ipsum" /> + <ods-dropdown-menu-button caption="Dolor" /> + </ods-dropdown-menu>`, }), }; export const LongText: Story = { render: (args) => ({ props: args, - template: `<ods-popup ${argsToTemplate(args)}> + template: `<ods-dropdown-menu ${argsToTemplate(args)}> <p button-content>Trigger popup</p> - <ods-popup-list-item caption="Lorem" /> - <ods-popup-list-item caption="Lorem ipsum dolor sit amet" /> - </ods-popup>`, + <ods-dropdown-menu-button caption="Lorem" /> + <ods-dropdown-menu-button caption="Lorem ipsum dolor sit amet" /> + </ods-dropdown-menu>`, }), }; export const ItemsWithIcons: Story = { render: (args) => ({ props: args, - template: `<ods-popup ${argsToTemplate(args)}> + template: `<ods-dropdown-menu ${argsToTemplate(args)}> <p button-content>Trigger popup</p> - <ods-popup-list-item caption="Lorem"> + <ods-dropdown-menu-button caption="Lorem"> <ods-save-icon icon size="small" /> - </ods-popup-list-item> - <ods-popup-list-item caption="Lorem ipsum dolor sit amet"> + </ods-dropdown-menu-button> + <ods-dropdown-menu-button caption="Lorem ipsum dolor sit amet"> <ods-save-icon icon size="small" /> - </ods-popup-list-item> - </ods-popup>`, + </ods-dropdown-menu-button> + </ods-dropdown-menu>`, }), }; diff --git a/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5327d1e498e727626a7061518a15bcfdb45c49d3 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SettingsIconComponent } from './settings-icon.component'; + +describe('SettingsIconComponent', () => { + let component: SettingsIconComponent; + let fixture: ComponentFixture<SettingsIconComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SettingsIconComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(SettingsIconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..72f83d3644b562fc6d7be857cc39b0a68a52ae6a --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settings-icon.component.ts @@ -0,0 +1,27 @@ +import { NgClass } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { IconVariants, iconVariants } from '@ods/system'; +import { twMerge } from 'tailwind-merge'; + +@Component({ + selector: 'ods-settings-icon', + standalone: true, + imports: [NgClass], + template: `<svg + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + [ngClass]="twMerge(iconVariants({ size }), 'fill-neutral-500', class)" + > + <path + d="M 10.490234 2 C 10.011234 2 9.6017656 2.3385938 9.5097656 2.8085938 L 9.1757812 4.5234375 C 8.3550224 4.8338012 7.5961042 5.2674041 6.9296875 5.8144531 L 5.2851562 5.2480469 C 4.8321563 5.0920469 4.33375 5.2793594 4.09375 5.6933594 L 2.5859375 8.3066406 C 2.3469375 8.7216406 2.4339219 9.2485 2.7949219 9.5625 L 4.1132812 10.708984 C 4.0447181 11.130337 4 11.559284 4 12 C 4 12.440716 4.0447181 12.869663 4.1132812 13.291016 L 2.7949219 14.4375 C 2.4339219 14.7515 2.3469375 15.278359 2.5859375 15.693359 L 4.09375 18.306641 C 4.33275 18.721641 4.8321562 18.908906 5.2851562 18.753906 L 6.9296875 18.1875 C 7.5958842 18.734206 8.3553934 19.166339 9.1757812 19.476562 L 9.5097656 21.191406 C 9.6017656 21.661406 10.011234 22 10.490234 22 L 13.509766 22 C 13.988766 22 14.398234 21.661406 14.490234 21.191406 L 14.824219 19.476562 C 15.644978 19.166199 16.403896 18.732596 17.070312 18.185547 L 18.714844 18.751953 C 19.167844 18.907953 19.66625 18.721641 19.90625 18.306641 L 21.414062 15.691406 C 21.653063 15.276406 21.566078 14.7515 21.205078 14.4375 L 19.886719 13.291016 C 19.955282 12.869663 20 12.440716 20 12 C 20 11.559284 19.955282 11.130337 19.886719 10.708984 L 21.205078 9.5625 C 21.566078 9.2485 21.653063 8.7216406 21.414062 8.3066406 L 19.90625 5.6933594 C 19.66725 5.2783594 19.167844 5.0910937 18.714844 5.2460938 L 17.070312 5.8125 C 16.404116 5.2657937 15.644607 4.8336609 14.824219 4.5234375 L 14.490234 2.8085938 C 14.398234 2.3385937 13.988766 2 13.509766 2 L 10.490234 2 z M 12 8 C 14.209 8 16 9.791 16 12 C 16 14.209 14.209 16 12 16 C 9.791 16 8 14.209 8 12 C 8 9.791 9.791 8 12 8 z" + /> + </svg>`, +}) +export class SettingsIconComponent { + @Input() size: IconVariants['size'] = 'medium'; + @Input() class: string = undefined; + + protected readonly iconVariants = iconVariants; + protected readonly twMerge = twMerge; +} diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts deleted file mode 100644 index a28201314e94cc47b348fd9082f158ec06326174..0000000000000000000000000000000000000000 --- a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular'; - -import { PopupListItemComponent } from './popup-list-item.component'; - -const meta: Meta<PopupListItemComponent> = { - title: 'Popup/Popup list item', - component: PopupListItemComponent, - decorators: [ - moduleMetadata({ - imports: [PopupListItemComponent], - }), - ], - excludeStories: /.*Data$/, - tags: ['autodocs'], -}; - -export default meta; -type Story = StoryObj<PopupListItemComponent>; - -export const Default: Story = { - args: { - caption: 'List item', - }, -}; diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css index 49ba05caeaf723693a01b5dbb9be991b4196afec..22790260b6e1dfc572920df9f126930e36fd683b 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css @@ -36,6 +36,7 @@ --color-doc: 219 63% 54%; --color-modal-bg: 0 0% 100%; + --color-dropdown-bg: 0 0% 98%; } .dark { @@ -69,6 +70,7 @@ --color-doc: 219 63% 54%; --color-modal-bg: 0 0% 26%; + --color-dropdown-bg: 0 0% 26%; } .bescheid-dialog-backdrop { diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js index 588bdac521f0d439cd3df6cd7d3ec1228156298a..3d33483b952c991b6d66bbf1170437c787cb80f4 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js @@ -106,6 +106,7 @@ module.exports = { }, mainbg: 'hsl(var(--color-mainbg) / <alpha-value>)', modalBg: 'hsl(var(--color-modal-bg) / <alpha-value>)', + dropdownBg: 'hsl(var(--color-dropdown-bg) / <alpha-value>)', primary: { 600: 'hsl(var(--color-primary-600) / <alpha-value>)', DEFAULT: 'hsl(var(--color-primary-600) / <alpha-value>)', diff --git a/alfa-client/libs/user-settings-shared/src/index.ts b/alfa-client/libs/user-settings-shared/src/index.ts index eaddff3023e818f059fdb1c33ee13ce0436f988f..413ed3e4414ba88ec6b7d3f44371b8fe0fbcf6ed 100644 --- a/alfa-client/libs/user-settings-shared/src/index.ts +++ b/alfa-client/libs/user-settings-shared/src/index.ts @@ -21,6 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +export * from '../test/user-settings'; export * from './lib/+state/user-settings.actions'; export * from './lib/+state/user-settings.facade'; export * from './lib/+state/user-settings.models'; @@ -30,3 +31,4 @@ export * from './lib/user-settings-shared.module'; export * from './lib/user-settings.linkrel'; export * from './lib/user-settings.model'; export * from './lib/user-settings.service'; +export * from './lib/user-settings.util'; diff --git a/alfa-client/libs/user-settings-shared/src/lib/user-settings.model.ts b/alfa-client/libs/user-settings-shared/src/lib/user-settings.model.ts index c9cbd96900720d290a6d77f98f9194fee3a2c313..ff7e9475c62651cc97212b39ebea960eaebc0e96 100644 --- a/alfa-client/libs/user-settings-shared/src/lib/user-settings.model.ts +++ b/alfa-client/libs/user-settings-shared/src/lib/user-settings.model.ts @@ -23,13 +23,25 @@ */ import { Resource } from '@ngxp/rest'; -export enum NotificationsSendFor { - NONE = 'NONE', - ALL = 'ALL', +export enum UserNotificationsTypes { + NOTIFICATIONS_SEND_FOR = 'notificationsSendFor', + VORGANGE_CREATED = 'vorgangCreated', + VORGANG_ASSIGNED_TO_USER = 'vorgangAssignedToUser', + POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER = 'postfachNachrichtFromAntragsteller', + WIEDERVORLAGE_DUE_TODAY = 'wiedervorlageDueToday', } -export interface UserSettings { - notificationsSendFor: string; +export enum NotificationSendForTypes { + ALL = 'ALL', + NONE = 'NONE', } +export type UserSettings = Partial<{ + [UserNotificationsTypes.NOTIFICATIONS_SEND_FOR]: NotificationSendForTypes; + [UserNotificationsTypes.VORGANGE_CREATED]: boolean; + [UserNotificationsTypes.VORGANG_ASSIGNED_TO_USER]: boolean; + [UserNotificationsTypes.POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER]: boolean; + [UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY]: boolean; +}>; + export interface UserSettingsResource extends UserSettings, Resource {} diff --git a/alfa-client/libs/user-settings-shared/src/lib/user-settings.service.ts b/alfa-client/libs/user-settings-shared/src/lib/user-settings.service.ts index 57c852f96077aa864686a02b55e46b24184f727f..9ff5a5b444f825dc06cbb1ed1201c1f39d6f6d47 100644 --- a/alfa-client/libs/user-settings-shared/src/lib/user-settings.service.ts +++ b/alfa-client/libs/user-settings-shared/src/lib/user-settings.service.ts @@ -21,15 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Injectable } from '@angular/core'; import { createEmptyStateResource, doIfLoadingRequired, StateResource, } from '@alfa-client/tech-shared'; import { UserProfileService } from '@alfa-client/user-profile-shared'; -import { combineLatest, Observable } from 'rxjs'; -import { map, startWith, tap } from 'rxjs/operators'; +import { Injectable } from '@angular/core'; +import { combineLatest, Observable, startWith, tap } from 'rxjs'; +import { map } from 'rxjs/operators'; import { UserSettingsFacade } from './+state/user-settings.facade'; import { UserSettings, UserSettingsResource } from './user-settings.model'; diff --git a/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.spec.ts b/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..af11512a6a81f217e1c4d7887b04d16059a78688 --- /dev/null +++ b/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.spec.ts @@ -0,0 +1,15 @@ +import { UserSettings, UserSettingsResource } from '@alfa-client/user-settings-shared'; +import { toResource } from '../../../tech-shared/test/resource'; +import { createUserSettings } from '../../test/user-settings'; +import { mapUserSettingsResourceToUserSettings } from './user-settings.util'; + +describe('mapUserSettingsResourceToUserSettings', () => { + it('should remove resource attributes', () => { + const userSettings: UserSettings = createUserSettings(); + const userSettingsResource: UserSettingsResource = toResource(userSettings); + + const result: UserSettings = mapUserSettingsResourceToUserSettings(userSettingsResource); + + expect(result).toEqual(userSettings); + }); +}); diff --git a/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.ts b/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e6a1b7556b55b221fef3601ce4c35d627160b35 --- /dev/null +++ b/alfa-client/libs/user-settings-shared/src/lib/user-settings.util.ts @@ -0,0 +1,8 @@ +import { UserSettings, UserSettingsResource } from '@alfa-client/user-settings-shared'; + +export function mapUserSettingsResourceToUserSettings( + resource: UserSettingsResource, +): UserSettings { + const { _links, _embedded, ...userSettings } = resource; + return <UserSettings>userSettings; +} diff --git a/alfa-client/libs/user-settings-shared/test/user-settings.ts b/alfa-client/libs/user-settings-shared/test/user-settings.ts index 5e787b1be075b6784b619a3abbe5eda8d1a4f91c..e0a8ac3c89531e67479b35f64a6a9129e731e4da 100644 --- a/alfa-client/libs/user-settings-shared/test/user-settings.ts +++ b/alfa-client/libs/user-settings-shared/test/user-settings.ts @@ -23,7 +23,8 @@ */ import { toResource } from 'libs/tech-shared/test/resource'; import { - NotificationsSendFor, + NotificationSendForTypes, + UserNotificationsTypes, UserSettings, UserSettingsResource, } from '../src/lib/user-settings.model'; @@ -32,8 +33,20 @@ export function createUserSettingsResource(linkRelations: string[] = []): UserSe return toResource(createUserSettings(), linkRelations); } -export function createUserSettings(): UserSettings { +export function createUserSettings(value: boolean = true): UserSettings { return { - notificationsSendFor: NotificationsSendFor.ALL, + [UserNotificationsTypes.VORGANGE_CREATED]: value, + [UserNotificationsTypes.VORGANG_ASSIGNED_TO_USER]: value, + [UserNotificationsTypes.POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER]: value, + [UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY]: value, + [UserNotificationsTypes.NOTIFICATIONS_SEND_FOR]: mapBooleanToNotificationSendFor(value), }; } + +export function mapBooleanToNotificationSendFor(value: boolean): NotificationSendForTypes { + return value ? NotificationSendForTypes.ALL : NotificationSendForTypes.NONE; +} + +export function mapNotificationSendForToBoolean(value: NotificationSendForTypes): boolean { + return value === NotificationSendForTypes.ALL; +} diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html index 9d321332c8895df4b94c7d2b8cc199a5a0bbbfe2..c970ebd39aad35cca530c1ea2bf79d1930522b89 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.html @@ -23,4 +23,4 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<alfa-user-settings [apiRoot]="apiRoot$ | async" class="mat-typography"></alfa-user-settings> +<alfa-user-settings [apiRoot]="apiRoot$ | async"></alfa-user-settings> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.html similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.html rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.html diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.scss b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.scss similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.scss rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.scss diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts index 5ae103c6a3ca8a318ac3f45268d7c2d75585763a..636b5468a0f5b98d2fc404441a96f902685ebf88 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.spec.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AppService } from '@alfa-client/app-shared'; import { mock } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; import { BehaviorSubject } from 'rxjs'; import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container.component'; diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.ts similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.ts index 5039d964cba91f75633f185a45369f6286d25c20..c138988340f762f5ebbf35f777ae066d67618ca1 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { AppService, localStorageDark } from '@alfa-client/app-shared'; import { DOCUMENT } from '@angular/common'; import { Component, Inject, OnInit, Renderer2 } from '@angular/core'; -import { AppService, localStorageDark } from '@alfa-client/app-shared'; import { Observable } from 'rxjs'; @Component({ diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.html diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.scss diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.spec.ts diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component.ts diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.html new file mode 100644 index 0000000000000000000000000000000000000000..46b6f0f815b6cb0fdfe06eee789e6ad2a1d6d754 --- /dev/null +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.html @@ -0,0 +1,7 @@ +<div class="menu-container w-72 p-4" (click)="$event.stopPropagation()"> + <alfa-user-settings-darkmode-container class="mb-3 block" /> + <alfa-user-settings-email-benachrichtigung-container + *ngIf="apiRoot.resource | hasLink: apiRootLinkRel.CURRENT_USER" + data-test-id="email-benachrichtigung-toggle" + /> +</div> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b61efad3b9289424500fcda873e676ccb12499a --- /dev/null +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.spec.ts @@ -0,0 +1,31 @@ +import { createEmptyStateResource, HasLinkPipe } from '@alfa-client/tech-shared'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container/user-settings-darkmode-container.component'; +import { UserSettingsDropdownComponent } from './user-settings-dropdown.component'; +import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; + +describe('UserSettingsDropdownComponent', () => { + let component: UserSettingsDropdownComponent; + let fixture: ComponentFixture<UserSettingsDropdownComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserSettingsDropdownComponent], + declarations: [ + MockComponent(UserSettingsDarkmodeContainerComponent), + MockComponent(UserSettingsEmailBenachrichtigungContainerComponent), + HasLinkPipe, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsDropdownComponent); + component = fixture.componentInstance; + component.apiRoot = createEmptyStateResource(); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..04bb934d03fb86357ae83e7182145c47679648ad --- /dev/null +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component.ts @@ -0,0 +1,12 @@ +import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'alfa-user-settings-dropdown', + templateUrl: './user-settings-dropdown.component.html', +}) +export class UserSettingsDropdownComponent { + @Input() apiRoot: StateResource<ApiRootResource>; + readonly apiRootLinkRel = ApiRootLinkRel; +} diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html similarity index 95% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html index ca5108e414a5dc65071051bdcacf9eeb7505cb13..78d046c50c3cacb5be3061837e45da25b50d601f 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.html @@ -25,6 +25,6 @@ --> <alfa-user-settings-email-benachrichtigung [userSettings]="userSettings$ | async" - (valueChanged)="changeNotificationsSendFor($event)" + (valueChanged)="changeUserSettings($event)" > </alfa-user-settings-email-benachrichtigung> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts similarity index 82% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts index 25b285ff3eb86bf18d04a549292eee9690b46b35..e2009c3eb44f7e2f83e687d23d8fa078a4b82ea1 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.spec.ts @@ -21,9 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { mock } from '@alfa-client/test-utils'; -import { NotificationsSendFor, UserSettingsService } from '@alfa-client/user-settings-shared'; +import { UserSettingsFacade, UserSettingsService } from '@alfa-client/user-settings-shared'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { createUserSettings } from 'libs/user-settings-shared/test/user-settings'; import { MockComponent } from 'ng-mocks'; import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-email-benachrichtigung-container.component'; import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; @@ -32,7 +33,10 @@ describe('UserSettingsEmailBenachrichtigungContainerComponent', () => { let component: UserSettingsEmailBenachrichtigungContainerComponent; let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungContainerComponent>; + const userSettings = createUserSettings(); + const userSettingsService = { ...mock(UserSettingsService), setUserSettings: jest.fn() }; + const userSettingsFacade = mock(UserSettingsFacade); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -45,6 +49,10 @@ describe('UserSettingsEmailBenachrichtigungContainerComponent', () => { provide: UserSettingsService, useValue: userSettingsService, }, + { + provide: UserSettingsFacade, + useValue: userSettingsFacade, + }, ], }).compileComponents(); @@ -65,21 +73,11 @@ describe('UserSettingsEmailBenachrichtigungContainerComponent', () => { }); }); - 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', () => { - component.changeNotificationsSendFor(false); + describe('changeUserSettings', () => { + it('should forward call to service setUserSettings', () => { + component.changeUserSettings(userSettings); - expect(userSettingsService.setUserSettings).toHaveBeenCalledWith({ - notificationsSendFor: NotificationsSendFor.NONE, - }); + expect(userSettingsService.setUserSettings).toHaveBeenCalledWith(userSettings); }); }); }); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts similarity index 72% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts index 6d0aae2e294f836c7bd4cb3aeb558215ac8e2085..e4f8188072ec8c7dc724696d5cf715a2a0adcd4f 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.ts @@ -21,20 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component } from '@angular/core'; import { StateResource } from '@alfa-client/tech-shared'; -import { - NotificationsSendFor, - UserSettings, - UserSettingsResource, - UserSettingsService, -} from '@alfa-client/user-settings-shared'; +import { UserSettings, UserSettingsResource, UserSettingsService } from '@alfa-client/user-settings-shared'; +import { Component } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ selector: 'alfa-user-settings-email-benachrichtigung-container', templateUrl: './user-settings-email-benachrichtigung-container.component.html', - styleUrls: ['./user-settings-email-benachrichtigung-container.component.scss'], }) export class UserSettingsEmailBenachrichtigungContainerComponent { userSettings$: Observable<StateResource<UserSettingsResource>>; @@ -45,13 +39,7 @@ export class UserSettingsEmailBenachrichtigungContainerComponent { this.userSettings$ = this.userSettingsService.getUserSettings(); } - 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 }; + changeUserSettings(userSettings: UserSettings): void { + this.userSettingsService.setUserSettings(userSettings); } } diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html new file mode 100644 index 0000000000000000000000000000000000000000..988e06dcbe077007f4d9e5839fce495040a744be --- /dev/null +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html @@ -0,0 +1,66 @@ +<!-- + + Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + Ministerpräsidenten des Landes Schleswig-Holstein + Staatskanzlei + Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + + Lizenziert unter der EUPL, Version 1.2 oder - sobald + diese von der Europäischen Kommission genehmigt wurden - + Folgeversionen der EUPL ("Lizenz"); + Sie dürfen dieses Werk ausschließlich gemäß + dieser Lizenz nutzen. + Eine Kopie der Lizenz finden Sie hier: + + https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + + Sofern nicht durch anwendbare Rechtsvorschriften + gefordert oder in schriftlicher Form vereinbart, wird + die unter der Lizenz verbreitete Software "so wie sie + ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + ausdrücklich oder stillschweigend - verbreitet. + Die sprachspezifischen Genehmigungen und Beschränkungen + unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<ng-container *ngIf="userSettings.resource | hasLink: userSettingsLinkRel.EDIT"> + <h2 class="mb-2 text-base font-bold text-text">E-Mail Benachrichtigungen</h2> + <ozgcloud-slide-toggle + [checked]=" + isChecked(UserNotifications.VORGANGE_CREATED) || + isChecked(UserNotifications.NOTIFICATIONS_SEND_FOR) + " + (valueChanged)="emitSettingsForVorgangCreated($event)" + data-test-id="email-benachrichtigung-neuer-Vorgang" + label="Neuer Vorgang im Alfa" + toolTip="E-Mail-Benachrichtigung bei Eingang eines Antrags" + > + </ozgcloud-slide-toggle> + <ozgcloud-slide-toggle + [checked]="isChecked(UserNotifications.POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER)" + (valueChanged)="emitSettings(UserNotifications.POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER, $event)" + data-test-id="email-benachrichtigung-neue-Nachricht-Antragsteller" + label="Neue Nachricht vom Antragsteller" + toolTip="E-Mail-Benachrichtigung bei neu eingegangener Nachricht des Antragstellers bei einem mir zugewiesenen Vorgang" + *ngIf="resourceHasKey(UserNotifications.POSTFACH_NACHRICHT_FROM_ANTRAGSTELLER)" + > + </ozgcloud-slide-toggle> + <ozgcloud-slide-toggle + [checked]="isChecked(UserNotifications.VORGANG_ASSIGNED_TO_USER)" + (valueChanged)="emitSettings(UserNotifications.VORGANG_ASSIGNED_TO_USER, $event)" + data-test-id="email-benachrichtigung-neuer-Vorgang-Assigned" + label="Vorgang wurde mir zugewiesen" + toolTip="E-Mail-Benachrichtigung bei fälliger Wiedervorlage eines mir zugewiesenen Vorgangs" + *ngIf="resourceHasKey(UserNotifications.VORGANG_ASSIGNED_TO_USER)" + > + </ozgcloud-slide-toggle> + <ozgcloud-slide-toggle + [checked]="isChecked(UserNotifications.WIEDERVORLAGE_DUE_TODAY)" + (valueChanged)="emitSettings(UserNotifications.WIEDERVORLAGE_DUE_TODAY, $event)" + data-test-id="email-benachrichtigung-Faellige-Wiedervorlage" + label="Fällige Wiedervorlage" + toolTip=" E-Mail-Benachrichtigung bei Zuweisung eines Vorgangs an mich" + *ngIf="resourceHasKey(UserNotifications.WIEDERVORLAGE_DUE_TODAY)" + > + </ozgcloud-slide-toggle> +</ng-container> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss similarity index 100% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.scss diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c99bdf35fe1103ef96c66a6f92770ed0c8d35828 --- /dev/null +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { createStateResource, HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + Mock, + mock, + notExistsAsHtmlElement, + useFromMock, +} from '@alfa-client/test-utils'; +import { + NotificationSendForTypes, + UserNotificationsTypes, + UserSettingsLinkRel, +} from '@alfa-client/user-settings-shared'; +import { EventEmitter } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { toResource } from 'libs/tech-shared/test/resource'; +import { SlideToggleComponent } from 'libs/ui/src/lib/ui/slide-toggle/slide-toggle.component'; +import { UserSettings } from 'libs/user-settings-shared/src/lib/user-settings.model'; +import { + createUserSettings, + createUserSettingsResource, +} from 'libs/user-settings-shared/test/user-settings'; +import { MockComponent } from 'ng-mocks'; +import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung.component'; + +describe('UserSettingsEmailBenachrichtigungComponent', () => { + let component: UserSettingsEmailBenachrichtigungComponent; + let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungComponent>; + + const vorgangCreatedToggle: string = getDataTestIdOf('email-benachrichtigung-neuer-Vorgang'); + const postfachNachrichtFromAntragstellerToggle: string = getDataTestIdOf( + 'email-benachrichtigung-neue-Nachricht-Antragsteller', + ); + const vorgangAssignedToUserToggle: string = getDataTestIdOf( + 'email-benachrichtigung-neuer-Vorgang-Assigned', + ); + const wiedervorlageDueTodayToggle: string = getDataTestIdOf( + 'email-benachrichtigung-Faellige-Wiedervorlage', + ); + + const valueChangedEmitter: Mock<EventEmitter<UserSettings>> = { + ...mock(EventEmitter), + emit: jest.fn(), + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + HasLinkPipe, + UserSettingsEmailBenachrichtigungComponent, + MockComponent(SlideToggleComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(UserSettingsEmailBenachrichtigungComponent); + component = fixture.componentInstance; + component.userSettings = createStateResource( + createUserSettingsResource([UserSettingsLinkRel.EDIT]), + ); + component.valueChanged = useFromMock(valueChangedEmitter); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('component', () => { + describe('isChecked', () => { + it('should return false if notificationType is not in resource', () => { + component.resourceHasKey = jest.fn().mockReturnValue(false); + + const result: boolean = component.isChecked(UserNotificationsTypes.VORGANGE_CREATED); + + expect(result).toEqual(false); + }); + + it('should return true if notificationType is true in resource', () => { + component.resourceHasKey = jest.fn().mockReturnValue(true); + component.userSettings.resource[UserNotificationsTypes.VORGANGE_CREATED] = true; + + const result: boolean = component.isChecked(UserNotificationsTypes.VORGANGE_CREATED); + + expect(result).toEqual(true); + }); + + it('should return false if notificationType is false in resource', () => { + component.resourceHasKey = jest.fn().mockReturnValue(true); + component.userSettings.resource[UserNotificationsTypes.VORGANGE_CREATED] = false; + + const result: boolean = component.isChecked(UserNotificationsTypes.VORGANGE_CREATED); + + expect(result).toEqual(false); + }); + + it('should call return true if notificationsSendFor is ALL', () => { + component.userSettings.resource[UserNotificationsTypes.NOTIFICATIONS_SEND_FOR] = + NotificationSendForTypes.ALL; + + const result: boolean = component.isChecked(UserNotificationsTypes.NOTIFICATIONS_SEND_FOR); + + expect(result).toEqual(true); + }); + + it('should call return false if notificationsSendFor is NONE', () => { + component.userSettings.resource[UserNotificationsTypes.NOTIFICATIONS_SEND_FOR] = + NotificationSendForTypes.NONE; + + const result: boolean = component.isChecked(UserNotificationsTypes.NOTIFICATIONS_SEND_FOR); + + expect(result).toEqual(false); + }); + }); + + describe('resourceHasKey', () => { + it('should return true if notificationType is in resource', () => { + component.userSettings.resource[UserNotificationsTypes.VORGANGE_CREATED] = true; + + const result: boolean = component.resourceHasKey(UserNotificationsTypes.VORGANGE_CREATED); + + expect(result).toEqual(true); + }); + + it('should return true if notificationType is in resource', () => { + delete component.userSettings.resource[UserNotificationsTypes.VORGANGE_CREATED]; + + const result: boolean = component.resourceHasKey(UserNotificationsTypes.VORGANGE_CREATED); + + expect(result).toEqual(false); + }); + }); + + describe('emitSettingsForVorgangCreated', () => { + it('should emit valueChanged with vorgangCreated and notificationsSendFor true if parameter is true', () => { + const settings = createUserSettings(false); + component.userSettings.resource = toResource(settings); + + component.emitSettingsForVorgangCreated(true); + + expect(valueChangedEmitter.emit).toBeCalledWith({ + ...settings, + [UserNotificationsTypes.VORGANGE_CREATED]: true, + [UserNotificationsTypes.NOTIFICATIONS_SEND_FOR]: NotificationSendForTypes.ALL, + }); + }); + + it('should emit valueChanged with vorgangCreated and notificationsSendFor false if parameter is false', () => { + const settings = createUserSettings(true); + component.userSettings.resource = toResource(settings); + + component.emitSettingsForVorgangCreated(false); + + expect(valueChangedEmitter.emit).toBeCalledWith({ + ...settings, + [UserNotificationsTypes.VORGANGE_CREATED]: false, + [UserNotificationsTypes.NOTIFICATIONS_SEND_FOR]: NotificationSendForTypes.NONE, + }); + }); + }); + + describe('emitSettings', () => { + it('should emit valueChanged with vorgangCreated and notificationsSendFor true if parameter is true', () => { + const settings = createUserSettings(false); + component.userSettings.resource = toResource(settings); + + component.emitSettings(UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY, true); + + expect(valueChangedEmitter.emit).toBeCalledWith({ + ...settings, + [UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY]: true, + }); + }); + + it('should emit valueChanged with vorgangCreated and notificationsSendFor false if parameter is false', () => { + const settings = createUserSettings(true); + component.userSettings.resource = toResource(settings); + + component.emitSettings(UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY, false); + + expect(valueChangedEmitter.emit).toBeCalledWith({ + ...settings, + [UserNotificationsTypes.WIEDERVORLAGE_DUE_TODAY]: false, + }); + }); + }); + }); + + describe('template', () => { + it('should not be empty if edit link in userSettings', () => { + existsAsHtmlElement(fixture, vorgangCreatedToggle); + }); + + it('should be empty if edit link not in userSettings', () => { + delete component.userSettings.resource._links[UserSettingsLinkRel.EDIT]; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, vorgangCreatedToggle); + }); + + describe('notification toggle', () => { + describe('mit Label "Neuer Vorgang im Alfa"', () => { + it('exists as HtmlElement', () => { + existsAsHtmlElement(fixture, vorgangCreatedToggle); + }); + }); + + describe('mit Label "Neue Nachricht vom Antragsteller"', () => { + it('exists as HtmlElement if corresponding key is in userSettings', () => { + existsAsHtmlElement(fixture, postfachNachrichtFromAntragstellerToggle); + }); + + it('not exists as HtmlElement if corresponding key is not in userSettings', () => { + delete component.userSettings.resource.postfachNachrichtFromAntragsteller; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, postfachNachrichtFromAntragstellerToggle); + }); + }); + + describe('mit Label "Vorgang wurde mir zugewiesen"', () => { + it('exists as HtmlElement if corresponding key is in userSettings', () => { + existsAsHtmlElement(fixture, vorgangAssignedToUserToggle); + }); + + it('not exists as HtmlElement if postfachNachrichtFromAntragsteller not in userSettings', () => { + delete component.userSettings.resource.vorgangAssignedToUser; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, vorgangAssignedToUserToggle); + }); + }); + + describe('mit Label "Fällige Wiedervorlage"', () => { + it('exists as HtmlElement if corresponding key is in userSettings', () => { + existsAsHtmlElement(fixture, wiedervorlageDueTodayToggle); + }); + + it('not exists as HtmlElement if corresponding key is not in userSettings', () => { + delete component.userSettings.resource.wiedervorlageDueToday; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, wiedervorlageDueTodayToggle); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts similarity index 55% rename from alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts rename to alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts index 7770c34f1ef8f4cdf2003b6f51803ac914598a21..d84f9782c6cb557d797f8581e68c0d42a6439b63 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.ts @@ -21,14 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { - NotificationsSendFor, + mapBooleanToNotificationSendFor, + mapNotificationSendForToBoolean, + mapUserSettingsResourceToUserSettings, + UserNotificationsTypes, UserSettings, UserSettingsLinkRel, UserSettingsResource, } from '@alfa-client/user-settings-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'alfa-user-settings-email-benachrichtigung', @@ -39,11 +42,39 @@ export class UserSettingsEmailBenachrichtigungComponent { @Input() userSettings: StateResource<UserSettingsResource> = createEmptyStateResource<UserSettingsResource>(); - @Output() valueChanged: EventEmitter<boolean> = new EventEmitter(); + @Output() valueChanged: EventEmitter<UserSettings> = new EventEmitter(); + readonly UserNotifications = UserNotificationsTypes; readonly userSettingsLinkRel = UserSettingsLinkRel; - public isChecked(userSettings: UserSettings): boolean { - return userSettings.notificationsSendFor === NotificationsSendFor.ALL; + public isChecked(notificationType: UserNotificationsTypes): boolean { + if (!this.resourceHasKey(notificationType)) { + return false; + } + + if (notificationType === UserNotificationsTypes.NOTIFICATIONS_SEND_FOR) { + return mapNotificationSendForToBoolean(this.userSettings.resource[notificationType]); + } + + return this.userSettings.resource[notificationType]; + } + + public resourceHasKey(notificationType: UserNotificationsTypes): boolean { + return this.userSettings.resource[notificationType] !== undefined; + } + + public emitSettingsForVorgangCreated(value: boolean): void { + this.valueChanged.emit({ + ...mapUserSettingsResourceToUserSettings(this.userSettings.resource), + [UserNotificationsTypes.VORGANGE_CREATED]: value, + [UserNotificationsTypes.NOTIFICATIONS_SEND_FOR]: mapBooleanToNotificationSendFor(value), + }); + } + + public emitSettings(type: UserNotificationsTypes, value: boolean): void { + this.valueChanged.emit({ + ...mapUserSettingsResourceToUserSettings(this.userSettings.resource), + [type]: value, + }); } } diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.scss b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.scss deleted file mode 100644 index 9a08a5aabce6cc4cdbb268c4190a8d67f82f19e5..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html deleted file mode 100644 index 2ba838cdb5bf7ce62c19a46dc40064719c2ede8c..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.html +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - - Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. - ---> -<ng-container *ngIf="userSettings.resource"> - <ozgcloud-slide-toggle - *ngIf="userSettings.resource | hasLink: userSettingsLinkRel.EDIT" - data-test-id="email-benachrichtigung" - label="Benachrichtigung per E-Mail" - toolTip="Benachrichtigung per E-Mail bei Eingang eines Antrags" - [checked]="isChecked(userSettings.resource)" - (valueChanged)="valueChanged.emit($event)" - > - </ozgcloud-slide-toggle> -</ng-container> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts deleted file mode 100644 index fd32e05adb6c76b0efbb232c0e0206447f164340..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component.spec.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { EventEmitter } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - createEmptyStateResource, - createStateResource, - HasLinkPipe, -} from '@alfa-client/tech-shared'; -import { - dispatchEventFromFixture, - getElementFromFixture, - Mock, - mock, - useFromMock, -} from '@alfa-client/test-utils'; -import { UserSettingsLinkRel } from '@alfa-client/user-settings-shared'; -import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; -import { SlideToggleComponent } from 'libs/ui/src/lib/ui/slide-toggle/slide-toggle.component'; -import { - NotificationsSendFor, - UserSettings, -} from 'libs/user-settings-shared/src/lib/user-settings.model'; -import { - createUserSettings, - createUserSettingsResource, -} from 'libs/user-settings-shared/test/user-settings'; -import { MockComponent } from 'ng-mocks'; -import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung.component'; - -describe('UserSettingsEmailBenachrichtigungComponent', () => { - let component: UserSettingsEmailBenachrichtigungComponent; - let fixture: ComponentFixture<UserSettingsEmailBenachrichtigungComponent>; - - const notificationSensForToggle: string = getDataTestIdOf('email-benachrichtigung'); - - const valueChangedEmitter: Mock<EventEmitter<boolean>> = { - ...mock(EventEmitter), - emit: jest.fn(), - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - HasLinkPipe, - UserSettingsEmailBenachrichtigungComponent, - MockComponent(SlideToggleComponent), - ], - }).compileComponents(); - - fixture = TestBed.createComponent(UserSettingsEmailBenachrichtigungComponent); - component = fixture.componentInstance; - component.userSettings = createEmptyStateResource(); - component.valueChanged = useFromMock(valueChangedEmitter); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('toggle', () => { - it('should be active if notificationsSendFor is ALL', () => { - const userSettings: UserSettings = { - ...createUserSettings(), - notificationsSendFor: NotificationsSendFor.ALL, - }; - - const result: boolean = component.isChecked(userSettings); - - expect(result).toBeTruthy(); - }); - - it('should be not active if notificationsSendFor is NONE', () => { - const userSettings: UserSettings = { - ...createUserSettings(), - notificationsSendFor: NotificationsSendFor.NONE, - }; - - const result: boolean = component.isChecked(userSettings); - - expect(result).toBeFalsy(); - }); - - it('should emit value if toggled', () => { - component.userSettings = createStateResource( - createUserSettingsResource([UserSettingsLinkRel.EDIT]), - ); - fixture.detectChanges(); - - dispatchEventFromFixture(fixture, notificationSensForToggle, 'valueChanged'); - - expect(component.valueChanged.emit).toHaveBeenCalled(); - }); - - it('should hide if edit link is missing', () => { - component.userSettings = createStateResource(createUserSettingsResource()); - fixture.detectChanges(); - - const element = getElementFromFixture(fixture, notificationSensForToggle); - - expect(element).not.toBeInTheDocument(); - }); - - it('should show if edit link exist', () => { - component.userSettings = createStateResource( - createUserSettingsResource([UserSettingsLinkRel.EDIT]), - ); - fixture.detectChanges(); - - const element = getElementFromFixture(fixture, notificationSensForToggle); - - expect(element).toBeInTheDocument(); - }); - }); -}); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html deleted file mode 100644 index b13bac6befba485ab93860d409d3f1b79492ebec..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.html +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - - Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - Ministerpräsidenten des Landes Schleswig-Holstein - Staatskanzlei - Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - - Lizenziert unter der EUPL, Version 1.2 oder - sobald - diese von der Europäischen Kommission genehmigt wurden - - Folgeversionen der EUPL ("Lizenz"); - Sie dürfen dieses Werk ausschließlich gemäß - dieser Lizenz nutzen. - Eine Kopie der Lizenz finden Sie hier: - - https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - - Sofern nicht durch anwendbare Rechtsvorschriften - gefordert oder in schriftlicher Form vereinbart, wird - die unter der Lizenz verbreitete Software "so wie sie - ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - ausdrücklich oder stillschweigend - verbreitet. - Die sprachspezifischen Genehmigungen und Beschränkungen - unter der Lizenz sind dem Lizenztext zu entnehmen. - ---> -<ozgcloud-icon-button-with-spinner - icon="settings" - toolTip="Einstellungen" - data-test-id="menu-button" - [matMenuTriggerFor]="matMenuTriggerFor" -></ozgcloud-icon-button-with-spinner> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss deleted file mode 100644 index b72d7213d6993a8f359da154e01d6f0154db6a54..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.scss +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -ozgcloud-icon-button-with-spinner { - display: block; -} diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts deleted file mode 100644 index f8b7705dc59130dfb436934aed1b3a225b409845..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { IconButtonWithSpinnerComponent } from '@alfa-client/ui'; -import { MockComponent } from 'ng-mocks'; -import { UserSettingsMenuButtonComponent } from './user-settings-menu-button.component'; - -describe('UserSettingsMenuButtonComponent', () => { - let component: UserSettingsMenuButtonComponent; - let fixture: ComponentFixture<UserSettingsMenuButtonComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - UserSettingsMenuButtonComponent, - MockComponent(IconButtonWithSpinnerComponent), - ], - }).compileComponents(); - - fixture = TestBed.createComponent(UserSettingsMenuButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts deleted file mode 100644 index e952c3b73d18d4ee756c56cabfc23f2a3d2cb5d5..0000000000000000000000000000000000000000 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'alfa-user-settings-menu-button', - templateUrl: './user-settings-menu-button.component.html', - styleUrls: ['./user-settings-menu-button.component.scss'], -}) -export class UserSettingsMenuButtonComponent { - @Input() matMenuTriggerFor: string; -} diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html index 23880a22fb1b6ebb371a9923d4631b2ae87a4e0c..47dd429e66112c65294868ea062488f4ff074cb6 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.html @@ -23,18 +23,10 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<alfa-user-settings-menu-button - [matMenuTriggerFor]="settingsMenu.matMenu" - data-test-id="menu-button" -></alfa-user-settings-menu-button> - -<!-- TODO Das Menu in eine eigene Componente auslagern um die Technik zu kapseln --> -<ozgcloud-menu #settingsMenu> - <div class="menu-container" (click)="$event.stopPropagation()"> - <alfa-user-settings-email-benachrichtigung-container - *ngIf="apiRoot.resource | hasLink: apiRootLinkRel.CURRENT_USER" - data-test-id="email-benachrichtigung-toggle" - ></alfa-user-settings-email-benachrichtigung-container> - <alfa-user-settings-darkmode-container></alfa-user-settings-darkmode-container> - </div> -</ozgcloud-menu> +<ods-dropdown-menu + buttonClass="p-2 rounded-full focus:outline-none focus:bg-zinc-200 hover:bg-zinc-100" + buttonTestId="user-settings-button" +> + <ods-settings-icon button-content /> + <alfa-user-settings-dropdown [apiRoot]="apiRoot" /> +</ods-dropdown-menu> diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts index 532ef326b84d75b6f720d29c825442567847ece7..917711ef1ddf31e04fea2f1aab9ed4ba7f718f38 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.spec.ts @@ -21,41 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { HasLinkPipe, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { UiModule } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ApiRootLinkRel } from '@alfa-client/api-root-shared'; -import { - HasLinkPipe, - createEmptyStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; -import { getElementFromDomRoot, getElementFromFixture } from '@alfa-client/test-utils'; -import { UiModule } from '@alfa-client/ui'; -import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; -import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { DropdownMenuComponent } from '@ods/system'; +import { SettingsIconComponent } from 'libs/design-system/src/lib/icons/settings-icon/settings-icon.component'; import { MockComponent } from 'ng-mocks'; -import { UserSettingsDarkmodeContainerComponent } from './user-settings-darkmode-container/user-settings-darkmode-container.component'; -import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; -import { UserSettingsMenuButtonComponent } from './user-settings-menu-button/user-settings-menu-button.component'; +import { UserSettingsDropdownComponent } from './user-settings-dropdown/user-settings-dropdown.component'; import { UserSettingsComponent } from './user-settings.component'; describe('UserSettingsComponent', () => { let component: UserSettingsComponent; let fixture: ComponentFixture<UserSettingsComponent>; - const menuButton: string = getDataTestIdOf('menu-button'); - const emailBenachrichtigung: string = getDataTestIdOf('email-benachrichtigung-toggle'); - beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [NoopAnimationsModule, MatButtonModule, UiModule], + imports: [NoopAnimationsModule, UiModule], declarations: [ HasLinkPipe, UserSettingsComponent, - MockComponent(UserSettingsMenuButtonComponent), - MockComponent(UserSettingsEmailBenachrichtigungContainerComponent), - MockComponent(UserSettingsDarkmodeContainerComponent), + MockComponent(SettingsIconComponent), + MockComponent(UserSettingsDropdownComponent), + MockComponent(DropdownMenuComponent), ], }).compileComponents(); @@ -68,25 +56,4 @@ describe('UserSettingsComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); - - describe('Toggle for "email benachrichtigung"', () => { - it('should show if link exists', () => { - component.apiRoot = createStateResource(createApiRootResource([ApiRootLinkRel.CURRENT_USER])); - fixture.detectChanges(); - - getElementFromFixture(fixture, menuButton).click(); - const element = getElementFromDomRoot(fixture, emailBenachrichtigung); - - expect(element).toBeInTheDocument(); - }); - - it('should hide if link not exists', () => { - component.apiRoot = createStateResource(createApiRootResource()); - - getElementFromFixture(fixture, menuButton).click(); - const element = getElementFromDomRoot(fixture, emailBenachrichtigung); - - expect(element).not.toBeInTheDocument(); - }); - }); }); diff --git a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts index 4ab02e278fe7338668f91f93a4c5d7ccf2babe8f..a64e39e691766868088384e11467a83e644e78e5 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings-container/user-settings/user-settings.component.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input } from '@angular/core'; -import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared'; +import { ApiRootResource } from '@alfa-client/api-root-shared'; import { StateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-user-settings', @@ -32,6 +32,4 @@ import { StateResource } from '@alfa-client/tech-shared'; }) export class UserSettingsComponent { @Input() apiRoot: StateResource<ApiRootResource>; - - readonly apiRootLinkRel = ApiRootLinkRel; } diff --git a/alfa-client/libs/user-settings/src/lib/user-settings.module.ts b/alfa-client/libs/user-settings/src/lib/user-settings.module.ts index ad98409aa31cae49637c31ef41cc4726ba9a39dc..9036b0a346400d296a1fa1480589dbf99d63fdb4 100644 --- a/alfa-client/libs/user-settings/src/lib/user-settings.module.ts +++ b/alfa-client/libs/user-settings/src/lib/user-settings.module.ts @@ -21,20 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; import { UiModule } from '@alfa-client/ui'; import { UserSettingsSharedModule } from '@alfa-client/user-settings-shared'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CloseIconComponent, DropdownMenuComponent } from '@ods/system'; +import { SettingsIconComponent } from '../../../design-system/src/lib/icons/settings-icon/settings-icon.component'; import { UserSettingsContainerComponent } from './user-settings-container/user-settings-container.component'; -import { UserSettingsDarkmodeContainerComponent } from './user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode-container.component'; -import { UserSettingsDarkmodeComponent } from './user-settings-container/user-settings/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component'; -import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; -import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-container/user-settings/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; -import { UserSettingsMenuButtonComponent } from './user-settings-container/user-settings/user-settings-menu-button/user-settings-menu-button.component'; +import { UserSettingsDarkmodeContainerComponent } from './user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode-container.component'; +import { UserSettingsDarkmodeComponent } from './user-settings-container/user-settings/user-settings-dropdown/user-settings-darkmode-container/user-settings-darkmode/user-settings-darkmode.component'; +import { UserSettingsDropdownComponent } from './user-settings-container/user-settings/user-settings-dropdown/user-settings-dropdown.component'; +import { UserSettingsEmailBenachrichtigungContainerComponent } from './user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung-container.component'; +import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-container/user-settings/user-settings-dropdown/user-settings-email-benachrichtigung-container/user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component'; import { UserSettingsComponent } from './user-settings-container/user-settings/user-settings.component'; @NgModule({ - imports: [CommonModule, UiModule, UserSettingsSharedModule], + imports: [ + CommonModule, + UiModule, + UserSettingsSharedModule, + DropdownMenuComponent, + CloseIconComponent, + SettingsIconComponent, + ], declarations: [ UserSettingsContainerComponent, UserSettingsEmailBenachrichtigungComponent, @@ -42,8 +51,13 @@ import { UserSettingsComponent } from './user-settings-container/user-settings/u UserSettingsComponent, UserSettingsDarkmodeContainerComponent, UserSettingsEmailBenachrichtigungContainerComponent, - UserSettingsMenuButtonComponent, + UserSettingsDropdownComponent, + ], + exports: [ + UserSettingsContainerComponent, + UserSettingsEmailBenachrichtigungComponent, + UserSettingsDarkmodeContainerComponent, + UserSettingsEmailBenachrichtigungContainerComponent, ], - exports: [UserSettingsContainerComponent, UserSettingsEmailBenachrichtigungComponent], }) export class UserSettingsModule {}