graycoreio/daffodil

View on GitHub
libs/seo/state/src/effects/ngrx-router/page-hook.effects.ts

Summary

Maintainability
A
0 mins
Test Coverage
import {
  Actions,
  createEffect,
  ofType,
} from '@ngrx/effects';
import {
  ROUTER_REQUEST,
  ROUTER_CANCEL,
  ROUTER_ERROR,
  ROUTER_NAVIGATED,
} from '@ngrx/router-store';
import { EMPTY } from 'rxjs';
import {
  map,
  tap,
  switchMap,
} from 'rxjs/operators';

import { DaffSeoRestoreableServiceInterface } from '@daffodil/seo';

import { DaffSeoUpdateActionPair } from '../../models/public_api';

/**
 * Hooks into the Angular router to manage SEO data on the page as navigation occurs.
 *
 * @docs-private
 */
export abstract class DaffSeoPageHookEffects<T extends DaffSeoRestoreableServiceInterface<V>, R extends DaffSeoUpdateActionPair = DaffSeoUpdateActionPair, V = unknown> {
  constructor(
    protected actions$: Actions,
    protected updates: R[],
    protected service: T,
  ) {}

  /**
   * Upserts SEO data according to the provided updates.
   *
   * @docs-private
   */
  getData$ = createEffect(
    () => this.actions$.pipe(
      ofType(...this.updates.map(({ action }) => action)),
      map(action => this.updates.filter(update =>
        action.type === update.action,
      ).map(({ getData }) =>
        getData(action),
      )),
      tap((data: V[]) => data.forEach(datum => {
        if (datum) {
          this.service.upsert(datum);
        };
      })),
      switchMap(() => EMPTY),
    ),
    {
      dispatch: false,
    },
  );

  /**
   * Removes SEO data when navigation starts.
   *
   * @docs-private
   */
  remove$ = createEffect(
    () => this.actions$.pipe(
      ofType(ROUTER_REQUEST),
      tap(() => this.service.clear()),
      switchMap(() => EMPTY),
    ),
    {
      dispatch: false,
    },
  );

  /**
   * Restores previously removed SEO data when navigation is canceled or fails.
   *
   * @docs-private
   */
  restore$ = createEffect(
    () => this.actions$.pipe(
      ofType(ROUTER_CANCEL, ROUTER_ERROR),
      tap(() => this.service.restore()),
      switchMap(() => EMPTY),
    ),
    {
      dispatch: false,
    },
  );

  /**
   * Empties the SEO data restore cache when navigation completes.
   *
   * @docs-private
   */
  emptyRestoreCache$ = createEffect(
    () => this.actions$.pipe(
      ofType(ROUTER_NAVIGATED),
      tap(() => this.service.emptyRestoreCache()),
      switchMap(() => EMPTY),
    ),
    {
      dispatch: false,
    },
  );
}