Skip to content

Loading State

Ivan Kasenkov edited this page Aug 31, 2021 · 3 revisions

ksLoading.ts

import {
  Option,
  Stream,
  Transformer,
  ksConcat,
  ksMap,
  ksOf,
  ksScan,
  ksSwitch,
  none,
  some,
} from '@keiii/k-stream';

export type LoadingState<T> = {
  loading: boolean;
  response: Option<T>;
};

const initialState: LoadingState<never> = {
  loading: false,
  response: none,
};

const patch = <A>(
  currentState: LoadingState<A>,
  patchState: Partial<LoadingState<A>>,
): LoadingState<A> => {
  return {
    ...currentState,
    ...patchState,
  };
};

const loadingTrue = ksOf({ loading: true } as const);

const loadedResponse = <A>(b: A): LoadingState<A> => {
  return {
    loading: false,
    response: some(b),
  };
};

/**
 * Transform a stream of requests into a stream of a state with loading indicator.
 */
export const ksLoading = <A, B>(
  project: (a: A) => Stream<B>,
): Transformer<A, LoadingState<B>> => {
  return stream => {
    return stream
      .pipe(
        ksSwitch(a => {
          return ksConcat(
            loadingTrue, // set the loading indicator as "true" before loading
            project(a).pipe(ksMap(loadedResponse)), // and concatenate with response
          );
        }),
      )
      .pipe(
        ksScan<Partial<LoadingState<B>>, LoadingState<B>>(patch, initialState),
      );
  };
};
Clone this wiki locally