Files
ISA-Frontend/apps/isa-app/src/page/customer/customer-search/edit-main-view/customer-data-edit.component.ts
Lorenz Hilpert 8ae990bcde Merged PR 1815: Angular Update V18
Related work items: #4830, #4834
2024-10-22 09:23:23 +00:00

181 lines
7.8 KiB
TypeScript

import { Location } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';
import { ChangeDetectorRef, Component, inject, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { CrmCustomerService } from '@domain/crm';
import { CountryDTO, CustomerDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
import { UiValidators } from '@ui/validators';
import { Observable, combineLatest } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';
import { validateEmail } from '../../validators/email-validator';
import { genderLastNameValidator } from '../../validators/gender-b2b-validator';
import { camelCase } from 'lodash';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation, NavigationRoute } from '@shared/services/navigation';
import { zipCodeValidator } from '../../validators/zip-code-validator';
import { GenderSettingsService } from '@shared/services/gender';
@Component({ template: '' })
export abstract class CustomerDataEditComponent implements OnInit {
private customerService = inject(CrmCustomerService);
private activatedRoute = inject(ActivatedRoute);
private fb = inject(UntypedFormBuilder);
private cdr = inject(ChangeDetectorRef);
private location = inject(Location);
private _store = inject(CustomerSearchStore);
private _navigation = inject(CustomerSearchNavigation);
public genderSettings = inject(GenderSettingsService);
customer$: Observable<CustomerDTO>;
customerId$: Observable<number>;
countries$: Observable<CountryDTO[]>;
customerFeatures$: Observable<KeyValueDTOOfStringAndString[]>;
customerType$: Observable<string>;
isWebshopOrGuest$: Observable<boolean>;
customerFeatureB2bOrB2c$: Observable<string>;
isOnlineOrCustomerCardUser$: Observable<boolean>;
control: UntypedFormGroup;
detailsRoute$: Observable<NavigationRoute>;
get customerId() {
return Number(this.activatedRoute.snapshot.params['customerId']);
}
afterInitForm?: (control: AbstractControl) => void;
ngOnInit() {
this.customerId$ = this.activatedRoute.params.pipe(map((p) => Number(p['customerId'])));
this.customer$ = this.customerId$.pipe(
switchMap((id) => this.customerService.getCustomer(id, 2)),
map((cr) => cr.result),
);
this.customerFeatures$ = this.customer$.pipe(
map((customer: CustomerDTO) => {
// Bugfix - Logik muss aus folgendem Grund angepasst werden:
// -> Bei B2B Kunden ist meist 'd-account' mit enabled: true versehen
// -> Das feature mit dem key 'b2b' wird somit nicht zurückgegeben (da auf diesem Feature kein enabled vorhanden ist)
// -> Die View im nachfolgenden Code wird jedoch anhand des keys 'b2b' aufgebaut
const enabledFeatures = Object.values(customer.features).filter((f) => f.enabled);
const b2bFeature = customer?.features?.find((f) => f?.key === 'b2b');
const isB2B = enabledFeatures?.every(
(f) => f?.key === 'd-account' && f?.description?.toLowerCase()?.includes('business') && b2bFeature,
);
return isB2B ? [b2bFeature, ...enabledFeatures] : enabledFeatures;
}),
);
this.customerType$ = this.customerFeatures$.pipe(
map(
(features: KeyValueDTOOfStringAndString[]) =>
features.find((f) => f.key === 'store' || f.key === 'webshop' || f.key === 'b2b' || f.key === 'guest')?.key,
),
);
this.isOnlineOrCustomerCardUser$ = combineLatest([this.customerType$, this.customerFeatures$]).pipe(
map(
([type, features]) =>
type === 'webshop' || !!features?.find((feature) => feature?.key === 'p4muser' || feature?.key === 'd-account'),
),
);
this.isWebshopOrGuest$ = this.customerType$.pipe(map((type) => type === 'webshop' || type === 'guest'));
this.customerFeatureB2bOrB2c$ = this.customerType$.pipe(map((type) => (type === 'b2b' ? 'b2b' : 'b2c')));
this.countries$ = this.isWebshopOrGuest$.pipe(
switchMap((webshopOrGuest) => {
if (!webshopOrGuest) {
return this.customerService.getCountries().pipe(map((p) => p.result));
} else {
return this.customerService.getCountries().pipe(
map((p) => p.result),
map((countries) => countries.filter((country) => country.name === 'Deutschland')),
);
}
}),
);
this.initForm();
this.detailsRoute$ = combineLatest([this._store.processId$, this._store.customerId$]).pipe(
map(([processId, customerId]) => this._navigation.detailsRoute({ processId, customerId })),
);
}
async initForm() {
const { fb } = this;
const customerDTO = await this.customer$.pipe(first()).toPromise();
const customerType = await this.customerType$.pipe(first()).toPromise();
const customerFeatures = await this.customerFeatures$.pipe(first()).toPromise();
const isB2b = customerType === 'b2b';
const isBranch = customerType === 'store';
const isWebshop = customerType === 'webshop';
const isCard = customerFeatures.find((feature) => feature.key === 'p4muser');
const zipCodeValidators = (isWebshop && isCard) || isWebshop || isB2b ? [Validators.required, zipCodeValidator()] : []; // #2573 Validierung nur für Onlinekonto, Onlinekonto+Kundenkarte, Business Konto
this.control = fb.group(
{
gender: fb.control(customerDTO?.gender, [isBranch ? Validators.required : () => null]),
title: fb.control(customerDTO?.title),
lastName: fb.control(customerDTO?.lastName, [Validators.required]),
firstName: fb.control(customerDTO?.firstName, [Validators.required]),
dateOfBirth: fb.control(customerDTO?.dateOfBirth, [isWebshop && isCard ? Validators.required : () => null, UiValidators.date]),
communicationDetails: fb.group({
email: fb.control(customerDTO?.communicationDetails?.email, [validateEmail]),
phone: fb.control(customerDTO?.communicationDetails?.phone),
mobile: fb.control(customerDTO?.communicationDetails?.mobile),
}),
organisation: fb.group({
name: fb.control(customerDTO?.organisation?.name),
vatId: fb.control(customerDTO?.organisation?.vatId),
department: fb.control(customerDTO?.organisation?.department),
}),
address: fb.group({
street: fb.control(customerDTO?.address?.street),
streetNumber: fb.control(customerDTO?.address?.streetNumber),
zipCode: fb.control(customerDTO?.address?.zipCode, zipCodeValidators),
city: fb.control(customerDTO?.address?.city),
country: fb.control(customerDTO?.address?.country),
info: fb.control(customerDTO?.address?.info),
}),
},
{ validators: genderLastNameValidator(isB2b) },
);
if (typeof this.afterInitForm === 'function') {
this.afterInitForm.call(this, this.control);
}
this.control.markAllAsTouched();
this.cdr.markForCheck();
}
cancel() {
this.location.back();
}
async submit() {
if (!this.control.valid || !this.control.enabled) {
return;
}
this.control.disable();
try {
await this.customerService.patchCustomer(this.customerId, this.control.value).toPromise();
this._store.selectCustomer({ customerId: this._store.customerId, reload: true });
this.location.back();
} catch (error) {
this.control.enable();
if (error instanceof HttpErrorResponse) {
if (error.error.invalidProperties) {
const invProps = error.error.invalidProperties;
const keys = Object.keys(invProps);
for (const key of keys) {
this.control.get('address')?.get(camelCase(key))?.setErrors({ validateAddress: invProps[key] });
}
}
}
console.error(error);
}
}
}