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 ea8dead0c35597b890a03adaea807a8e49c66ba9..e6436ce4e8a931213a5afb0b891a777ca0613c1f 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 @@ -327,7 +327,7 @@ public class CustomerInternalService extends VitamUICrudService<CustomerDto, Cus case "themeColors": Object themeColorsValue = entry.getValue(); - System.out.println("UPDATE THEME COLORS : "); + LOGGER.debug("Update theme colors"); System.out.println(themeColorsValue); if (themeColorsValue instanceof Map) { @@ -345,23 +345,23 @@ public class CustomerInternalService extends VitamUICrudService<CustomerDto, Cus } private void processGraphicIdentityPatch(final boolean newCustomGraphicIdentityValue, final Customer customer, final Optional<MultipartFile> logo) { + + customer.getGraphicIdentity().setHasCustomGraphicIdentity(newCustomGraphicIdentityValue); + String base64logo = null; if(logo.isPresent()) { try { + base64logo = VitamUIUtils.getBase64(logo.get()); + + customer.getGraphicIdentity().setLogoDataBase64(base64logo); + } catch (IOException e) { throw new InvalidFormatException("Cannot store logo", e); } } - if(newCustomGraphicIdentityValue ^ logo.isPresent()) { - throw new IllegalArgumentException( - String.format("Unable to patch customer %s : Custom graphic identity toggle doesn't match logo provision (logo provided without enabling customization, or customization enabled without providing a logo).", customer.getId())); - } - - customer.getGraphicIdentity().setHasCustomGraphicIdentity(newCustomGraphicIdentityValue); - customer.getGraphicIdentity().setLogoDataBase64(base64logo); } @Transactional diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts index 3ed7d36709b4487aea7e19a7554e48b76e14bf16..03be8298a5eeb75c3f58eaecc7e8eccad635be62 100644 --- a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts +++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts @@ -36,7 +36,7 @@ */ /* tslint:disable: no-use-before-declare */ import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Component, ElementRef, forwardRef, HostBinding, HostListener, Input, ViewChild } from '@angular/core'; +import {Component, ElementRef, forwardRef, HostBinding, HostListener, Input, OnInit, ViewChild} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; export const VITAMUI_INPUT_VALUE_ACCESSOR: any = { @@ -51,12 +51,13 @@ export const VITAMUI_INPUT_VALUE_ACCESSOR: any = { styleUrls: ['./vitamui-input.component.scss'], providers: [VITAMUI_INPUT_VALUE_ACCESSOR] }) -export class VitamUIInputComponent implements ControlValueAccessor { +export class VitamUIInputComponent implements ControlValueAccessor, OnInit { @Input() type = 'text'; @Input() maxlength: number; @Input() placeholder: string; @Input() autofocus: boolean; + @Input() value: string | number; @Input() get required(): boolean { return this._required; } set required(value: boolean) { this._required = coerceBooleanProperty(value); } @@ -73,7 +74,6 @@ export class VitamUIInputComponent implements ControlValueAccessor { @HostBinding('class.vitamui-focused') focused = false; @HostBinding('class.vitamui-float') labelFloat = false; - value: string | number; onChange = (_: any) => { }; onTouched = () => { }; @@ -83,6 +83,10 @@ export class VitamUIInputComponent implements ControlValueAccessor { this.input.nativeElement.focus(); } + ngOnInit() { + this.labelFloat = !!this.value; + } + writeValue(value: string | number) { this.value = value; this.labelFloat = !!this.value; @@ -109,6 +113,7 @@ export class VitamUIInputComponent implements ControlValueAccessor { onFocus() { this.focused = true; + this.onTouched(); } onBlur() { diff --git a/ui/ui-frontend-common/src/app/modules/startup.service.ts b/ui/ui-frontend-common/src/app/modules/startup.service.ts index 835e7a61ab94fec281e2baa9b14af5e9294ffb9f..b0fd5babc3597cf061e742fb5c6a6c5c5e5432ad 100644 --- a/ui/ui-frontend-common/src/app/modules/startup.service.ts +++ b/ui/ui-frontend-common/src/app/modules/startup.service.ts @@ -50,8 +50,6 @@ import { AppConfiguration, AuthUser } from './models'; import {ThemeService} from './theme.service'; const WARNING_DURATION = 2000; -const DARK_SUFFIX = '-dark'; -const LIGHT_SUFFIX = '-light'; @Injectable({ providedIn: 'root' @@ -95,16 +93,21 @@ export class StartupService { }) .then(() => { - const applicationColorMap = this.configurationData.THEME_COLORS; - const customerColorMap = this.authService.user.basicCustomer.graphicIdentity.themeColors; + let customerColorMap = null; - this.themeService.init(applicationColorMap, customerColorMap); + if (this.authService.user.basicCustomer.graphicIdentity.hasCustomGraphicIdentity) { + customerColorMap = this.authService.user.basicCustomer.graphicIdentity.themeColors; + } + + this.themeService.init(this.configurationData.THEME_COLORS); - for (const themeColorsKey in this.themeService.themeColors) { - if (this.themeService.themeColors.hasOwnProperty(themeColorsKey)) { - this.themeWrapper.style.setProperty('--' + themeColorsKey, this.themeService.themeColors[themeColorsKey]); + const themeColors = this.themeService.getThemeColors(customerColorMap); + for (const key in themeColors) { + if (themeColors.hasOwnProperty(key)) { + this.themeWrapper.style.setProperty('--' + key, themeColors[key]); } } + }) .then(() => this.applicationService.list().toPromise()); } diff --git a/ui/ui-frontend-common/src/app/modules/theme.service.ts b/ui/ui-frontend-common/src/app/modules/theme.service.ts index 9f8819b8ea946cb4469d3eef8f136819193fddc5..c1cf784b897b96dd5830219cc581ddca19a95c4a 100644 --- a/ui/ui-frontend-common/src/app/modules/theme.service.ts +++ b/ui/ui-frontend-common/src/app/modules/theme.service.ts @@ -1,16 +1,13 @@ import { Injectable } from '@angular/core'; import {getColorFromMaps, ThemeColors} from './utils'; + @Injectable({ providedIn: 'root' }) export class ThemeService { - applicationColorMap; - - customerColorMap; - - themeColors: ThemeColors = { + defaultMap: ThemeColors = { 'vitamui-primary': '#fe4f02', 'vitamui-primary-light': '#ff8559', 'vitamui-primary-light-20': '#ffa789', @@ -21,43 +18,23 @@ export class ThemeService { }; + applicationColorMap; + constructor() { } - init(appMap, customerMap) { + init(appMap) { this.applicationColorMap = appMap; - this.customerColorMap = customerMap; - this.themeColors = this.getThemeColors(customerMap); - } - - getThemeColors(customerColorMap: any) { - - const applicationColorMap = this.applicationColorMap; - const defaultPrimary = this.themeColors['vitamui-primary']; - const defaultSecondary = this.themeColors['vitamui-secondary']; - - return { - 'vitamui-primary': getColorFromMaps('vitamui-primary', defaultPrimary, applicationColorMap, customerColorMap), - 'vitamui-primary-light': getColorFromMaps('vitamui-primary-light', null, applicationColorMap, customerColorMap), - 'vitamui-primary-light-20': getColorFromMaps('vitamui-primary-light-20', null, applicationColorMap, customerColorMap), - 'vitamui-secondary': getColorFromMaps('vitamui-secondary', defaultSecondary, applicationColorMap, customerColorMap), - 'vitamui-secondary-light': getColorFromMaps('vitamui-secondary-light', null, applicationColorMap, customerColorMap), - 'vitamui-secondary-light-8': getColorFromMaps('vitamui-secondary-light-8', null, applicationColorMap, customerColorMap), - 'vitamui-secondary-dark-5': getColorFromMaps('vitamui-secondary-dark-5', null, applicationColorMap, customerColorMap) - }; - } - refresh(primary: string, secondary: string): void { - this.themeColors = { - 'vitamui-primary': getColorFromMaps('vitamui-primary', primary, null, null), - 'vitamui-primary-light': getColorFromMaps('vitamui-primary-light', null, null, null), - 'vitamui-primary-light-20': getColorFromMaps('vitamui-primary-light-20', null, null, null), - 'vitamui-secondary': getColorFromMaps('vitamui-secondary', secondary, null, null), - 'vitamui-secondary-light': getColorFromMaps('vitamui-secondary-light', null, null, null), - 'vitamui-secondary-light-8': getColorFromMaps('vitamui-secondary-light-8', null, null, null), - 'vitamui-secondary-dark-5': getColorFromMaps('vitamui-secondary-dark-5', null, null, null) - }; + getThemeColors(customerColors = null): {[key: string]: string} { + const colors = {}; + for (const key in this.defaultMap) { + if (this.defaultMap.hasOwnProperty(key)) { + colors[key] = getColorFromMaps(key, this.defaultMap, this.applicationColorMap, customerColors); + } + } + return colors; } } diff --git a/ui/ui-frontend-common/src/app/modules/utils/colors.util.ts b/ui/ui-frontend-common/src/app/modules/utils/colors.util.ts index 922224386fc20132b7bf247046ab80fad9443e86..a97edc9ebb2d54fe0c037417bf514f152c8ad044 100644 --- a/ui/ui-frontend-common/src/app/modules/utils/colors.util.ts +++ b/ui/ui-frontend-common/src/app/modules/utils/colors.util.ts @@ -14,24 +14,26 @@ class HSL { /** * Find, compute or return default value for the given name and maps of colors. * @param name the color name - * @param defaultColor the color default value if no overriding in priority and fallback maps + * @param defaultMap the default color map if no overriding in priority and fallback maps * @param fallbackMap the fallback map. The function will search in it if no color is found in priority map. Should be application config * @param priorityMap the priority map. If the color is found in it, the fallbackMap is not used. Should be customer config * @return The hex RBG color find or computed from all sources */ -export function getColorFromMaps(name: string, defaultColor: string, fallbackMap: any, priorityMap: any): string { +export function getColorFromMaps(name: string, defaultMap: any, fallbackMap: any, priorityMap: any): string { const customColor = getColorFromMap(name, priorityMap); + if ( customColor ) { return customColor; } + const applicationColor = getColorFromMap(name, fallbackMap); if ( applicationColor ) { return applicationColor; } - return defaultColor; + return getColorFromMap(name, defaultMap); } function getColorFromMap(colorName: string, colorMap: any) { @@ -74,9 +76,7 @@ function convertToLightColor(color: string, lightModificator: number = 10) { return color; } - if (!lightModificator) { - lightModificator = 10; - } + lightModificator *= 2; const max = 255; const rgbValue: RGB = hexToRgb(color); @@ -84,7 +84,7 @@ function convertToLightColor(color: string, lightModificator: number = 10) { // lighten hslValue.l = Math.min(hslValue.l + lightModificator, 100); - const lightRGBvalue: RGB = hslToRgb(hslValue); + const lightRGBvalue: RGB = hslToRgbExperimental(hslValue); return '#' + toHex(lightRGBvalue.r) + toHex(lightRGBvalue.g) + toHex(lightRGBvalue.b); } @@ -99,12 +99,14 @@ function convertToDarkColor(color: string, lightModificator: number = 10) { return color; } + lightModificator *= 2; + const rgbValue: RGB = hexToRgb(color); const hslValue: HSL = rgbToHsl(rgbValue); // darken hslValue.l = Math.max(hslValue.l - lightModificator, 0); - const darkRGBvalue: RGB = hslToRgb(hslValue); + const darkRGBvalue: RGB = hslToRgbExperimental(hslValue); return '#' + toHex(darkRGBvalue.r) + toHex(darkRGBvalue.g) + toHex(darkRGBvalue.b); } @@ -124,30 +126,34 @@ function hexToRgb(hex): RGB { null; } -function hslToRgb(inputHSL): RGB { - const hsl: HSL = new HSL( inputHSL.h, inputHSL.s / 100, inputHSL.l / 100); - const rgb: RGB = new RGB(hsl.l, hsl.l, hsl.l); - - // if no saturation, all colors parts are the same and equls to lightness. Nothing to do - if (hsl.s !== 0) { - const q = hsl.l < 0.5 ? hsl.l * (1 + hsl.s) : hsl.l + hsl.s - hsl.l * hsl.s; - const p = 2 * hsl.l - q; - - rgb.r = Math.round(hueToRGBComponent(p, q, hsl.h + 1 / 3) * 255); - rgb.g = Math.round(hueToRGBComponent(p, q, hsl.h) * 255); - rgb.b = Math.round(hueToRGBComponent(p, q, hsl.h - 1 / 3) * 255); +function hslToRgbExperimental(inputHSL): RGB { + const hsl: HSL = new HSL( inputHSL.h * 360, inputHSL.s / 100, inputHSL.l / 100); + let rgb: RGB; + + const c = (1 - Math.abs(2 * hsl.l - 1)) * hsl.s; + const x = c * (1 - Math.abs((hsl.h / 60) % 2 - 1)); + const m = hsl.l - c / 2; + + if (hsl.h < 60) { + rgb = new RGB(c, x, 0); + } else if (hsl.h < 120) { + rgb = new RGB(x, c, 0); + } else if (hsl.h < 180) { + rgb = new RGB(0, c, x); + } else if (hsl.h < 240) { + rgb = new RGB(0, x, c); + } else if (hsl.h < 300) { + rgb = new RGB(x, 0, c); + } else if (hsl.h < 360) { + rgb = new RGB(c, 0, x); } + rgb.r = Math.round((rgb.r + m) * 255); + rgb.g = Math.round((rgb.g + m) * 255); + rgb.b = Math.round((rgb.b + m) * 255); + return rgb; -} -function hueToRGBComponent(p, q, t): number { - if (t < 0) { t += 1; } - if (t > 1) { t -= 1; } - if (t < 1 / 6) { return p + (q - p) * 6 * t; } - if (t < 1 / 2) { return q; } - if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; } - return p; } function rgbToHsl(inputRGB: RGB): HSL { diff --git a/ui/ui-frontend-common/src/sass/material/_preview-tab.scss b/ui/ui-frontend-common/src/sass/material/_preview-tab.scss index 8d1a5ef223d2c7f7faeb25b4e868de681cb1f6a0..00cffc75011ea4ef0a33ba4b4a2fac8f3051d70c 100644 --- a/ui/ui-frontend-common/src/sass/material/_preview-tab.scss +++ b/ui/ui-frontend-common/src/sass/material/_preview-tab.scss @@ -50,7 +50,7 @@ } .mat-tab-body-content { - padding: 30px 105px 30px 40px; + padding: 30px 85px 30px 40px; overflow: visible; } } diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.html b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.html index c7235b490942bb64382dd9c59b274c0980292a8c..55a1365c666087b17f18ef6d21a2e463f13e1a1b 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.html +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.html @@ -2,19 +2,22 @@ <div [formGroup]="colorForm"> <p><vitamui-common-input class="field-primary-color" formControlName="primary" maxlength="7" placeholder="Couleur principale" - i18n-placeholder="Customer primary theme color input placeholder@@customerUpdatePrimaryColorThemeInputPlaceholder" - (change)="handleValueChange()" required > + i18n-placeholder="Customer primary theme color input placeholder@@customerUpdatePrimaryColorThemeInputPlaceholder"> </vitamui-common-input> <span class="field-color-preview primary"></span> + <span class="field-color-preview primary-light"></span> + <span class="field-color-preview primary-light-20"></span> </p> <p> <vitamui-common-input class="field-secondary-color" formControlName="secondary" maxlength="7" placeholder="Couleur secondaire" - i18n-placeholder="Customer secondary theme color input placeholder@@customerUpdateSecondaryColorThemeInputPlaceholder" - (change)="handleValueChange()" required > + i18n-placeholder="Customer secondary theme color input placeholder@@customerUpdateSecondaryColorThemeInputPlaceholder"> </vitamui-common-input> <span class="field-color-preview secondary"></span> + <span class="field-color-preview secondary-light"></span> + <span class="field-color-preview secondary-light-8"></span> + <span class="field-color-preview secondary-dark-5"></span> </p> </div> <div class="dlab-input-errors"> diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.scss b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.scss index f22045068e05d227dd5a6bb79f9d2398a23112c9..825c6908cd3cabf9b5457dd79d4164f76babb757 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.scss +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.scss @@ -1,32 +1,43 @@ @import '~ui-frontend-common/sass/variables/colors'; -$field-spacing: 15px; -.field-color-name { - width: 300px + $field-spacing / 2; - margin-right: $field-spacing; +p { + height: 80px; } -.field-color-value { - width: 150px + $field-spacing / 2; - margin-right: $field-spacing; +div { + margin-bottom: 30px; } .field-color-preview { padding: 0; - margin: 0; + margin: 0 5px 0 0; display: inline-block; - width: 49px; - height: 49px; + width: 50px; + height: 50px; border-radius: 100%; position: relative; - top: 34px; + top: 35px; left: -50px; &.primary { background-color: var(--vitamui-primary); } - + &.primary-light { + background-color: var(--vitamui-primary-light); + } + &.primary-light-20 { + background-color: var(--vitamui-primary-light-20); + } &.secondary { background-color: var(--vitamui-secondary); } + &.secondary-light { + background-color: var(--vitamui-secondary-light); + } + &.secondary-light-8 { + background-color: var(--vitamui-secondary-light-8); + } + &.secondary-dark-5 { + background-color: var(--vitamui-secondary-dark-5); + } } diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.ts index ab1b1c8af816db7a34929201eef1aea50b60a380..d504974030475aa962c5ae3e70b38af3956195b3 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-create/customer-colors-input/customer-colors-input.component.ts @@ -1,4 +1,4 @@ -import {Component, forwardRef, Input} from '@angular/core'; +import {Component, forwardRef, Input, OnInit} from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -21,17 +21,22 @@ export const COLORS_INPUT_ACCESSOR: any = { styleUrls: ['./customer-colors-input.component.scss'], providers: [COLORS_INPUT_ACCESSOR] }) -export class CustomerColorsInputComponent implements ControlValueAccessor { +export class CustomerColorsInputComponent implements ControlValueAccessor, OnInit { @Input() placeholder: string; @Input() spinnerDiameter = 25; + // css selector to overload color theme for preview (default = only color circles around inputs) + @Input() overloadSelector = '.field-color-preview'; + colorForm: FormGroup; - colors: {[key: string]: string}; + colors: {[colorId: string]: string} = { + 'vitamui-primary': '', + 'vitamui-secondary': '' + }; - onChange: (colors: {[key: string]: string}) => void; onTouched: () => void; validator: ValidatorFn = Validators.pattern(/#([0-9A-Fa-f]{6})/); @@ -41,18 +46,18 @@ export class CustomerColorsInputComponent implements ControlValueAccessor { primary: ['', this.validator], secondary: ['', this.validator] }); + } + get value(): {[key: string]: string} { + return this.colors; } writeValue(colors: {primary: string, secondary: string}) { - this.colorForm.get('primary').setValue(colors.primary); - this.colorForm.get('secondary').setValue(colors.secondary); - - this.overloadLocalTheme(); + this.colorForm.setValue(colors); } registerOnChange(fn: (colors: {[key: string]: string}) => void) { - this.onChange = fn; + this.colorForm.valueChanges.subscribe(fn); } registerOnTouched(fn: () => void) { @@ -60,46 +65,48 @@ export class CustomerColorsInputComponent implements ControlValueAccessor { } - handleValueChange() { - // Force color hex to start with '#' - if ( ! this.colorForm.value.primary.startsWith('#') ) { - const newPrimary: string = '#' + this.colorForm.value.primary; - const oldSecondary: string = this.colorForm.value.secondary; - this.colorForm.setValue({primary: newPrimary, secondary: oldSecondary}); - } + handleValueChanges() { + this.colorForm.valueChanges.subscribe((colors) => { - if ( ! this.colorForm.value.secondary.startsWith('#') ) { - const newSecondary: string = '#' + this.colorForm.value.secondary; - const oldPrimary: string = this.colorForm.value.primary; - this.colorForm.setValue({primary: oldPrimary, secondary: newSecondary}); - } + // Force color hex to start with '#' + if (!colors.primary.startsWith('#')) { + const newPrimary: string = '#' + colors.primary; + const oldSecondary: string = colors.secondary; + this.colorForm.setValue({primary: newPrimary, secondary: oldSecondary}); + } - if (this.colorForm.invalid || this.colorForm.pending) { - return; - } + if (!this.colorForm.value.secondary.startsWith('#')) { + const newSecondary: string = '#' + colors.secondary; + const oldPrimary: string = colors.primary; + this.colorForm.setValue({primary: oldPrimary, secondary: newSecondary}); + } - this.colors = { - 'vitamui-primary': this.colorForm.value.primary, - 'vitamui-secondary': this.colorForm.value.secondary - }; + if (this.colorForm.invalid || this.colorForm.pending) { + return; + } - // propagate changes - this.onChange(this.colors); + this.colors = { + 'vitamui-primary': this.colorForm.value.primary, + 'vitamui-secondary': this.colorForm.value.secondary + }; - // If form is valid, overload local theme for preview - this.overloadLocalTheme(); + // If form is valid, overload local theme for preview + this.overloadLocalTheme(); + }); } overloadLocalTheme() { - - this.themeService.refresh(this.colorForm.value.primary, this.colorForm.value.secondary); - - const selector: HTMLElement = document.querySelector('div.customer-colors-input'); - for (const key in this.themeService.themeColors) { - if (this.themeService.themeColors.hasOwnProperty(key)) { - selector.style.setProperty('--' + key, this.themeService.themeColors[key]); + const newTheme = this.themeService.getThemeColors(this.colors); + const selector: HTMLElement = document.querySelector(this.overloadSelector); + for (const key in newTheme) { + if (newTheme.hasOwnProperty(key)) { + selector.style.setProperty('--' + key, newTheme[key]); } } } + + ngOnInit(): void { + this.handleValueChanges(); + } } 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 4dee390a14a1f8af18285abda592cd8cd7e34779..d1370dd7148e804a39ff9234e044da65197f8ea9 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 @@ -2,7 +2,7 @@ <mat-progress-bar mode="determinate" [value]="stepProgress" class="stepper-progress-bar"></mat-progress-bar> </div> -<form [formGroup]="form" (ngSubmit)="onSubmit()"> +<form [formGroup]="form" (ngSubmit)="onSubmit()" id="formCreateCustomer"> <vitamui-common-stepper (selectionChange)="stepIndex=$event.selectedIndex"> <cdk-step> @@ -182,10 +182,10 @@ </p> </div> </div> + </div> - <div class="theme-colors"> - <app-customer-colors-input formControlName="themeColors"></app-customer-colors-input> - </div> + <div class="customer-colors-input"> + <app-customer-colors-input formControlName="themeColors" overloadSelector="form#formCreateCustomer"></app-customer-colors-input> </div> <div class="error-message" *ngIf="hasError"> {{ message }} 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 90876d2537a934d41e414ae050fdd8a3060357a4..c7e0a5dcef39be5e63ece7d1a592494166dc1271 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 } from 'ui-frontend-common'; +import {ConfirmDialogService, Customer, OtpState, ThemeService} from 'ui-frontend-common'; import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @@ -82,7 +82,8 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { private formBuilder: FormBuilder, private customerService: CustomerService, private customerCreateValidators: CustomerCreateValidators, - private confirmDialogService: ConfirmDialogService + private confirmDialogService: ConfirmDialogService, + private themeService: ThemeService ) { } @@ -108,7 +109,7 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { emailDomains: [null, Validators.required], defaultEmailDomain: [null, Validators.required], hasCustomGraphicIdentity: false, - themeColors: [null], + themeColors: null, owners: this.formBuilder.array([ this.formBuilder.control(null, Validators.required), ]) @@ -129,6 +130,12 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { } }); + const colors = this.themeService.getThemeColors(); + this.form.get('themeColors').setValue({ + primary: colors['vitamui-primary'], + secondary: colors['vitamui-secondary'] + }); + this.keyPressSubscription = this.confirmDialogService.listenToEscapeKeyPress(this.dialogRef).subscribe(() => this.onCancel()); } @@ -177,14 +184,15 @@ export class CustomerCreateComponent implements OnInit, OnDestroy { } updateForCustomerModel(formValue: any): Customer { + console.log(formValue); const { themeColors, ...customer } = formValue; + const customerTheme = { + 'vitamui-primary': themeColors.primary, + 'vitamui-secondary': themeColors.secondary + }; + + customer.themeColors = this.themeService.getThemeColors(customerTheme); - customer.themeColors = {}; - for (const key in themeColors) { - if (themeColors.hasOwnProperty(key)) { - customer.themeColors[key] = themeColors[key]; - } - } return customer; } diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.html b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.html index 111e542a330db19514c136982c7d355b4e71878c..afb718fe37b3afbf3baf939289bbefcdb5055336 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.html +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.html @@ -17,14 +17,20 @@ </div> </div> <div class="row"> - <span>Couleurs de l'organisation</span> - - <div class="vitamui-chip-list"> - <div *ngFor="let color of customer.themeColors | keyvalue" class="vitamui-chip color-chip"> - <div class="vitamui-chip-content"> - <i class="openvitamui-icon openvitamui-icon-triangle" [style.color]="color.value"></i> - {{color.key}}</div> - </div> - </div> + <span i18n="Organisation color theme@@customerGraphicIdentityTabColorTheme">Couleurs de l'organisation</span> + <p><vitamui-common-input + disabled placeholder="Couleur principale" + [value]="themeColors['vitamui-primary']" class="vitamui-float"></vitamui-common-input> + <span class="field-color-preview primary"></span> + <span class="field-color-preview primary-light"></span> + <span class="field-color-preview primary-light-20"></span> + </p> + <p><vitamui-common-input + disabled placeholder="Couleur secondaire" + [value]="themeColors['vitamui-secondary']" class="vitamui-float"></vitamui-common-input> + <span class="field-color-preview secondary"></span> + <span class="field-color-preview secondary-light"></span> + <span class="field-color-preview secondary-light-8"></span> + <span class="field-color-preview secondary-dark-5"></span></p> </div> diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.scss b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.scss index 4a3ee4221f6d736b6c6b07ca61317c9aaad11253..6db72c70b8935c967b4cdffe1f3f53275a477379 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.scss +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.scss @@ -5,6 +5,40 @@ margin-left: 5% } -.color-chip { - border: 2px solid; +p { + height: 80px; +} + +.field-color-preview { + padding: 0; + margin: 0 5px 0 0; + display: inline-block; + width: 50px; + height: 50px; + border-radius: 100%; + position: relative; + top: 35px; + left: -50px; + + &.primary { + background-color: var(--vitamui-primary); + } + &.primary-light { + background-color: var(--vitamui-primary-light); + } + &.primary-light-20 { + background-color: var(--vitamui-primary-light-20); + } + &.secondary { + background-color: var(--vitamui-secondary); + } + &.secondary-light { + background-color: var(--vitamui-secondary-light); + } + &.secondary-light-8 { + background-color: var(--vitamui-secondary-light-8); + } + &.secondary-dark-5 { + background-color: var(--vitamui-secondary-dark-5); + } } diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.ts index 053a674f9012c726f512a208cb66f68f3a630d87..21fa19499d43f3485ed000a6019dd64648196607 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-tab.component.ts @@ -34,11 +34,11 @@ * 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. */ -import { Component, Input } from '@angular/core'; +import {Component, Input, OnInit} from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; -import { Customer } from 'ui-frontend-common'; -import { CustomerService } from './../../../core/customer.service'; +import {Customer, ThemeService} from 'ui-frontend-common'; +import { CustomerService } from '../../../core/customer.service'; import { GraphicIdentityUpdateComponent } from './graphic-identity-update/graphic-identity-update.component'; @Component({ @@ -46,7 +46,7 @@ import { GraphicIdentityUpdateComponent } from './graphic-identity-update/graphi templateUrl: './graphic-identity-tab.component.html', styleUrls: ['./graphic-identity-tab.component.scss'] }) -export class GraphicIdentityTabComponent { +export class GraphicIdentityTabComponent implements OnInit { @Input() set customer(customer: Customer) { @@ -68,15 +68,35 @@ export class GraphicIdentityTabComponent { logo: any; trustedUrlInline: SafeUrl; - constructor(private customerService: CustomerService, private sanitizer: DomSanitizer, private dialog: MatDialog) { } + themeColors: {[key: string]: string}; + + constructor(private customerService: CustomerService, private sanitizer: DomSanitizer, private dialog: MatDialog, + private themeService: ThemeService) { + } + + ngOnInit() { + this.resetTab(this._customer); + } + resetTab(customer: Customer) { if (customer.hasCustomGraphicIdentity) { - this.customerService.getCustomerLogo(customer.id).subscribe((data: any) => { - const logo = data; - this.trustedUrlInline = this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(logo.body)); + this.customerService.getCustomerLogo(customer.id).subscribe((data: any) => { + const logo = data; + this.trustedUrlInline = this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(logo.body)); }); } + + this.themeColors = this.themeService.getThemeColors(customer.themeColors); + this.overloadLocalTheme(); + } + + overloadLocalTheme() { + const selector: HTMLElement = document.querySelector('div.vitamui-sidepanel'); + // tslint:disable-next-line:forin + for (const key in this.themeColors) { + selector.style.setProperty('--' + key, this.themeColors[key]); + } } openUpdateCustomerLogo() { diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.html b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.html index 6a075ee04cae2d758e520c5073e213f566f82474..cfd88da84a3cb1716151bf7a022ff7433615a9bb 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.html +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.html @@ -1,4 +1,4 @@ -<form [formGroup]="graphicIdentityForm"> +<form [formGroup]="graphicIdentityForm" id="graphicIdentityForm"> <div class="content"> <h2 i18n="Customer graphical identity title@@customerGraphicalIdentityTitle">Identité graphique du client</h2> @@ -35,7 +35,7 @@ </div> <div class="customer-colors-input"> - <app-customer-colors-input formControlName="themeColors"></app-customer-colors-input> + <app-customer-colors-input formControlName="themeColors" overloadSelector="form#graphicIdentityForm" ></app-customer-colors-input> </div> <div class="actions"> diff --git a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.ts b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.ts index 45608e2da28fa5dfba098a910f8a9577b6721065..969320ba207c7f6e165366b19bdf61b8fe7ac744 100644 --- a/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/customer/customer-preview/graphic-identity-tab/graphic-identity-update/graphic-identity-update.component.ts @@ -83,13 +83,6 @@ export class GraphicIdentityUpdateComponent implements OnInit { this.graphicIdentityForm.get('hasCustomGraphicIdentity').setValue(this.customer.hasCustomGraphicIdentity); this.hasCustomGraphicIdentity = this.graphicIdentityForm.get('hasCustomGraphicIdentity').value; - const customerTheme = this.themeService.getThemeColors(this.customer.themeColors); - this.graphicIdentityForm.get('themeColors').setValue({ - primary: customerTheme['vitamui-primary'], - secondary: customerTheme['vitamui-secondary'] - }); - - this.graphicIdentityForm.get('hasCustomGraphicIdentity').valueChanges.subscribe(() => { this.hasCustomGraphicIdentity = this.graphicIdentityForm.get('hasCustomGraphicIdentity').value; this.message = null; @@ -103,6 +96,13 @@ export class GraphicIdentityUpdateComponent implements OnInit { this.imageUrl = null; } }); + + const customerTheme = this.themeService.getThemeColors(this.customer.themeColors); + this.graphicIdentityForm.get('themeColors').setValue({ + primary: customerTheme['vitamui-primary'], + secondary: customerTheme['vitamui-secondary'] + }); + } onCancel() { @@ -162,15 +162,15 @@ export class GraphicIdentityUpdateComponent implements OnInit { updateGraphicIdentity() { - const themeFormValues = this.graphicIdentityForm.get('themeColors').value; + const colorValues = this.graphicIdentityForm.get('themeColors').value; const formData = { id : this.customer.id, hasCustomGraphicIdentity: this.graphicIdentityForm.get('hasCustomGraphicIdentity').value, - themeColors: { - 'vitamui-primary': themeFormValues.primary, - 'vitamui-secondary': themeFormValues.secondary - } + themeColors: this.themeService.getThemeColors({ + 'vitamui-primary': colorValues.primary, + 'vitamui-secondary': colorValues.secondary + }) }; this.customerService.patch(formData, this.imageToUpload) .subscribe(