diff --git a/book-rating/libs/data-books/src/index.ts b/book-rating/libs/data-books/src/index.ts index 3226e1c..cfdbf05 100644 --- a/book-rating/libs/data-books/src/index.ts +++ b/book-rating/libs/data-books/src/index.ts @@ -3,3 +3,4 @@ export * from './lib/book'; export * from './lib/book-rating.service'; export * from './lib/book-store.service'; export * from './lib/store/book.selectors'; +export * from './lib/store/book.actions'; diff --git a/book-rating/libs/data-books/src/lib/book-rating.service.ts b/book-rating/libs/data-books/src/lib/book-rating.service.ts index b619d23..1b1b738 100644 --- a/book-rating/libs/data-books/src/lib/book-rating.service.ts +++ b/book-rating/libs/data-books/src/lib/book-rating.service.ts @@ -1,5 +1,8 @@ -import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Inject, Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; import { Book } from '..'; +import { API_URL } from './book-store.service'; const minRating = 1; const maxRating = 5; @@ -10,16 +13,11 @@ const maxRating = 5; }) export class BookRatingService { - rateDown(book: Book): Book { - return { - ...book, - rating: (book.rating > minRating) ? book.rating - 1 : minRating - }; - } + constructor(public http: HttpClient, + @Inject(API_URL) private api: string) {} - rateUp(book: Book): Book { - const rating = Math.min(book.rating + 1, maxRating); - return { ...book, rating }; + rateBook(isbn: string, rating: number): Observable { + return this.http.post(this.api + '/books/' + isbn + '/rate', { rating }); } isRateUpAllowed(book: Book) { diff --git a/book-rating/libs/data-books/src/lib/store/book.actions.ts b/book-rating/libs/data-books/src/lib/store/book.actions.ts index 815b49d..1f5035f 100644 --- a/book-rating/libs/data-books/src/lib/store/book.actions.ts +++ b/book-rating/libs/data-books/src/lib/store/book.actions.ts @@ -15,3 +15,31 @@ export const loadBooksFailure = createAction( '[Book] Load Books Failure', props<{ error: HttpErrorResponse }>() ); + +export const createBook = createAction( + '[Book] Create Book', + props<{ book: Book }>() +); + +export const createBookSuccess = createAction( + '[Book] Create Book Success' +); + +export const createBookFailure = createAction( + '[Book] Create Book Failure', + props<{ error: HttpErrorResponse }>() +); + +export const rateBook = createAction( + '[Book] Rate Book', + props<{ book: Book, rating: number }>() +); + +export const rateBookSuccess = createAction( + '[Book] Rate Book Success' +); + +export const rateBookFailure = createAction( + '[Book] Rate Book Failure', + props<{ error: HttpErrorResponse }>() +); diff --git a/book-rating/libs/data-books/src/lib/store/book.effects.ts b/book-rating/libs/data-books/src/lib/store/book.effects.ts index 1a46a8f..13264f3 100644 --- a/book-rating/libs/data-books/src/lib/store/book.effects.ts +++ b/book-rating/libs/data-books/src/lib/store/book.effects.ts @@ -2,7 +2,8 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { of } from 'rxjs'; import { catchError, map, switchMap } from 'rxjs/operators'; - +import { Book } from '../book'; +import { BookRatingService } from '../book-rating.service'; import { BookStoreService } from '../book-store.service'; import * as BookActions from './book.actions'; @@ -13,15 +14,55 @@ export class BookEffects { return this.actions$.pipe( ofType(BookActions.loadBooks), - switchMap(() => - this.bs.getBooks().pipe( - map(books => BookActions.loadBooksSuccess({ books })), - catchError(error => of(BookActions.loadBooksFailure({ error })))) + switchMap(() => this.onLoadBooks()) + ); + }); + + createBook$ = createEffect(() => { + return this.actions$.pipe( + ofType(BookActions.createBook), + switchMap((type: {book: Book}) => + this.bs.createBook(type.book).pipe( + map(() => BookActions.createBookSuccess()), + catchError(error => of(BookActions.createBookFailure({ error })))) ) ); }); - constructor(private actions$: Actions, - private bs: BookStoreService) {} + createBookSuccess$ = createEffect(() => { + return this.actions$.pipe( + ofType(BookActions.createBookSuccess), + switchMap(() => this.onLoadBooks()) + ); + }); + + rateBook$ = createEffect(() => { + return this.actions$.pipe( + ofType(BookActions.rateBook), + switchMap((type: {book: Book, rating: number}) => + this.br.rateBook(type.book.isbn, type.rating).pipe( + map(() => BookActions.rateBookSuccess()), + catchError(error => of(BookActions.rateBookFailure({ error })))) + ) + ); + }); + + rateBookSuccess$ = createEffect(() => { + return this.actions$.pipe( + ofType(BookActions.rateBookSuccess), + switchMap(() => this.onLoadBooks()) + ); + }); + + constructor( + private actions$: Actions, + private bs: BookStoreService, + private br: BookRatingService) {} + + private onLoadBooks() { + return this.bs.getBooks().pipe( + map(books => BookActions.loadBooksSuccess({ books })), + catchError(error => of(BookActions.loadBooksFailure({ error })))); + } } diff --git a/book-rating/libs/data-books/src/lib/store/book.reducer.ts b/book-rating/libs/data-books/src/lib/store/book.reducer.ts index be12e54..5e3c9f6 100644 --- a/book-rating/libs/data-books/src/lib/store/book.reducer.ts +++ b/book-rating/libs/data-books/src/lib/store/book.reducer.ts @@ -1,5 +1,5 @@ import { Book } from '@book-rating/data-books'; -import { Action, createReducer, on } from '@ngrx/store'; +import { createReducer, on } from '@ngrx/store'; import * as BookActions from './book.actions'; export const bookFeatureKey = 'book'; @@ -11,7 +11,7 @@ export interface State { export const initialState: State = { books: [], - loading: false, + loading: false }; @@ -23,16 +23,46 @@ export const reducer = createReducer( loading: true })), - on(BookActions.loadBooksSuccess, (state, { books }) => ({ + on(BookActions.loadBooksSuccess, (state, { books }) => ({ ...state, loading: false, books })), - on(BookActions.loadBooksFailure, state => ({ + on(BookActions.loadBooksFailure, state => ({ ...state, loading: false, books: [] + })), + + on(BookActions.createBook, (state) => ({ + ...state, + loading: true + })), + + on(BookActions.createBookSuccess, (state) => ({ + ...state, + loading: false + })), + + on(BookActions.createBookFailure, state => ({ + ...state, + loading: false + })), + + on(BookActions.rateBook, (state) => ({ + ...state, + loading: true + })), + + on(BookActions.rateBookSuccess, (state) => ({ + ...state, + loading: false + })), + + on(BookActions.rateBookFailure, state => ({ + ...state, + loading: false })) ); diff --git a/book-rating/libs/feature-books/src/lib/dashboard/dashboard.component.ts b/book-rating/libs/feature-books/src/lib/dashboard/dashboard.component.ts index 9894011..97cbdbf 100644 --- a/book-rating/libs/feature-books/src/lib/dashboard/dashboard.component.ts +++ b/book-rating/libs/feature-books/src/lib/dashboard/dashboard.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Book, selectBookByIsbn, selectBooks, selectBooksLoading } from '@book-rating/data-books'; +import { Book, createBook, rateBook, selectBookByIsbn, selectBooks, selectBooksLoading } from '@book-rating/data-books'; import { select, Store } from '@ngrx/store'; @@ -24,27 +24,18 @@ export class DashboardComponent { doRateDown(book: Book): void { - // const ratedBook = this.br.rateDown(book); - // this.updateAndSort(ratedBook); + this.store.dispatch(rateBook({ book, rating: book.rating - 1 })); } doRateUp(book: Book): void { - // const ratedBook = this.br.rateUp(book); - // // const ratedBook = { - // // ...book, - // // rating: Math.min(book.rating + 1, 5) - // // }; - // this.updateAndSort(ratedBook); + this.store.dispatch(rateBook({ book, rating: book.rating + 1 })); } updateAndSort(ratedBook: Book): void { - // this.books = this.books - // .map(b => b.isbn === ratedBook.isbn ? ratedBook : b) - // .sort((a , b) => b.rating - a.rating) + // rating triggers reload } - addBook(newBook: Book): void { - // this.bs.createBook(newBook) - // .subscribe(() => this.books = [...this.books, newBook]); + addBook(book: Book): void { + this.store.dispatch(createBook({ book })); } }