diff --git a/src/app/admin/admin-routing.module.ts b/src/app/admin/admin-routing.module.ts
new file mode 100644
index 0000000..e49a121
--- /dev/null
+++ b/src/app/admin/admin-routing.module.ts
@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { BookCreateComponent } from './book-create/book-create.component';
+
+const routes: Routes = [
+ { path: 'admin', redirectTo: 'admin/create' },
+ { path: 'admin/create', component: BookCreateComponent },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class AdminRoutingModule {}
diff --git a/src/app/admin/admin.module.ts b/src/app/admin/admin.module.ts
new file mode 100644
index 0000000..8914a58
--- /dev/null
+++ b/src/app/admin/admin.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { AdminRoutingModule } from './admin-routing.module';
+import { FormsModule } from '@angular/forms';
+import { BookFormComponent } from './book-form/book-form.component';
+import { BookCreateComponent } from './book-create/book-create.component';
+
+@NgModule({
+ declarations: [
+ BookFormComponent,
+ BookCreateComponent
+ ],
+ imports: [CommonModule, AdminRoutingModule, FormsModule],
+})
+export class AdminModule {}
diff --git a/src/app/admin/book-create/book-create.component.css b/src/app/admin/book-create/book-create.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/admin/book-create/book-create.component.html b/src/app/admin/book-create/book-create.component.html
new file mode 100644
index 0000000..8b7d594
--- /dev/null
+++ b/src/app/admin/book-create/book-create.component.html
@@ -0,0 +1,3 @@
+
Create Book
+
+
diff --git a/src/app/admin/book-create/book-create.component.spec.ts b/src/app/admin/book-create/book-create.component.spec.ts
new file mode 100644
index 0000000..c24f07a
--- /dev/null
+++ b/src/app/admin/book-create/book-create.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BookCreateComponent } from './book-create.component';
+
+describe('BookCreateComponent', () => {
+ let component: BookCreateComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [BookCreateComponent]
+ });
+ fixture = TestBed.createComponent(BookCreateComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/book-create/book-create.component.ts b/src/app/admin/book-create/book-create.component.ts
new file mode 100644
index 0000000..c4bae86
--- /dev/null
+++ b/src/app/admin/book-create/book-create.component.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { BookStoreService } from 'src/app/shared/book-store.service';
+import { Book } from 'src/shared/book';
+
+@Component({
+ selector: 'bm-book-create',
+ templateUrl: './book-create.component.html',
+ styleUrls: ['./book-create.component.css'],
+})
+export class BookCreateComponent {
+ constructor(
+ private service: BookStoreService,
+ private router: Router,
+ ) {}
+
+ create(book: Book) {
+ this.service.create(book).subscribe((createdBook) => {
+ this.router.navigate(['/books', createdBook.isbn]);
+ });
+ }
+}
diff --git a/src/app/admin/book-form/book-form.component.css b/src/app/admin/book-form/book-form.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/admin/book-form/book-form.component.html b/src/app/admin/book-form/book-form.component.html
new file mode 100644
index 0000000..b084601
--- /dev/null
+++ b/src/app/admin/book-form/book-form.component.html
@@ -0,0 +1,19 @@
+
diff --git a/src/app/admin/book-form/book-form.component.spec.ts b/src/app/admin/book-form/book-form.component.spec.ts
new file mode 100644
index 0000000..15f2e4a
--- /dev/null
+++ b/src/app/admin/book-form/book-form.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BookFormComponent } from './book-form.component';
+
+describe('BookFormComponent', () => {
+ let component: BookFormComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [BookFormComponent]
+ });
+ fixture = TestBed.createComponent(BookFormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/book-form/book-form.component.ts b/src/app/admin/book-form/book-form.component.ts
new file mode 100644
index 0000000..25afafa
--- /dev/null
+++ b/src/app/admin/book-form/book-form.component.ts
@@ -0,0 +1,21 @@
+import { Component, Output, EventEmitter } from '@angular/core';
+import { Book } from 'src/shared/book';
+
+@Component({
+ selector: 'bm-book-form',
+ templateUrl: './book-form.component.html',
+ styleUrls: ['./book-form.component.css'],
+})
+export class BookFormComponent {
+ @Output() submitBook = new EventEmitter();
+
+ submitForm() {
+ this.submitBook.emit(this.book);
+ }
+
+ book: Book = {
+ isbn: '',
+ title: '',
+ authors: [''],
+ };
+}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 635289f..3c6e160 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,10 +1,21 @@
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 97d0803..06bca4a 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,19 +1,12 @@
import { Component } from '@angular/core';
-import { Book } from 'src/shared/book';
-
+import { AuthService } from './shared/auth.service';
@Component({
selector: 'bm-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
- title = 'book-monkey';
- book: Book | null = null;
+ constructor(public auth: AuthService) {}
- showList() {
- this.book = null;
- }
- showDetails(book: Book) {
- this.book = book;
- }
+ title = 'book-monkey';
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 1237d76..450cbff 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -5,12 +5,17 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BooksModule } from './books/books.module';
import { HomeComponent } from './home/home.component';
-import { HttpClientModule } from '@angular/common/http';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
+import { SearchComponent } from './search/search.component';
+import { AuthInterceptor } from './shared/auth.interceptor';
+import { AdminModule } from './admin/admin.module';
@NgModule({
- declarations: [AppComponent, HomeComponent],
- imports: [BrowserModule, AppRoutingModule, BooksModule, HttpClientModule],
- providers: [],
+ declarations: [AppComponent, HomeComponent, SearchComponent],
+ imports: [BrowserModule, AppRoutingModule, BooksModule, HttpClientModule, AdminModule],
+ providers: [
+ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
+ ],
bootstrap: [AppComponent],
})
export class AppModule {}
diff --git a/src/app/books/book-list/book-list.component.ts b/src/app/books/book-list/book-list.component.ts
index 2d8147e..f33a0c7 100644
--- a/src/app/books/book-list/book-list.component.ts
+++ b/src/app/books/book-list/book-list.component.ts
@@ -15,8 +15,4 @@ export class BookListComponent {
constructor(private service: BookStoreService) {
this.books$ = this.service.getAll();
}
-
- doSelect(book: Book) {
- this.selectBook.emit(book);
- }
}
diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html
index d872ed6..649a058 100644
--- a/src/app/home/home.component.html
+++ b/src/app/home/home.component.html
@@ -1,3 +1,6 @@
Home
Show book list
+
+Search
+
diff --git a/src/app/search/search.component.css b/src/app/search/search.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/search/search.component.html b/src/app/search/search.component.html
new file mode 100644
index 0000000..acfdeb2
--- /dev/null
+++ b/src/app/search/search.component.html
@@ -0,0 +1,18 @@
+
+
+
diff --git a/src/app/search/search.component.spec.ts b/src/app/search/search.component.spec.ts
new file mode 100644
index 0000000..94a4cfa
--- /dev/null
+++ b/src/app/search/search.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SearchComponent } from './search.component';
+
+describe('SearchComponent', () => {
+ let component: SearchComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [SearchComponent]
+ });
+ fixture = TestBed.createComponent(SearchComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/search/search.component.ts b/src/app/search/search.component.ts
new file mode 100644
index 0000000..3becc34
--- /dev/null
+++ b/src/app/search/search.component.ts
@@ -0,0 +1,34 @@
+import { Component } from '@angular/core';
+import {
+ Subject,
+ debounceTime,
+ distinctUntilChanged,
+ filter,
+ switchMap,
+ tap,
+ Observable,
+} from 'rxjs';
+import { BookStoreService } from '../shared/book-store.service';
+import { Book } from 'src/shared/book';
+
+@Component({
+ selector: 'bm-search',
+ templateUrl: './search.component.html',
+ styleUrls: ['./search.component.css'],
+})
+export class SearchComponent {
+ input$ = new Subject();
+ isLoading = false;
+ results$: Observable;
+
+ constructor(private service: BookStoreService) {
+ this.results$ = this.input$.pipe(
+ filter((term) => term.length >= 3),
+ debounceTime(500),
+ distinctUntilChanged(),
+ tap(() => (this.isLoading = true)),
+ switchMap((term) => this.service.getAllSearch(term)),
+ tap(() => (this.isLoading = false)),
+ );
+ }
+}
diff --git a/src/app/shared/auth.interceptor.spec.ts b/src/app/shared/auth.interceptor.spec.ts
new file mode 100644
index 0000000..7ab58db
--- /dev/null
+++ b/src/app/shared/auth.interceptor.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthInterceptor } from './auth.interceptor';
+
+describe('AuthInterceptor', () => {
+ beforeEach(() => TestBed.configureTestingModule({
+ providers: [
+ AuthInterceptor
+ ]
+ }));
+
+ it('should be created', () => {
+ const interceptor: AuthInterceptor = TestBed.inject(AuthInterceptor);
+ expect(interceptor).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/auth.interceptor.ts b/src/app/shared/auth.interceptor.ts
new file mode 100644
index 0000000..4630512
--- /dev/null
+++ b/src/app/shared/auth.interceptor.ts
@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+import {
+ HttpRequest,
+ HttpHandler,
+ HttpEvent,
+ HttpInterceptor,
+} from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { AuthService } from './auth.service';
+
+@Injectable()
+export class AuthInterceptor implements HttpInterceptor {
+ constructor(private authService: AuthService) {}
+ intercept(
+ request: HttpRequest,
+ next: HttpHandler,
+ ): Observable> {
+ const token = '1234567890';
+ if (this.authService.isAuthenticated) {
+ //token in hearder einfügen
+ const reqWithToken = request.clone({
+ setHeaders: { Authorization: `Bearer${token}` },
+ });
+ return next.handle(reqWithToken);
+ } else {
+ //Request unverändert weitergeben
+ return next.handle(request);
+ }
+ }
+}
diff --git a/src/app/shared/auth.service.spec.ts b/src/app/shared/auth.service.spec.ts
new file mode 100644
index 0000000..f1251ca
--- /dev/null
+++ b/src/app/shared/auth.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthService } from './auth.service';
+
+describe('AuthService', () => {
+ let service: AuthService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(AuthService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/auth.service.ts b/src/app/shared/auth.service.ts
new file mode 100644
index 0000000..e235c84
--- /dev/null
+++ b/src/app/shared/auth.service.ts
@@ -0,0 +1,24 @@
+import { Injectable } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class AuthService {
+ private _isAuthenticated$ = new BehaviorSubject(true);
+ readonly isAuthenticated$ = this._isAuthenticated$.asObservable();
+
+ constructor() {}
+
+ get isAuthenticated() {
+ return this._isAuthenticated$.value;
+ }
+
+ login() {
+ this._isAuthenticated$.next(true);
+ }
+
+ logout() {
+ this._isAuthenticated$.next(false);
+ }
+}
diff --git a/src/app/shared/book-store.service.ts b/src/app/shared/book-store.service.ts
index f054a21..f42e72c 100644
--- a/src/app/shared/book-store.service.ts
+++ b/src/app/shared/book-store.service.ts
@@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
+import { Observable, catchError, of } from 'rxjs';
import { Book } from 'src/shared/book';
@Injectable({
@@ -12,7 +12,12 @@ export class BookStoreService {
constructor(private http: HttpClient) {}
getAll(): Observable {
- return this.http.get(`${this.apiUrl}/books`);
+ return this.http.get(`${this.apiUrl}/books`).pipe(
+ catchError((err) => {
+ console.error(err);
+ return of([]);
+ }),
+ );
}
getSingle(isbn: string): Observable {
@@ -22,4 +27,17 @@ export class BookStoreService {
remove(isbn: string): Observable {
return this.http.delete(`${this.apiUrl}/books/${isbn}`);
}
+
+ getAllSearch(term: string): Observable {
+ return this.http.get(`${this.apiUrl}/books/search/${term}`).pipe(
+ catchError((err) => {
+ console.error(err);
+ return of([]);
+ }),
+ );
+ }
+
+ create(book: Book): Observable {
+ return this.http.post(`${this.apiUrl}/books`, book);
+ }
}