Skip to content
Snippets Groups Projects
Commit d0af3424 authored by Martin's avatar Martin
Browse files

OZG-6988 refactor postfach setting handling (as an example)

parent cb3016b2
No related branches found
No related tags found
No related merge requests found
Showing
with 150 additions and 197 deletions
...@@ -41,7 +41,6 @@ import { OAuthModule } from 'angular-oauth2-oidc'; ...@@ -41,7 +41,6 @@ import { OAuthModule } from 'angular-oauth2-oidc';
import { HttpUnauthorizedInterceptor } from '@authentication'; import { HttpUnauthorizedInterceptor } from '@authentication';
import { ConfigurationsProviders } from 'libs/admin/configuration-shared/src/lib/configuration.providers'; import { ConfigurationsProviders } from 'libs/admin/configuration-shared/src/lib/configuration.providers';
import { OrganisationEinheitProviders } from 'libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.providers'; import { OrganisationEinheitProviders } from 'libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.providers';
import { PostfachProviders } from 'libs/admin/postfach-shared/src/lib/postfach.providers';
import { SettingsProviders } from 'libs/admin/settings-shared/src/lib/settings.providers'; import { SettingsProviders } from 'libs/admin/settings-shared/src/lib/settings.providers';
import { UserProviders } from 'libs/admin/user/src/lib/user.providers'; import { UserProviders } from 'libs/admin/user/src/lib/user.providers';
import { AppComponent } from './app/app.component'; import { AppComponent } from './app/app.component';
...@@ -63,7 +62,6 @@ loadEnvironment(environment.environmentUrl).then((env) => { ...@@ -63,7 +62,6 @@ loadEnvironment(environment.environmentUrl).then((env) => {
bootstrapApplication(AppComponent, { bootstrapApplication(AppComponent, {
providers: [ providers: [
ConfigurationsProviders, ConfigurationsProviders,
PostfachProviders,
SettingsProviders, SettingsProviders,
OrganisationEinheitProviders, OrganisationEinheitProviders,
UserProviders, UserProviders,
......
export * from './lib/postfach.model'; export * from './lib/postfach.model';
export * from './lib/postfach.service';
...@@ -21,21 +21,17 @@ ...@@ -21,21 +21,17 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen * Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { SettingsService } from '@admin-client/settings-shared';
import { ApiResourceService, ResourceRepository, ResourceServiceConfig } from '@alfa-client/tech-shared';
import { PostfachLinkRel } from './postfach.linkrel';
import { PostfachResource } from './postfach.model';
export class PostfachResourceService extends ApiResourceService<PostfachResource, PostfachResource> {} // export class PostfachResourceService extends ApiResourceService<PostfachResource, PostfachResource> {}
export function createPostfachResourceService(repository: ResourceRepository, settingService: SettingsService) { // export function createPostfachResourceService(repository: ResourceRepository, settingService: SettingsService) {
return new ApiResourceService(buildConfig(settingService), repository); // return new ApiResourceService(buildConfig(settingService), repository);
} // }
function buildConfig(settingService: SettingsService): ResourceServiceConfig<PostfachResource> { // function buildConfig(settingService: SettingsService): ResourceServiceConfig<PostfachResource> {
return { // return {
resource: settingService.getPostfach(), // resource: settingService.getPostfach(),
getLinkRel: PostfachLinkRel.SELF, // getLinkRel: PostfachLinkRel.SELF,
edit: { linkRel: PostfachLinkRel.SELF }, // edit: { linkRel: PostfachLinkRel.SELF },
}; // };
} // }
...@@ -42,4 +42,9 @@ export declare type PostfachSettingsItem = { ...@@ -42,4 +42,9 @@ export declare type PostfachSettingsItem = {
settingBody: Postfach; settingBody: Postfach;
}; };
export declare type PostfachResource = Resource & PostfachSettingsItem; export declare type PostfachResource = Resource & PostfachSettingsItem & SettingsItem;
export interface SettingsItem {
name: SettingName;
settingBody: any; //typisieren
}
import { SettingsService } from '@admin-client/settings-shared';
import { ResourceRepository } from '@alfa-client/tech-shared';
import { createPostfachResourceService, PostfachResourceService } from './postfach-resource.service';
export const PostfachProviders = [
SettingsService,
{
provide: PostfachResourceService,
useFactory: createPostfachResourceService,
deps: [ResourceRepository, SettingsService],
},
];
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { SettingName } from '@admin-client/settings-shared';
import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared';
import { SnackBarService } from '@alfa-client/ui';
import { inject, Injectable } from '@angular/core';
import { Observable, startWith, tap } from 'rxjs';
import { PostfachResourceService } from './postfach-resource.service';
import { Postfach, PostfachResource, PostfachSettingsItem } from './postfach.model';
@Injectable()
export class PostfachService {
private postfachResourceService = inject(PostfachResourceService)
private snackbarService = inject(SnackBarService)
public get(): Observable<StateResource<PostfachResource>> {
return this.postfachResourceService.get();
}
public save(postfach: Postfach): Observable<StateResource<PostfachResource>> {
return this.postfachResourceService.save(this.buildPostfachSettingItem(postfach)).pipe(
tap((stateResource: StateResource<PostfachResource>) => this.showInfoAfterSave(stateResource)),
startWith(createEmptyStateResource<PostfachResource>(true)),
);
}
private showInfoAfterSave(stateResource: StateResource<PostfachResource>) {
if (!stateResource.loading) {
this.snackbarService.showInfo('Die Signatur wurde erfolgreich gespeichert.');
}
}
private buildPostfachSettingItem(postfach: Postfach): PostfachSettingsItem {
return {
name: SettingName.POSTFACH,
settingBody: postfach,
};
}
}
<h1 class="heading-1">Postfach</h1> <admin-postfach-form />
<admin-postfach-form [postfachStateResource]="postfachStateResource$ | async" />
...@@ -21,11 +21,8 @@ ...@@ -21,11 +21,8 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen * Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { PostfachResource, PostfachService } from '@admin-client/postfach-shared';
import { StateResource } from '@alfa-client/tech-shared';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core'; import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { PostfachFormComponent } from './postfach-form/postfach-form.component'; import { PostfachFormComponent } from './postfach-form/postfach-form.component';
@Component({ @Component({
...@@ -33,14 +30,5 @@ import { PostfachFormComponent } from './postfach-form/postfach-form.component'; ...@@ -33,14 +30,5 @@ import { PostfachFormComponent } from './postfach-form/postfach-form.component';
templateUrl: './postfach-container.component.html', templateUrl: './postfach-container.component.html',
standalone: true, standalone: true,
imports: [CommonModule, PostfachFormComponent], imports: [CommonModule, PostfachFormComponent],
providers: [PostfachService],
}) })
export class PostfachContainerComponent implements OnInit { export class PostfachContainerComponent {}
private postfachService = inject(PostfachService);
postfachStateResource$: Observable<StateResource<PostfachResource>>;
ngOnInit(): void {
this.postfachStateResource$ = this.postfachService.get();
}
}
...@@ -23,43 +23,9 @@ ...@@ -23,43 +23,9 @@
unter der Lizenz sind dem Lizenztext zu entnehmen. unter der Lizenz sind dem Lizenztext zu entnehmen.
--> -->
<h1 class="heading-1">Postfach</h1>
<form class="form flex-col" [formGroup]="formService.form"> <form class="form flex-col" [formGroup]="formService.form">
<!--
<h2 class="heading-2">Absender</h1>
<p id="absender-desc" class="p-1">Hinterlegen Sie Absenderinformationen zu Ihrem Postfach.</p>
<div
[formGroupName]="PostfachFormService.ASBSENDER_GROUP"
aria-describedby="absender-desc"
class="grid-col-1 mb-2 mt-2 grid w-96 gap-1"
>
<text-field
data-test-id="absender-name"
label="Name"
[formControlName]="PostfachFormService.NAME_FIELD"
></text-field>
<text-field
data-test-id="absender-anschrift"
label="Anschrift"
[formControlName]="PostfachFormService.ANSCHRIFT_FIELD"
></text-field>
<text-field
data-test-id="absender-dienst"
label="Dienst"
[formControlName]="PostfachFormService.DIENST_FIELD"
></text-field>
<text-field
data-test-id="absender-mandant"
label="Mandant"
[formControlName]="PostfachFormService.MANDANT_FIELD"
></text-field>
<text-field
data-test-id="absender-gemeindeschluessel"
label="Gemeindeschlüssel"
[formControlName]="PostfachFormService.GEMEINDESCHLUESSEL_FIELD"
></text-field>
</div>
<div class="h-20"></div>
-->
<admin-postfach-signatur class="mb-6 block" /> <admin-postfach-signatur class="mb-6 block" />
<ods-button-with-spinner <ods-button-with-spinner
...@@ -68,13 +34,4 @@ ...@@ -68,13 +34,4 @@
[stateResource]="submitInProgress$ | async" [stateResource]="submitInProgress$ | async"
(clickEmitter)="submit()" (clickEmitter)="submit()"
></ods-button-with-spinner> ></ods-button-with-spinner>
@if (formService.isInvalid()) {
<span
data-test-id="invalid-empty-message-span"
class="m-2 text-red-500"
>
*Es müssen alle Felder ausgefüllt sein.
</span>
}
</form> </form>
...@@ -21,10 +21,9 @@ ...@@ -21,10 +21,9 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen * Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { PostfachResource } from '@admin-client/postfach-shared'; import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared';
import { createEmptyStateResource, isNotNil, StateResource } from '@alfa-client/tech-shared';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, inject, Input } from '@angular/core'; import { Component, inject } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Resource } from '@ngxp/rest'; import { Resource } from '@ngxp/rest';
import { ButtonWithSpinnerComponent } from '@ods/component'; import { ButtonWithSpinnerComponent } from '@ods/component';
...@@ -40,21 +39,9 @@ import { PostfachFormService } from './postfach.formservice'; ...@@ -40,21 +39,9 @@ import { PostfachFormService } from './postfach.formservice';
imports: [CommonModule, FormsModule, ReactiveFormsModule, PostfachSignaturComponent, ButtonWithSpinnerComponent], imports: [CommonModule, FormsModule, ReactiveFormsModule, PostfachSignaturComponent, ButtonWithSpinnerComponent],
}) })
export class PostfachFormComponent { export class PostfachFormComponent {
public formService = inject(PostfachFormService); public readonly formService = inject(PostfachFormService);
submitInProgress$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>()); public submitInProgress$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>());
@Input() set postfachStateResource(stateResource: StateResource<PostfachResource>) {
this.updatePostfachResource(stateResource.resource);
}
updatePostfachResource(postfachRessource: PostfachResource): void {
if (isNotNil(postfachRessource)) {
this.formService.patch(postfachRessource.settingBody);
}
}
protected readonly PostfachFormService = PostfachFormService;
public submit(): void { public submit(): void {
this.submitInProgress$ = this.formService.submit(); this.submitInProgress$ = this.formService.submit();
......
...@@ -21,16 +21,18 @@ ...@@ -21,16 +21,18 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen * Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { Postfach, PostfachResource, PostfachService } from '@admin-client/postfach-shared'; import { Postfach, PostfachResource } from '@admin-client/postfach-shared';
import { AbstractFormService, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; import { SettingName } from '@admin-client/settings-shared';
import { inject, Injectable } from '@angular/core'; import { EMPTY_STRING, StateResource } from '@alfa-client/tech-shared';
import { FormControl, UntypedFormGroup } from '@angular/forms'; import { Injectable } from '@angular/core';
import { FormBuilder, FormControl, UntypedFormGroup } from '@angular/forms';
import { isNil } from 'lodash-es'; import { isNil } from 'lodash-es';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { SettingFormService } from '../../../../../settings-shared/src/lib/settings-fom.service';
@Injectable() @Injectable()
export class PostfachFormService extends AbstractFormService { export class PostfachFormService extends SettingFormService<PostfachResource> {
private postfachService: PostfachService = inject(PostfachService); static readonly ITEM_NAME: SettingName = SettingName.POSTFACH;
public static readonly ASBSENDER_GROUP: string = 'absender'; public static readonly ASBSENDER_GROUP: string = 'absender';
public static readonly NAME_FIELD: string = 'name'; public static readonly NAME_FIELD: string = 'name';
...@@ -41,6 +43,10 @@ export class PostfachFormService extends AbstractFormService { ...@@ -41,6 +43,10 @@ export class PostfachFormService extends AbstractFormService {
public static readonly SIGNATUR_FIELD: string = 'signatur'; public static readonly SIGNATUR_FIELD: string = 'signatur';
constructor(formBuilder: FormBuilder) {
super(formBuilder, PostfachFormService.ITEM_NAME);
}
protected initForm(): UntypedFormGroup { protected initForm(): UntypedFormGroup {
return this.formBuilder.group({ return this.formBuilder.group({
[PostfachFormService.ASBSENDER_GROUP]: this.formBuilder.group({ [PostfachFormService.ASBSENDER_GROUP]: this.formBuilder.group({
...@@ -56,17 +62,13 @@ export class PostfachFormService extends AbstractFormService { ...@@ -56,17 +62,13 @@ export class PostfachFormService extends AbstractFormService {
protected doSubmit(): Observable<StateResource<PostfachResource>> { protected doSubmit(): Observable<StateResource<PostfachResource>> {
const value: Postfach = this.getFormValue(); const value: Postfach = this.getFormValue();
if (this.shouldSkipAbsender(value)) { if (this.shouldRemoveAbsender(value)) {
delete value.absender; delete value.absender;
} }
return this.postfachService.save(value); return this.settingService.save(this.source, value, PostfachFormService.ITEM_NAME);
}
private shouldSkipAbsender(postfach: Postfach): boolean {
return isNil(this.source?.absender) && Object.values(postfach.absender).every((v) => isNil(v) || v.length === 0);
} }
protected getPathPrefix(): string { private shouldRemoveAbsender(postfach: Postfach): boolean {
return 'settingBody'; return isNil(this.source.absender) || Object.values(postfach.absender).every((v) => isNil(v) || v.length === 0);
} }
} }
import { SettingsItem } from '@admin-client/postfach-shared';
import { SettingName, SettingsService } from '@admin-client/settings-shared';
import { AbstractFormService, isLoaded, isNotNull, StateResource } from '@alfa-client/tech-shared';
import { inject, Injectable, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Subscription, tap } from 'rxjs';
@Injectable()
export abstract class SettingFormService<T extends SettingsItem> extends AbstractFormService implements OnInit, OnDestroy {
settingService: SettingsService = inject(SettingsService);
private sub: Subscription;
constructor(formBuilder: FormBuilder, name: SettingName) {
super(formBuilder);
console.info('SETTINGS FORMSERVICE: Constructor');
this.sub = this.settingService
.get(name)
.pipe(tap((stateResource: StateResource<T>) => this.handleSettingChange(stateResource)))
.subscribe();
}
handleSettingChange(stateResource: StateResource<T>) {
if (isLoaded(stateResource) && isNotNull(stateResource.resource)) {
this.patch(stateResource.resource.settingBody);
this.source = stateResource.resource;
}
}
ngOnInit(): void {
console.info('SETTINGS FORMSERVICE: ngOnInit');
}
ngOnDestroy(): void {
console.info('SETTINGS FORMSERVICE: ngOnDestrpy');
this.unsubscribe();
this.settingService.refresh();
}
unsubscribe(): void {
this.sub.unsubscribe();
}
protected getPathPrefix(): string {
return 'settingBody';
}
}
import { PostfachResource } from '@admin-client/postfach-shared'; import { PostfachSettingsItem } from '@admin-client/postfach-shared';
import { StateResource } from '@alfa-client/tech-shared'; import { createEmptyStateResource, createStateResource, ResourceRepository, StateResource } from '@alfa-client/tech-shared';
import { SnackBarService } from '@alfa-client/ui';
import { inject, Injectable } from '@angular/core'; import { inject, Injectable } from '@angular/core';
import { map, Observable } from 'rxjs'; import { Resource } from '@ngxp/rest';
import { map, Observable, startWith, tap } from 'rxjs';
import { SettingListResourceService } from './settings-resource.service'; import { SettingListResourceService } from './settings-resource.service';
import { getPostfachResource } from './settings.util'; import { SettingName } from './settings.model';
import { getSettingItem } from './settings.util';
@Injectable() @Injectable()
export class SettingsService { export class SettingsService {
private settingListResourceService = inject(SettingListResourceService); private settingListResourceService = inject(SettingListResourceService);
private repository: ResourceRepository = inject(ResourceRepository);
private snackbarService: SnackBarService = inject(SnackBarService);
public getPostfach(): Observable<StateResource<PostfachResource>> { public get<T>(name: SettingName): Observable<StateResource<T>> {
return this.settingListResourceService.getList().pipe(map(getPostfachResource)); return this.settingListResourceService.getList().pipe(map((list) => getSettingItem<T>(list, name)));
}
//Objekt bauen, snackbar configuration/message ergänzen
public save<T extends Resource>(resource: Resource, toSave: unknown, name: SettingName): Observable<StateResource<T>> {
return this.repository
.save({
resource,
linkRel: 'self',
toSave: this.buildSettingItem(toSave, name),
})
.pipe(
map((res: T) => createStateResource<T>(res)),
tap((stRes: StateResource<T>) => this.showInfoAfterSave(stRes)),
startWith(createEmptyStateResource<T>(true)),
);
}
private showInfoAfterSave<T>(stateResource: StateResource<T>) {
if (!stateResource.loading) {
this.snackbarService.showInfo('Die Signatur wurde erfolgreich gespeichert.');
}
}
private buildSettingItem(settingBody: any, name: SettingName): PostfachSettingsItem {
return {
name: name,
settingBody: settingBody,
};
}
public refresh(): void {
this.settingListResourceService.refresh();
} }
} }
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
* Die sprachspezifischen Genehmigungen und Beschränkungen * Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen. * unter der Lizenz sind dem Lizenztext zu entnehmen.
*/ */
import { PostfachResource } from '@admin-client/postfach-shared';
import { import {
createEmptyStateResource, createEmptyStateResource,
createStateResource, createStateResource,
...@@ -32,14 +31,25 @@ import { ...@@ -32,14 +31,25 @@ import {
import { SettingListLinkRel } from './settings.linkrel'; import { SettingListLinkRel } from './settings.linkrel';
import { SettingItemResource, SettingListResource, SettingName } from './settings.model'; import { SettingItemResource, SettingListResource, SettingName } from './settings.model';
export function getPostfachResource(settingsListResource: StateResource<SettingListResource>): StateResource<PostfachResource> { // export function getPostfachResource<T>(settingsListResource: StateResource<SettingListResource>): StateResource<T> {
// const entries: SettingItemResource[] = getEmbeddedResources(settingsListResource, SettingListLinkRel.LIST);
// const postfachSettingItemResource: SettingItemResource = entries.find(isPostfachSettingItem);
// return isNotNil(postfachSettingItemResource) ?
// createStateResource(postfachSettingItemResource as T)
// : createEmptyStateResource();
// }
// function isPostfachSettingItem(item: SettingItemResource): boolean {
// return item.name === SettingName.POSTFACH;
// }
export function getSettingItem<T>(
settingsListResource: StateResource<SettingListResource>,
itemName: SettingName,
): StateResource<T> {
const entries: SettingItemResource[] = getEmbeddedResources(settingsListResource, SettingListLinkRel.LIST); const entries: SettingItemResource[] = getEmbeddedResources(settingsListResource, SettingListLinkRel.LIST);
const postfachSettingItemResource: SettingItemResource = entries.find(isPostfachSettingItem); const postfachSettingItemResource: SettingItemResource = entries.find((item) => item.name === itemName);
return isNotNil(postfachSettingItemResource) ? return isNotNil(postfachSettingItemResource) ?
createStateResource(postfachSettingItemResource as PostfachResource) createStateResource(postfachSettingItemResource as T)
: createEmptyStateResource(); : createEmptyStateResource();
} }
function isPostfachSettingItem(item: SettingItemResource): boolean {
return item.name === SettingName.POSTFACH;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment