diff --git a/goofy-client/libs/tech-shared/src/lib/error/error.util.ts b/goofy-client/libs/tech-shared/src/lib/error/error.util.ts index 4b2d137096ec8fb1a7dad559d62cef7f54d8c99f..903fda393fea2b976ad40d6a6a365015e353c1d9 100644 --- a/goofy-client/libs/tech-shared/src/lib/error/error.util.ts +++ b/goofy-client/libs/tech-shared/src/lib/error/error.util.ts @@ -1,3 +1,4 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { ApiError, MessageCode } from '@goofy-client/tech-shared'; import { isNil } from 'lodash-es'; @@ -7,4 +8,8 @@ export function isApiError(value: any): boolean { export function isServiceUnavailableMessageCode(error: ApiError): boolean { return error.issues[0].messageCode == MessageCode.SERVICE_UNAVAILABLE; +} + +export function getApiErrorFromHttpErrorResponse(httpErrorResponse: HttpErrorResponse): ApiError { + return httpErrorResponse?.error?.error; } \ No newline at end of file diff --git a/goofy-client/libs/tech-shared/test/error.ts b/goofy-client/libs/tech-shared/test/error.ts index 3205a1a61e418468636d6930aeb4780070435ab6..216da5aa424236a75f97aa28756b2562c4d39d8f 100644 --- a/goofy-client/libs/tech-shared/test/error.ts +++ b/goofy-client/libs/tech-shared/test/error.ts @@ -1,3 +1,4 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { faker } from '@faker-js/faker'; import { ApiError, Issue, IssueParam } from '../src/lib/tech.model'; @@ -26,4 +27,12 @@ export function createApiError(): ApiError { //TODO typisieren -> wirkt sich entsprechend auf die actions und den reducer/state aus export function createError(): unknown { return {}; -} \ No newline at end of file +} + +export function createHttpErrorResponse(apiError: ApiError = null): HttpErrorResponse { + return <HttpErrorResponse>{ + error: { + error: apiError ?? createApiError() + } + }; +} diff --git a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.actions.ts b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.actions.ts index 943c904788224ca805828199234e50a3e4923c79..457226be6675a6ab8a4c9ae0a2d47109b7a99994 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.actions.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.actions.ts @@ -1,3 +1,4 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { ApiRootResource } from '@goofy-client/api-root-shared'; import { ApiError } from '@goofy-client/tech-shared'; import { ActionCreator, createAction, props } from '@ngrx/store'; @@ -24,6 +25,9 @@ export interface ApiRootAction { export interface ApiErrorAction { apiError: ApiError } +export interface HttpErrorAction { + httpErrorResponse: HttpErrorResponse +} export interface VorgangListAction { vorgangList: VorgangListResource @@ -34,6 +38,7 @@ export const noOperation: TypedActionCreator = createAction('[Vorgang-Routing] N export const loadVorgangList: VorgangActionCreator<ApiRootAction> = createAction('[Vorgang] Load VorgangList', props<ApiRootAction>()); export const searchVorgaengeBy: VorgangActionCreator<SearchVorgaengeByProps> = createAction('[Vorgang] Search VorgangList', props<SearchVorgaengeByProps>()); export const searchVorgaengeBySuccess: VorgangActionCreator<VorgangListAction> = createAction('[Vorgang] Search VorgangList Success', props<VorgangListAction>()); +export const searchVorgaengeByFailure: VorgangActionCreator<HttpErrorAction> = createAction('[Vorgang] Search VorgangList Failure', props<HttpErrorAction>()); export const loadMyVorgaengeList: VorgangActionCreator<ApiRootAction> = createAction('[Vorgang] Load MyVorgaengList', props<ApiRootAction>()); export const loadVorgangListSuccess: VorgangActionCreator<VorgangListAction> = createAction('[Vorgang] Load VorgangList Success', props<VorgangListAction>()); @@ -44,6 +49,6 @@ export const loadNextPageSuccess: VorgangActionCreator<VorgangListAction> = crea export const searchForPreview: VorgangActionCreator<StringBasedProps> = createAction('[Vorgang] Search for preview', props<StringBasedProps>()); export const searchForPreviewSuccess: VorgangActionCreator<VorgangListAction> = createAction('[Vorgang] Search for preview Success', props<VorgangListAction>()); -export const searchForPreviewFailure: VorgangActionCreator<ApiErrorAction> = createAction('[Vorgang] Search for preview Failure', props<ApiErrorAction>()); +export const searchForPreviewFailure: VorgangActionCreator<HttpErrorAction> = createAction('[Vorgang] Search for preview Failure', props<HttpErrorAction>()); export const clearSearchPreviewList: TypedActionCreator = createAction('[Vorgang] Clear Search preview'); \ No newline at end of file diff --git a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.spec.ts b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.spec.ts index df3d8ba4cd22716a357be93bca5fe36f48bf07eb..fde4f3688ad7abdcbd16bb69cb577a3d55bb3a01 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.spec.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.spec.ts @@ -1,15 +1,17 @@ +import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { ApiRootFacade, ApiRootLinkRel, ApiRootResource } from '@goofy-client/api-root-shared'; import { NavigationFacade } from '@goofy-client/navigation-shared'; import { ApiError, createStateResource } from '@goofy-client/tech-shared'; import { mock } from '@goofy-client/test-utils'; +import { SnackBarService } from '@goofy-client/ui'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { NxModule } from '@nrwl/angular'; import { cold, hot } from 'jest-marbles'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; -import { createApiError } from 'libs/tech-shared/test/error'; +import { createApiError, createHttpErrorResponse } from 'libs/tech-shared/test/error'; import { createVorgangListResource } from 'libs/vorgang-shared/test/vorgang'; import { Observable, of } from 'rxjs'; import { createRouteData } from '../../../../navigation-shared/test/navigation-test-factory'; @@ -27,6 +29,7 @@ describe('VorgangEffects', () => { const apiRootFacade = mock(ApiRootFacade); const vorgangRepository = mock(VorgangRepository); const navigationFacade = mock(NavigationFacade); + const snackbarService = mock(SnackBarService); const vorgangList: VorgangListResource = createVorgangListResource(); @@ -48,6 +51,10 @@ describe('VorgangEffects', () => { { provide: NavigationFacade, useValue: navigationFacade + }, + { + provide: SnackBarService, + useValue: snackbarService } ] }); @@ -119,13 +126,12 @@ describe('VorgangEffects', () => { expect(effects.searchVorgaengeBy$).toBeObservable(expected); }) - it('should dispatch loadVorgangListFailure action', () => { - const apiError: ApiError = createApiError() - const error = { error: { error: apiError } }; + it('should dispatch searchVorgaengeByFailure action', () => { + const error: HttpErrorResponse = createHttpErrorResponse(); const errorResponse = cold('-#', {}, error); vorgangRepository.searchVorgaengeBy = jest.fn(() => errorResponse); - const expected = cold('--b', { b: VorgangActions.loadVorgangListFailure({ apiError }) }); + const expected = cold('--b', { b: VorgangActions.searchVorgaengeByFailure({ httpErrorResponse: error }) }); actions = hot('-a', { a: action }); expect(effects.searchVorgaengeBy$).toBeObservable(expected); @@ -189,7 +195,7 @@ describe('VorgangEffects', () => { expect(vorgangRepository.getNextVorgangListPage).toHaveBeenCalledWith(vorgangList); }) - it('should dispatch loadVorgangListSuccess action', () => { + it('should dispatch loadNextPageSuccess action', () => { vorgangRepository.getNextVorgangListPage.mockReturnValue(of(vorgangList)); actions = hot('-a-|', { a: action }); @@ -258,15 +264,44 @@ describe('VorgangEffects', () => { }) it('should dispatch searchForPreviewFailure action', () => { - const apiError: ApiError = createApiError() - const error = { error: { error: apiError } }; + const error: HttpErrorResponse = createHttpErrorResponse(); const errorResponse = cold('-#', {}, error); vorgangRepository.searchVorgaengeBy = jest.fn(() => errorResponse); - const expected = cold('--c', { c: VorgangActions.searchForPreviewFailure({ apiError }) }); + const expected = cold('--c', { c: VorgangActions.searchForPreviewFailure({ httpErrorResponse: error }) }); actions = hot('-a', { a: action }); expect(effects.searchForPreview$).toBeObservable(expected); }) }) + + describe('search error', () => { + const action = VorgangActions.searchForPreviewFailure({ httpErrorResponse: null }); + const error: HttpErrorResponse = createHttpErrorResponse(); + + it('should trigger showSearchError$', () => { + actions = of(action); + effects.showSearchError = jest.fn(); + + effects.showSearchError$.subscribe(); + + expect(effects.showSearchError).toHaveBeenCalled(); + }) + + it('should call snackbarService.showError if HTTP status code is NOT 503 ', () => { + error.error.status = HttpStatusCode.ExpectationFailed; + + effects.showSearchError(error); + + expect(snackbarService.showError).not.toHaveBeenCalled(); + }) + + it('should call snackbarService.showError if HTTP status code is 503 ', () => { + error.error.status = HttpStatusCode.ServiceUnavailable; + + effects.showSearchError(error); + + expect(snackbarService.showError).toHaveBeenCalled(); + }) + }) }); \ No newline at end of file diff --git a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.ts b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.ts index 899ee49b85c033d0ad671895483e6d739765a697..ca2f9eff00a5d448e85d42cd9a71bf5789e022c7 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.effects.ts @@ -1,15 +1,18 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiRootFacade } from '@goofy-client/api-root-shared'; import { NavigationFacade } from '@goofy-client/navigation-shared'; -import { ApiError } from '@goofy-client/tech-shared'; +import { getApiErrorFromHttpErrorResponse, isServiceUnavailable } from '@goofy-client/tech-shared'; +import { SnackBarService } from '@goofy-client/ui'; import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { of } from 'rxjs'; import { catchError, map, switchMap } from 'rxjs/operators'; import { getSearchLinkRel } from '../vorgang-navigation.util'; +import { VorgangMessages } from '../vorgang.messages'; import { VorgangRepository } from '../vorgang.repository'; import * as VorgangActions from './vorgang.actions'; -import { ApiRootAction, SearchVorgaengeByProps } from './vorgang.actions'; +import { ApiRootAction, HttpErrorAction, SearchVorgaengeByProps } from './vorgang.actions'; import * as VorgangSelectors from './vorgang.selectors'; @Injectable() @@ -19,14 +22,14 @@ export class VorgangEffects { static readonly SEARCH_QUERY_PARAM: string = 'search'; static readonly MY_VORGAENGE_URI_SEGMENT: string = 'myVorgaenge'; - constructor(private readonly actions$: Actions, private store: Store, private repository: VorgangRepository, private apiRootFacade: ApiRootFacade, private navigationFacade: NavigationFacade) { } + constructor(private readonly actions$: Actions, private store: Store, private repository: VorgangRepository, private apiRootFacade: ApiRootFacade, private navigationFacade: NavigationFacade, private snackbarService: SnackBarService) { } loadVorgangList$ = createEffect(() => this.actions$.pipe( ofType(VorgangActions.loadVorgangList), switchMap((action: ApiRootAction) => this.repository.loadVorgangList(action.apiRoot).pipe( map(loadedVorgangList => VorgangActions.loadVorgangListSuccess({ vorgangList: loadedVorgangList })), - catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: this.getApiErrorFromHttpError(error) }))) + catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: getApiErrorFromHttpErrorResponse(error) }))) )) ) ) @@ -36,7 +39,7 @@ export class VorgangEffects { ofType(VorgangActions.searchVorgaengeBy), switchMap((action: SearchVorgaengeByProps) => this.repository.searchVorgaengeBy(action.apiRoot, action.searchString, action.linkRel).pipe( map(loadedVorgangList => VorgangActions.searchVorgaengeBySuccess({ vorgangList: loadedVorgangList })), - catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: this.getApiErrorFromHttpError(error) }))) + catchError(error => of(VorgangActions.searchVorgaengeByFailure({ httpErrorResponse: error }))) )) ) ) @@ -46,7 +49,7 @@ export class VorgangEffects { ofType(VorgangActions.loadMyVorgaengeList), switchMap((action: ApiRootAction) => this.repository.loadMyVorgaengeList(action.apiRoot).pipe( map(loadedVorgangList => VorgangActions.loadVorgangListSuccess({ vorgangList: loadedVorgangList })), - catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: this.getApiErrorFromHttpError(error) }))) + catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: getApiErrorFromHttpErrorResponse(error) }))) )) ) ) @@ -57,7 +60,7 @@ export class VorgangEffects { concatLatestFrom(() => this.store.select(VorgangSelectors.vorgangList)), switchMap(([, vorgangList]) => this.repository.getNextVorgangListPage(vorgangList.resource).pipe( map(loadedVorgangList => VorgangActions.loadNextPageSuccess({ vorgangList: loadedVorgangList })), - catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: this.getApiErrorFromHttpError(error) }))) + catchError(error => of(VorgangActions.loadVorgangListFailure({ apiError: getApiErrorFromHttpErrorResponse(error) }))) )) ) ) @@ -69,13 +72,25 @@ export class VorgangEffects { switchMap(([stringBasedProps, apiRoot, currentRouteData]) => { return this.repository.searchVorgaengeBy(apiRoot.resource, stringBasedProps.string, getSearchLinkRel(currentRouteData), VorgangEffects.SEARCH_PREVIEW_LIST_LIMIT).pipe( map(loadedVorgangList => VorgangActions.searchForPreviewSuccess({ vorgangList: loadedVorgangList })), - catchError(error => of(VorgangActions.searchForPreviewFailure({ apiError: this.getApiErrorFromHttpError(error) }))) + catchError(error => of(VorgangActions.searchForPreviewFailure({ httpErrorResponse: error }))) ) }) ) ) - private getApiErrorFromHttpError(error: any): ApiError { - return error.error.error; + showSearchError$ = createEffect(() => + this.actions$.pipe( + ofType( + VorgangActions.searchForPreviewFailure, + VorgangActions.searchVorgaengeByFailure + ), + map((action: HttpErrorAction) => this.showSearchError(action.httpErrorResponse)), + ), { dispatch: false } + ); + + showSearchError(error: HttpErrorResponse): void { + if (isServiceUnavailable(error.error.status)) { + this.snackbarService.showError(VorgangMessages.SEARCH_UNAVAILABLE); + } } } \ No newline at end of file diff --git a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts index 3430a6b2c0857f983fdefa02355a9fb1756a7a67..e98219c8f76dccc4520b2ae10372f5ae4b701797 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts @@ -1,3 +1,4 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { UrlSegment } from '@angular/router'; import { ApiRootResource } from '@goofy-client/api-root-shared'; import { RouteData } from '@goofy-client/navigation-shared'; @@ -7,7 +8,7 @@ import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { createRouteData } from 'libs/navigation-shared/test/navigation-test-factory'; import { createVorgangListResource, createVorgangListResourceWithResource, createVorgangResource, createVorgangResources } from 'libs/vorgang-shared/test/vorgang'; import * as NavigationActions from '../../../../navigation-shared/src/lib/+state/navigation.actions'; -import { createApiError } from '../../../../tech-shared/test/error'; +import { createApiError, createHttpErrorResponse } from '../../../../tech-shared/test/error'; import * as VorgangNavigationUtil from '../vorgang-navigation.util'; import { VorgangListLinkRel } from '../vorgang.linkrel'; import { VorgangListResource, VorgangResource } from '../vorgang.model'; @@ -183,6 +184,20 @@ describe('Vorgang Reducer', () => { expect(state.searchPreviewList).toStrictEqual(createEmptyStateResource()); }) }) + + describe('on "searchVorgaengeByFailure" action', () => { + + const apiError: ApiError = createApiError(); + const httpErrorResponse: HttpErrorResponse = createHttpErrorResponse(apiError); + const action = VorgangActions.searchVorgaengeByFailure({ httpErrorResponse }); + + it('should set error', () => { + const state: VorgangState = reducer(initialState, action); + + expect(state.vorgangList.error).toStrictEqual(apiError); + }) + }) + }) describe('searchForPreview', () => { @@ -214,7 +229,8 @@ describe('Vorgang Reducer', () => { describe('on "searchForPreviewFailure" action', () => { const apiError: ApiError = createApiError(); - const action = VorgangActions.searchForPreviewFailure({ apiError }); + const httpErrorResponse: HttpErrorResponse = createHttpErrorResponse(apiError); + const action = VorgangActions.searchForPreviewFailure({ httpErrorResponse }); it('should set error', () => { const state: VorgangState = reducer(initialState, action); diff --git a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts index 17f1307522dfa0c786361b989b20aeb74517f922..ef058adb7617c4b21ba9e66fcd7bb1b7dc0cbd3a 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts @@ -1,12 +1,12 @@ import { RouteData } from '@goofy-client/navigation-shared'; -import { createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_ARRAY, StateResource } from '@goofy-client/tech-shared'; +import { createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_ARRAY, getApiErrorFromHttpErrorResponse, StateResource } from '@goofy-client/tech-shared'; import { Action, createReducer, on } from '@ngrx/store'; import * as NavigationActions from '../../../../navigation-shared/src/lib/+state/navigation.actions'; import { getSearchString, isMyVorgaenge, isSearch, isVorgangDetailPage, isVorgangListPage } from '../vorgang-navigation.util'; import { SearchInfo, VorgangListResource, VorgangResource } from '../vorgang.model'; import { getVorgaengeFromList } from '../vorgang.util'; import * as VorgangActions from './vorgang.actions'; -import { ApiErrorAction, VorgangListAction } from './vorgang.actions'; +import { ApiErrorAction, HttpErrorAction, VorgangListAction } from './vorgang.actions'; export const VORGANG_FEATURE_KEY = 'VorgangState'; @@ -73,6 +73,11 @@ const vorgangReducer = createReducer( vorgaenge: getVorgaengeFromList(action.vorgangList), searchPreviewList: createEmptyStateResource<VorgangListResource>() })), + on(VorgangActions.searchVorgaengeByFailure, (state: VorgangState, action: HttpErrorAction): VorgangState => ({ + ...state, + vorgangList: createErrorStateResource(getApiErrorFromHttpErrorResponse(action.httpErrorResponse)), + searchPreviewList: createEmptyStateResource() + })), on(VorgangActions.searchForPreview, (state: VorgangState): VorgangState => ({ @@ -83,9 +88,9 @@ const vorgangReducer = createReducer( ...state, searchPreviewList: createStateResource<VorgangListResource>(action.vorgangList) })), - on(VorgangActions.searchForPreviewFailure, (state: VorgangState, action: ApiErrorAction): VorgangState => ({ + on(VorgangActions.searchForPreviewFailure, (state: VorgangState, action: HttpErrorAction): VorgangState => ({ ...state, - searchPreviewList: createErrorStateResource(action.apiError) + searchPreviewList: createErrorStateResource(getApiErrorFromHttpErrorResponse(action.httpErrorResponse)) })), on(VorgangActions.clearSearchPreviewList, (state: VorgangState): VorgangState => ({ ...state, diff --git a/goofy-client/libs/vorgang-shared/src/lib/vorgang.messages.ts b/goofy-client/libs/vorgang-shared/src/lib/vorgang.messages.ts index 8ac8ecd6d93a07bf4f476ac9d5bb78cda648afb8..0778e28c6721916cd8343e58184b6d5b0238924b 100644 --- a/goofy-client/libs/vorgang-shared/src/lib/vorgang.messages.ts +++ b/goofy-client/libs/vorgang-shared/src/lib/vorgang.messages.ts @@ -17,5 +17,6 @@ export enum VorgangMessages { BESCHIEDEN = 'Der Vorgang wurde beschieden.', ZURUECKGESTELLT = 'Der Vorgang wurde zurückgestellt.', ABGESCHLOSSEN = 'Der Vorgang wurde abgeschlossen.', - WIEDEREROEFFNET = 'Der Vorgang wurde wiedereröffnet.' + WIEDEREROEFFNET = 'Der Vorgang wurde wiedereröffnet.', + SEARCH_UNAVAILABLE = 'Die Suche ist vorübergehen nicht verfügbar. Versuchen Sie es zu einem späteren Zeitpunkt erneut.' } diff --git a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.html b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.html index e4b2eef1b21f0d4ff087486d941a7c9788494835..480a77368e6fb3a27b25edb93fc40598d7b540ac 100644 --- a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.html +++ b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.html @@ -2,6 +2,6 @@ <goofy-client-spinner diameter="60" [stateResource]="vorgangListPageResource"></goofy-client-spinner> -<goofy-client-empty-list *ngIf="!vorgangListPageResource.loading && vorgangListPageResource.loaded && !(vorgaenge && vorgaenge.length)" data-test-id="empty-list" +<goofy-client-empty-list *ngIf="isEmptySearchResult()" data-test-id="empty-list" [searchString]="searchString"> </goofy-client-empty-list> \ No newline at end of file diff --git a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.spec.ts b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.spec.ts index 6dfbbdbc9671fb92707732f30e914878637ee9ac..dabbe87f2016e9c781d9c1f2a83acd51e9460164 100644 --- a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.spec.ts +++ b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.spec.ts @@ -102,7 +102,7 @@ describe('VorgangListComponent', () => { component.nextPage = <any>mock(EventEmitter); }) - it('should emit "nextPage" if necesarry', () => { + it('should emit "nextPage" if necessary', () => { component.shouldLoadNextPage = jest.fn().mockReturnValue(true); component.loadNextPage(); @@ -110,7 +110,7 @@ describe('VorgangListComponent', () => { expect(component.nextPage.emit).toHaveBeenCalled(); }) - it('should emit "nextPage" if necesarry', () => { + it('should emit "nextPage" if necessary', () => { component.shouldLoadNextPage = jest.fn().mockReturnValue(false); component.loadNextPage(); diff --git a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.ts b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.ts index 9f95f07878122af52ef2cc42c3276dcf427087de..57ea77a3da5cb83658c00ac2a5c7e7bf10a6aa0b 100644 --- a/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.ts +++ b/goofy-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list.component.ts @@ -47,4 +47,16 @@ export class VorgangListComponent { hasNextPage(): boolean { return hasLink(this.vorgangListPageResource.resource, VorgangListLinkRel.NEXT) } + + isEmptySearchResult(): boolean { + return this.isValidList() && this.notExistsVorgaenge(); + } + + private notExistsVorgaenge(): boolean { + return this.vorgaenge.length === 0; + } + + private isValidList(): boolean { + return !this.vorgangListPageResource.loading && this.vorgangListPageResource.loaded && !this.vorgangListPageResource.hasOwnProperty('error'); + } }