RED-6774 - updated details radio component

This commit is contained in:
Valentin Mihai 2023-06-21 00:52:03 +03:00
parent 88babfd1f6
commit afbfaf2959
5 changed files with 95 additions and 17 deletions

View File

@ -25,9 +25,9 @@ export abstract class BaseDialogComponent implements AfterViewInit, OnDestroy {
protected readonly _formBuilder = inject(UntypedFormBuilder); protected readonly _formBuilder = inject(UntypedFormBuilder);
protected readonly _loadingService = inject(LoadingService); protected readonly _loadingService = inject(LoadingService);
protected readonly _toaster = inject(Toaster); protected readonly _toaster = inject(Toaster);
protected readonly _subscriptions: Subscription = new Subscription();
readonly #confirmationDialogService = inject(ConfirmationDialogService); readonly #confirmationDialogService = inject(ConfirmationDialogService);
readonly #dialog = inject(MatDialog); readonly #dialog = inject(MatDialog);
readonly #subscriptions: Subscription = new Subscription();
#hasErrors = false; #hasErrors = false;
protected constructor(protected readonly _dialogRef: MatDialogRef<BaseDialogComponent>, private readonly _isInEditMode = false) {} protected constructor(protected readonly _dialogRef: MatDialogRef<BaseDialogComponent>, private readonly _isInEditMode = false) {}
@ -45,20 +45,20 @@ export abstract class BaseDialogComponent implements AfterViewInit, OnDestroy {
} }
ngAfterViewInit() { ngAfterViewInit() {
this.#subscriptions.add(this._dialogRef.backdropClick().subscribe(() => this.close())); this._subscriptions.add(this._dialogRef.backdropClick().subscribe(() => this.close()));
const events = [fromEvent(window, 'keyup'), fromEvent(window, 'input'), this.form?.valueChanges]; const events = [fromEvent(window, 'keyup'), fromEvent(window, 'input'), this.form?.valueChanges];
const events$ = merge(...events).pipe( const events$ = merge(...events).pipe(
debounceTime(10), debounceTime(10),
tap(() => (this.#hasErrors = !!document.getElementsByClassName('ng-invalid')[0])), tap(() => (this.#hasErrors = !!document.getElementsByClassName('ng-invalid')[0])),
); );
this.#subscriptions.add(events$.subscribe()); this._subscriptions.add(events$.subscribe());
} }
abstract save(options?: SaveOptions): void; abstract save(options?: SaveOptions): void;
ngOnDestroy(): void { ngOnDestroy(): void {
this.#subscriptions.unsubscribe(); this._subscriptions.unsubscribe();
} }
close() { close() {

View File

@ -1,6 +1,14 @@
interface ExtraOption {
label: string;
checked: boolean;
}
export interface DetailsRadioOption<I> { export interface DetailsRadioOption<I> {
id?: string; id?: string;
label: string; label: string;
description: string; description: string;
descriptionParams?: Record<string, string>;
icon?: string;
value: I; value: I;
extraOption?: ExtraOption;
} }

View File

@ -7,11 +7,35 @@
[ngClass]="{ 'mb-8': !displayInRow, 'mr-8': displayInRow }" [ngClass]="{ 'mb-8': !displayInRow, 'mr-8': displayInRow }"
class="option pointer" class="option pointer"
> >
<div class="flex-align-items-center mb-8"> <div class="icon-option" *ngIf="option.icon; else withoutIcon">
<iqser-round-checkbox [active]="option.value === value?.value" class="mr-6"></iqser-round-checkbox> <mat-icon class="icon" [svgIcon]="option.icon"></mat-icon>
<label class="details-radio-label pointer">{{ option.label | translate }}</label>
<div class="text">
<label class="details-radio-label pointer">{{ option.label | translate }}</label>
<span class="hint" [innerHTML]="option.description | translate : option.descriptionParams"></span>
<div class="iqser-input-group" *ngIf="option.extraOption && isSelected(option)">
<mat-checkbox
color="primary"
[(ngModel)]="option.extraOption.checked"
[checked]="option.extraOption.checked"
(change)="emitExtraOption()"
>
{{ option.extraOption.label | translate }}
</mat-checkbox>
</div>
</div>
<mat-icon *ngIf="isSelected(option)" class="checked" svgIcon="iqser:radio-selected"></mat-icon>
</div> </div>
<span class="hint">{{ option.description | translate }}</span> <ng-template #withoutIcon>
<div class="flex-align-items-center mb-8">
<iqser-round-checkbox [active]="isSelected(option)" class="mr-6"></iqser-round-checkbox>
<label class="details-radio-label pointer">{{ option.label | translate }}</label>
</div>
<span class="hint">{{ option.description | translate }}</span>
</ng-template>
</div> </div>
</div> </div>

View File

@ -10,6 +10,28 @@ label {
&.active { &.active {
background-color: rgba(var(--iqser-primary-rgb), 0.1); background-color: rgba(var(--iqser-primary-rgb), 0.1);
} }
.icon-option {
display: flex;
gap: 20px;
.icon {
transform: scale(1.2);
margin-top: 5px;
}
.text {
display: flex;
flex-direction: column;
}
.checked {
margin-left: auto;
margin-top: 5px;
transform: scale(0.8);
color: var(--iqser-primary);
}
}
} }
.row { .row {

View File

@ -1,10 +1,12 @@
import { Component, Input } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { DetailsRadioOption } from './details-radio-option'; import { DetailsRadioOption } from './details-radio-option';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { FormFieldComponent } from '../form-field/form-field-component.directive'; import { FormFieldComponent } from '../form-field/form-field-component.directive';
import { NgClass, NgForOf } from '@angular/common'; import { NgClass, NgForOf, NgIf } from '@angular/common';
import { RoundCheckboxComponent } from '../round-checkbox/round-checkbox.component'; import { RoundCheckboxComponent } from '../round-checkbox/round-checkbox.component';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { MatCheckboxModule } from '@angular/material/checkbox';
@Component({ @Component({
selector: 'iqser-details-radio [options]', selector: 'iqser-details-radio [options]',
@ -23,20 +25,42 @@ import { TranslateModule } from '@ngx-translate/core';
useExisting: DetailsRadioComponent, useExisting: DetailsRadioComponent,
}, },
], ],
imports: [NgForOf, NgClass, RoundCheckboxComponent, TranslateModule], imports: [
NgForOf,
NgClass,
RoundCheckboxComponent,
TranslateModule,
MatIconModule,
NgIf,
FormsModule,
MatCheckboxModule,
ReactiveFormsModule,
],
}) })
export class DetailsRadioComponent<I> extends FormFieldComponent<DetailsRadioOption<I>> { export class DetailsRadioComponent<I> extends FormFieldComponent<DetailsRadioOption<I>> {
@Input() options: DetailsRadioOption<I>[] = []; @Input() options: DetailsRadioOption<I>[] = [];
@Input() displayInRow = false; @Input() displayInRow = false;
@Output() readonly extraOptionChanged: EventEmitter<DetailsRadioOption<I>> = new EventEmitter();
toggleOption(option: DetailsRadioOption<I>): void { toggleOption(option: DetailsRadioOption<I>): void {
this.markAsTouched(); if (option.value !== this._value?.value) {
const currentlyChecked = this.value?.value === option.value; this.markAsTouched();
this._value = currentlyChecked ? undefined : option; const currentlyChecked = this.value?.value === option.value;
this.onChange(this._value); this._value = currentlyChecked ? undefined : option;
this.onChange(this._value);
}
} }
groupId(option: DetailsRadioOption<I>) { groupId(option: DetailsRadioOption<I>): string {
return (option.id ?? option.label.replace('.', '-')) + '-checkbox-details-input'; return (option.id ?? option.label.replace('.', '-')) + '-checkbox-details-input';
} }
isSelected(option: DetailsRadioOption<I>): boolean {
return option.value === this.value?.value;
}
emitExtraOption(): void {
this.extraOptionChanged.emit(this.value);
}
} }