From 0a55c46775aa809db2236454e854079da69e7371 Mon Sep 17 00:00:00 2001
From: Albert <Albert.Bruns@mgm-tp.com>
Date: Wed, 26 Mar 2025 11:24:09 +0100
Subject: [PATCH] OZG-3563 merge

---
 ...gregation-mapping-list-resource.service.ts | 13 +++--
 ...gregation-mapping-resource.service.spec.ts |  2 +-
 .../aggregation-mapping-resource.service.ts   | 10 +++-
 .../api-list-resource.service.spec.ts         | 51 +++++++++++++++++--
 .../lib/resource/api-list-resource.service.ts | 20 +++++++-
 5 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts
index 1378b74475..ab781c8a76 100644
--- a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts
+++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts
@@ -1,5 +1,10 @@
 import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
-import { ListResourceServiceConfig, ResourceListService, ResourceRepository } from '@alfa-client/tech-shared';
+import {
+  ApiListResourceService,
+  ListResourceServiceConfig,
+  ResourceListService,
+  ResourceRepository,
+} from '@alfa-client/tech-shared';
 import { AggregationMappingListLinkRel } from './aggregation-mapping.linkrel';
 import { AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model';
 
@@ -13,14 +18,14 @@ export function createAggregationMappingListResourceService(
   repository: ResourceRepository,
   configurationService: ConfigurationService,
 ) {
-  return new ResourceListService(buildConfig(configurationService), repository);
+  return new ApiListResourceService(buildConfig(configurationService), repository);
 }
 
 function buildConfig(configurationService: ConfigurationService): ListResourceServiceConfig<ConfigurationResource> {
   return {
     baseResource: configurationService.get(),
-    listLinkRel: ConfigurationLinkRel.AGGREGATION_MAPPINGS,
     listResourceListLinkRel: AggregationMappingListLinkRel.LIST,
-    createLinkRel: AggregationMappingListLinkRel.SELF,
+    getLinkRel: ConfigurationLinkRel.AGGREGATION_MAPPINGS,
+    create: { linkRel: AggregationMappingListLinkRel.SELF },
   };
 }
diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts
index d9131bbba3..5730eb0567 100644
--- a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts
+++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts
@@ -60,7 +60,7 @@ describe('AggregationMappingResourceService', () => {
         useFromMock(navigationService),
       );
 
-      expect(config.resource).toBeObservable(singleColdCompleted(staticResource));
+      expect(config.baseResource).toBeObservable(singleColdCompleted(staticResource));
     });
   });
 
diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts
index 0bfa0689a8..8ac05193e0 100644
--- a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts
+++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts
@@ -8,6 +8,7 @@ import {
   ResourceRepository,
   ResourceServiceConfig,
   StateResource,
+  StateService,
 } from '@alfa-client/tech-shared';
 import { UrlSegment } from '@angular/router';
 import { iif, map, Observable, of, switchMap } from 'rxjs';
