import { ChangeDetectionStrategy, Component, HostListener, inject, TemplateRef } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { CircleButtonComponent, IconButtonComponent, IconButtonTypes } from '../../buttons'; import { NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; import { MatIconModule } from '@angular/material/icon'; import { FormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { ValuesOf } from '../../utils'; export const TitleColors = { DEFAULT: 'default', WARN: 'warn', } as const; export type TitleColor = ValuesOf; export const ConfirmOptions = { CONFIRM: 1, SECOND_CONFIRM: 2, DISCARD_CHANGES: 3, } as const; export type ConfirmOption = ValuesOf; interface CheckBox { value: boolean; label: string; extraContent?: TemplateRef; extraContentData?: Record; } interface InternalConfirmationDialogData { readonly title: string; readonly titleColor: TitleColor; readonly question: string; readonly details: string; readonly confirmationText: string; readonly alternativeConfirmationText?: string; readonly discardChangesText?: string; readonly requireInput: boolean; readonly disableConfirm: boolean; readonly denyText: string; readonly translateParams?: Record; readonly checkboxes: CheckBox[]; readonly checkboxesValidation: boolean; readonly toastMessage?: string; } export type IConfirmationDialogData = Partial; function getConfig(options?: IConfirmationDialogData): InternalConfirmationDialogData { return { ...options, title: options?.title ?? _('common.confirmation-dialog.title'), titleColor: options?.titleColor ?? TitleColors.DEFAULT, question: options?.question ?? _('common.confirmation-dialog.description'), details: options?.details ?? '', confirmationText: options?.confirmationText ?? _('common.confirmation-dialog.confirm'), requireInput: options?.requireInput ?? false, disableConfirm: options?.disableConfirm ?? false, denyText: options?.denyText ?? _('common.confirmation-dialog.deny'), checkboxes: options?.checkboxes ?? [], checkboxesValidation: typeof options?.checkboxesValidation === 'boolean' ? options.checkboxesValidation : true, }; } @Component({ templateUrl: './confirmation-dialog.component.html', styleUrls: ['./confirmation-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ NgIf, MatIconModule, FormsModule, NgForOf, MatCheckboxModule, TranslateModule, NgTemplateOutlet, IconButtonComponent, CircleButtonComponent, MatDialogModule, ], }) export class ConfirmationDialogComponent { readonly config = getConfig(inject(MAT_DIALOG_DATA)); inputValue = ''; showToast = false; readonly inputLabel: string; readonly confirmOptions = ConfirmOptions; readonly iconButtonTypes = IconButtonTypes; constructor( private readonly _dialogRef: MatDialogRef, private readonly _translateService: TranslateService, ) { this.translate(this.config); this.inputLabel = `${this._translateService.instant('confirmation-dialog.input-label')} '${this.config.confirmationText || ''}'`; } get uncheckedBoxes(): boolean { return this.config.checkboxesValidation && this.config.checkboxes.some(c => !c.value); } get isDeleteAction(): boolean { return this.config.titleColor === TitleColors.WARN; } get confirmOption(): ConfirmOption { if (!this.config.checkboxesValidation && this.config.checkboxes[0]?.value) { return ConfirmOptions.SECOND_CONFIRM; } return ConfirmOptions.CONFIRM; } @HostListener('window:keyup.enter') onKeyupEnter(): void { if (this.config.requireInput && !this.confirmationDoesNotMatch()) { this.confirm(ConfirmOptions.CONFIRM); } } confirmationDoesNotMatch(): boolean { return this.inputValue.toLowerCase() !== this.config.confirmationText.toLowerCase(); } deny() { this._dialogRef.close(); } confirm(option: ConfirmOption) { if (this.uncheckedBoxes) { this.showToast = true; } else { this._dialogRef.close(option); } } translate(obj: InternalConfirmationDialogData) { const translateKeys: (keyof InternalConfirmationDialogData)[] = [ 'title', 'question', 'details', 'confirmationText', 'alternativeConfirmationText', 'discardChangesText', 'denyText', ]; const filtered = translateKeys.filter(key => !!obj[key]); filtered.forEach(key => { const value = this._translateService.instant(obj[key] as string, this.config.translateParams); Object.assign(obj, { [key]: value }); }); } }