cloudfoundry/stratos

View on GitHub
src/frontend/packages/store/src/effects/user-favorites-effect.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { catchError, first, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';

import { EntityDeleteCompleteAction } from '../actions/entity.delete.actions';
import { ClearPaginationOfEntity } from '../actions/pagination.actions';
import {
  GetUserFavoritesAction,
  GetUserFavoritesFailedAction,
  GetUserFavoritesSuccessAction,
  RemoveUserFavoriteAction,
  RemoveUserFavoriteSuccessAction,
  SaveUserFavoriteAction,
  SaveUserFavoriteSuccessAction,
  ToggleUserFavoriteAction,
  UpdateUserFavoriteMetadataAction,
  UpdateUserFavoriteMetadataSuccessAction,
} from '../actions/user-favourites.actions';
import { InternalAppState } from '../app-state';
import { entityCatalog } from '../entity-catalog/entity-catalog';
import { proxyAPIVersion } from '../jetstream';
import { NormalizedResponse } from '../types/api.types';
import { StartRequestAction, WrapperRequestActionFailed, WrapperRequestActionSuccess } from '../types/request.types';
import { IFavoriteMetadata, UserFavorite, userFavoritesPaginationKey } from '../types/user-favorites.types';
import { UserFavoriteManager } from '../user-favorite-manager';
import { STRATOS_ENDPOINT_TYPE, userFavouritesEntityType } from './../helpers/stratos-entity-factory';

const favoriteUrlPath = `/pp/${proxyAPIVersion}/favorites`;

@Injectable()
export class UserFavoritesEffect {

  constructor(
    private http: HttpClient,
    private actions$: Actions,
    private store: Store<InternalAppState>,
    private userFavoriteManager: UserFavoriteManager
  ) {
  }

  @Effect() saveFavorite = this.actions$.pipe(
    ofType<SaveUserFavoriteAction>(SaveUserFavoriteAction.ACTION_TYPE),
    mergeMap(action => {
      const actionType = 'update';
      this.store.dispatch(new StartRequestAction(action, actionType));
      return this.http.post<UserFavorite<IFavoriteMetadata>>(favoriteUrlPath, action.favorite.getPayload()).pipe(
        switchMap(newFavorite => {
          this.store.dispatch(new WrapperRequestActionSuccess(null, action, actionType));
          this.store.dispatch(new SaveUserFavoriteSuccessAction(newFavorite));
          return [];
        }),
        catchError(() => {
          this.store.dispatch(new WrapperRequestActionFailed('Failed to update user favorite', action, actionType));
          return [];
        })
      );
    })
  );

  @Effect({ dispatch: false }) getFavorite$ = this.actions$.pipe(
    ofType<GetUserFavoritesAction>(GetUserFavoritesAction.ACTION_TYPE),
    switchMap((action: GetUserFavoritesAction) => {
      const favEntityKey = entityCatalog.getEntityKey(action);
      const actionType = 'fetch';
      this.store.dispatch(new StartRequestAction(action, actionType));
      return this.http.get<UserFavorite<IFavoriteMetadata>[]>(favoriteUrlPath).pipe(
        switchMap(favorites => {
          const mappedData = favorites.reduce<NormalizedResponse<UserFavorite<IFavoriteMetadata>>>((data, favorite) => {
            const { guid } = favorite;
            if (guid) {
              data.entities[favEntityKey][guid] = favorite;
              data.result.push(guid);
            }
            return data;
          }, { entities: { [favEntityKey]: {} }, result: [] });
          this.store.dispatch(new WrapperRequestActionSuccess(mappedData, action, actionType, mappedData.result.length, 1));
          this.store.dispatch(new GetUserFavoritesSuccessAction(favorites));
          return [];
        }),
        catchError(() => {
          this.store.dispatch(new GetUserFavoritesFailedAction());
          this.store.dispatch(new WrapperRequestActionFailed('Failed to fetch user favorites', action, actionType));
          return [];
        })
      );
    })
  );

  @Effect() toggleFavorite = this.actions$.pipe(
    ofType<ToggleUserFavoriteAction>(ToggleUserFavoriteAction.ACTION_TYPE),
    mergeMap(action =>
      this.userFavoriteManager.getIsFavoriteObservable(action.favorite).pipe(
        first(),
        switchMap(isFav => {
          if (isFav) {
            return [new RemoveUserFavoriteAction(action.favorite)];
          } else {
            return [new SaveUserFavoriteAction(action.favorite)];
          }
        })
      )
    )
  );

  @Effect({ dispatch: false }) removeFavorite$ = this.actions$.pipe(
    ofType<RemoveUserFavoriteAction>(RemoveUserFavoriteAction.ACTION_TYPE),
    mergeMap((action: RemoveUserFavoriteAction) => {
      const actionType = 'update';
      this.store.dispatch(new StartRequestAction(action, actionType));
      return this.http.delete<UserFavorite<IFavoriteMetadata>>(`${favoriteUrlPath}/${action.guid}`).pipe(
        switchMap(() => {
          this.store.dispatch(new WrapperRequestActionSuccess(null, action));
          this.store.dispatch(new RemoveUserFavoriteSuccessAction(action.favorite));
          this.store.dispatch(new ClearPaginationOfEntity(action.entity[0], action.guid, userFavoritesPaginationKey));
          return [];
        }),
        catchError(() => {
          this.store.dispatch(new WrapperRequestActionFailed('Failed to remove user favorite', action, actionType));
          return [];
        })
      );
    })
  );

  @Effect() updateMetadata$ = this.actions$.pipe(
    ofType<UpdateUserFavoriteMetadataAction>(UpdateUserFavoriteMetadataAction.ACTION_TYPE),
    mergeMap((action: UpdateUserFavoriteMetadataAction) => {
      const actionType = 'update';
      this.store.dispatch(new StartRequestAction(action, actionType));
      return this.http.post<UserFavorite<IFavoriteMetadata>>(
        `${favoriteUrlPath}/${action.favorite.guid}/metadata`,
        action.favorite.metadata
      ).pipe(
        switchMap(() => {
          this.store.dispatch(new WrapperRequestActionSuccess(null, action));
          this.store.dispatch(new UpdateUserFavoriteMetadataSuccessAction(action.favorite));
          return [];
        }),
        catchError(() => {
          this.store.dispatch(new WrapperRequestActionFailed('Failed to update user favorite', action, actionType));
          return [];
        })
      );
    })
  );

  @Effect()
  entityDeleteRequest$ = this.actions$.pipe(
    ofType<EntityDeleteCompleteAction>(EntityDeleteCompleteAction.ACTION_TYPE),
    withLatestFrom(this.store),
    mergeMap(([action, appState]) => {
      // If there is a favorite, delete it
      const fav = action.asFavorite();
      const entityKey = entityCatalog.getEntityKey(STRATOS_ENDPOINT_TYPE, userFavouritesEntityType);
      if (appState.requestData && appState.requestData[entityKey] && appState.requestData[entityKey][fav.guid]) {
        this.store.dispatch(new RemoveUserFavoriteAction(fav));
      }
      return [];
    })
  );

}