Skip to content

Commit

Permalink
m9: Optimistic and Pessimistic
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-okrushko committed Nov 18, 2020
1 parent ae262d1 commit 95abc5d
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 9 deletions.
6 changes: 5 additions & 1 deletion apps/api/src/app/cart/cart.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { CartItem } from '@ngrx-nx-workshop/api-interfaces';


@Injectable()
export class CartService {
private cartProducts: CartItem[] = [];
Expand All @@ -10,6 +11,9 @@ export class CartService {
}

addProduct(id: string): CartItem[] {
if (Math.random() < 0.25) {
throw new HttpException('cart failed', HttpStatus.FORBIDDEN);
}
const item = this.getItem(id);
if (item) {
item.quantity += 1;
Expand Down
7 changes: 7 additions & 0 deletions apps/ngrx-workshop/src/app/cart/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ export const fetchCartItemsSuccess = createAction(
);

export const fetchCartItemsError = createAction('[Cart API] fetch items error');

export const addToCartSuccess = createAction('[Cart API] add product success');

export const addToCartError = createAction(
'[Cart API] add product error',
props<{ productId: string }>()
);
2 changes: 2 additions & 0 deletions apps/ngrx-workshop/src/app/cart/cart.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { StoreModule } from '@ngrx/store';
import { CART_FEATURE_KEY, reducer } from './reducer';
import { CartEffects } from './effects';
import { EffectsModule } from '@ngrx/effects';
import { MatSnackBarModule } from '@angular/material/snack-bar';

@NgModule({
imports: [
MatSnackBarModule,
StoreModule.forFeature(CART_FEATURE_KEY, reducer),
EffectsModule.forFeature([CartEffects])
]
Expand Down
6 changes: 2 additions & 4 deletions apps/ngrx-workshop/src/app/cart/cart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ export class CartService {

constructor(private readonly http: HttpClient) {}

addProduct(id: string): void {
this.http
.post<CartItem[]>(`/api/cart/add/${id}`, {})
.subscribe(arr => this.cartItemsSubject$.next(arr));
addProduct(id: string): Observable<CartItem[]> {
return this.http.post<CartItem[]>(`/api/cart/add/${id}`, {});
}

removeProduct(id: string): void {
Expand Down
38 changes: 35 additions & 3 deletions apps/ngrx-workshop/src/app/cart/effects.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { Injectable } from '@angular/core';
import { Injectable, ApplicationRef } from '@angular/core';
import { CartService } from './cart.service';
import { Actions, createEffect, ofType } from '@ngrx/effects';

import * as actions from './actions';
import * as cartDetailsActions from './cart-details/actions';
import { switchMap, catchError, map } from 'rxjs/operators';
import * as productDetailsActions from '../product/product-details/actions';

import { switchMap, catchError, map, mergeMap, tap } from 'rxjs/operators';
import { of, defer, timer } from 'rxjs';
import { MatSnackBar } from '@angular/material/snack-bar';

const REFRESH_CART_ITEMS_INTEVAL_MS = 20 * 1000; // 20 seconds

@Injectable()
export class CartEffects {
constructor(
private readonly actions$: Actions,
private readonly cartService: CartService
private readonly cartService: CartService,
private readonly snackBar: MatSnackBar,
private readonly appRef: ApplicationRef
) {}

fetchCartItems$ = createEffect(() =>
Expand All @@ -32,6 +37,33 @@ export class CartEffects {
)
);

addProductToCart$ = createEffect(() =>
this.actions$.pipe(
ofType(productDetailsActions.addToCart),
mergeMap(({ productId }) =>
this.cartService.addProduct(productId).pipe(
map(() => actions.addToCartSuccess()),
// passing the productId to the Error, so it can be restored
catchError(() => of(actions.addToCartError({ productId })))
)
)
)
);

handleAddProductError$ = createEffect(
() =>
this.actions$.pipe(
ofType(actions.addToCartError),
tap(() => {
this.snackBar.open('Could not add item to the cart', 'Error', {
duration: 2500
});
this.appRef.tick();
})
),
{ dispatch: false }
);

init$ = createEffect(() =>
defer(() =>
timer(0, REFRESH_CART_ITEMS_INTEVAL_MS).pipe(
Expand Down
15 changes: 14 additions & 1 deletion apps/ngrx-workshop/src/app/cart/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,20 @@ const cartReducer = createReducer(
},
{}
)
}))
})),
on(actions.addToCartError, (state, { productId }) => {
const currentQuantity = state.cartItems && state.cartItems[productId];
const newCartItems = {...state.cartItems};
if (currentQuantity && currentQuantity > 1) {
newCartItems[productId] = currentQuantity - 1;
} else {
delete newCartItems[productId];
}
return {
...state,
cartItems: newCartItems,
};
})
);

export function reducer(state: CartState | undefined, action: Action) {
Expand Down

0 comments on commit 95abc5d

Please sign in to comment.