From 4feb08832de8b0c95ec3fbbd38698c3f6332c59a Mon Sep 17 00:00:00 2001 From: 4gray Date: Mon, 24 May 2021 00:17:48 +0200 Subject: [PATCH] refactor: add confirm dialog with dialog service --- src/app/services/dialog.service.spec.ts | 36 ++++++++++++++++ src/app/services/dialog.service.ts | 25 +++++++++++ .../confirm-dialog.component.html | 14 +++++++ .../confirm-dialog.component.spec.ts | 41 +++++++++++++++++++ .../confirm-dialog.component.ts | 26 ++++++++++++ src/app/shared/shared.module.ts | 4 +- src/assets/i18n/de.json | 10 ++++- src/assets/i18n/en.json | 8 +++- src/assets/i18n/ru.json | 10 ++++- 9 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 src/app/services/dialog.service.spec.ts create mode 100644 src/app/services/dialog.service.ts create mode 100644 src/app/shared/components/confirm-dialog/confirm-dialog.component.html create mode 100644 src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts create mode 100644 src/app/shared/components/confirm-dialog/confirm-dialog.component.ts diff --git a/src/app/services/dialog.service.spec.ts b/src/app/services/dialog.service.spec.ts new file mode 100644 index 000000000..716a5fe78 --- /dev/null +++ b/src/app/services/dialog.service.spec.ts @@ -0,0 +1,36 @@ +import { ConfirmDialogComponent } from './../shared/components/confirm-dialog/confirm-dialog.component'; +import { MockModule, MockComponent } from 'ng-mocks'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { TestBed, inject } from '@angular/core/testing'; +import { DialogService } from './dialog.service'; +import { ConfirmDialogData } from '../shared/components/confirm-dialog/confirm-dialog.component'; +import { EMPTY } from 'rxjs'; + +describe('Service: Dialog', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [MockComponent(ConfirmDialogComponent)], + providers: [DialogService, MatDialog], + imports: [MockModule(MatDialogModule)], + }); + }); + + it('should create the service', inject( + [DialogService], + (service: DialogService) => { + expect(service).toBeTruthy(); + } + )); + + it('should open a confirm dialog', inject( + [MatDialog, DialogService], + (dialog: MatDialog, service: DialogService) => { + spyOn(dialog, 'open').and.returnValue({ afterClosed: () => EMPTY }); + service.openConfirmDialog({ + title: 'Remove dialog', + message: 'Message', + } as ConfirmDialogData); + expect(dialog.open).toHaveBeenCalled(); + } + )); +}); diff --git a/src/app/services/dialog.service.ts b/src/app/services/dialog.service.ts new file mode 100644 index 000000000..b77590e71 --- /dev/null +++ b/src/app/services/dialog.service.ts @@ -0,0 +1,25 @@ +import { ConfirmDialogComponent } from './../shared/components/confirm-dialog/confirm-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { Injectable } from '@angular/core'; +import { ConfirmDialogData } from '../shared/components/confirm-dialog/confirm-dialog.component'; + +@Injectable({ + providedIn: 'root', +}) +export class DialogService { + constructor(private dialog: MatDialog) {} + + /** + * Opens the confirm dialog with provided data + * @param data dialog meta info + */ + openConfirmDialog(data: ConfirmDialogData): void { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + data, + width: '300px', + }); + dialogRef + .afterClosed() + .subscribe((result) => (result ? data.onConfirm() : null)); + } +} diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.html b/src/app/shared/components/confirm-dialog/confirm-dialog.component.html new file mode 100644 index 000000000..320ea3262 --- /dev/null +++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.html @@ -0,0 +1,14 @@ +

+ {{ dialogData?.title }} +

