Skip to content

Commit

Permalink
Added a confirmation service and dialog [#328]
Browse files Browse the repository at this point in the history
  • Loading branch information
mcpierce committed Mar 1, 2021
1 parent 7ae213c commit 7b0ed7b
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 1 deletion.
@@ -0,0 +1,15 @@
<h1 mat-dialog-title>
{{title}}
</h1>

<div mat-dialog-content>
<p>{{message}}</p>
</div>

<div mat-dialog-actions>
<button mat-button
(click)="onDecline()">{{noButton}}</button>
<button mat-raised-button
color="primary"
(click)="onConfirm()">{{yesButton}}</button>
</div>
Empty file.
@@ -0,0 +1,82 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmationComponent } from './confirmation.component';
import {
MAT_DIALOG_DATA,
MatDialogModule,
MatDialogRef
} from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';

describe('ConfirmationComponent', () => {
let component: ConfirmationComponent;
let fixture: ComponentFixture<ConfirmationComponent>;
let dialogRef: jasmine.SpyObj<MatDialogRef<ConfirmationComponent>>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MatDialogModule, MatButtonModule],
declarations: [ConfirmationComponent],
providers: [
{
provide: MatDialogRef,
useValue: {
close: jasmine.createSpy('MatDialogRef.close()')
}
},
{
provide: MAT_DIALOG_DATA,
useValue: {}
}
]
}).compileComponents();

fixture = TestBed.createComponent(ConfirmationComponent);
component = fixture.componentInstance;
dialogRef = TestBed.inject(MatDialogRef) as jasmine.SpyObj<
MatDialogRef<ConfirmationComponent>
>;
fixture.detectChanges();
}));

it('should create', () => {
expect(component).toBeTruthy();
});

describe('when the user confirms', () => {
beforeEach(() => {
component.onConfirm();
});

it('closes the dialog with true', () => {
expect(dialogRef.close).toHaveBeenCalledWith(true);
});
});

describe('when the user declines', () => {
beforeEach(() => {
component.onDecline();
});

it('closes the dialog with true', () => {
expect(dialogRef.close).toHaveBeenCalledWith(false);
});
});
});
@@ -0,0 +1,51 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ConfirmationDialogModel } from '@app/core/models/confirmation-dialog-model';

@Component({
selector: 'cx-confirmation',
templateUrl: './confirmation.component.html',
styleUrls: ['./confirmation.component.scss']
})
export class ConfirmationComponent {
title: string;
message: string;
yesButton: string;
noButton: string;

constructor(
public dialogRef: MatDialogRef<ConfirmationComponent>,
@Inject(MAT_DIALOG_DATA) public data: ConfirmationDialogModel
) {
this.title = data.title;
this.message = data.message;
this.yesButton = data.yesButton;
this.noButton = data.noButton;
}

onConfirm(): void {
this.dialogRef.close(true);
}

onDecline(): void {
this.dialogRef.close(false);
}
}
3 changes: 2 additions & 1 deletion comixed-web/src/app/core/core.module.ts
Expand Up @@ -19,9 +19,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { ConfirmationComponent } from './components/confirmation/confirmation.component';

@NgModule({
declarations: [],
declarations: [ConfirmationComponent],
imports: [CommonModule, MatSnackBarModule],
exports: [MatSnackBarModule],
providers: []
Expand Down
1 change: 1 addition & 0 deletions comixed-web/src/app/core/index.ts
Expand Up @@ -18,5 +18,6 @@

export { TokenService } from '@app/core/services/token.service';
export { AlertService } from '@app/core/services/alert.service';
export { ConfirmationService } from '@app/core/services/confirmation.service';
export { ApiResponse } from '@app/core/models/api-response';
export * from '@app/core/core.functions';
25 changes: 25 additions & 0 deletions comixed-web/src/app/core/models/confirmation-dialog-model.ts
@@ -0,0 +1,25 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

/** ConfirmationDialogModel defines the content to be displayed in a confirmation dialog. */
export interface ConfirmationDialogModel {
title: string;
message: string;
yesButton?: string;
noButton?: string;
}
24 changes: 24 additions & 0 deletions comixed-web/src/app/core/models/confirmation.ts
@@ -0,0 +1,24 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

/** Defines a type used by ConfirmationComponent as a callback. */
export interface Confirmation {
title: string;
message: string;
confirm: () => void;
}
105 changes: 105 additions & 0 deletions comixed-web/src/app/core/services/confirmation.service.spec.ts
@@ -0,0 +1,105 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { TestBed } from '@angular/core/testing';
import { ConfirmationService } from './confirmation.service';
import { TranslateModule } from '@ngx-translate/core';
import {
MatDialog,
MatDialogModule,
MatDialogRef
} from '@angular/material/dialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ConfirmationComponent } from '@app/core/components/confirmation/confirmation.component';
import { LoggerModule } from '@angular-ru/logger';
import { of } from 'rxjs';

describe('ConfirmationService', () => {
let service: ConfirmationService;
let dialog: MatDialog;
let dialogRef: jasmine.SpyObj<MatDialogRef<any>>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ConfirmationComponent],
imports: [
BrowserAnimationsModule,
TranslateModule.forRoot(),
LoggerModule.forRoot(),
MatDialogModule
],
providers: [
{
provide: MatDialogRef,
useValue: {
afterClosed: jasmine.createSpy('MatDialogRef.afterClosed()')
}
}
]
});
service = TestBed.inject(ConfirmationService);
dialog = TestBed.inject(MatDialog);
dialogRef = TestBed.inject(MatDialogRef) as jasmine.SpyObj<
MatDialogRef<any>
>;
});

it('should be created', () => {
expect(service).toBeTruthy();
});

describe('when a user confirms', () => {
let confirmCalled = false;

beforeEach(() => {
spyOn(dialog, 'open').and.returnValue(dialogRef);
dialogRef.afterClosed.and.returnValue(of(true));
service.confirm({
title: '',
message: '',
confirm: () => {
confirmCalled = true;
}
});
});

it('invokes the confirm callback', () => {
expect(confirmCalled).toBeTruthy();
});
});

describe('when a user declines', () => {
let confirmCalled = false;

beforeEach(() => {
spyOn(dialog, 'open').and.returnValue(dialogRef);
dialogRef.afterClosed.and.returnValue(of(false));
service.confirm({
title: '',
message: '',
confirm: () => {
confirmCalled = true;
}
});
});

it('invokes the confirm callback', () => {
expect(confirmCalled).toBeFalsy();
});
});
});
53 changes: 53 additions & 0 deletions comixed-web/src/app/core/services/confirmation.service.ts
@@ -0,0 +1,53 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
import { LoggerService } from '@angular-ru/logger';
import { ConfirmationDialogModel } from '@app/core/models/confirmation-dialog-model';
import { Confirmation } from '@app/core/models/confirmation';
import { ConfirmationComponent } from '@app/core/components/confirmation/confirmation.component';

@Injectable({
providedIn: 'root'
})
export class ConfirmationService {
constructor(
private logger: LoggerService,
private translateService: TranslateService,
private dialog: MatDialog
) {}

confirm(confirmation: Confirmation): void {
this.logger.trace('Showing confirmation dialog:', confirmation);
const dialogRef = this.dialog.open(ConfirmationComponent, {
data: {
title: confirmation.title,
message: confirmation.message,
yesButton: this.translateService.instant('button.yes'),
noButton: this.translateService.instant('button.no')
} as ConfirmationDialogModel
});
dialogRef.afterClosed().subscribe(accepted => {
if (accepted) {
confirmation.confirm();
}
});
}
}

0 comments on commit 7b0ed7b

Please sign in to comment.