diff --git a/src/lib/common-ui.module.ts b/src/lib/common-ui.module.ts index db1f558..63e3168 100644 --- a/src/lib/common-ui.module.ts +++ b/src/lib/common-ui.module.ts @@ -4,13 +4,11 @@ import { MatIconModule, MatIconRegistry } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; import { CommonUiOptions, IqserAppConfig, ModuleOptions } from './utils'; -import { ToastComponent } from './shared'; import { ConnectionStatusComponent, FullPageErrorComponent } from './error'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar'; -import { ConfirmationDialogComponent } from './dialog'; import { MatTooltipModule } from '@angular/material/tooltip'; import { ApiPathInterceptor, DefaultUserPreferenceService, IqserConfigService, IqserUserPreferenceService } from './services'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; @@ -30,7 +28,7 @@ const matModules = [ MatTooltipModule, MatProgressBarModule, ]; -const components = [ConnectionStatusComponent, FullPageErrorComponent, ConfirmationDialogComponent, ToastComponent]; +const components = [ConnectionStatusComponent, FullPageErrorComponent]; @NgModule({ declarations: [...components], diff --git a/src/lib/dialog/base-dialog.component.ts b/src/lib/dialog/base-dialog.component.ts index c73b6a1..a5bb814 100644 --- a/src/lib/dialog/base-dialog.component.ts +++ b/src/lib/dialog/base-dialog.component.ts @@ -61,20 +61,20 @@ export abstract class BaseDialogComponent implements OnInit, OnDestroy { this.#subscriptions.unsubscribe(); } - close(): void { - if (this._isInEditMode && this.changed) { - this._openConfirmDialog().then(result => { - if (result in ConfirmOptions) { - if (result === ConfirmOptions.CONFIRM) { - this.save({ closeAfterSave: true }); - } else { - this._dialogRef.close(); - } - } - }); - } else { + close() { + if (!this._isInEditMode || !this.changed) { this._dialogRef.close(); } + + this._openConfirmDialog().then(result => { + if (result) { + if (result === ConfirmOptions.CONFIRM) { + this.save({ closeAfterSave: true }); + } else { + this._dialogRef.close(); + } + } + }); } @HostListener('window:keydown.Enter', ['$event']) @@ -94,7 +94,7 @@ export abstract class BaseDialogComponent implements OnInit, OnDestroy { } protected _openConfirmDialog() { - const dialogRef = this.#confirmationDialogService.openDialog({ disableConfirm: !this.valid }); + const dialogRef = this.#confirmationDialogService.open({ disableConfirm: !this.valid }); return firstValueFrom(dialogRef.afterClosed()); } } diff --git a/src/lib/dialog/confirmation-dialog.service.ts b/src/lib/dialog/confirmation-dialog.service.ts index abcc205..dfba015 100644 --- a/src/lib/dialog/confirmation-dialog.service.ts +++ b/src/lib/dialog/confirmation-dialog.service.ts @@ -1,39 +1,29 @@ -import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { inject, Injectable } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DialogConfig, DialogService } from '../services'; -import { ConfirmationDialogComponent, ConfirmationDialogInput, TitleColors } from '.'; - -type DialogType = 'confirm'; +import { ConfirmationDialogComponent, ConfirmOption, defaultDialogConfig, IConfirmationDialogData, TitleColors } from '.'; +import { MatDialog } from '@angular/material/dialog'; @Injectable({ providedIn: 'root', }) -export class ConfirmationDialogService extends DialogService { - protected readonly _config: DialogConfig = { - confirm: { - component: ConfirmationDialogComponent, - dialogConfig: { disableClose: false }, - }, - }; +export class ConfirmationDialogService { + readonly #dialog = inject(MatDialog); - constructor(protected readonly _dialog: MatDialog) { - super(_dialog); - } + open(data?: { disableConfirm: boolean }) { + const dialogData: IConfirmationDialogData = { + title: _('confirmation-dialog.unsaved-changes.title'), + question: _('confirmation-dialog.unsaved-changes.question'), + details: _('confirmation-dialog.unsaved-changes.details'), + confirmationText: _('confirmation-dialog.unsaved-changes.confirmation-text'), + discardChangesText: _('confirmation-dialog.unsaved-changes.discard-changes-text'), + disableConfirm: data?.disableConfirm, + titleColor: TitleColors.WARN, + }; - // @ts-ignore - openDialog(data?: { disableConfirm: boolean; [key: string]: unknown }): MatDialogRef { - return super.openDialog( - 'confirm', - new ConfirmationDialogInput({ - title: _('confirmation-dialog.unsaved-changes.title'), - question: _('confirmation-dialog.unsaved-changes.question'), - details: _('confirmation-dialog.unsaved-changes.details'), - confirmationText: _('confirmation-dialog.unsaved-changes.confirmation-text'), - discardChangesText: _('confirmation-dialog.unsaved-changes.discard-changes-text'), - disableConfirm: data?.disableConfirm, - titleColor: TitleColors.WARN, - }), - ); + return this.#dialog.open(ConfirmationDialogComponent, { + ...defaultDialogConfig, + disableClose: false, + data: dialogData, + }); } } diff --git a/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.html b/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.html index c205af2..7bacdf2 100644 --- a/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.html +++ b/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.html @@ -34,19 +34,17 @@ [label]="config.confirmationText" [type]="iconButtonTypes.primary" buttonId="confirm" - > - + > - + > -
+
{{ config.discardChangesText }}
diff --git a/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.ts b/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.ts index d2b3a49..0f1c635 100644 --- a/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.ts +++ b/src/lib/dialog/confirmation-dialog/confirmation-dialog.component.ts @@ -1,21 +1,28 @@ -import { ChangeDetectionStrategy, Component, HostListener, Inject, TemplateRef } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { TranslateService } from '@ngx-translate/core'; +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 { IconButtonTypes } from '../../buttons'; +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 type TitleColor = 'default' | 'warn'; +export const TitleColors = { + DEFAULT: 'default', + WARN: 'warn', +} as const; -export enum TitleColors { - DEFAULT = 'default', - WARN = 'warn', -} +export type TitleColor = ValuesOf; -export enum ConfirmOptions { - CONFIRM = 1, - SECOND_CONFIRM = 2, - DISCARD_CHANGES = 3, -} +export const ConfirmOptions = { + CONFIRM: 1, + SECOND_CONFIRM: 2, + DISCARD_CHANGES: 3, +} as const; + +export type ConfirmOption = ValuesOf; interface CheckBox { value: boolean; @@ -24,76 +31,71 @@ interface CheckBox { extraContentData?: Record; } -interface IConfirmationDialogInput { - title?: string; - titleColor?: TitleColor; - question?: string; - details?: string; - confirmationText?: string; - alternativeConfirmationText?: string; - discardChangesText?: string; - requireInput?: boolean; - disableConfirm?: boolean; - denyText?: string; - translateParams?: Record; - checkboxes?: CheckBox[]; - checkboxesValidation?: boolean; - toastMessage?: string; +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 class ConfirmationDialogInput implements IConfirmationDialogInput { - title: string; - titleColor: TitleColor; - question: string; - details: string; - confirmationText: string; - alternativeConfirmationText?: string; - discardChangesText?: string; - requireInput: boolean; - disableConfirm: boolean; - denyText: string; - translateParams: Record; - checkboxes: CheckBox[]; - checkboxesValidation: boolean; - toastMessage?: string; +export type IConfirmationDialogData = Partial; - constructor(options?: IConfirmationDialogInput) { - this.title = options?.title || _('common.confirmation-dialog.title'); - this.titleColor = options?.titleColor || TitleColors.DEFAULT; - this.question = options?.question || _('common.confirmation-dialog.description'); - this.details = options?.details || ''; - this.confirmationText = options?.confirmationText || _('common.confirmation-dialog.confirm'); - this.alternativeConfirmationText = options?.alternativeConfirmationText; - this.discardChangesText = options?.discardChangesText; - this.requireInput = options?.requireInput || false; - this.disableConfirm = options?.disableConfirm || false; - this.denyText = options?.denyText || _('common.confirmation-dialog.deny'); - this.translateParams = options?.translateParams || {}; - this.checkboxes = options?.checkboxes || []; - this.checkboxesValidation = typeof options?.checkboxesValidation === 'boolean' ? options.checkboxesValidation : true; - this.toastMessage = options?.toastMessage; - } +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 { - config: ConfirmationDialogInput; + readonly config = getConfig(inject(MAT_DIALOG_DATA)); inputValue = ''; showToast = false; readonly inputLabel: string; - readonly ConfirmOptions = ConfirmOptions; + readonly confirmOptions = ConfirmOptions; readonly iconButtonTypes = IconButtonTypes; constructor( - private readonly _dialogRef: MatDialogRef, + private readonly _dialogRef: MatDialogRef, private readonly _translateService: TranslateService, - @Inject(MAT_DIALOG_DATA) private readonly _confirmationDialogInput: ConfirmationDialogInput, ) { - this.config = _confirmationDialogInput ?? new ConfirmationDialogInput(); this.translate(this.config); this.inputLabel = `${this._translateService.instant('confirmation-dialog.input-label')} '${this.config.confirmationText || ''}'`; } @@ -103,10 +105,10 @@ export class ConfirmationDialogComponent { } get isDeleteAction(): boolean { - return this.config?.titleColor === TitleColors.WARN; + return this.config.titleColor === TitleColors.WARN; } - get confirmOption(): ConfirmOptions { + get confirmOption(): ConfirmOption { if (!this.config.checkboxesValidation && this.config.checkboxes[0]?.value) { return ConfirmOptions.SECOND_CONFIRM; } @@ -116,19 +118,19 @@ export class ConfirmationDialogComponent { @HostListener('window:keyup.enter') onKeyupEnter(): void { if (this.config.requireInput && !this.confirmationDoesNotMatch()) { - this.confirm(1); + this.confirm(ConfirmOptions.CONFIRM); } } confirmationDoesNotMatch(): boolean { - return this.inputValue.toLowerCase() !== this.config.confirmationText?.toLowerCase(); + return this.inputValue.toLowerCase() !== this.config.confirmationText.toLowerCase(); } - deny(): void { + deny() { this._dialogRef.close(); } - confirm(option: ConfirmOptions): void { + confirm(option: ConfirmOption) { if (this.uncheckedBoxes) { this.showToast = true; } else { @@ -136,8 +138,8 @@ export class ConfirmationDialogComponent { } } - translate(obj: ConfirmationDialogInput): void { - const translateKeys: (keyof typeof obj)[] = [ + translate(obj: InternalConfirmationDialogData) { + const translateKeys: (keyof InternalConfirmationDialogData)[] = [ 'title', 'question', 'details', @@ -147,12 +149,10 @@ export class ConfirmationDialogComponent { 'denyText', ]; - translateKeys - .filter(key => !!obj[key]) - .forEach(key => { - Object.assign(obj, { - [key]: this._translateService.instant(obj[key] as string, this.config.translateParams) as string, - }); - }); + 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 }); + }); } } diff --git a/src/lib/services/dialog.service.ts b/src/lib/dialog/dialog.service.ts similarity index 100% rename from src/lib/services/dialog.service.ts rename to src/lib/dialog/dialog.service.ts diff --git a/src/lib/dialog/index.ts b/src/lib/dialog/index.ts index 95e9686..274a697 100644 --- a/src/lib/dialog/index.ts +++ b/src/lib/dialog/index.ts @@ -1,3 +1,4 @@ export * from './base-dialog.component'; export * from './confirmation-dialog.service'; export * from './confirmation-dialog/confirmation-dialog.component'; +export * from './dialog.service'; diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index a1d9cdc..274d888 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -1,4 +1,3 @@ -export * from './dialog.service'; export * from './toaster.service'; export * from './error-message.service'; export * from './generic.service'; diff --git a/src/lib/shared/toast/toast.component.html b/src/lib/shared/toast/toast.component.html index 4ef3146..2319a16 100644 --- a/src/lib/shared/toast/toast.component.html +++ b/src/lib/shared/toast/toast.component.html @@ -15,6 +15,7 @@
+