Sana Assistant (online)
Table of Contents

Epic

The redux-observable epic can be used in add-on project with additional features. The add-on epic signature is described below:

function (action$: Observable<Action>, state$: StateObservable<State>, services: EpicServices): Observable<Action>;
Note

The knowledge of redux and reactive epics is required to proceed with this tutorial. Also get acquainted with RxJS library, which epics are built on top of.

Unlike a standard redux-observable epic, add-on epic supports another 3rd parameter: services.

Service Type Description
Api Api Api
AppContext { getCurrent(): AppContext; } AppContext
BufferUntilLoading () => (source$: Observable) => Observable<T[]> BufferUntilLoading

Api service

This service provides information about application Api available for addons.

Example:

const requestProductUoms$ = action$.pipe(
  ofType(PRODUCT_UOMS_REQUESTED),
  switchMap(() => api.graphApi(productUomQuery, { options: { ids: productIds }  }).pipe(
    map(data => data.catalog.products.products),
    map(receiveProductUoms),
  )),
);

const clearAddonFields$ = action$.pipe(
  ofType(ADDON_FIELDS_CLEARED),
  switchMap(() => api.fetch(`api/addon/${ADDON_ID}/clearCache`, {
    method: 'DELETE',
  }).pipe(
    map(response => {
      return receivedFieldsClearResponse(response);
    }),
    catchError(() => {
      return of(receivedFieldsClearResponse('failed'));
    }),
  )),
);

AppContext service

This service provides the information about AppContext.

Example:

const requestAddonFields$ = action$.pipe(
  ofType(ADDON_FIELDS_REQUESTED),
  switchMap(() => {
    if (appContext.getCurrent().offlineMode)
      return of(showAlert());

    return api.graphApi(addonFieldsQuery).pipe(
      map(receiveAddonFields),
    );
  }),
);

BufferUntilLoading service

This service allows buffering of requests. This is necessary when the HTTP request is expected to be executed on the page many times for different items (for example, in the case of using an addon to display certain data in the items collection).

Example:

const getProductUoms$ = action$.pipe(
  ofType(UOM_FOR_PRODUCT_REQUESTED),
  bufferUntilLoading(),
  mergeMap(actions => {
    const productIds = actions.flatMap(({ payload: { productId } }) => productId);

    return api.graphApi(productUomQuery, { options: { ids: productIds } }).pipe(
      map(data => receiveUomForProducts(data.catalog.products.products)),
    );
  }),
);

See also