159 lines
5.3 KiB
TypeScript
159 lines
5.3 KiB
TypeScript
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<typeof TitleColors>;
|
|
|
|
export const ConfirmOptions = {
|
|
CONFIRM: 1,
|
|
SECOND_CONFIRM: 2,
|
|
DISCARD_CHANGES: 3,
|
|
} as const;
|
|
|
|
export type ConfirmOption = ValuesOf<typeof ConfirmOptions>;
|
|
|
|
interface CheckBox {
|
|
value: boolean;
|
|
label: string;
|
|
extraContent?: TemplateRef<unknown>;
|
|
extraContentData?: Record<string, unknown>;
|
|
}
|
|
|
|
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<string, unknown>;
|
|
readonly checkboxes: CheckBox[];
|
|
readonly checkboxesValidation: boolean;
|
|
readonly toastMessage?: string;
|
|
}
|
|
|
|
export type IConfirmationDialogData = Partial<InternalConfirmationDialogData>;
|
|
|
|
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<ConfirmationDialogComponent, ConfirmOption>,
|
|
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 });
|
|
});
|
|
}
|
|
}
|