@@ -22,9 +23,14 @@ export class AggregationMappingResourceService extends ApiResourceService<
 
 export function createAggregationMappingResourceService(
   repository: ResourceRepository,
+  stateService: StateService,
   navigationService: NavigationService,
 ): AggregationMappingResourceService {
-  return new AggregationMappingResourceService(_buildResourceServiceConfig(repository, navigationService), repository);
+  return new AggregationMappingResourceService(
+    _buildResourceServiceConfig(repository, navigationService),
+    stateService,
+    repository,
+  );
 }
 
 export function _buildResourceServiceConfig(
@@ -32,7 +38,7 @@ export function _buildResourceServiceConfig(
   navigationService: NavigationService,
 ): ResourceServiceConfig<AggregationMappingResource> {
   return {
-    resource: self._getResourceByNavigationRoute(repository, navigationService),
+    baseResource: self._getResourceByNavigationRoute(repository, navigationService),
     getLinkRel: AggregationMappingLinkRel.SELF,
     edit: { linkRel: AggregationMappingLinkRel.SELF },
     delete: { linkRel: AggregationMappingLinkRel.SELF },
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.spec.ts
index 87451e3301..4b619c70e4 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.spec.ts
@@ -1,13 +1,23 @@
+import { ProblemDetail } from '@alfa-client/tech-shared';
 import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
 import { Resource } from '@ngxp/rest';
-import { BehaviorSubject, Observable } from 'rxjs';
+import { cold } from 'jest-marbles';
+import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
 import { DummyLinkRel, DummyListLinkRel } from '../../../test/dummy';
-import { multipleCold, singleCold } from '../../../test/marbles';
+import { createProblemDetail } from '../../../test/error';
+import { multipleCold, singleCold, singleColdCompleted } from '../../../test/marbles';
 import { createDummyListResource, createDummyResource } from '../../../test/resource';
 import { ApiListResourceService } from './api-list-resource.service';
 import { CreateResourceData, LinkRelationName, ListItemResource, ListResourceServiceConfig } from './resource.model';
 import { ResourceRepository } from './resource.repository';
-import { createEmptyStateResource, createStateResource, ListResource, StateResource } from './resource.util';
+import {
+  createEmptyStateResource,
+  createErrorStateResource,
+  createLoadingStateResource,
+  createStateResource,
+  ListResource,
+  StateResource,
+} from './resource.util';
 
 describe('ListResourceService', () => {
   let service: ApiListResourceService<Resource, ListResource, ListItemResource>;
@@ -24,6 +34,7 @@ describe('ListResourceService', () => {
   const baseResourceSubj: BehaviorSubject<StateResource<Resource>> = new BehaviorSubject<StateResource<Resource>>(
     baseStateResource,
   );
+
   beforeEach(() => {
     config = {
       baseResource: baseResourceSubj,
@@ -81,5 +92,39 @@ describe('ListResourceService', () => {
         multipleCold(createEmptyStateResource(true), createStateResource(returnResource)),
       );
     });
+
+    it('should handle error', () => {
+      const error: ProblemDetail = createProblemDetail();
+      service._handleError = jest.fn();
+      resourceRepository.createResource.mockReturnValue(throwError(() => error));
+
+      service.create(toCreate).subscribe();
+
+      expect(service._handleError).toHaveBeenCalledWith(error);
+    });
+
+    it('should emit on error', () => {
+      const error: ProblemDetail = createProblemDetail();
+      service._handleError = jest.fn().mockReturnValue(of(createErrorStateResource(error)));
+      resourceRepository.createResource.mockReturnValue(cold('-#', null, error));
+
+      expect(service.create(toCreate)).toBeObservable(
+        cold('a(b|)', { a: createLoadingStateResource(), b: createErrorStateResource(error) }),
+      );
+    });
+  });
+
+  describe('handle error', () => {
+    it('should return error state resource on unprocessable entity', () => {
+      const error: ProblemDetail = createProblemDetail();
+
+      expect(service._handleError(error)).toBeObservable(singleColdCompleted(createErrorStateResource(error)));
+    });
+
+    it('should throw error', () => {
+      const error: ProblemDetail = { ...createProblemDetail(), status: 500 };
+
+      expect(service._handleError(error)).toBeObservable(cold('#', null, error));
+    });
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.ts
index 03d1d46175..1bedc05a6f 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/api-list-resource.service.ts
@@ -1,9 +1,17 @@
 import { Resource } from '@ngxp/rest';
-import { first, map, Observable, startWith, switchMap } from 'rxjs';
+import { catchError, first, map, Observable, of, startWith, switchMap, throwError } from 'rxjs';
+import { isUnprocessableEntity } from '../http.util';
+import { ProblemDetail } from '../tech.model';
 import { ResourceListService } from './list-resource.service';
 import { CreateResourceData, ListItemResource, ListResourceServiceConfig } from './resource.model';
 import { ResourceRepository } from './resource.repository';
-import { createEmptyStateResource, createStateResource, ListResource, StateResource } from './resource.util';
+import {
+  createEmptyStateResource,
+  createErrorStateResource,
+  createStateResource,
+  ListResource,
+  StateResource,
+} from './resource.util';
 
 export class ApiListResourceService<
   B extends Resource,
@@ -25,10 +33,18 @@ export class ApiListResourceService<
         this.repository.createResource(this.buildCreateResourceData(toCreate, this.config.create.linkRel, listResource.resource)),
       ),
       map((listItemResource: I) => createStateResource(listItemResource)),
+      catchError((error: ProblemDetail) => this._handleError(error)),
       startWith(createEmptyStateResource<I>(true)),
     );
   }
 
+  _handleError(error: ProblemDetail): Observable<StateResource<I>> {
+    if (isUnprocessableEntity(error.status)) {
+      return of(createErrorStateResource(error));
+    }
+    return throwError(() => error);
+  }
+
   private verifyBeforeCreation(): void {
     this.verifyValidListResource();
     this.throwErrorOn(!this.isCreateLinkPresent(), 'No creation link exists.');
-- 
GitLab