diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html index 672cb8f71c1d5426b777273eb7d3f2d12239b6b4..6fa4cdf5e5fc0d882439227f2f56a42c4a9bd426 100644 --- a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html +++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html @@ -1,6 +1,6 @@ @if (configurationStateResource.resource | hasLink: configurationLinkRel.SETTING) { <ods-nav-item data-test-id="postfach-navigation" caption="Postfach" path="/postfach"> - <ods-icon icon name="mailbox" fill="text" /> + <ods-icon icon name="mail" fill="text" /> </ods-nav-item> } @if (configurationStateResource.resource | hasLink: configurationLinkRel.AGGREGATION_MAPPINGS) { diff --git a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html index 724611322e3e1981be20759e047c75d528b3bdbf..14969fcd27aa025339218f897d1b910a33859c67 100644 --- a/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-list-container/user-list/user/user-data/user-data.component.html @@ -2,7 +2,7 @@ <div *ngIf="user.email" class="flex items-center gap-2"> <dt> <span class="sr-only">E-Mail:</span> - <ods-icon name="mailbox" size="small" class="fill-gray-600" /> + <ods-icon name="mail" size="small" class="fill-gray-600" /> </dt> <dd data-test-class="email">{{ user.email }}</dd> </div> diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts index e3190c7e52079ffe86a516ab9996eca556da6bf0..c54347c8602b2938404b3c95a5579770d32cd9c1 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts @@ -196,7 +196,7 @@ describe('BescheidService', () => { it('should reload postfach list', () => { service.exit(); - expect(postfachService._setPostfachMailOnReload).toHaveBeenCalled(); + expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); }); it('should clear uploaded files', () => { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index 18e048dcf2802f7c39cd6ee5b5b172a44af7a448..ebc1fabf474900bd73059787b26fc641353a7f72 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -113,7 +113,7 @@ export class BescheidService { public exit(): void { this.bescheidListResourceService.refresh(); - this.postfachService._setPostfachMailOnReload(); + this.postfachService.setPostfachMailOnReload(); this._clearUploadedFiles(); } diff --git a/alfa-client/libs/design-system/src/assets/mail-unread.svg b/alfa-client/libs/design-system/src/assets/mail-unread.svg new file mode 100644 index 0000000000000000000000000000000000000000..d70254f7274d6950356771f1b6c7ce4cdaf23d3c --- /dev/null +++ b/alfa-client/libs/design-system/src/assets/mail-unread.svg @@ -0,0 +1,4 @@ +<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <path + d="M4 20C3.45 20 2.97917 19.8042 2.5875 19.4125C2.19583 19.0208 2 18.55 2 18V6C2 5.45 2.19583 4.97917 2.5875 4.5875C2.97917 4.19583 3.45 4 4 4H14.1C14.0333 4.33333 14 4.66667 14 5C14 5.33333 14.0333 5.66667 14.1 6H4L12 11L15.65 8.725C15.8833 8.94167 16.1375 9.12917 16.4125 9.2875C16.6875 9.44583 16.975 9.58333 17.275 9.7L12 13L4 8V18H20V9.9C20.3833 9.81667 20.7417 9.7 21.075 9.55C21.4083 9.4 21.7167 9.21667 22 9V18C22 18.55 21.8042 19.0208 21.4125 19.4125C21.0208 19.8042 20.55 20 20 20H4ZM19 8C18.1667 8 17.4583 7.70833 16.875 7.125C16.2917 6.54167 16 5.83333 16 5C16 4.16667 16.2917 3.45833 16.875 2.875C17.4583 2.29167 18.1667 2 19 2C19.8333 2 20.5417 2.29167 21.125 2.875C21.7083 3.45833 22 4.16667 22 5C22 5.83333 21.7083 6.54167 21.125 7.125C20.5417 7.70833 19.8333 8 19 8Z" /> +</svg> \ No newline at end of file diff --git a/alfa-client/libs/design-system/src/assets/mailbox.svg b/alfa-client/libs/design-system/src/assets/mail.svg similarity index 100% rename from alfa-client/libs/design-system/src/assets/mailbox.svg rename to alfa-client/libs/design-system/src/assets/mail.svg diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index be39753a4ea4f3b00c1605b96a33fce8ff5b5fe1..fb40b55e1d1daca4a38beb748c4ae2e3828589e4 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -47,6 +47,7 @@ export * from './lib/forwarding-item/forwarding-item.component'; export * from './lib/icon/icon.component'; export * from './lib/icons/file-icon/file-icon.component'; export * from './lib/icons/iconVariants'; +export * from './lib/icons/mail-icon/mail-icon.component'; export * from './lib/icons/spinner-icon/spinner-icon.component'; export * from './lib/instant-search/instant-search/instant-search.component'; export * from './lib/instant-search/instant-search/instant-search.model'; diff --git a/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts b/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts index 9dca7ffa6b29759768a9f714bce77f411d2069b3..d20e0938dd7ca7bf20c770fb1244cd0410bfffc2 100644 --- a/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts +++ b/alfa-client/libs/design-system/src/lib/icon/icon.stories.ts @@ -68,7 +68,7 @@ const ICONS_LIST: string[] = [ 'help', 'info', 'logout', - 'mailbox', + 'mail', 'more', 'office', 'open-link', @@ -97,7 +97,7 @@ type Story = StoryObj<IconComponent>; export const Default: Story = { args: { - name: 'mailbox', + name: 'mail', size: 'extra-large', fill: 'primary', class: '', diff --git a/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..31c0239ddf6992b6eb516bcb6e6820874da0f159 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MailIconComponent } from './mail-icon.component'; + +describe('MailIconComponent', () => { + let component: MailIconComponent; + let fixture: ComponentFixture<MailIconComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MailIconComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(MailIconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..9637fa49a5b1bcf44b3448f7ac22ea86d8a3c65b --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.component.ts @@ -0,0 +1,46 @@ +import { NgClass } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { twMerge } from 'tailwind-merge'; +import { IconVariants, iconVariants } from '../iconVariants'; + +@Component({ + selector: 'ods-mail-icon', + standalone: true, + imports: [NgClass], + template: ` <div class="relative inline-block"> + <svg + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + [ngClass]="twMerge(iconVariants({ size }), 'stroke-text', class)" + > + <path + d="M20 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V6C22 4.89543 21.1046 4 20 4Z" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M22 7L13.03 12.7C12.7213 12.8934 12.3643 12.996 12 12.996C11.6357 12.996 11.2787 12.8934 10.97 12.7L2 7" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + /> + </svg> + @if (withBadge) { + <div + [ngClass]="twMerge('absolute right-0.5 top-1 h-2.5 w-2.5 -translate-y-1/2 translate-x-1/2 rounded-full', badgeClass)" + data-test-class="mail-icon-badge" + ></div> + } + </div>`, +}) +export class MailIconComponent { + @Input() size: IconVariants['size'] = 'medium'; + @Input() class: string = undefined; + @Input() withBadge: boolean = false; + @Input() badgeClass: string = 'bg-primary'; + + readonly iconVariants = iconVariants; + readonly twMerge = twMerge; +} diff --git a/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fe25c255e0edd123a7f14c47898b6a43085a3b1 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/icons/mail-icon/mail-icon.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/angular'; + +import { MailIconComponent } from './mail-icon.component'; + +const meta: Meta<MailIconComponent> = { + title: 'Icons/Mail icon', + component: MailIconComponent, + excludeStories: /.*Data$/, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj<MailIconComponent>; + +export const Default: Story = { + args: { size: 'medium' }, + argTypes: { + size: { + control: 'select', + options: ['small', 'medium', 'large', 'extra-large', 'full'], + description: 'Size of icon. Property "full" means 100%', + table: { + defaultValue: { summary: 'medium' }, + }, + }, + }, +}; diff --git a/alfa-client/libs/navigation-shared/src/lib/navigation.service.spec.ts b/alfa-client/libs/navigation-shared/src/lib/navigation.service.spec.ts index 2dfb53b8b701d62064bc186796bcb2ec4edfacb8..d24cf96c299b8542c54e1daab9a9089c44b38e95 100644 --- a/alfa-client/libs/navigation-shared/src/lib/navigation.service.spec.ts +++ b/alfa-client/libs/navigation-shared/src/lib/navigation.service.spec.ts @@ -243,32 +243,6 @@ describe('NavigationService', () => { }); }); - describe('is postfach page', () => { - it('should return true if "postfach" exists in url', () => { - service.routeUrlSegment$.next(<any>[{ path: 'postfach' }]); - - const isPostfachPage: boolean = service.isPostfachPage(); - - expect(isPostfachPage).toBeTruthy(); - }); - - it('should return false if "postfach" not exists in url', () => { - service.routeUrlSegment$.next(<any>[{ path: 'something else' }]); - - const isPostfachPage: boolean = service.isPostfachPage(); - - expect(isPostfachPage).toBeFalsy(); - }); - - it('should return false if routeUrl is empty', () => { - service.routeUrlSegment$.next(<any>[]); - - const isPostfachPage: boolean = service.isPostfachPage(); - - expect(isPostfachPage).toBeFalsy(); - }); - }); - describe('navigate', () => { const navigationRoute: string = 'dummyNavigationRoute'; diff --git a/alfa-client/libs/navigation-shared/src/lib/navigation.service.ts b/alfa-client/libs/navigation-shared/src/lib/navigation.service.ts index 7b1c65e93ef278fb0fd09c73a5fcb5403ab5ea36..ecbcbbfd012cae62a49da0077a9325312fbf3067 100644 --- a/alfa-client/libs/navigation-shared/src/lib/navigation.service.ts +++ b/alfa-client/libs/navigation-shared/src/lib/navigation.service.ts @@ -232,13 +232,6 @@ export class NavigationService { ]); } - public isPostfachPage(): boolean { - const postfachUrlSegement: UrlSegment = this.routeUrlSegment$.value.find((urlSegment) => - urlSegment.path.includes('postfach'), - ); - return isNotNil(postfachUrlSegement); - } - public getCurrentRouteData(): Observable<RouteData> { return this.facade.getCurrentRouteData(); } diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.linkrel.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.linkrel.ts index 5860f9c51f3eab5fa1f6132a74890b74faac7a7f..8617b6bab78053fe6e186c151b298ba25dafed97 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.linkrel.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.linkrel.ts @@ -26,6 +26,7 @@ export enum PostfachMailListLinkRel { SEND_POSTFACH_MAIL = 'sendPostfachMail', UPLOAD_ATTACHMENT = 'uploadAttachment', RESET_HAS_NEW_POSTFACH_NACHRICHT = 'resetHasNewPostfachNachricht', + SET_HAS_NEW_POSTFACH_NACHRICHT = 'setHasNewPostfachNachricht', } export enum PostfachMailLinkRel { diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.repository.spec.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.repository.spec.ts index 19dc4a384e2a936b2230b38914c40e85ee5c7377..377719bb0187815df301380b394fd0e924df684f 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.repository.spec.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.repository.spec.ts @@ -84,10 +84,29 @@ describe('PostfachRepository', () => { it('should call resourceWrapper with link', () => { repository.resetHasNewPostfachNachrichten(postfachMailListResource); - expect(resourceWrapper.put).toHaveBeenCalledWith( - PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, - { hasNewPostfachNachricht: false }, - ); + expect(resourceWrapper.put).toHaveBeenCalledWith(PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, { + hasNewPostfachNachricht: false, + }); + }); + }); + + describe('markPostfachAsUnread', () => { + const postfachMailListResource: PostfachMailListResource = createPostfachMailListResource([ + PostfachMailListLinkRel.SET_HAS_NEW_POSTFACH_NACHRICHT, + ]); + + it('should call resourceFactory with resource', () => { + repository.markPostfachAsUnread(postfachMailListResource); + + expect(resourceFactory.from).toHaveBeenCalledWith(postfachMailListResource); + }); + + it('should call resourceWrapper with link', () => { + repository.markPostfachAsUnread(postfachMailListResource); + + expect(resourceWrapper.put).toHaveBeenCalledWith(PostfachMailListLinkRel.SET_HAS_NEW_POSTFACH_NACHRICHT, { + hasNewPostfachNachricht: true, + }); }); }); }); diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.repository.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.repository.ts index b56f7e1a51b3942c53a45264c1c546fc29cfc057..8a8b03f3d3e046197489b035ef6071b8026178cd 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.repository.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.repository.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Injectable } from '@angular/core'; import { VorgangHeaderLinkRel, VorgangResource } from '@alfa-client/vorgang-shared'; +import { Injectable } from '@angular/core'; import { ResourceFactory } from '@ngxp/rest'; import { Observable } from 'rxjs'; import { PostfachMailListLinkRel } from './postfach.linkrel'; @@ -36,13 +36,15 @@ export class PostfachRepository { return this.resourceFactory.from(vorgang).get(VorgangHeaderLinkRel.POSTFACH_MAILS); } - public resetHasNewPostfachNachrichten( - postfachNachrichtenList: PostfachMailListResource, - ): Observable<unknown> { - return this.resourceFactory - .from(postfachNachrichtenList) - .put(PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, { - hasNewPostfachNachricht: false, - }); + public resetHasNewPostfachNachrichten(postfachNachrichtenList: PostfachMailListResource): Observable<unknown> { + return this.resourceFactory.from(postfachNachrichtenList).put(PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, { + hasNewPostfachNachricht: false, + }); + } + + public markPostfachAsUnread(postfachNachrichtenList: PostfachMailListResource): Observable<unknown> { + return this.resourceFactory.from(postfachNachrichtenList).put(PostfachMailListLinkRel.SET_HAS_NEW_POSTFACH_NACHRICHT, { + hasNewPostfachNachricht: true, + }); } } diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts index 5c12de2fd83f0627efe61ab7dd04681173fba0a3..f56688a6e9631052cc6ae12b4b1a173e8e1eda30 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts @@ -23,20 +23,29 @@ */ import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandResource, CommandService } from '@alfa-client/command-shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { NavigationFacade, NavigationService, RouteData } from '@alfa-client/navigation-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + createStateResource, + StateResource, +} from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; -import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { VORGANG_WITH_EINGANG_ROUTE_PARAM, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { TestBed } from '@angular/core/testing'; import { MatDialog } from '@angular/material/dialog'; -import { expect } from '@jest/globals'; +import { faker } from '@faker-js/faker'; +import { beforeEach, expect } from '@jest/globals'; import { getUrl } from '@ngxp/rest'; +import { hot } from 'jest-marbles'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandErrorResource, createCommandResource } from 'libs/command-shared/test/command'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { singleColdCompleted } from '../../../tech-shared/test/marbles'; +import { createProblemDetail } from '../../../tech-shared/test/error'; +import { multipleCold, singleColdCompleted, singleHot } from '../../../tech-shared/test/marbles'; import { createPostfachFeatures, createPostfachMail, @@ -63,6 +72,7 @@ describe('PostfachService', () => { const dialog: Mock<MatDialog> = <Mock<MatDialog>>{ closeAll: jest.fn() }; const postfachFacade: Mock<PostfachFacade> = mock(PostfachFacade); const binaryFileService: Mock<BinaryFileService> = mock(BinaryFileService); + const navigationFacade = mock(NavigationFacade); const urlChangedParams = {}; @@ -72,6 +82,7 @@ describe('PostfachService', () => { beforeEach(() => { vorgangService = { ...mock(VorgangService), + getVorgangWithEingang: jest.fn().mockReturnValue(of(vorgangWithEingangStateResource)), selectVorgangWithEingang: jest.fn().mockReturnValue(of(vorgangWithEingangStateResource)), }; navigationService.urlChanged = jest.fn(); @@ -89,6 +100,7 @@ describe('PostfachService', () => { { provide: PostfachFacade, useValue: postfachFacade }, { provide: BinaryFileService, useValue: binaryFileService }, { provide: PostfachRepository, useValue: repository }, + { provide: NavigationFacade, useValue: navigationFacade }, PostfachService, ], }); @@ -348,27 +360,6 @@ describe('PostfachService', () => { expect(service.postfachMailList$.value.reload).toEqual(true); }); }); - - describe('to postfach page', () => { - beforeEach(() => { - service._resetHasNewPostfachNachrichten = jest.fn(); - navigationService.isPostfachPage.mockReturnValue(true); - }); - - it('should call navigationService', () => { - service._onNavigation({}); - - expect(navigationService.isPostfachPage).toHaveBeenCalled(); - }); - - it('should reset hasNewPostfachNachrichten', () => { - navigationService.isPostfachPage.mockReturnValue(true); - - service._onNavigation({}); - - expect(service._resetHasNewPostfachNachrichten).toHaveBeenCalled(); - }); - }); }); describe('getPendingSendPostfachMailCommand', () => { @@ -387,56 +378,125 @@ describe('PostfachService', () => { }); }); + describe('getPostfachNachrichtListAsRead', () => { + const state: StateResource<PostfachMailListResource> = createStateResource(createPostfachMailListResource()); + const stateAfterReset: StateResource<PostfachMailListResource> = createStateResource(createPostfachMailListResource()); + + beforeEach(() => { + service.getPostfachMailListByVorgang = jest.fn().mockReturnValue(of(state)); + service._resetHasNewPostfachNachrichten = jest.fn().mockReturnValue(of(stateAfterReset)); + }); + + it('should get postfach nachrichten list', () => { + service.getPostfachNachrichtListAsRead().subscribe(); + + expect(service.getPostfachMailListByVorgang).toHaveBeenCalled(); + }); + + it('should call service resetHasNewPostfachNachrichten', () => { + service.getPostfachNachrichtListAsRead().subscribe(); + + expect(service._resetHasNewPostfachNachrichten).toHaveBeenCalled(); + }); + + it('should have return with loading', () => { + service.getPostfachMailListByVorgang = jest.fn().mockReturnValue(singleHot(state)); + service._resetHasNewPostfachNachrichten = jest.fn().mockReturnValue(hot('-a', { a: stateAfterReset })); + + const result = service.getPostfachNachrichtListAsRead(); + + expect(result).toBeObservable(multipleCold(createEmptyStateResource(true), stateAfterReset)); + }); + }); + describe('resetHasNewPostfachNachrichten', () => { - const postfachListNachrichtenResource: PostfachMailListResource = createPostfachMailListResource(); + const stateWithoutLink: StateResource<PostfachMailListResource> = createStateResource(createPostfachMailListResource()); + const stateWithLink: StateResource<PostfachMailListResource> = createStateResource( + createPostfachMailListResource([PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT]), + ); - it('should call doResetHasNewPostfachNachrichten', () => { - service.getPostfachMailListByVorgang = jest.fn(); - service._doResetHasNewPostfachNachrichten = jest.fn(); - (<any>service.getPostfachMailListByVorgang).mockReturnValue(of(postfachListNachrichtenResource)); + beforeEach(() => { + service._loadAfterResetHasNewPostfachNachrichten = jest.fn().mockReturnValue(of(createEmptyStateResource(true))); + }); - service._resetHasNewPostfachNachrichten(); + it('should call loadAfterResetHasNewPostfachNachrichten if link', () => { + service._resetHasNewPostfachNachrichten(stateWithLink).subscribe(); - expect(service._doResetHasNewPostfachNachrichten).toHaveBeenCalled(); + expect(service._loadAfterResetHasNewPostfachNachrichten).toHaveBeenCalledWith(stateWithLink.resource); + }); + + it('should return loading state if link', () => { + const result: Observable<StateResource<PostfachMailListResource>> = service._resetHasNewPostfachNachrichten(stateWithLink); + + expect(result).toBeObservable(singleColdCompleted(createLoadingStateResource<PostfachMailListResource>())); + }); + + it('should return state if no link', () => { + const result: Observable<StateResource<PostfachMailListResource>> = + service._resetHasNewPostfachNachrichten(stateWithoutLink); + + expect(result).toBeObservable(singleColdCompleted(stateWithoutLink)); }); }); - describe('doResetHasNewPostfachNachrichten', () => { - describe('on existing link', () => { - const postfachNachrichtenListResource: PostfachMailListResource = createPostfachMailListResource([ - PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT, - ]); + describe('loadAfterResetHasNewPostfachNachrichten', () => { + const postfachMailListResource: PostfachMailListResource = createPostfachMailListResource(); - beforeEach(() => { - service.postfachMailList$.next(createStateResource(postfachNachrichtenListResource)); - repository.resetHasNewPostfachNachrichten.mockReturnValue(of(postfachNachrichtenListResource)); - }); + beforeEach(() => { + service._loadPostfachMailList = jest.fn(); + repository.resetHasNewPostfachNachrichten = jest.fn().mockReturnValue(of({})); + }); - it('should call repository if link exists', () => { - service._doResetHasNewPostfachNachrichten(); + it('should call repository resetHasNewPostfachNachrichten', () => { + service._loadAfterResetHasNewPostfachNachrichten(postfachMailListResource); - expect(repository.resetHasNewPostfachNachrichten).toHaveBeenCalledWith(postfachNachrichtenListResource); - }); + expect(repository.resetHasNewPostfachNachrichten).toHaveBeenCalledWith(postfachMailListResource); }); - it('should NOT call repository if link not exists', () => { - const postfachNachrichtenListResource: PostfachMailListResource = createPostfachMailListResource(); - service.postfachMailList$.next(createStateResource(postfachNachrichtenListResource)); + it('should load postfach mail list', () => { + service._loadAfterResetHasNewPostfachNachrichten(postfachMailListResource); - service._doResetHasNewPostfachNachrichten(); + expect(service._loadPostfachMailList).toHaveBeenCalled(); + }); + }); + + describe('setPostfachNachrichtListAsUnread', () => { + beforeEach(() => { + service._navigateToCurrentVorgang = jest.fn(); + repository.markPostfachAsUnread = jest.fn().mockReturnValue(of(null)); + }); + + it('should mark postfach as unread', () => { + service.setPostfachNachrichtListAsUnread(); - expect(repository.resetHasNewPostfachNachrichten).not.toHaveBeenCalled(); + expect(repository.markPostfachAsUnread).toHaveBeenCalled(); + }); + + it('should navigate to vorgang', () => { + service.setPostfachNachrichtListAsUnread(); + + expect(service._navigateToCurrentVorgang).toHaveBeenCalled(); }); }); - describe('getPostfachMailListByVorgang', () => { - const postfachMailList: PostfachMailListResource = createPostfachMailListResource(); + describe('navigateToCurrentVorgang', () => { + it('should navigate to current vorgang', () => { + const vorgangId: string = faker.string.uuid(); + const routeData: RouteData = { + urlSegments: [], + queryParameter: { [VORGANG_WITH_EINGANG_ROUTE_PARAM]: vorgangId }, + }; + navigationFacade.getCurrentRouteData.mockReturnValue(of(routeData)); + service._navigateToCurrentVorgang(); + + expect(navigationService.navigateToVorgang).toHaveBeenCalledWith(vorgangId); + }); + }); + + describe('getPostfachMailListByVorgang', () => { beforeEach(() => { - repository.loadPostfachMailList.mockReturnValue(of(postfachMailList)); - service._setPostfachMailListLoading = jest.fn(); - service._setPostfachMailList = jest.fn(); - vorgangService.getVorgangWithEingang.mockReturnValue(of(createStateResource(createVorgangWithEingangResource()))); + service._loadPostfachMailList = jest.fn(); service.postfachMailList$.next(createEmptyStateResource()); service._refreshVorgangSubscription = jest.fn(); }); @@ -447,28 +507,64 @@ describe('PostfachService', () => { expect(service._refreshVorgangSubscription).toHaveBeenCalled(); }); - it('should set loading to true', () => { + it('should call service loadPostfachMailList', () => { service.getPostfachMailListByVorgang(); + expect(service._loadPostfachMailList).toHaveBeenCalled(); + }); + }); + + describe('loadPostfachMailList', () => { + beforeEach(() => { + service._setPostfachMailListLoading = jest.fn(); + service._handleVorgangError = jest.fn(); + service.loadPostfachMailsByVorgang = jest.fn(); + }); + + it('should set loading to true', () => { + service._loadPostfachMailList(); + expect(service._setPostfachMailListLoading).toHaveBeenCalled(); }); it('should call vorgang service', () => { - service.getPostfachMailListByVorgang(); + service._loadPostfachMailList(); expect(vorgangService.getVorgangWithEingang).toHaveBeenCalled(); }); - it('should call repository', () => { - service.getPostfachMailListByVorgang().subscribe(); + it('should handle vorgang error', () => { + service._loadPostfachMailList(); - expect(repository.loadPostfachMailList).toHaveBeenCalled(); + expect(service._handleVorgangError).toHaveBeenCalledWith(vorgangWithEingangStateResource); }); - it('should set loading to false', () => { - service.getPostfachMailListByVorgang(); + it('should call loadPostfachMailsByVorgang', () => { + service._loadPostfachMailList(); - expect(service._setPostfachMailList).toHaveBeenCalled(); + expect(service.loadPostfachMailsByVorgang).toHaveBeenCalledWith(vorgang); + }); + }); + + describe('handleVorgangError', () => { + beforeEach(() => { + service.postfachMailList$.next = jest.fn(); + }); + + it('should set error', () => { + const errorState: StateResource<VorgangWithEingangResource> = createErrorStateResource(createProblemDetail()); + + service._handleVorgangError(errorState); + + expect(service.postfachMailList$.next).toHaveBeenCalledWith(errorState); + }); + + it('should not set if there is no error', () => { + const errorState: StateResource<VorgangWithEingangResource> = createStateResource(vorgang); + + service._handleVorgangError(errorState); + + expect(service.postfachMailList$.next).not.toHaveBeenCalled(); }); }); @@ -502,8 +598,6 @@ describe('PostfachService', () => { }); describe('isDownloadPdfInProgress', () => { - const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource(); - it('should call facade to download pdf', (done) => { vorgangService.getVorgangWithEingang.mockReturnValue(of(createStateResource(vorgang))); postfachFacade.isDownloadPdfInProgress.mockReturnValue(of(true)); @@ -615,7 +709,7 @@ describe('PostfachService', () => { describe('on setted reload flag', () => { beforeEach(() => { - service._setPostfachMailOnReload = jest.fn(); + service.setPostfachMailOnReload = jest.fn(); service.shouldReload = true; }); @@ -623,7 +717,7 @@ describe('PostfachService', () => { it('should call set kommentar list reload', () => { service._handleVorgangChange(vorgangWithEingangStateResource); - expect(service._setPostfachMailOnReload).toHaveBeenCalled(); + expect(service.setPostfachMailOnReload).toHaveBeenCalled(); }); it('and loaded vorgang resource should call set kommentar list reload', () => { diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts index a5dbb53f46bae1c4865d7801284fd7cf6eafb406..3abb5760ccdbb06cbd42c744e27f5b63f396d763 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts @@ -32,9 +32,11 @@ import { isPending, tapOnCommandSuccessfullyDone, } from '@alfa-client/command-shared'; -import { NavigationService } from '@alfa-client/navigation-shared'; +import { NavigationFacade, NavigationService, RouteData } from '@alfa-client/navigation-shared'; import { createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, createStateResource, doIfLoadingRequired, isLoaded, @@ -43,14 +45,14 @@ import { StateResource, } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; -import { VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { getVorgangParam, VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { inject, Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Params } from '@angular/router'; import { getUrl, hasLink, Resource } from '@ngxp/rest'; import { isNil, isNull } from 'lodash-es'; -import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; -import { first, map, take, tap } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, filter, Observable, of, startWith, Subscription } from 'rxjs'; +import { first, map, switchMap, take, tap } from 'rxjs/operators'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; import { PostfachMessages } from './postfach.message'; @@ -75,6 +77,7 @@ export class PostfachService { private readonly dialog = inject(MatDialog); private readonly postfachFacade = inject(PostfachFacade); private readonly binaryFileService = inject(BinaryFileService); + private readonly navigationFacade = inject(NavigationFacade); postfachMailList$: BehaviorSubject<StateResource<PostfachMailListResource>> = new BehaviorSubject< StateResource<PostfachMailListResource> @@ -87,8 +90,6 @@ export class PostfachService { private sendPostfachMailSubscription: Subscription; private loadPostfachMailSubscription: Subscription; private vorgangSubscription: Subscription; - private postfachNachrichtenListSubscription: Subscription; - private vorgangChangeSubscription: Subscription; shouldReload: boolean = false; @@ -187,10 +188,7 @@ export class PostfachService { this._unsubscribe(); } if (NavigationService.isVorgangDetailPage(params, VorgangService.VORGANG_WITH_EINGANG_URL)) { - this._setPostfachMailOnReload(); - } - if (this.navigationService.isPostfachPage()) { - this._resetHasNewPostfachNachrichten(); + this.setPostfachMailOnReload(); } } @@ -213,25 +211,10 @@ export class PostfachService { if (isNotUndefined(this.vorgangSubscription)) this.vorgangSubscription.unsubscribe(); } - _setPostfachMailOnReload(): void { + public setPostfachMailOnReload(): void { this.postfachMailList$.next({ ...this.postfachMailList$.value, reload: true }); } - _resetHasNewPostfachNachrichten(): void { - this.postfachNachrichtenListSubscription = this.getPostfachMailListByVorgang().subscribe((postfachNachrichtenList) => { - if (isNotNull(postfachNachrichtenList.resource)) { - setTimeout(() => this.postfachNachrichtenListSubscription.unsubscribe(), 0); - this._doResetHasNewPostfachNachrichten(); - } - }); - } - - _doResetHasNewPostfachNachrichten(): void { - if (hasLink(this.postfachMailList$.value.resource, PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT)) { - this.repository.resetHasNewPostfachNachrichten(this.postfachMailList$.value.resource).pipe(take(1)).subscribe(); - } - } - _pollSendPostfachMailCommand(command: StateResource<CommandResource>): StateResource<CommandResource> { if (this.shouldPoll(command)) { this._setPollingTrue(); @@ -273,6 +256,57 @@ export class PostfachService { return this.commandService.getEffectedResource<PostfachMailListResource>(updatedStateResource.resource); } + public getPostfachNachrichtListAsRead(): Observable<StateResource<PostfachMailListResource>> { + return this.getPostfachMailListByVorgang().pipe( + switchMap((postfachMailList: StateResource<PostfachMailListResource>) => { + return this._resetHasNewPostfachNachrichten(postfachMailList); + }), + startWith(createLoadingStateResource<PostfachMailListResource>()), + ); + } + + _resetHasNewPostfachNachrichten( + postfachMailList: StateResource<PostfachMailListResource>, + ): Observable<StateResource<PostfachMailListResource>> { + if ( + isLoaded(postfachMailList) && + hasLink(postfachMailList.resource, PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT) + ) { + this._loadAfterResetHasNewPostfachNachrichten(postfachMailList.resource); + return of(createLoadingStateResource<PostfachMailListResource>()); + } + + return of(postfachMailList); + } + + _loadAfterResetHasNewPostfachNachrichten(postfachMailListResource: PostfachMailListResource): void { + this.repository + .resetHasNewPostfachNachrichten(postfachMailListResource) + .pipe( + take(1), + tap(() => this._loadPostfachMailList()), + ) + .subscribe(); + } + + public setPostfachNachrichtListAsUnread() { + this.repository + .markPostfachAsUnread(this.postfachMailList$.value.resource) + .pipe(take(1)) + .subscribe(() => { + this._navigateToCurrentVorgang(); + }); + } + + _navigateToCurrentVorgang() { + this.navigationFacade + .getCurrentRouteData() + .pipe(take(1)) + .subscribe((currentRoute: RouteData) => { + this.navigationService.navigateToVorgang(getVorgangParam(currentRoute)); + }); + } + public getPostfachMailListByGivenVorgang(vorgang: VorgangResource): Observable<StateResource<PostfachMailListResource>> { doIfLoadingRequired(this.postfachMailList$.value, () => { this._setPostfachMailListLoading(); @@ -284,17 +318,29 @@ export class PostfachService { public getPostfachMailListByVorgang(): Observable<StateResource<PostfachMailListResource>> { this._refreshVorgangSubscription(); doIfLoadingRequired(this.postfachMailList$.value, () => { - this._setPostfachMailListLoading(); - this.vorgangSubscription = this.vorgangService.getVorgangWithEingang().subscribe((vorgangWithEingangStateResource) => { - if (vorgangWithEingangStateResource.resource) { - this.loadPostfachMailsByVorgang(vorgangWithEingangStateResource.resource); - setTimeout(() => this.vorgangSubscription.unsubscribe(), 0); - } - }); + this._loadPostfachMailList(); }); return this.postfachMailList$.asObservable(); } + _loadPostfachMailList(): void { + this._setPostfachMailListLoading(); + this.vorgangService + .getVorgangWithEingang() + .pipe( + tap((state: StateResource<VorgangWithEingangResource>) => this._handleVorgangError(state)), + filter(isLoaded), + take(1), + ) + .subscribe((vorgangWithEingangStateResource) => { + this.loadPostfachMailsByVorgang(vorgangWithEingangStateResource.resource); + }); + } + + _handleVorgangError(state: StateResource<VorgangWithEingangResource>): void { + if (state.error) this.postfachMailList$.next(createErrorStateResource(state.error)); + } + _refreshVorgangSubscription(): void { this.vorgangChangeSubscription.unsubscribe(); this._listenToVorgangChange(); @@ -313,7 +359,7 @@ export class PostfachService { this.shouldReload = true; } if (isLoaded(vorgangWithEingangStateResource) && this.shouldReload) { - this._setPostfachMailOnReload(); + this.setPostfachMailOnReload(); this.shouldReload = false; } } @@ -330,12 +376,15 @@ export class PostfachService { } public loadPostfachMailsByVorgang(vorgang: VorgangResource): void { - this.loadPostfachMailSubscription = this.repository.loadPostfachMailList(vorgang).subscribe((postfachMaiList) => { - if (!isNull(postfachMaiList)) { - this._setPostfachMailList(postfachMaiList); - setTimeout(() => this.loadPostfachMailSubscription.unsubscribe(), 0); - } - }); + this.loadPostfachMailSubscription = this.repository + .loadPostfachMailList(vorgang) + .pipe() + .subscribe((postfachMaiList) => { + if (!isNull(postfachMaiList)) { + this._setPostfachMailList(postfachMaiList); + setTimeout(() => this.loadPostfachMailSubscription.unsubscribe(), 0); + } + }); } _setPostfachMailList(postfachMailList: PostfachMailListResource): void { @@ -358,17 +407,21 @@ export class PostfachService { } public getFeatures(): Observable<PostfachFeatures> { - return this.getPostfachMailListByVorgang().pipe( + return this.selectPostfachMailList().pipe( map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.features), ); } public getSettings(): Observable<PostfachSettings> { - return this.getPostfachMailListByVorgang().pipe( + return this.selectPostfachMailList().pipe( map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.settings), ); } + private selectPostfachMailList(): Observable<StateResource<PostfachMailListResource>> { + return this.postfachMailList$.asObservable(); + } + public clearUploadedFiles(): void { this.binaryFileService.clearUploadedFiles(POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS); } diff --git a/alfa-client/libs/postfach-shared/test/postfach.ts b/alfa-client/libs/postfach-shared/test/postfach.ts index 831f9b7eeafd5401719b392b56d1a79b2c0cb212..8f5abd0ae423b823545323039f6cda385250ee9d 100644 --- a/alfa-client/libs/postfach-shared/test/postfach.ts +++ b/alfa-client/libs/postfach-shared/test/postfach.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { createStateResource } from '@alfa-client/tech-shared'; import { faker } from '@faker-js/faker'; import { Resource } from '@ngxp/rest'; +import { createStateResource } from 'libs/tech-shared/src/lib/resource/resource.util'; import { toResource } from 'libs/tech-shared/test/resource'; import { times } from 'lodash-es'; import { PostfachMailListLinkRel } from '../src/lib/postfach.linkrel'; diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component.html index f525e2f08ca97387663e4094106905a746a2b00c..6ee0bc07b437a2a9f42839e231344857ea34fd70 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component.html @@ -34,7 +34,7 @@ size="fit" (clickEmitter)="openPostfachNachrichtenDialog.emit()" > - <ods-icon icon name="mailbox" fill="text" /> + <ods-icon icon name="mail" fill="text" /> </ods-button> } @if (!showAsIconButton && text && !toolTip) { diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts index 62804bcc27411f45fac774d32995f4267b2162f7..f2b47f34a70349440a1b12df07830044472fc724 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts @@ -82,7 +82,7 @@ describe('PostfachMailListContainerComponent', () => { describe('reloadPostfachMailListOnVorgangReload', () => { beforeEach(() => { - postfachService._setPostfachMailOnReload.mockClear(); + postfachService.setPostfachMailOnReload.mockClear(); }); it('should call postfachService', () => { @@ -93,7 +93,7 @@ describe('PostfachMailListContainerComponent', () => { component.reloadPostfachMailListOnVorgangReload(); - expect(postfachService._setPostfachMailOnReload).toHaveBeenCalled(); + expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); }); it('should not call postfachService', () => { @@ -104,7 +104,7 @@ describe('PostfachMailListContainerComponent', () => { component.reloadPostfachMailListOnVorgangReload(); - expect(postfachService._setPostfachMailOnReload).not.toHaveBeenCalled(); + expect(postfachService.setPostfachMailOnReload).not.toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts index 14c858585f1b747ec7175b1d717c13f23e44d547..01ff00262cb79ad94583901f9384514cb24b58e3 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts @@ -51,7 +51,7 @@ export class PostfachMailListContainerComponent implements OnChanges { reloadPostfachMailListOnVorgangReload(): void { if (this.vorgangStateResource.reload) { - this.postfachService._setPostfachMailOnReload(); + this.postfachService.setPostfachMailOnReload(); } } } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.html index 44d553b95fc0e784b4d66bcd22287e9700325f8a..7f825d014b00f9a3c132641946a8645f5a2817eb 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.html @@ -24,43 +24,40 @@ --> <div class="nachrichten-header"> - <h3 class="nachrichten">Nachrichten</h3> - <alfa-postfach-mail-pdf-button-container - [postfachMailListResource]="postfachMailListStateResource.resource" - ></alfa-postfach-mail-pdf-button-container> - <ng-container *ngIf="postfachMailListStateResource.resource | hasLink: postfachMailListLinkRel.SEND_POSTFACH_MAIL"> + <div class="flex gap-2"> + <h3 class="nachrichten">Nachrichten</h3> + <ods-mail-icon [withBadge]="vorgangStateResource.resource.hasNewPostfachNachricht" data-test-id="postfach-mail-list-mail-icon"/> + </div> + + <alfa-postfach-mail-pdf-button-container [postfachMailListResource]="postfachMailListStateResource.resource" /> + + @if(postfachMailListStateResource.resource | hasLink: postfachMailListLinkRel.SEND_POSTFACH_MAIL){ <alfa-postfach-mail-button-container toolTip="Neue Nachricht erstellen" tooltipAriaType="aria-labelledby" [vorgang]="vorgangStateResource.resource" data-test-id="postfach-mail-button-container-no-label" - ></alfa-postfach-mail-button-container> - </ng-container> + /> + } </div> <ozgcloud-spinner [stateResource]="postfachMailListStateResource"> - <alfa-postfach-mail - *ngFor=" - let postfachMail of postfachMailListStateResource.resource | toEmbeddedResources: postfachMailListLinkRel.POSTFACH_MAIL_LIST - " - class="postfach" - [vorgangStateResource]="vorgangStateResource" - [postfachMail]="postfachMail" - [attr.data-test-id]="(postfachMail.subject | convertForDataTest) + '-item'" - > - </alfa-postfach-mail> + @for (postfachMail of postfachMailListStateResource.resource | toEmbeddedResources: postfachMailListLinkRel.POSTFACH_MAIL_LIST; track $index){ + <alfa-postfach-mail + class="postfach" + [vorgangStateResource]="vorgangStateResource" + [postfachMail]="postfachMail" + [attr.data-test-id]="(postfachMail.subject | convertForDataTest) + '-item'" + /> + } </ozgcloud-spinner> -<ng-container - *ngIf="postfachMailListStateResource.resource | hasLink: postfachMailListLinkRel.SEND_POSTFACH_MAIL; else noPostfach" -> +@if(postfachMailListStateResource.resource | hasLink: postfachMailListLinkRel.SEND_POSTFACH_MAIL){ <alfa-postfach-mail-button-container text="Nachricht" [vorgang]="vorgangStateResource.resource" data-test-id="postfach-mail-button-container" - ></alfa-postfach-mail-button-container> -</ng-container> - -<ng-template #noPostfach> + /> +} @else { <span class="no-postfach-text" data-test-id="no-postfach-text">Dieser Vorgang ist nicht mit einem Postfach verknüpft.</span> -</ng-template> +} \ No newline at end of file diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.spec.ts index bad2ceb1eaf216b0611dc18a2211c7b33635a9d5..90dae1fb628b03822ecb60f62fcbd237cbe87c9e 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.spec.ts @@ -21,7 +21,6 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PostfachMailListLinkRel } from '@alfa-client/postfach-shared'; import { ConvertForDataTestPipe, @@ -30,9 +29,11 @@ import { ToEmbeddedResourcesPipe, createStateResource, } from '@alfa-client/tech-shared'; -import { getElementFromFixture, getMockComponent } from '@alfa-client/test-utils'; +import { getElementFromFixture, getElementFromFixtureByType, getMockComponent } from '@alfa-client/test-utils'; import { ExpansionPanelComponent, SpinnerComponent } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MailIconComponent } from '@ods/system'; import { createPostfachMailListResource } from 'libs/postfach-shared/test/postfach'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; @@ -49,9 +50,7 @@ describe('PostfachMailListComponent', () => { const postfachMailButton: string = getDataTestIdOf('postfach-mail-button-container'); const noPostfachText: string = getDataTestIdOf('no-postfach-text'); - const vorgangStateResource: StateResource<VorgangWithEingangResource> = createStateResource( - createVorgangWithEingangResource(), - ); + const vorgangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(createVorgangWithEingangResource()); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -65,6 +64,7 @@ describe('PostfachMailListComponent', () => { MockComponent(SpinnerComponent), MockComponent(PostfachMailButtonContainerComponent), MockComponent(PostfachMailPdfButtonContainerComponent), + MockComponent(MailIconComponent), ], }).compileComponents(); }); @@ -105,9 +105,7 @@ describe('PostfachMailListComponent', () => { describe('postfach does not exists', () => { beforeEach(() => { - component.postfachMailListStateResource = createStateResource( - createPostfachMailListResource(), - ); + component.postfachMailListStateResource = createStateResource(createPostfachMailListResource()); fixture.detectChanges(); }); @@ -126,12 +124,20 @@ describe('PostfachMailListComponent', () => { describe('postfachMail component', () => { it('should have been called with vorgangStateResource', () => { - const postfachMailComponent: PostfachMailComponent = getMockComponent( - fixture, - PostfachMailComponent, - ); + const postfachMailComponent: PostfachMailComponent = getMockComponent(fixture, PostfachMailComponent); expect(postfachMailComponent.vorgangStateResource).toBe(vorgangStateResource); }); }); + + describe('mail icon', () => { + it('should exist', () => { + component.vorgangStateResource.resource.hasNewPostfachNachricht = false; + + fixture.detectChanges(); + + const mailIcon: MailIconComponent = getElementFromFixtureByType(fixture, MailIconComponent); + expect(mailIcon.withBadge).toEqual(false); + }); + }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.ts index db1b3add68978493e2e5f260ff89487e7c0e17a5..6304cd5aff53376be02b5d00fe55138cfc2bdae0 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail-list.component.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input } from '@angular/core'; import { PostfachMailListLinkRel, PostfachMailListResource } from '@alfa-client/postfach-shared'; import { StateResource } from '@alfa-client/tech-shared'; -import { VorgangHeaderLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-postfach-mail-list', @@ -36,5 +36,4 @@ export class PostfachMailListComponent { @Input() vorgangStateResource: StateResource<VorgangWithEingangResource>; readonly postfachMailListLinkRel = PostfachMailListLinkRel; - readonly vorgangHeaderLinkRel = VorgangHeaderLinkRel; } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component.ts index 4a331e57b3392b3d487422157f6ff6b9e9aae3a5..f8624c082e8b229ac790ae52f002fa86cf198f43 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; import { Component, Input, OnInit } from '@angular/core'; -import { PostfachMailResource, PostfachService } from '@alfa-client/postfach-shared'; import { Observable } from 'rxjs'; @Component({ @@ -31,7 +31,7 @@ import { Observable } from 'rxjs'; styleUrls: ['./postfach-mail-pdf-button-container.component.scss'], }) export class PostfachMailPdfButtonContainerComponent implements OnInit { - @Input() postfachMailListResource: PostfachMailResource; + @Input() postfachMailListResource: PostfachMailListResource; @Input() showButtonWithLabel: boolean = false; isDownloadPdfInProgress$: Observable<boolean>; diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.spec.ts index 23bf41d68cf6fa7c41631dd8c338853376659a63..85fc756effd11c86758f97cd19d88e7d527f1ae0 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-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 { PostfachService } from '@alfa-client/postfach-shared'; import { mock } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; import { PostfachPageContainerComponent } from './postfach-page-container.component'; import { PostfachPageComponent } from './postfach-page/postfach-page.component'; @@ -60,7 +60,7 @@ describe('PostfachPageContainerComponent', () => { it('should call postfach service', () => { component.ngOnInit(); - expect(postfachService.getPostfachMailListByVorgang).toHaveBeenCalled(); + expect(postfachService.getPostfachNachrichtListAsRead).toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.ts index 8c7b0a372bc23ad82d10b7dd43d3e01076b90876..5b62696989e5fe48edbb585ef69723422e5508bc 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page-container.component.ts @@ -21,9 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, OnInit } from '@angular/core'; import { ON_PAGE, PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; import { StateResource } from '@alfa-client/tech-shared'; +import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ @@ -38,6 +38,6 @@ export class PostfachPageContainerComponent implements OnInit { constructor(private postfachService: PostfachService) {} ngOnInit() { - this.postfachMailListStateResource$ = this.postfachService.getPostfachMailListByVorgang(); + this.postfachMailListStateResource$ = this.postfachService.getPostfachNachrichtListAsRead(); } } diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.html b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0f3c1dfebf9d600a18d6cfa18e18cb776989e8be --- /dev/null +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.html @@ -0,0 +1,26 @@ +@if (postfachMailListResource | hasLink: PostfachMailListLinkRel.SET_HAS_NEW_POSTFACH_NACHRICHT) { + @if (showAsIconButton) { + <ods-button + (clickEmitter)="markMailAsUnread()" + [tooltip]="'Nachrichten als ungelesen markieren'" + tooltipAriaType="aria-labelledby" + variant="ghost" + size="fit" + dataTestId="mail-unread-icon-button-link" + data-test-id="mail-unread-icon-button-link-host" + > + <ods-icon icon name="mail-unread" fill="text" /> + </ods-button> + } @else { + <ods-button + (clickEmitter)="markMailAsUnread()" + [tooltip]="'Nachrichten als ungelesen markieren'" + text="Als ungelesen markieren" + variant="outline" + dataTestId="mail-unread-button-link" + data-test-id="mail-unread-button-link-host" + > + <ods-icon icon name="mail-unread" /> + </ods-button> + } +} diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1a73a9c136fc608eaaa6e9152820c835fc67e9c --- /dev/null +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.spec.ts @@ -0,0 +1,142 @@ +import { PostfachMailListLinkRel, PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + dispatchEventFromFixture, + existsAsHtmlElement, + mock, + Mock, + MockEvent, + notExistsAsHtmlElement, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonComponent, IconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createPostfachMailListResource } from '../../../../../../postfach-shared/test/postfach'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { MailUnreadButtonLinkContainerComponent } from './mail-unread-button-link-container.component'; + +describe('MailUnreadButtonLinkContainerComponent', () => { + let component: MailUnreadButtonLinkContainerComponent; + let fixture: ComponentFixture<MailUnreadButtonLinkContainerComponent>; + + let postfachService: Mock<PostfachService>; + + const postfachMailListResource: PostfachMailListResource = createPostfachMailListResource([ + PostfachMailListLinkRel.SET_HAS_NEW_POSTFACH_NACHRICHT, + ]); + + const button: string = getDataTestIdOf('mail-unread-button-link-host'); + const iconButton: string = getDataTestIdOf('mail-unread-icon-button-link-host'); + + beforeEach(async () => { + postfachService = mock(PostfachService); + + await TestBed.configureTestingModule({ + imports: [MailUnreadButtonLinkContainerComponent, HasLinkPipe], + declarations: [MockComponent(ButtonComponent), MockComponent(IconComponent)], + providers: [ + { + provide: PostfachService, + useValue: postfachService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(MailUnreadButtonLinkContainerComponent); + component = fixture.componentInstance; + component.postfachMailListResource = postfachMailListResource; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('component', () => { + describe('mark mail as unread', () => { + it('should call set postfach nachrichten as unread', () => { + component.markMailAsUnread(); + + expect(postfachService.setPostfachNachrichtListAsUnread).toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + it('no button should exist', () => {}); + + describe('icon button', () => { + it('should exist', () => { + component.showAsIconButton = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, iconButton); + }); + + it('should not exist if link does not exist', () => { + component.showAsIconButton = true; + component.postfachMailListResource = createPostfachMailListResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, iconButton); + }); + + it('should not exist if not shown as icon button', () => { + component.showAsIconButton = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, iconButton); + }); + + it('should call markMailAsUnread on click', () => { + component.showAsIconButton = true; + component.markMailAsUnread = jest.fn(); + + fixture.detectChanges(); + dispatchEventFromFixture(fixture, iconButton, MockEvent.CLICK); + + expect(component.markMailAsUnread).toHaveBeenCalled(); + }); + }); + }); + + describe('button', () => { + it('should exist', () => { + component.showAsIconButton = false; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, button); + }); + + it('should not exist if link does not exist', () => { + component.showAsIconButton = false; + component.postfachMailListResource = createPostfachMailListResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, button); + }); + + it('should not exist if shown as icon button', () => { + component.showAsIconButton = true; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, button); + }); + + it('should call markMailAsUnread on click', () => { + component.showAsIconButton = false; + component.markMailAsUnread = jest.fn(); + + fixture.detectChanges(); + dispatchEventFromFixture(fixture, button, MockEvent.CLICK); + + expect(component.markMailAsUnread).toHaveBeenCalled(); + }); + }); +}); diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..16c39db732329e490e84055fd9bb94d64a06352d --- /dev/null +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component.ts @@ -0,0 +1,27 @@ +import { CommandResource } from '@alfa-client/command-shared'; +import { PostfachMailListLinkRel, PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; +import { createEmptyStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { Component, inject, Input } from '@angular/core'; +import { ButtonComponent, IconComponent, TooltipDirective } from '@ods/system'; +import { Observable, of } from 'rxjs'; + +@Component({ + selector: 'alfa-mail-unread-button-link-container', + standalone: true, + imports: [HasLinkPipe, IconComponent, TooltipDirective, ButtonComponent], + templateUrl: './mail-unread-button-link-container.component.html', +}) +export class MailUnreadButtonLinkContainerComponent { + private readonly postfachService = inject(PostfachService); + + @Input() postfachMailListResource: PostfachMailListResource; + @Input() showAsIconButton: boolean = false; + + commandStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + protected readonly PostfachMailListLinkRel = PostfachMailListLinkRel; + + public markMailAsUnread() { + this.postfachService.setPostfachNachrichtListAsUnread(); + } +} diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html index 9d74f0c569922238813f128c9def3394b701e647..e6ab2f9717f81043221c63057b214b3f6d175f46 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html @@ -23,20 +23,28 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<ozgcloud-spinner *ngIf="postfachMailListStateResource"> - <alfa-postfach-mail - *ngFor=" - let postfachMail of postfachMailListStateResource.resource | toEmbeddedResources: postfachMailListLinkRel.POSTFACH_MAIL_LIST - " - [attr.data-test-id]="(postfachMail.subject | convertForDataTest) + '-item'" - class="postfach w-full lg:w-1/2" - [postfachMail]="postfachMail" - > - </alfa-postfach-mail> +<ozgcloud-spinner [stateResource]="postfachMailListStateResource"> + @if (postfachMailListStateResource.resource) { + <div data-test-id="postfach-page-mail-list"> + @for ( + postfachMail of postfachMailListStateResource.resource | toEmbeddedResources: postfachMailListLinkRel.POSTFACH_MAIL_LIST; + track $index + ) { + <alfa-postfach-mail + [attr.data-test-id]="(postfachMail.subject | convertForDataTest) + '-item'" + class="postfach w-full lg:w-1/2" + [postfachMail]="postfachMail" + /> + } - <alfa-postfach-mail-pdf-button-container - [showButtonWithLabel]="true" - [postfachMailListResource]="postfachMailListStateResource.resource" - > - </alfa-postfach-mail-pdf-button-container> + <div class="mb-4 ml-6 mt-4 flex gap-4"> + <alfa-postfach-mail-pdf-button-container + [postfachMailListResource]="postfachMailListStateResource.resource" + [showButtonWithLabel]="true" + /> + + <alfa-mail-unread-button-link-container [postfachMailListResource]="postfachMailListStateResource.resource" /> + </div> + </div> + } </ozgcloud-spinner> diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss index 0c338513b8477a7bb670284fea1d50c4ddce82fe..1773ac885eb06b92037aaba2a89d961714f25cb3 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss @@ -65,8 +65,3 @@ } } } - -alfa-postfach-mail-pdf-button-container { - display: block; - margin: 16px 24px; -} diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.spec.ts index c5cb09bbcddf5ecc5518db78714d4854b3418a69..fc2527033ffe69e2059f4d5c0ef29c6bd483788c 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.spec.ts @@ -21,22 +21,31 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PostfachMailListResource } from '@alfa-client/postfach-shared'; import { ConvertForDataTestPipe, + createEmptyStateResource, + createStateResource, HasLinkPipe, ToEmbeddedResourcesPipe, } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils'; import { SpinnerComponent } from '@alfa-client/ui'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; +import { createPostfachMailListResource } from '../../../../../../postfach-shared/test/postfach'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; import { PostfachMailComponent } from '../../../postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail.component'; import { PostfachMailPdfButtonContainerComponent } from '../../../postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component'; +import { MailUnreadButtonLinkContainerComponent } from '../mail-unread-button/mail-unread-button-link-container.component'; import { PostfachPageMailListComponent } from './postfach-page-mail-list.component'; describe('PostfachPageMailListComponent', () => { let component: PostfachPageMailListComponent; let fixture: ComponentFixture<PostfachPageMailListComponent>; + const mailList: string = getDataTestIdOf('postfach-page-mail-list'); + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ @@ -47,6 +56,7 @@ describe('PostfachPageMailListComponent', () => { MockComponent(PostfachMailComponent), MockComponent(SpinnerComponent), MockComponent(PostfachMailPdfButtonContainerComponent), + MockComponent(MailUnreadButtonLinkContainerComponent), ], }).compileComponents(); }); @@ -54,10 +64,29 @@ describe('PostfachPageMailListComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PostfachPageMailListComponent); component = fixture.componentInstance; + component.postfachMailListStateResource = createStateResource<PostfachMailListResource>(createPostfachMailListResource()); fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + + describe('mail list', () => { + it('should exist if resource', () => { + component.postfachMailListStateResource = createStateResource<PostfachMailListResource>(createPostfachMailListResource()); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, mailList); + }); + + it('should not exist if no resource', () => { + component.postfachMailListStateResource = createEmptyStateResource<PostfachMailListResource>(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, mailList); + }); + }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html index 57a7c39bdf82f2009c40741ffcf82935202fbcf4..5b3a6128d731837cef2d40158f1e6534f670604d 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html @@ -24,15 +24,16 @@ --> <ozgcloud-subnavigation class="mat-typography mat-app-background"> - <ozgcloud-back-button linkTo="../" label="zurück zur Detailseite"></ozgcloud-back-button> + <ozgcloud-back-button linkTo="../" label="zurück zur Detailseite" /> + <alfa-mail-unread-button-link-container + [postfachMailListResource]="postfachMailListStateResource.resource" + showAsIconButton="true" + /> </ozgcloud-subnavigation> <div class="l-scroll-area--full flex flex-col"> - <h1 data-test-id="postfach-mail-heading" class="pl-7 pt-4 text-lg font-medium"> - Nachrichten zum Vorgang - </h1> + <h1 data-test-id="postfach-mail-heading" class="pl-7 pt-4 text-lg font-medium">Nachrichten zum Vorgang</h1> <alfa-postfach-page-mail-list [postfachMailListStateResource]="postfachMailListStateResource" - data-test-id="postfach-mail-list" - ></alfa-postfach-page-mail-list> + /> </div> diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts index 81e5ddd9f869f75cd2a90e3fa860e75c10f5f113..c2e2ee46a53ffe3510568c15ebf445cb58417778 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts @@ -21,10 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { createStateResource } from '@alfa-client/tech-shared'; import { BackButtonComponent, SubnavigationComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; import { MockComponent } from 'ng-mocks'; +import { createPostfachMailListResource } from '../../../../../postfach-shared/test/postfach'; +import { MailUnreadButtonLinkContainerComponent } from './mail-unread-button/mail-unread-button-link-container.component'; import { PostfachPageMailListComponent } from './postfach-page-mail-list/postfach-page-mail-list.component'; import { PostfachPageComponent } from './postfach-page.component'; @@ -40,6 +43,7 @@ describe('PostfachPageComponent', () => { MockComponent(BackButtonComponent), MockComponent(SubnavigationComponent), MockComponent(PostfachPageMailListComponent), + MockComponent(MailUnreadButtonLinkContainerComponent), ], }).compileComponents(); }); @@ -47,6 +51,7 @@ describe('PostfachPageComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PostfachPageComponent); component = fixture.componentInstance; + component.postfachMailListStateResource = createStateResource(createPostfachMailListResource()); fixture.detectChanges(); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach.module.ts b/alfa-client/libs/postfach/src/lib/postfach.module.ts index a57c2ce81047016799a2d29da42e81c962850bd3..87dc40897d9418e5fff554a59299272580d5e605 100644 --- a/alfa-client/libs/postfach/src/lib/postfach.module.ts +++ b/alfa-client/libs/postfach/src/lib/postfach.module.ts @@ -42,7 +42,7 @@ import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatIcon } from '@angular/material/icon'; import { RouterModule, Routes } from '@angular/router'; -import { ButtonComponent, IconComponent, TooltipDirective } from '@ods/system'; +import { ButtonComponent, IconComponent, MailIconComponent, TooltipDirective } from '@ods/system'; import { MultiFileUploadComponent } from '../../../binary-file/src/lib/multi-file-upload/multi-file-upload.component'; import { PostfachMailButtonContainerComponent } from './postfach-mail-button-container/postfach-mail-button-container.component'; import { PostfachMailButtonComponent } from './postfach-mail-button-container/postfach-mail-button/postfach-mail-button.component'; @@ -60,6 +60,7 @@ import { PostfachMailComponent } from './postfach-mail-list-container/postfach-m import { PostfachMailPdfButtonContainerComponent } from './postfach-mail-pdf-button-container/postfach-mail-pdf-button-container.component'; import { PostfachMailPdfButtonComponent } from './postfach-mail-pdf-button-container/postfach-mail-pdf-button/postfach-mail-pdf-button.component'; import { PostfachPageContainerComponent } from './postfach-page-container/postfach-page-container.component'; +import { MailUnreadButtonLinkContainerComponent } from './postfach-page-container/postfach-page/mail-unread-button/mail-unread-button-link-container.component'; import { PostfachPageMailListComponent } from './postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component'; import { PostfachPageComponent } from './postfach-page-container/postfach-page/postfach-page.component'; @@ -98,6 +99,8 @@ const routes: Routes = [ IconComponent, TooltipDirective, MultiFileUploadComponent, + MailUnreadButtonLinkContainerComponent, + MailIconComponent, ], declarations: [ PostfachMailListContainerComponent, diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts index 053d9eb1c84a2b396d86b45fbf8908b4790f76a9..31e236a31c13420adf23b3b391b2ef6a3a09e3ab 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts @@ -231,6 +231,10 @@ function hasVorgangParam(routeData: RouteData): boolean { return isNotNull(routeData.queryParameter[VORGANG_WITH_EINGANG_ROUTE_PARAM]); } +export function getVorgangParam(routeData: RouteData): string { + return routeData.queryParameter[VORGANG_WITH_EINGANG_ROUTE_PARAM]; +} + function hasSegements(routeData: RouteData, numberOfSegements: number): boolean { return routeData.urlSegments.length === numberOfSegements; }