frontend: improve visual customization form handling and update theme toggle functionality

This commit is contained in:
juancarmore 2025-09-29 14:55:46 +02:00
parent d5c559d572
commit f12795dbed
2 changed files with 58 additions and 32 deletions

View File

@ -4,7 +4,10 @@
<mat-icon class="material-symbols-outlined ov-settings-icon">settings</mat-icon> <mat-icon class="material-symbols-outlined ov-settings-icon">settings</mat-icon>
<h1>Visual Customization</h1> <h1>Visual Customization</h1>
</div> </div>
<p class="subtitle">Personalize the visual appearance of your video conference rooms to reflect your organization's brand and style.</p> <p class="subtitle">
Personalize the visual appearance of your video conference rooms to reflect your organization's brand and
style.
</p>
</div> </div>
@if (isLoading()) { @if (isLoading()) {
@ -43,7 +46,12 @@
<span>Use my own visual design</span> <span>Use my own visual design</span>
<mat-slide-toggle <mat-slide-toggle
formControlName="enabled" formControlName="enabled"
[matTooltip]="!isThemeEnabled ? 'Enable this option to customize the colors and appearance of your room' : ''" (change)="onToggleTheme($event)"
[matTooltip]="
!isThemeEnabled
? 'Enable this option to customize the colors and appearance of your room'
: ''
"
[matTooltipDisabled]="isThemeEnabled" [matTooltipDisabled]="isThemeEnabled"
></mat-slide-toggle> ></mat-slide-toggle>
</div> </div>
@ -54,7 +62,8 @@
<div class="theme-section"> <div class="theme-section">
<h4 class="section-title">Background Style</h4> <h4 class="section-title">Background Style</h4>
<p class="section-description ov-mt-xs"> <p class="section-description ov-mt-xs">
Choose whether you prefer a light or dark background as the starting point for your customization. Choose whether you prefer a light or dark background as the starting point for your
customization.
</p> </p>
<mat-form-field appearance="outline" class="full-width"> <mat-form-field appearance="outline" class="full-width">
<mat-label>Background style</mat-label> <mat-label>Background style</mat-label>
@ -110,14 +119,14 @@
mat-button mat-button
class="primary-button" class="primary-button"
(click)="onSaveAppearanceConfig()" (click)="onSaveAppearanceConfig()"
[disabled]="appearanceForm.invalid || !hasChanges()" [disabled]="appearanceForm.invalid || !hasFormChanges()"
> >
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
Save Changes Save Changes
</button> </button>
<button mat-stroked-button (click)="onResetForm()" [disabled]="!hasChanges()"> <button mat-stroked-button (click)="onResetColors()" [disabled]="!hasColorChanges()">
<mat-icon>undo</mat-icon> <mat-icon>undo</mat-icon>
Reset Changes Reset Colors
</button> </button>
</mat-card-actions> </mat-card-actions>
} }

View File

