import { Directive, HostListener, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { IconButtonTypes } from '../buttons'; import { hasFormChanged, IqserEventTarget } from '../utils'; const DIALOG_CONTAINER = 'mat-dialog-container'; const DATA_TYPE_SYMBOL = Symbol.for('DATA_TYPE'); const RETURN_TYPE_SYMBOL = Symbol.for('RETURN_TYPE'); export type DATA_TYPE = typeof DATA_TYPE_SYMBOL; export type RETURN_TYPE = typeof RETURN_TYPE_SYMBOL; @Directive() export abstract class IqserDialogComponent { readonly [DATA_TYPE_SYMBOL]!: DataType; readonly [RETURN_TYPE_SYMBOL]!: ReturnType; readonly iconButtonTypes = IconButtonTypes; readonly dialogRef = inject(MatDialogRef); readonly data = inject(MAT_DIALOG_DATA); readonly dialog = inject(MatDialog); readonly form?: FormGroup; readonly ignoredKeys: string[] = []; initialFormValue: Record = {}; constructor(private readonly _editMode = false) { this.dialogRef .backdropClick() .pipe(takeUntilDestroyed()) // eslint-disable-next-line rxjs/no-ignored-subscription .subscribe(() => this.dialogRef.close()); } get valid(): boolean { return !this.form || this.form.valid; } get changed(): boolean { return !this.form || hasFormChanged(this.form, this.initialFormValue, this.ignoredKeys); } get disabled(): boolean { return !this.valid || !this.changed; } @HostListener('window:keydown.Escape', ['$event']) onEscape(): void { if (this.dialog.openDialogs.length === 1) { this.dialogRef.close(); } } @HostListener('window:keydown.Enter', ['$event']) onEnter(event: KeyboardEvent): void { event?.stopImmediatePropagation(); if (this.onEnterValidator(event)) { this.close(); } } onEnterValidator(event: KeyboardEvent) { const targetElement = (event.target as IqserEventTarget).localName?.trim()?.toLowerCase(); const canClose = targetElement === DIALOG_CONTAINER && this.valid; if (this._editMode) { return canClose && this.changed; } return canClose; } close(dialogResult?: ReturnType) { this.dialogRef.close(dialogResult); } } /** * This is for testing only */ // eslint-disable-next-line @typescript-eslint/no-unused-vars class DialogComponentImpl extends IqserDialogComponent {}