export function createStore()

in src/utils/create-store.js [12:94]


export function createStore(initialStore) {
  const INTERNAL_STORE = writable(initialStore);
  const getState = () => get(INTERNAL_STORE);

  // FIXME: going to keep dispatch for historical purposes,
  // but in general I think setField below is just far less
  // boilerplate for simple changes to the store.
  // If more complex operations appear in this repository,
  // it might make more sense to go down the dispatch route.
  // These types of data apps are pretty simplistic, however.
  function dispatch(func) {
    // this is really just a slight addendum to update
    // that allows you to pass in produce-friendly functions.
    if (func.constructor.name === 'AsyncFunction') {
      // composite update (thunk). Async may or may not be
      // necessary here, but might as well make all of these async by
      // default.
      func(dispatch, getState);
    } else {
      // atomic update (singular state change).
      INTERNAL_STORE.update((state) => produce(state, func));
    }
  }
  // this is the pattern that @openjck and I worked out
  // on the GUD refactor. It turns out the ultimate way to remove
  // boilerplate is to just make something that simply updates
  // the store as we have it.
  // we call it setField to differentiate it from the store's
  // set function.
  function setField(key, value) {
    INTERNAL_STORE.update((state) =>
      produce(state, (draft) => {
        draft[key] = value;
      })
    );
  }

  function setDimension(key, value) {
    INTERNAL_STORE.update((state) =>
      produce(state, (draft) => {
        // When changing aggregation level, reset zoom states.
        if (key === 'aggregationLevel') {
          draft.hov = '';
          draft.ref = '';
          draft.timeHorizon = 'MONTH';
        }
        draft.productDimensions[key] = value;
      })
    );
  }

  function connect(func) {
    return (...args) => dispatch(func(...args));
  }

  function reinitialize(options = {}) {
    let stateToKeep = {};
    if (options.exceptions) {
      const currentState = getState();
      stateToKeep = options.exceptions.reduce((acc, field) => {
        acc[field] = currentState[field];
        return acc;
      }, {});
    }

    INTERNAL_STORE.set({ ...initialStore, ...stateToKeep });
  }

  function setState(state) {
    INTERNAL_STORE.set(state);
  }

  return {
    dispatch,
    connect,
    subscribe: INTERNAL_STORE.subscribe,
    getState,
    setField,
    setDimension,
    reinitialize,
    setState,
  };
}