@@ -1,4 +1,3 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
|
4 |
import { BookCreateComponent } from './book-create.component';
|
@@ -9,8 +8,7 @@ describe('BookCreateComponent', () => {
|
|
9 |
|
10 |
beforeEach(async () => {
|
11 |
await TestBed.configureTestingModule({
|
12 |
-
|
13 |
-
declarations: [BookCreateComponent]
|
14 |
})
|
15 |
.compileComponents();
|
16 |
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
|
3 |
import { BookCreateComponent } from './book-create.component';
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookCreateComponent ]
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -1,6 +1,4 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
-
import { RouterTestingModule } from '@angular/router/testing';
|
4 |
|
5 |
import { BookEditComponent } from './book-edit.component';
|
6 |
|
@@ -10,8 +8,7 @@ describe('BookEditComponent', () => {
|
|
10 |
|
11 |
beforeEach(async () => {
|
12 |
await TestBed.configureTestingModule({
|
13 |
-
|
14 |
-
declarations: [BookEditComponent]
|
15 |
})
|
16 |
.compileComponents();
|
17 |
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
|
2 |
|
3 |
import { BookEditComponent } from './book-edit.component';
|
4 |
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookEditComponent ]
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -1,6 +1,4 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
-
import { ReactiveFormsModule } from '@angular/forms';
|
4 |
|
5 |
import { BookFormComponent } from './book-form.component';
|
6 |
|
@@ -10,8 +8,7 @@ describe('BookFormComponent', () => {
|
|
10 |
|
11 |
beforeEach(async () => {
|
12 |
await TestBed.configureTestingModule({
|
13 |
-
|
14 |
-
declarations: [BookFormComponent]
|
15 |
})
|
16 |
.compileComponents();
|
17 |
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
|
2 |
|
3 |
import { BookFormComponent } from './book-form.component';
|
4 |
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookFormComponent ]
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -1,5 +1,4 @@
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
-
import { FormGroupDirective, ReactiveFormsModule } from '@angular/forms';
|
3 |
|
4 |
import { FormErrorsComponent } from './form-errors.component';
|
5 |
|
@@ -9,9 +8,7 @@ describe('FormErrorsComponent', () => {
|
|
9 |
|
10 |
beforeEach(async () => {
|
11 |
await TestBed.configureTestingModule({
|
12 |
-
|
13 |
-
declarations: [FormErrorsComponent],
|
14 |
-
providers: [FormGroupDirective]
|
15 |
})
|
16 |
.compileComponents();
|
17 |
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
|
2 |
|
3 |
import { FormErrorsComponent } from './form-errors.component';
|
4 |
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ FormErrorsComponent ]
|
|
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -1,4 +1,3 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { TestBed } from '@angular/core/testing';
|
3 |
|
4 |
import { AsyncValidatorsService } from './async-validators.service';
|
@@ -7,9 +6,7 @@ describe('AsyncValidatorsService', () => {
|
|
7 |
let service: AsyncValidatorsService;
|
8 |
|
9 |
beforeEach(() => {
|
10 |
-
TestBed.configureTestingModule({
|
11 |
-
imports: [HttpClientTestingModule],
|
12 |
-
});
|
13 |
service = TestBed.inject(AsyncValidatorsService);
|
14 |
});
|
15 |
|
|
|
1 |
import { TestBed } from '@angular/core/testing';
|
2 |
|
3 |
import { AsyncValidatorsService } from './async-validators.service';
|
6 |
let service: AsyncValidatorsService;
|
7 |
|
8 |
beforeEach(() => {
|
9 |
+
TestBed.configureTestingModule({});
|
|
|
|
|
10 |
service = TestBed.inject(AsyncValidatorsService);
|
11 |
});
|
12 |
|
@@ -23,11 +23,13 @@
|
|
23 |
[src]="book.thumbnailUrl"
|
24 |
alt="Cover">
|
25 |
<a class="button arrow-left" routerLink="..">Back to list</a>
|
26 |
-
<
|
27 |
-
Remove book
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
33 |
</div>
|
23 |
[src]="book.thumbnailUrl"
|
24 |
alt="Cover">
|
25 |
<a class="button arrow-left" routerLink="..">Back to list</a>
|
26 |
+
<ng-container *bmLoggedinOnly>
|
27 |
+
<button class="red" bmConfirm="Remove book?" (confirm)="removeBook(book.isbn)">
|
28 |
+
Remove book
|
29 |
+
</button>
|
30 |
+
<a class="button"
|
31 |
+
[routerLink]="['/admin/edit', book.isbn]">
|
32 |
+
Edit book
|
33 |
+
</a>
|
34 |
+
</ng-container>
|
35 |
</div>
|
@@ -1,6 +1,4 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
-
import { RouterTestingModule } from '@angular/router/testing';
|
4 |
|
5 |
import { BookDetailsComponent } from './book-details.component';
|
6 |
|
@@ -10,8 +8,7 @@ describe('BookDetailsComponent', () => {
|
|
10 |
|
11 |
beforeEach(async () => {
|
12 |
await TestBed.configureTestingModule({
|
13 |
-
|
14 |
-
declarations: [BookDetailsComponent]
|
15 |
})
|
16 |
.compileComponents();
|
17 |
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
|
2 |
|
3 |
import { BookDetailsComponent } from './book-details.component';
|
4 |
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookDetailsComponent ]
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -23,10 +23,8 @@ export class BookDetailsComponent {
|
|
23 |
}
|
24 |
|
25 |
removeBook(isbn: string) {
|
26 |
-
|
27 |
-
this.
|
28 |
-
|
29 |
-
});
|
30 |
-
}
|
31 |
}
|
32 |
}
|
23 |
}
|
24 |
|
25 |
removeBook(isbn: string) {
|
26 |
+
this.service.remove(isbn).subscribe(() => {
|
27 |
+
this.router.navigateByUrl('/books');
|
28 |
+
});
|
|
|
|
|
29 |
}
|
30 |
}
|
@@ -1,4 +1,3 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
|
4 |
import { BookListComponent } from './book-list.component';
|
@@ -9,8 +8,7 @@ describe('BookListComponent', () => {
|
|
9 |
|
10 |
beforeEach(async () => {
|
11 |
await TestBed.configureTestingModule({
|
12 |
-
|
13 |
-
declarations: [BookListComponent]
|
14 |
})
|
15 |
.compileComponents();
|
16 |
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
|
3 |
import { BookListComponent } from './book-list.component';
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookListComponent ]
|
|
|
12 |
})
|
13 |
.compileComponents();
|
14 |
|
@@ -6,13 +6,17 @@ import { BookListComponent } from './book-list/book-list.component';
|
|
6 |
import { BookListItemComponent } from './book-list-item/book-list-item.component';
|
7 |
import { BookDetailsComponent } from './book-details/book-details.component';
|
8 |
import { IsbnPipe } from './shared/isbn.pipe';
|
|
|
|
|
9 |
|
10 |
@NgModule({
|
11 |
declarations: [
|
12 |
BookListComponent,
|
13 |
BookListItemComponent,
|
14 |
BookDetailsComponent,
|
15 |
-
IsbnPipe
|
|
|
|
|
16 |
],
|
17 |
imports: [
|
18 |
CommonModule,
|
6 |
import { BookListItemComponent } from './book-list-item/book-list-item.component';
|
7 |
import { BookDetailsComponent } from './book-details/book-details.component';
|
8 |
import { IsbnPipe } from './shared/isbn.pipe';
|
9 |
+
import { ConfirmDirective } from './shared/confirm.directive';
|
10 |
+
import { LoggedinOnlyDirective } from './shared/loggedin-only.directive';
|
11 |
|
12 |
@NgModule({
|
13 |
declarations: [
|
14 |
BookListComponent,
|
15 |
BookListItemComponent,
|
16 |
BookDetailsComponent,
|
17 |
+
IsbnPipe,
|
18 |
+
ConfirmDirective,
|
19 |
+
LoggedinOnlyDirective
|
20 |
],
|
21 |
imports: [
|
22 |
CommonModule,
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ConfirmDirective } from './confirm.directive';
|
2 |
+
|
3 |
+
describe('ConfirmDirective', () => {
|
4 |
+
it('should create an instance', () => {
|
5 |
+
const directive = new ConfirmDirective();
|
6 |
+
expect(directive).toBeTruthy();
|
7 |
+
});
|
8 |
+
});
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
2 |
+
|
3 |
+
@Directive({
|
4 |
+
selector: '[bmConfirm]'
|
5 |
+
})
|
6 |
+
export class ConfirmDirective {
|
7 |
+
@Input('bmConfirm') confirmText?: string;
|
8 |
+
@Output() confirm = new EventEmitter<void>();
|
9 |
+
|
10 |
+
@HostListener('click') onClick() {
|
11 |
+
if (window.confirm(this.confirmText)) {
|
12 |
+
this.confirm.emit();
|
13 |
+
}
|
14 |
+
}
|
15 |
+
}
|
@@ -1,19 +1,8 @@
|
|
1 |
import { IsbnPipe } from './isbn.pipe';
|
2 |
|
3 |
describe('IsbnPipe', () => {
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
beforeEach(() => {
|
8 |
-
pipe = new IsbnPipe();
|
9 |
-
});
|
10 |
-
|
11 |
-
it('should format an ISBN with a dash', () => {
|
12 |
-
expect(pipe.transform('9783864909467'))
|
13 |
-
.toBe('978-3864909467');
|
14 |
-
});
|
15 |
-
|
16 |
-
it('should ignore empty values', () => {
|
17 |
-
expect(pipe.transform('')).toBe('');
|
18 |
});
|
19 |
});
|
1 |
import { IsbnPipe } from './isbn.pipe';
|
2 |
|
3 |
describe('IsbnPipe', () => {
|
4 |
+
it('create an instance', () => {
|
5 |
+
const pipe = new IsbnPipe();
|
6 |
+
expect(pipe).toBeTruthy();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
});
|
8 |
});
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { LoggedinOnlyDirective } from './loggedin-only.directive';
|
2 |
+
|
3 |
+
describe('LoggedinOnlyDirective', () => {
|
4 |
+
it('should create an instance', () => {
|
5 |
+
const directive = new LoggedinOnlyDirective();
|
6 |
+
expect(directive).toBeTruthy();
|
7 |
+
});
|
8 |
+
});
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Directive, OnDestroy, TemplateRef, ViewContainerRef } from '@angular/core';
|
2 |
+
import { Subject, takeUntil } from 'rxjs';
|
3 |
+
|
4 |
+
import { AuthService } from '../../shared/auth.service';
|
5 |
+
|
6 |
+
@Directive({
|
7 |
+
selector: '[bmLoggedinOnly]'
|
8 |
+
})
|
9 |
+
export class LoggedinOnlyDirective implements OnDestroy {
|
10 |
+
private destroy$ = new Subject<void>();
|
11 |
+
|
12 |
+
constructor(
|
13 |
+
private template: TemplateRef<unknown>,
|
14 |
+
private viewContainer: ViewContainerRef,
|
15 |
+
private authService: AuthService
|
16 |
+
) {
|
17 |
+
this.authService.isAuthenticated$.pipe(
|
18 |
+
takeUntil(this.destroy$)
|
19 |
+
).subscribe(isAuthenticated => {
|
20 |
+
if (isAuthenticated) {
|
21 |
+
this.viewContainer.createEmbeddedView(this.template);
|
22 |
+
} else {
|
23 |
+
this.viewContainer.clear();
|
24 |
+
}
|
25 |
+
});
|
26 |
+
}
|
27 |
+
|
28 |
+
ngOnDestroy(): void {
|
29 |
+
this.destroy$.next();
|
30 |
+
}
|
31 |
+
}
|
@@ -1,4 +1,3 @@
|
|
1 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
2 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3 |
|
4 |
import { SearchComponent } from './search.component';
|
@@ -9,7 +8,6 @@ describe('SearchComponent', () => {
|
|
9 |
|
10 |
beforeEach(async () => {
|
11 |
await TestBed.configureTestingModule({
|
12 |
-
imports: [HttpClientTestingModule],
|
13 |
declarations: [ SearchComponent ]
|
14 |
})
|
15 |
.compileComponents();
|
|
|
1 |
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
|
3 |
import { SearchComponent } from './search.component';
|
8 |
|
9 |
beforeEach(async () => {
|
10 |
await TestBed.configureTestingModule({
|
|
|
11 |
declarations: [ SearchComponent ]
|
12 |
})
|
13 |
.compileComponents();
|
@@ -1,5 +1,4 @@
|
|
1 |
import { TestBed } from '@angular/core/testing';
|
2 |
-
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
3 |
|
4 |
import { BookStoreService } from './book-store.service';
|
5 |
|
@@ -7,9 +6,7 @@ describe('BookStoreService', () => {
|
|
7 |
let service: BookStoreService;
|
8 |
|
9 |
beforeEach(() => {
|
10 |
-
TestBed.configureTestingModule({
|
11 |
-
imports: [HttpClientTestingModule],
|
12 |
-
});
|
13 |
service = TestBed.inject(BookStoreService);
|
14 |
});
|
15 |
|
1 |
import { TestBed } from '@angular/core/testing';
|
|
|
2 |
|
3 |
import { BookStoreService } from './book-store.service';
|
4 |
|
6 |
let service: BookStoreService;
|
7 |
|
8 |
beforeEach(() => {
|
9 |
+
TestBed.configureTestingModule({});
|
|
|
|
|
10 |
service = TestBed.inject(BookStoreService);
|
11 |
});
|
12 |
|