+ + {{ dialogData?.message }} + + + + + diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts b/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts new file mode 100644 index 000000000..b03504349 --- /dev/null +++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts @@ -0,0 +1,41 @@ +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { MockModule, MockPipe, MockProvider } from 'ng-mocks'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ConfirmDialogComponent } from './confirm-dialog.component'; +import { + MatDialog, + MatDialogModule, + MAT_DIALOG_DATA, +} from '@angular/material/dialog'; + +describe('ConfirmDialogComponent', () => { + let component: ConfirmDialogComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ + ConfirmDialogComponent, + MockPipe(TranslatePipe, (value) => JSON.stringify(value)), + ], + providers: [ + MockProvider(MatDialog), + MockProvider(MAT_DIALOG_DATA), + MockProvider(TranslateService), + ], + imports: [MockModule(MatDialogModule)], + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts b/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts new file mode 100644 index 000000000..d6d6878ce --- /dev/null +++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts @@ -0,0 +1,26 @@ +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Component, Inject } from '@angular/core'; + +export interface ConfirmDialogData { + title: string; + message: string; + confirmLabel?: string; + cancelLabel?: string; + onConfirm: () => void; +} + +@Component({ + selector: 'app-confirm-dialog', + templateUrl: './confirm-dialog.component.html', +}) +export class ConfirmDialogComponent { + /** Contains meta information to show in the dialog */ + dialogData; + + /** Creates an instance of ConfirmDialogComponent + * @param data dialog data + */ + constructor(@Inject(MAT_DIALOG_DATA) data: ConfirmDialogData) { + this.dialogData = data; + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 44d85c85b..b46469701 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -7,9 +7,10 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MaterialModule } from '../material.module'; import { FilterPipeModule } from 'ngx-filter-pipe'; import { MomentDatePipe } from './pipes/moment-date.pipe'; +import { ConfirmDialogComponent } from './components/confirm-dialog/confirm-dialog.component'; @NgModule({ - declarations: [HeaderComponent, MomentDatePipe], + declarations: [ConfirmDialogComponent, HeaderComponent, MomentDatePipe], imports: [ CommonModule, FilterPipeModule, @@ -20,6 +21,7 @@ import { MomentDatePipe } from './pipes/moment-date.pipe'; TranslateModule, ], exports: [ + ConfirmDialogComponent, FilterPipeModule, FlexLayoutModule, FormsModule, diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 486e8578e..3fce04508 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -65,7 +65,11 @@ "CUSTOM_USER_AGENT": "Einige IPTV-Anbieter benötigen einen bestimmten 'User-Agent', um ihre Playlist abspielen zu können." }, "UPDATED": "Aktualisiert am", - "REFRESH": "Aktualisieren" + "REFRESH": "Aktualisieren", + "REMOVE_DIALOG": { + "MESSAGE": "Sind Sie sicher, dass Sie diese Wiedergabeliste vollständig löschen möchten", + "TITLE": "" + } }, "TABS": { "FILE_UPLOAD": "Aus Dateisystem hochladen", @@ -108,5 +112,7 @@ "OPEN_CHANNELS_LIST": "Senderliste öffnen", "OPEN_EPG_LIST": "TV-Guide (EPG) öffnen", "TOGGLE_FAVORITE_FLAG": "Als Favoriten hinzufügen/entfernen" - } + }, + "NO": "Nein", + "YES": "Ja" } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 32c2f9b25..67cb0fcc2 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -32,6 +32,10 @@ "AUTO_UPDATE_DESCRIPTION": "If the auto-refresh function is activated, the playlist will be updated automatically each time the app is started.", "CUSTOM_USER_AGENT": "Some IPTV providers need a specific user-agent in order to play their playlist." }, + "REMOVE_DIALOG": { + "TITLE": "Remove playlist", + "MESSAGE": "Are you sure you want to delete this playlist completely?" + }, "UPDATED": "Updated", "REFRESH": "Refresh playlist" }, @@ -108,5 +112,7 @@ "ENGLISH": "English", "RUSSIAN": "Русский", "GERMAN": "Deutsch" - } + }, + "YES": "Yes", + "NO": "No" } diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 88876218d..12cfa760c 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -33,7 +33,11 @@ "CUSTOM_USER_AGENT": "Некоторые IPTV провайдеры требуют указанние определенного пользовательского агента (User Agent) для воспроизведения своего плейлиста." }, "UPDATED": "Обновлен", - "REFRESH": "Обновить плейлист" + "REFRESH": "Обновить плейлист", + "REMOVE_DIALOG": { + "MESSAGE": "Вы уверены, что хотите удалить этот плейлист?", + "TITLE": "" + } }, "FILE_UPLOAD": { "DRAG_DROP": "Перетащите файл в эту область", @@ -108,5 +112,7 @@ "ENGLISH": "English", "RUSSIAN": "Русский", "GERMAN": "Deutsch" - } + }, + "NO": "Нет", + "YES": "Да" }