From 7317a918ba40c72f1291fe165aff1b5cc8754983 Mon Sep 17 00:00:00 2001 From: Fadil Zemmari <fadil.zemmari@xelians.fr> Date: Fri, 18 Sep 2020 15:06:32 +0200 Subject: [PATCH] [US TRTL-113] Add internal code on customer creation form --- .../vitamui/iam/common/dto/CustomerDto.java | 7 +- .../iam/common/utils/CustomerDtoEditor.java | 2 +- .../customer/converter/CustomerConverter.java | 4 + .../server/customer/domain/Customer.java | 7 +- .../service/CustomerInternalService.java | 4 + .../owner/converter/OwnerConverter.java | 6 + .../internal/server/owner/domain/Owner.java | 6 + .../owner/service/OwnerInternalService.java | 9 + .../vitamui/commons/api/domain/OwnerDto.java | 7 + .../commons/api/enums/AddressType.java | 43 ++++ .../models/customer/address-type.enum.ts | 40 ++++ .../models/customer/customer.interface.ts | 3 + .../src/app/modules/models/customer/index.ts | 1 + .../models/customer/owner.interface.ts | 3 + .../src/app/core/api/customer-api.service.ts | 2 + .../customer-create.component.html | 201 +++++++++++------- .../customer-create.component.scss | 16 ++ .../customer-create.component.ts | 114 +++++++--- .../customer-list/customer-list.service.ts | 1 + .../owner-form/owner-form.component.html | 13 +- .../owner-form/owner-form.component.ts | 22 +- 21 files changed, 398 insertions(+), 113 deletions(-) create mode 100644 commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java create mode 100644 ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts diff --git a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java index fc056c80..c6b5040f 100644 --- a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java +++ b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/dto/CustomerDto.java @@ -43,6 +43,7 @@ import java.util.Map; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import fr.gouv.vitamui.commons.api.enums.AddressType; import org.hibernate.validator.constraints.Length; import com.fasterxml.jackson.annotation.JsonInclude; @@ -100,9 +101,13 @@ public class CustomerDto extends IdDto { @NotNull private String defaultEmailDomain; - @NotNull private AddressDto address; + private String internalCode; + + @NotNull + private AddressType addressType; + private boolean subrogeable = false; private boolean readonly = false; diff --git a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java index 918359a4..a273b69a 100644 --- a/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java +++ b/api/api-iam/iam-commons/src/main/java/fr/gouv/vitamui/iam/common/utils/CustomerDtoEditor.java @@ -60,7 +60,7 @@ public class CustomerDtoEditor extends PropertyEditorSupport { if (StringUtils.hasText(text)) { try { final ObjectMapper mapper = new ObjectMapper(); - final CustomerDto customerDto = mapper.readValue(text, new TypeReference<CustomerDto>() { + final CustomerDto customerDto = mapper.readValue(text, new TypeReference<>() { }); setValue(customerDto); } diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java index bf01b2a1..b6befc88 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/converter/CustomerConverter.java @@ -84,6 +84,8 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> { public static final String EMAIL_DOMAINS_KEY = "Domaines"; + public static final String INTERNAL_CODE_KEY = "Code interne"; + public static final String DEFAULT_EMAIL_DOMAIN_KEY = "Domaine par défaut"; public static final String SUBROGEABLE_KEY = "Subrogeable"; @@ -111,6 +113,7 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> { logbookData.put(EMAIL_DOMAINS_KEY, customer.getEmailDomains().toString()); logbookData.put(DEFAULT_EMAIL_DOMAIN_KEY, LogbookUtils.getValue(customer.getDefaultEmailDomain())); logbookData.put(SUBROGEABLE_KEY, LogbookUtils.getValue(customer.isSubrogeable())); + logbookData.put(INTERNAL_CODE_KEY, LogbookUtils.getValue(customer.getInternalCode())); logbookData.put(CUSTOM_GRAPHIC_IDENTITY_KEY, LogbookUtils.getValue(customer.isHasCustomGraphicIdentity())); return ApiUtils.toJson(logbookData); } @@ -153,6 +156,7 @@ public class CustomerConverter implements Converter<CustomerDto, Customer> { if (customer.getAddress() != null) { dto.setAddress(VitamUIUtils.copyProperties(customer.getAddress(), new AddressDto())); } + if (customer.getGraphicIdentity() != null) { GraphicIdentity graphicalIdentity = customer.getGraphicIdentity(); dto.setHasCustomGraphicIdentity(graphicalIdentity.isHasCustomGraphicIdentity()); diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java index 1add4d97..36286385 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/domain/Customer.java @@ -41,6 +41,7 @@ import java.util.List; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import fr.gouv.vitamui.commons.api.enums.AddressType; import org.hibernate.validator.constraints.Length; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.mongodb.core.index.Indexed; @@ -104,9 +105,13 @@ public class Customer extends IdDocument { @NotNull private String defaultEmailDomain; - @NotNull private Address address; + private String internalCode; + + @NotNull + private AddressType addressType; + private boolean readonly = false; private boolean subrogeable = false; diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java index 5b08157b..acb7ddea 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/customer/service/CustomerInternalService.java @@ -312,6 +312,10 @@ public class CustomerInternalService extends VitamUICrudService<CustomerDto, Cus } addressService.processPatch(customer.getAddress(), CastUtils.toMap(entry.getValue()), logbooks); break; + case "internalCode" : + logbooks.add(new EventDiffDto(CustomerConverter.INTERNAL_CODE_KEY, customer.getInternalCode(), entry.getValue())); + customer.setInternalCode(CastUtils.toString(entry.getValue())); + break; case "subrogeable" : logbooks.add(new EventDiffDto(CustomerConverter.SUBROGEABLE_KEY, customer.isSubrogeable(), entry.getValue())); customer.setSubrogeable(CastUtils.toBoolean(entry.getValue())); diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java index f172b68a..0bd0c1a8 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/converter/OwnerConverter.java @@ -56,6 +56,10 @@ public class OwnerConverter implements Converter<OwnerDto, Owner> { public static final String COMPANY_NAME_KEY = "Raison sociale"; + public static final String ADDRESS_TYPE_KEY = "Type d'adresse"; + + public static final String INTERNAL_CODE_KEY = "Code interne"; + private final AddressConverter addressConverter; public OwnerConverter(final AddressConverter addressConverter) { @@ -68,6 +72,8 @@ public class OwnerConverter implements Converter<OwnerDto, Owner> { ownerLogbookData.put(CODE_KEY, LogbookUtils.getValue(owner.getCode())); ownerLogbookData.put(NAME_KEY, LogbookUtils.getValue(owner.getName())); ownerLogbookData.put(COMPANY_NAME_KEY, LogbookUtils.getValue(owner.getCompanyName())); + ownerLogbookData.put(ADDRESS_TYPE_KEY, LogbookUtils.getValue(owner.getAddressType())); + ownerLogbookData.put(INTERNAL_CODE_KEY, LogbookUtils.getValue(owner.getInternalCode())); AddressDto address = owner.getAddress() != null ? owner.getAddress() : new AddressDto(); addressConverter.addAddress(address, ownerLogbookData); return ApiUtils.toJson(ownerLogbookData); diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java index 04662c10..9c6c00fd 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/domain/Owner.java @@ -38,6 +38,7 @@ package fr.gouv.vitamui.iam.internal.server.owner.domain; import javax.validation.constraints.NotNull; +import fr.gouv.vitamui.commons.api.enums.AddressType; import org.hibernate.validator.constraints.Length; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.mongodb.core.index.Indexed; @@ -83,5 +84,10 @@ public class Owner extends CustomerIdDocument { private Address address; + private String internalCode; + + @NotNull + private AddressType addressType; + private boolean readonly; } diff --git a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java index 6b9e5a7b..85f1c1f7 100644 --- a/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java +++ b/api/api-iam/iam-internal/src/main/java/fr/gouv/vitamui/iam/internal/server/owner/service/OwnerInternalService.java @@ -44,6 +44,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import fr.gouv.vitamui.commons.api.enums.AddressType; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.query.Criteria; @@ -214,6 +215,14 @@ public class OwnerInternalService extends VitamUICrudService<OwnerDto, Owner> { logbooks.add(new EventDiffDto(OwnerConverter.COMPANY_NAME_KEY, owner.getCompanyName(), entry.getValue())); owner.setCompanyName(CastUtils.toString(entry.getValue())); break; + case "addressType" : + logbooks.add(new EventDiffDto(OwnerConverter.ADDRESS_TYPE_KEY, owner.getAddressType(), entry.getValue())); + owner.setAddressType((AddressType) entry.getValue()); + break; + case "internalCode" : + logbooks.add(new EventDiffDto(OwnerConverter.INTERNAL_CODE_KEY, owner.getInternalCode(), entry.getValue())); + owner.setInternalCode(CastUtils.toString(entry.getValue())); + break; case "address" : Address address; if (owner.getAddress() == null) { diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java index 02f1c3df..6089a8f9 100644 --- a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java +++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/OwnerDto.java @@ -38,6 +38,7 @@ package fr.gouv.vitamui.commons.api.domain; import javax.validation.constraints.NotNull; +import fr.gouv.vitamui.commons.api.enums.AddressType; import org.hibernate.validator.constraints.Length; import lombok.EqualsAndHashCode; @@ -70,8 +71,14 @@ public class OwnerDto extends CustomerIdDto { private AddressDto address; + private String internalCode; + + @NotNull + private AddressType addressType; + private boolean readonly; // no validations for identifier. Because during the creation step, the identifier is set by the backend. private String identifier; + } diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java new file mode 100644 index 00000000..0c90007c --- /dev/null +++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/enums/AddressType.java @@ -0,0 +1,43 @@ +/** + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020) + * and the signatories of the "VITAM - Accord du Contributeur" agreement. + * + * contact@programmevitam.fr + * + * This software is a computer program whose purpose is to implement + * implement a digital archiving front-office system for the secure and + * efficient high volumetry VITAM solution. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +package fr.gouv.vitamui.commons.api.enums; + +/** Possible address types of a Customer or an Owner **/ +public enum AddressType { + POSTAL, + INTERNAL_CODE, +} diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts b/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts new file mode 100644 index 00000000..3e5d3f99 --- /dev/null +++ b/ui/ui-frontend-common/src/app/modules/models/customer/address-type.enum.ts @@ -0,0 +1,40 @@ +/* + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020) + * and the signatories of the "VITAM - Accord du Contributeur" agreement. + * + * contact@programmevitam.fr + * + * This software is a computer program whose purpose is to implement + * implement a digital archiving front-office system for the secure and + * efficient high volumetry VITAM solution. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +export enum AddressType { + POSTAL = 'POSTAL', + INTERNAL_CODE = 'INTERNAL_CODE' +} diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts b/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts index 56e93753..0221cef6 100644 --- a/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts +++ b/ui/ui-frontend-common/src/app/modules/models/customer/customer.interface.ts @@ -35,6 +35,7 @@ * knowledge of the CeCILL-C license and that you accept its terms. */ import { Id } from '../id.interface'; +import { AddressType } from './address-type.enum'; import { Address } from './address.interface'; import { OtpState } from './otp-state.enum'; import { Owner } from './owner.interface'; @@ -49,6 +50,8 @@ export interface Customer extends Id { otp: OtpState; idp?: boolean; address: Address; + internalCode?: string; + addressType: AddressType; language: string; emailDomains: string[]; defaultEmailDomain: string; diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/index.ts b/ui/ui-frontend-common/src/app/modules/models/customer/index.ts index 00d32156..4540adc7 100644 --- a/ui/ui-frontend-common/src/app/modules/models/customer/index.ts +++ b/ui/ui-frontend-common/src/app/modules/models/customer/index.ts @@ -42,3 +42,4 @@ export * from './identity-provider.interface'; export * from './tenant.interface'; export * from './basic-customer.interface'; export * from './customer.interface'; +export * from './address-type.enum'; diff --git a/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts b/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts index 1d5a3661..bd0f7f14 100644 --- a/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts +++ b/ui/ui-frontend-common/src/app/modules/models/customer/owner.interface.ts @@ -35,6 +35,7 @@ * knowledge of the CeCILL-C license and that you accept its terms. */ import { Id } from '../id.interface'; +import { AddressType } from './address-type.enum'; import { Address } from './address.interface'; export interface Owner extends Id { @@ -43,6 +44,8 @@ export interface Owner extends Id { name: string; companyName: string; address: Address; + internalCode?: string; + addressType: AddressType; customerId: string; readonly: boolean; } diff --git a/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts b/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts index f8a533c5..e5dc8bc0 100644 --- a/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts +++ b/ui/ui-frontend/projects/identity/src/app/core/api/customer-api.service.ts @@ -77,6 +77,8 @@ export class CustomerApiService extends BaseHttpClient<Customer> { otp: customer.otp, idp: customer.idp, address: customer.address, + addressType: customer.addressType, + internalCode: customer.internalCode, language: customer.language, emailDomains: customer.emailDomains, defaultEmailDomain: customer.defaultEmailDomain, diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html index 85e7cb39..1efe4678 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.html @@ -9,51 +9,84 @@ <div class="content"> <h2 i18n="Create customer title@@customerCreateTitle1">Création d'un client</h2> <div> - <vitamui-common-input - class="field-code" - formControlName="code" - maxlength="20" - required - placeholder="Code client" i18n-placeholder="Customer code input placeholder + format@@customerCreateCustomerCodeInputPlaceholder" - > + <vitamui-common-input class="field-code" formControlName="code" maxlength="20" required + placeholder="Code client" + i18n-placeholder="Customer code input placeholder + format@@customerCreateCustomerCodeInputPlaceholder"> <ng-container *ngIf="form.get('code')?.touched"> - <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> - <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.pattern" i18n="Wrong format (6 digits minimum) error hint@@formError6DigitsField">Format incorrect (6 chiffres minimum)</vitamui-common-input-error> - <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.uniqueCode" i18n="Code exists error hint@@formErrorCodeExists">Code déjà existant</vitamui-common-input-error> + <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.pattern" + i18n="Wrong format (6 digits minimum) error hint@@formError6DigitsField">Format incorrect (6 chiffres + minimum)</vitamui-common-input-error> + <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.uniqueCode" + i18n="Code exists error hint@@formErrorCodeExists">Code déjà existant</vitamui-common-input-error> </ng-container> </vitamui-common-input> </div> <div class="d-flex"> - <vitamui-common-input class="field-name" formControlName="name" maxlength="100" required placeholder="Client" i18n-placeholder="Customer name input placeholder@@customerCreateNameInputPlaceholder"> - <vitamui-common-input-error *ngIf="form.get('name')?.touched && !!form.get('name')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input class="field-name" formControlName="name" maxlength="100" required placeholder="Client" + i18n-placeholder="Customer name input placeholder@@customerCreateNameInputPlaceholder"> + <vitamui-common-input-error *ngIf="form.get('name')?.touched && !!form.get('name')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> - <vitamui-common-input class="field-company-name" formControlName="companyName" maxlength="250" required placeholder="Raison sociale" i18n-placeholder="Customer company name input placeholder@@customerCreateCompanyNameInputPlaceholder"> - <vitamui-common-input-error *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input class="field-company-name" formControlName="companyName" maxlength="250" required + placeholder="Raison sociale" + i18n-placeholder="Customer company name input placeholder@@customerCreateCompanyNameInputPlaceholder"> + <vitamui-common-input-error + *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> </div> - <ng-container formGroupName="address"> + <div class="mb-4"> + <div i18n="Address type@@CustomerAddressType" class="mb-2">Type d'adresse</div> + <mat-button-toggle-group #group="matButtonToggleGroup" formControlName="addressType"> + <mat-button-toggle color="primary" value="POSTAL" + [ngClass]="{'selected': form.get('addressType').value === ADDRESS_TYPE.POSTAL}">Postale</mat-button-toggle> + <mat-button-toggle color="primary" value="INTERNAL_CODE" + [ngClass]="{'selected': form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE}">Code interne</mat-button-toggle> + </mat-button-toggle-group> + </div> + + <div *ngIf="form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE"> + <vitamui-common-input class="field-street" formControlName="internalCode" maxlength="20" required placeholder="Code interne" + i18n-placeholder="Internal code@@customerInternalCodePlaceholder"> + <vitamui-common-input-error + *ngIf="form.get('internalCode')?.touched && !!form.get('internalCode')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + </vitamui-common-input> + </div> + + <ng-container formGroupName="address" *ngIf="form.get('addressType').value === ADDRESS_TYPE.POSTAL"> <div> - <vitamui-common-input class="field-street" formControlName="street" maxlength="250" required placeholder="N° et nom de rue" i18n-placeholder="Customer street input placeholder@@customerCreateStreetInputPlaceholder"> - <vitamui-common-input-error *ngIf="form.get('address.street')?.touched && !!form.get('address.street')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input class="field-street" formControlName="street" maxlength="250" required + placeholder="N° et nom de rue" + i18n-placeholder="Customer street input placeholder@@customerCreateStreetInputPlaceholder"> + <vitamui-common-input-error + *ngIf="form.get('address.street')?.touched && !!form.get('address.street')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> </div> <div class="d-flex"> - <vitamui-common-input class="field-zip-code" formControlName="zipCode" maxlength="10" required placeholder="Code postal" i18n-placeholder="Customer zip code input placeholder@@customerCreateZipCodeInputPlaceholder"> - <vitamui-common-input-error *ngIf="form.get('address.zipCode')?.touched && !!form.get('address.zipCode')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input class="field-zip-code" formControlName="zipCode" maxlength="10" required + placeholder="Code postal" + i18n-placeholder="Customer zip code input placeholder@@customerCreateZipCodeInputPlaceholder"> + <vitamui-common-input-error + *ngIf="form.get('address.zipCode')?.touched && !!form.get('address.zipCode')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> - <vitamui-common-input class="field-city" formControlName="city" maxlength="100" required placeholder="Ville" i18n-placeholder="Customer city input placeholder@@customerCreateCityInputPlaceholder"> - <vitamui-common-input-error *ngIf="form.get('address.city')?.touched && !!form.get('address.city')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> + <vitamui-common-input class="field-city" formControlName="city" maxlength="100" required placeholder="Ville" + i18n-placeholder="Customer city input placeholder@@customerCreateCityInputPlaceholder"> + <vitamui-common-input-error + *ngIf="form.get('address.city')?.touched && !!form.get('address.city')?.errors?.required" + i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> <mat-form-field class="field-country vitamui-mat-select"> - <mat-select - formControlName="country" - required - placeholder="Pays" i18n-placeholder="Customer country select placeholder@@customerCreateCountrySelectPlaceholder" - panelClass="vitamui-mat-select" - > + <mat-select formControlName="country" required placeholder="Pays" + i18n-placeholder="Customer country select placeholder@@customerCreateCountrySelectPlaceholder" + panelClass="vitamui-mat-select"> <!-- TODO Fetch those values from a referential --> <mat-option value="GB">Royaume Uni</mat-option> <mat-option value="FR">France</mat-option> @@ -71,7 +104,8 @@ </ng-container> <div class="d-flex"> - <label for="language" class="inline-label label-language" i18n="Interface language (by default for the user)@@customerCreateLanguageInputLabel"> + <label for="language" class="inline-label label-language" + i18n="Interface language (by default for the user)@@customerCreateLanguageInputLabel"> Langue de l'interface <span class="required-marker">*</span><br> <small>(par défault pour l'utilisateur)</small> </label> @@ -88,8 +122,10 @@ </div> <div class="actions"> - <button type="button" class="btn primary" cdkStepperNext [disabled]="firstStepInvalid()" i18n="Next step button label@@customerCreateNextButton">Suivant</button> - <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> + <button type="button" class="btn primary" cdkStepperNext [disabled]="firstStepInvalid()" + i18n="Next step button label@@customerCreateNextButton">Suivant</button> + <button type="button" class="btn cancel" (click)="onCancel()" + i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> </div> </div> </cdk-step> @@ -99,19 +135,21 @@ <h2 i18n="Customer access title@@customerCreateTitle2">Accès client</h2> <div class="d-flex"> - <label for="passwordRevocationDelay" class="inline-label label-password-revocation-delay" i18n="Duration until password revocation (since the last change)@@customerCreatePasswordRevocationInputLabel"> + <label for="passwordRevocationDelay" class="inline-label label-password-revocation-delay" + i18n="Duration until password revocation (since the last change)@@customerCreatePasswordRevocationInputLabel"> Durée de révocation du mot de passe<br> <small>(depuis le dernier changement)</small> </label> <mat-form-field class="field-password-revocation-delay vitamui-mat-select"> - <mat-select - formControlName="passwordRevocationDelay" - placeholder="Durée de révocation des mots de passe" i18n-placeholder="Customer password revocation delay select placeholder@@customerCreatePasswordRevocationDelaySelectPlaceholder" - panelClass="vitamui-mat-select" - > - <mat-option [value]="6" i18n="6 months@@customerCreatePasswordRevocationDelayOption6Months">6 mois</mat-option> - <mat-option [value]="9" i18n="9 months@@customerCreatePasswordRevocationDelayOption9Months">9 mois</mat-option> - <mat-option [value]="12" i18n="12 months@@customerCreatePasswordRevocationDelayOption12Months">12 mois</mat-option> + <mat-select formControlName="passwordRevocationDelay" placeholder="Durée de révocation des mots de passe" + i18n-placeholder="Customer password revocation delay select placeholder@@customerCreatePasswordRevocationDelaySelectPlaceholder" + panelClass="vitamui-mat-select"> + <mat-option [value]="6" i18n="6 months@@customerCreatePasswordRevocationDelayOption6Months">6 mois + </mat-option> + <mat-option [value]="9" i18n="9 months@@customerCreatePasswordRevocationDelayOption9Months">9 mois + </mat-option> + <mat-option [value]="12" i18n="12 months@@customerCreatePasswordRevocationDelayOption12Months">12 mois + </mat-option> </mat-select> <div class="select-arrow"> <i class="material-icons">keyboard_arrow_up</i> @@ -124,10 +162,14 @@ <label for="otp" i18n="OTP label@@customerCreateOTPInputLabel"> Validation en deux étapes <span class="required-marker">*</span> </label> - <mat-button-toggle-group formControlName="otp" #group="matButtonToggleGroup" class="vitamui-button-toggle-group"> - <mat-button-toggle value="DISABLED" i18n="OTP deactivate button@@customerCreateOTPDeactivatedButton">Non</mat-button-toggle> - <mat-button-toggle value="OPTIONAL" i18n="OTP optional button@@customerCreateOTPOptionalButton">Optionnelle</mat-button-toggle> - <mat-button-toggle value="MANDATORY" i18n="OTP mandatory button@@customerCreateOTPMandatoryButton">Obligatoire</mat-button-toggle> + <mat-button-toggle-group formControlName="otp" #group="matButtonToggleGroup" + class="vitamui-button-toggle-group"> + <mat-button-toggle value="DISABLED" i18n="OTP deactivate button@@customerCreateOTPDeactivatedButton">Non + </mat-button-toggle> + <mat-button-toggle value="OPTIONAL" i18n="OTP optional button@@customerCreateOTPOptionalButton">Optionnelle + </mat-button-toggle> + <mat-button-toggle value="MANDATORY" i18n="OTP mandatory button@@customerCreateOTPMandatoryButton"> + Obligatoire</mat-button-toggle> </mat-button-toggle-group> </div> @@ -136,20 +178,21 @@ Restriction de domaine e-mail<br> <small>(cliquer sur l'étiquette pour définir le domaine par défaut)</small> </label> - <app-domains-input - formControlName="emailDomains" - placeholder="domaine.xyz" i18n-placeholder="Email domain input placeholder@@customerCreateEmailDomainInputPlaceholder" + <app-domains-input formControlName="emailDomains" placeholder="domaine.xyz" + i18n-placeholder="Email domain input placeholder@@customerCreateEmailDomainInputPlaceholder" [selected]="form.get('defaultEmailDomain').value" - (selectedChange)="form.get('defaultEmailDomain').setValue($event)" - ></app-domains-input> + (selectedChange)="form.get('defaultEmailDomain').setValue($event)"></app-domains-input> </div> <div class="actions"> - <button type="button" class="btn primary" cdkStepperNext [disabled]="secondStepInvalid()" i18n="Next step button label@@customerCreateNextButton">Suivant</button> - <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> + <button type="button" class="btn primary" cdkStepperNext [disabled]="secondStepInvalid()" + i18n="Next step button label@@customerCreateNextButton">Suivant</button> + <button type="button" class="btn cancel" (click)="onCancel()" + i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> </div> <button type="button" class="back" cdkStepperPrevious> - <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> + <i class="material-icons">arrow_back</i> + <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> </button> </div> </cdk-step> @@ -159,21 +202,23 @@ <h2 i18n="Customer graphical identity title@@customerGraphicalIdentityTitle">Identité graphique du client</h2> <div class="form-group"> - <vitamui-common-slide-toggle formControlName="hasCustomGraphicIdentity" i18n="Custom visual identity@@customerCreateVisualIdentityToggleLabel">Afficher l'identité graphique personnalisée</vitamui-common-slide-toggle> + <vitamui-common-slide-toggle formControlName="hasCustomGraphicIdentity" + i18n="Custom visual identity@@customerCreateVisualIdentityToggleLabel">Afficher l'identité graphique + personnalisée</vitamui-common-slide-toggle> </div> <div class="d-flex"> <div class="upload-text"> - <div class="upload" i18n="Customer graphical identity upload label@@customerGraphicalIdentityUploadLabel"><span class="underline" (click)="addLogo()">Sélectionner</span> le logo du client</div> - <div i18n="Customer graphical identity max size label@@customerGraphicalIdentityMaxSizeLabel">(taille max 280px * 100px)</div> + <div class="upload" i18n="Customer graphical identity upload label@@customerGraphicalIdentityUploadLabel"> + <span class="underline" (click)="addLogo()">Sélectionner</span> le logo du client</div> + <div i18n="Customer graphical identity max size label@@customerGraphicalIdentityMaxSizeLabel">(taille max + 280px * 100px)</div> </div> - <div class="drag-and-drop-area" [ngClass]="{'on-over': hasDropZoneOver}" - vitamuiCommonDragAndDrop - (fileToUploadEmitter)="onImageDropped($event)" - (fileDragOverEmitter)="onImageDragOver($event)" + <div class="drag-and-drop-area" [ngClass]="{'on-over': hasDropZoneOver}" vitamuiCommonDragAndDrop + (fileToUploadEmitter)="onImageDropped($event)" (fileDragOverEmitter)="onImageDragOver($event)" (fileDragLeaveEmitter)="onImageDragLeave($event)"> <div *ngIf="imageUrl" class="image-container"> - <img class="logo-image" [src]="imageUrl"/> + <img class="logo-image" [src]="imageUrl" /> </div> <input type="file" #fileSearch class="input-file" (change)="handleFileInput($event.target.files)"> <div class="drop-area"> @@ -185,40 +230,48 @@ </div> <div class="customer-colors-input"> - <app-customer-colors-input formControlName="themeColors" [disabled]="!hasCustomGraphicIdentity" themeOverloadSelector="form#formCreateCustomer"></app-customer-colors-input> + <app-customer-colors-input formControlName="themeColors" [disabled]="!hasCustomGraphicIdentity" + themeOverloadSelector="form#formCreateCustomer"></app-customer-colors-input> </div> <div class="error-message" *ngIf="hasError"> {{ message }} </div> <div class="actions"> - <button type="button" class="btn primary" cdkStepperNext [disabled]="!thirdStepValid()" i18n="Create owner button@@customerCreateCreateOwnerButton"> - Créer le propriétaire - <small> des éléments de preuves</small> - </button> - <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> + <button type="button" class="btn primary" cdkStepperNext [disabled]="!thirdStepValid()" + i18n="Create owner button@@customerCreateCreateOwnerButton"> + Créer le propriétaire + <small> des éléments de preuves</small> + </button> + <button type="button" class="btn cancel" (click)="onCancel()" + i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> </div> <button type="button" class="back" cdkStepperPrevious> - <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> + <i class="material-icons">arrow_back</i> + <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> </button> </div> - </cdk-step> <cdk-step> <div class="content"> - <h2 i18n="Create evidence owner title@@customerCreateTitle3">Création du propriétaire des éléments de preuve</h2> + <h2 i18n="Create evidence owner title@@customerCreateTitle3">Création du propriétaire des éléments de preuve + </h2> <div class="form-group"> <app-owner-form [formControl]="form.get(['owners', 0])" [customerInfo]="customerInfo"></app-owner-form> - <p class="hint" i18n="the evidence tenant is automatically created with the owner@@customerCreateHint">Le coffre des éléments de preuve est créé automatiquement avec son propriétaire</p> + <p class="hint" i18n="the evidence tenant is automatically created with the owner@@customerCreateHint">Le + coffre des éléments de preuve est créé automatiquement avec son propriétaire</p> </div> - - <button type="submit" class="btn primary" [disabled]="form.pending || form.invalid || creating" i18n="Finish customer creation button@@customerCreateFinishButton">Terminer</button> - <button type="button" class="btn cancel" (click)="onCancel()" i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> + + <button type="submit" class="btn primary" + i18n="Finish customer creation button@@customerCreateFinishButton" [disabled]="lastStepIsInvalid()">Terminer</button> + <button type="button" class="btn cancel" (click)="onCancel()" + i18n="Cancel customer creation@@customerCreateCancelButton">Annuler</button> <button type="button" class="back" cdkStepperPrevious> - <i class="material-icons">arrow_back</i> <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> + <i class="material-icons">arrow_back</i> + <ng-container i18n="Previous step button label@@customerCreateBackButton">Retour</ng-container> </button> </div> </cdk-step> </vitamui-common-stepper> -</form> +</form> \ No newline at end of file diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss index b93541ff..50e5ee46 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.scss @@ -217,3 +217,19 @@ button > small { font-size: 14px; margin-bottom: 30px; } + +.selected { + background-color: var(--vitamui-secondary); + color: $white; +} + +:host::ng-deep { + .mat-button-toggle-button { + min-width: 100px; + } + + .mat-button-toggle-label-content { + max-height: 40px!important; + line-height: 2!important; + } +} \ No newline at end of file diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts index f349a3e8..3b5dcfe8 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-create.component.ts @@ -35,7 +35,7 @@ * knowledge of the CeCILL-C license and that you accept its terms. */ import { merge, Subscription } from 'rxjs'; -import {ConfirmDialogService, Customer, OtpState, ThemeService} from 'ui-frontend-common'; +import { AddressType, ConfirmDialogService, Customer, OtpState, ThemeService } from 'ui-frontend-common'; import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @@ -45,8 +45,16 @@ import { CustomerService } from '../../core/customer.service'; import { CustomerCreateValidators } from './customer-create.validators'; const PROGRESS_BAR_MULTIPLICATOR = 100; + const IMAGE_TYPE_PREFIX = 'image'; +interface CustomerInfo { + code: string; + name: string; + companyName: string; + addressType: AddressType; +} + @Component({ selector: 'app-customer-create', templateUrl: './customer-create.component.html', @@ -54,30 +62,53 @@ const IMAGE_TYPE_PREFIX = 'image'; }) export class CustomerCreateComponent implements OnInit, OnDestroy { - form: FormGroup; - stepIndex = 0; - customerInfo: { code: string, name: string, companyName: string } = { code: '', name: '', companyName: '' }; - hasCustomGraphicIdentity = false; - hasDropZoneOver = false; - imageToUpload: File = null; - lastImageUploaded: File = null; - imageUrl: any; - lastUploadedImageUrl: any; - lastColors: {[key: string]: string}; - hasError = true; - message: string; - creating = false; - - hexPattern = /#([0-9A-Fa-f]{6})/; + public form: FormGroup; + + public stepIndex = 0; + + public hasCustomGraphicIdentity = false; + + public hasDropZoneOver = false; + + public imageToUpload: File = null; + + public lastImageUploaded: File = null; + + public imageUrl: any; + + public lastUploadedImageUrl: any; + + public lastColors: {[key: string]: string}; + + public hasError = true; + + + public message: string; + + public creating = false; + + public JSON = JSON; + + public hexPattern = /#([0-9A-Fa-f]{6})/; + + public customerInfo: CustomerInfo = { + code: '', + name: '', + companyName: '', + addressType: AddressType.POSTAL + }; + + public ADDRESS_TYPE = AddressType; + + @ViewChild('fileSearch', { static: false }) public fileSearch: any; // stepCount is the total number of steps and is used to calculate the advancement of the progress bar. // We could get the number of steps using ViewChildren(StepComponent) but this triggers a // "Expression has changed after it was checked" error so we instead manually define the value. // Make sure to update this value whenever you add or remove a step from the template. private stepCount = 4; - private keyPressSubscription: Subscription; - @ViewChild('fileSearch', { static: false }) fileSearch: any; + private keyPressSubscription: Subscription; constructor( public dialogRef: MatDialogRef<CustomerCreateComponent>, @@ -103,16 +134,18 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { passwordRevocationDelay: 6, otp: OtpState.OPTIONAL, address: this.formBuilder.group({ - street: [null, Validators.required], - zipCode: [null, Validators.required], - city: [null, Validators.required], - country: ['FR', Validators.required], + street: [''], + zipCode: [''], + city: [''], + country: ['FR'] }), + internalCode: [null], + addressType: [AddressType.POSTAL, Validators.required], language: ['FRENCH', Validators.required], emailDomains: [null, Validators.required], defaultEmailDomain: [null, Validators.required], hasCustomGraphicIdentity: false, - themeColors: null, + themeColors: [null], owners: this.formBuilder.array([ this.formBuilder.control(null, Validators.required), ]) @@ -155,14 +188,16 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { merge( this.form.get('code').valueChanges, this.form.get('name').valueChanges, - this.form.get('companyName').valueChanges + this.form.get('companyName').valueChanges, + this.form.get('addressType').valueChanges ) .subscribe(() => { // reset object to trigger customerInfo input update in child component this.customerInfo = { code: this.form.get('code').value, name: this.form.get('name').value, - companyName: this.form.get('companyName').value + companyName: this.form.get('companyName').value, + addressType: this.form.get('addressType').value }; }); } @@ -176,9 +211,8 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { } onSubmit() { - if (this.form.invalid) { return; } + if (this.lastStepIsInvalid()) { return; } this.creating = true; - const customer: Customer = this.updateForCustomerModel(this.form.value); this.customerService.create(customer, this.imageToUpload).subscribe( @@ -191,6 +225,14 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { }); } + isFormValid(form: FormGroup): boolean { + if (this.form.get('addressType').value === AddressType.INTERNAL_CODE) { + return form.get('internalCode').valid; + } else { + return form.valid; + } + } + updateForCustomerModel(formValue: any): Customer { const { themeColors, ...customer } = formValue; const customerTheme = { @@ -254,13 +296,18 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { } firstStepInvalid(): boolean { - return this.form.get('code').invalid || this.form.get('code').pending || - this.form.get('name').invalid || this.form.get('name').pending || - this.form.get('companyName').invalid || this.form.get('companyName').pending || - this.form.get('address.street').invalid || this.form.get('address.street').pending || + const response = this.form.get('code').invalid || this.form.get('code').pending || + this.form.get('name').invalid || this.form.get('name').pending || + this.form.get('companyName').invalid || this.form.get('companyName').pending; + + if (this.form.get('addressType').value === AddressType.POSTAL) { + return response || this.form.get('address.street').invalid || this.form.get('address.street').pending || this.form.get('address.zipCode').invalid || this.form.get('address.zipCode').pending || this.form.get('address.city').invalid || this.form.get('address.city').pending || this.form.get('address.country').invalid || this.form.get('address.country').pending; + } else if (this.form.get('addressType').value === AddressType.INTERNAL_CODE) { + return response || this.form.get('internalCode').invalid || this.form.get('internalCode').pending; + } } secondStepInvalid(): boolean { @@ -277,6 +324,11 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { ); } + lastStepIsInvalid(): boolean { + const invalid = this.firstStepInvalid() || this.secondStepInvalid() || !this.thirdStepValid(); + return this.form.pending || invalid || this.creating; + } + private isThemeColorsFormValid(): boolean { const value = this.form.get('themeColors').value; for (const key of Object.keys(value)) { diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts index 11c75ac6..6f66b08f 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-list/customer-list.service.ts @@ -94,6 +94,7 @@ export class CustomerListService extends SearchService<Customer> { passwordRevocationDelay: customer.passwordRevocationDelay, otp: customer.otp, address: customer.address, + addressType: customer.addressType, language: customer.language, emailDomains: customer.emailDomains, defaultEmailDomain: customer.defaultEmailDomain, diff --git a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html index 7ae17390..62756a5f 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html +++ b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.html @@ -1,4 +1,6 @@ <ng-container [formGroup]="form"> + + <vitamui-common-input class="field-code" formControlName="code" maxlength="20" required placeholder="Code propriétaire" i18n-placeholder="Owner code input placeholder@@ownerFormCodeInputPlaceholder"> <ng-container *ngIf="form.get('code')?.touched"> <vitamui-common-input-error *ngIf="!!form?.get('code')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> @@ -14,7 +16,13 @@ <vitamui-common-input-error *ngIf="form.get('companyName')?.touched && !!form.get('companyName')?.errors?.required" i18n="Required field error hint@@formErrorRequiredField">Champ requis</vitamui-common-input-error> </vitamui-common-input> </div> - <ng-container formGroupName="address"> + + <div *ngIf="form.get('addressType').value === ADDRESS_TYPE.INTERNAL_CODE"> + <vitamui-common-input class="field-street" formControlName="internalCode" maxlength="20" placeholder="Code interne" + i18n-placeholder="Internal code@@OwnerInternalCodePlaceholder"></vitamui-common-input> + </div> + + <ng-container formGroupName="address" *ngIf="form.get('addressType').value === ADDRESS_TYPE.POSTAL"> <div> <vitamui-common-input class="field-street" formControlName="street" maxlength="250" placeholder="N° et nom de la rue" i18n-placeholder="Owner street input placeholder@@ownerFormStreetInputPlaceholder"></vitamui-common-input> </div> @@ -24,8 +32,7 @@ <mat-select formControlName="country" placeholder="Pays" i18n-placeholder="Owner country select placeholder@@ownerFormCountrySelectPlaceholder" - panelClass="vitamui-mat-select" - > + panelClass="vitamui-mat-select"> <!-- TODO Fetch those values from a referential --> <mat-option value="GB">Royaume Uni</mat-option> <mat-option value="FR">France</mat-option> diff --git a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts index 9e6c72f9..2c5185a9 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/owner-form/owner-form.component.ts @@ -39,6 +39,7 @@ import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { merge } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; +import { AddressType, Customer } from 'ui-frontend-common'; import { Owner } from 'ui-frontend-common'; import { OwnerFormValidators } from './owner-form.validators'; @@ -61,30 +62,42 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn private sub: any; + public ADDRESS_TYPE = AddressType; + @Input() set customerId(customerId: string) { this._customerId = customerId; if (!this.form) { return; } this.form.get('customerId').setValue(customerId); } + get customerId() { return this._customerId; } + // tslint:disable-next-line:variable-name private _customerId: string; @Input() - set customerInfo(customerInfo: any) { + set customerInfo(customerInfo: Customer) { this._customerInfo = customerInfo; if (customerInfo && this.form) { - this.form.patchValue({ code: customerInfo.code, name: customerInfo.name, companyName: customerInfo.companyName }); + this.form.patchValue({ + code: customerInfo.code, + name: customerInfo.name, + companyName: customerInfo.companyName, + addressType: customerInfo.addressType + }); } } + get customerInfo() { return this._customerInfo; } + // tslint:disable-next-line:variable-name private _customerInfo: any; constructor(private formBuilder: FormBuilder, private ownerFormValidators: OwnerFormValidators) {} onChange = (_: any) => {}; + onTouched = () => {}; ngOnInit() { @@ -99,6 +112,8 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn ], name: [null, Validators.required], companyName: [null, Validators.required], + internalCode: [null], + addressType: [this.customerInfo.addressType], address: this.formBuilder.group({ street: null, zipCode: null, @@ -107,6 +122,7 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn }), readonly: false }); + this.subscribeToValueChanges(); } @@ -124,6 +140,8 @@ export class OwnerFormComponent implements ControlValueAccessor, OnDestroy, OnIn code: null, name: null, companyName: null, + internalCode: null, + addressType: this.customerInfo.addressType, address: { street: null, zipCode: null, -- GitLab