@ -8,14 +8,11 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatSlideToggleChange, MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { GlobalConfigService, NotificationService } from '@lib/services'; import { GlobalConfigService, NotificationService } from '@lib/services';
import { MeetAppearanceConfig, MeetRoomTheme, MeetRoomThemeMode } from '@lib/typings/ce'; import { MeetAppearanceConfig, MeetRoomTheme, MeetRoomThemeMode } from '@lib/typings/ce';
import { import { OPENVIDU_COMPONENTS_DARK_THEME, OPENVIDU_COMPONENTS_LIGHT_THEME } from 'openvidu-components-angular';
OPENVIDU_COMPONENTS_DARK_THEME,
OPENVIDU_COMPONENTS_LIGHT_THEME,
} from 'openvidu-components-angular';
type ColorField = 'backgroundColor' | 'primaryColor' | 'secondaryColor' | 'surfaceColor'; type ColorField = 'backgroundColor' | 'primaryColor' | 'secondaryColor' | 'surfaceColor';
@ -47,7 +44,8 @@ interface ThemeColors {
}) })
export class ConfigComponent implements OnInit { export class ConfigComponent implements OnInit {
isLoading = signal(true); isLoading = signal(true);
hasChanges = signal(false); hasFormChanges = signal(false);
hasColorChanges = signal(false);
appearanceForm = new FormGroup({ appearanceForm = new FormGroup({
enabled: new FormControl<boolean>(false, { nonNullable: true }), enabled: new FormControl<boolean>(false, { nonNullable: true }),
@ -116,14 +114,6 @@ export class ConfigComponent implements OnInit {
return this.appearanceForm.get('enabled')?.value ?? false; return this.appearanceForm.get('enabled')?.value ?? false;
} }
// Form actions
onResetForm(): void {
if (this.initialFormValue) {
this.appearanceForm.patchValue(this.initialFormValue);
this.hasChanges.set(false);
}
}
// Color management methods // Color management methods
getColorValue(colorField: ColorField): string { getColorValue(colorField: ColorField): string {
const formValue = this.appearanceForm.get(colorField)?.value; const formValue = this.appearanceForm.get(colorField)?.value;
@ -149,9 +139,9 @@ export class ConfigComponent implements OnInit {
private async loadAppearanceConfig(): Promise<void> { private async loadAppearanceConfig(): Promise<void> {
try { try {
const { appearance } = await this.configService.getRoomsAppearanceConfig(); const { appearance } = await this.configService.getRoomsAppearanceConfig();
const themeConfig = appearance?.themes?.[0];
if (themeConfig) { if (appearance.themes.length > 0) {
const themeConfig = appearance.themes[0];
this.appearanceForm.patchValue({ this.appearanceForm.patchValue({
enabled: themeConfig.enabled, enabled: themeConfig.enabled,
baseTheme: themeConfig.baseTheme, baseTheme: themeConfig.baseTheme,
@ -190,7 +180,8 @@ export class ConfigComponent implements OnInit {
private storeInitialValues(): void { private storeInitialValues(): void {
this.initialFormValue = { ...this.appearanceForm.value } as MeetRoomTheme; this.initialFormValue = { ...this.appearanceForm.value } as MeetRoomTheme;
this.hasChanges.set(false); this.hasFormChanges.set(false);
this.hasColorChanges.set(false);
} }
private checkForChanges(): void { private checkForChanges(): void {
@ -198,14 +189,40 @@ export class ConfigComponent implements OnInit {
return; return;
} }
const currentValue = this.appearanceForm.value; // Check for general form changes
const hasChangesDetected = JSON.stringify(currentValue) !== JSON.stringify(this.initialFormValue); const currentFormValue = this.appearanceForm.value;
this.hasChanges.set(hasChangesDetected); const hasFormChangesDetected = JSON.stringify(currentFormValue) !== JSON.stringify(this.initialFormValue);
if (!currentValue.enabled) { this.hasFormChanges.set(hasFormChangesDetected);
// Check for color-specific changes
const hasColorChangesDetected =
currentFormValue.backgroundColor !== this.initialFormValue.backgroundColor ||
currentFormValue.primaryColor !== this.initialFormValue.primaryColor ||
currentFormValue.secondaryColor !== this.initialFormValue.secondaryColor ||
currentFormValue.surfaceColor !== this.initialFormValue.surfaceColor;
this.hasColorChanges.set(hasColorChangesDetected);
}
onToggleTheme(event: MatSlideToggleChange): void {
// If theme was initially enabled and now disabled, save immediately
if (this.initialFormValue?.enabled && !event.checked) {
this.appearanceForm.patchValue({ ...this.initialFormValue, enabled: false });
this.onSaveAppearanceConfig(); this.onSaveAppearanceConfig();
} }
} }
onResetColors(): void {
if (this.initialFormValue) {
this.appearanceForm.patchValue({
backgroundColor: this.initialFormValue.backgroundColor,
primaryColor: this.initialFormValue.primaryColor,
secondaryColor: this.initialFormValue.secondaryColor,
surfaceColor: this.initialFormValue.surfaceColor
});
this.hasColorChanges.set(false);
}
}
async onSaveAppearanceConfig(): Promise<void> { async onSaveAppearanceConfig(): Promise<void> {
if (this.appearanceForm.invalid) { if (this.appearanceForm.invalid) {
this.notificationService.showSnackbar('Please fix the form errors before saving'); this.notificationService.showSnackbar('Please fix the form errors before saving');
@ -233,13 +250,13 @@ export class ConfigComponent implements OnInit {
const defaults = this.defaultColors[baseTheme]; const defaults = this.defaultColors[baseTheme];
return { return {
enabled: formData.enabled,
name: 'default', name: 'default',
enabled: formData.enabled,
baseTheme, baseTheme,
backgroundColor: formData.backgroundColor?.trim() ? formData.backgroundColor : defaults.backgroundColor, backgroundColor: formData.backgroundColor?.trim() || defaults.backgroundColor,
primaryColor: formData.primaryColor?.trim() ? formData.primaryColor : defaults.primaryColor, primaryColor: formData.primaryColor?.trim() || defaults.primaryColor,
secondaryColor: formData.secondaryColor?.trim() ? formData.secondaryColor : defaults.secondaryColor, secondaryColor: formData.secondaryColor?.trim() || defaults.secondaryColor,
surfaceColor: formData.surfaceColor?.trim() ? formData.surfaceColor : defaults.surfaceColor surfaceColor: formData.surfaceColor?.trim() || defaults.surfaceColor
}; };
} }
} }