Source: app/actions/entities/collectionActions.js

import createAction from 'redux-actions/lib/createAction';
import { PAGINATION_NONE } from '../../data/paginationType';

/**
 * Redux actions to manage collections
 * @module collectionActions
 * @category redux-state
 */

/**
 * The name of the property on an action meta that indicates which collection it is meant for
 * @private
 * @type {string}
 */
export const META_PROP_COLLECTION = 'collectionId';

export const COLLECTION_SET_AT_OFFSET = 'collectionActions/COLLECTION_SET_AT_OFFSET';
export const COLLECTION_SET_PAGINATION = 'collectionActions/COLLECTION_SET_PAGINATION';
export const COLLECTION_SET_TOTAL = 'collectionActions/COLLECTION_SET_TOTAL';
export const COLLECTION_REPLACE = 'collectionActions/COLLECTION_REPLACE';
export const COLLECTION_PARTITION_SET_BEFORE = 'collectionActions/COLLECTION_PARTITION_SET_BEFORE';
export const COLLECTION_PARTITION_SET_AFTER = 'collectionActions/COLLECTION_PARTITION_SET_AFTER';
export const COLLECTION_PARTITION_CHECK_COMPLETE =
  'collectionActions/COLLECTION_PARTITION_CHECK_COMPLETE';
export const COLLECTION_UNSHIFT = 'collectionActions/COLLECTION_UNSHIFT';
export const COLLECTION_REMOVE_REFS = 'collectionActions/COLLECTION_REMOVE_REFS';
export const COLLECTION_CLEAR_IF_CONTAINS_REF =
  'collectionActions/COLLECTION_CLEAR_IF_CONTAINS_REF';
export const COLLECTION_CLEAR_ALL = 'collectionActions/COLLECTION_CLEAR_ALL';

const createCollectionIdMeta = collectionId => ({
  [META_PROP_COLLECTION]: collectionId,
});

/**
 * Replaces the entities at the given `offset` with the given `refs`.
 * @function collectionSetAtOffset
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array} An array of new `{ id, type }` references to entities
 * @param [offset=0] {number} The offset in the collection at which to start replacing
 */
export const collectionSetAtOffset = createAction(
  COLLECTION_SET_AT_OFFSET,
  (collectionId, refs, offset = 0, hasMore) => ({ refs, offset, hasMore }),
  createCollectionIdMeta,
);

/**
 * Replaces all the entities in a collection
 * @function collectionReplace
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array} An array of new `{ id, type }` references to entities
 */
export const collectionReplace = createAction(
  COLLECTION_REPLACE,
  (collectionId, refs) => ({ refs }),
  createCollectionIdMeta,
);

/**
 * Removes the given entities from a collection
 * @function collectionRemoveRefs
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array} An array of new `{ id, type }` references that should be removed
 */
export const collectionRemoveRefs = createAction(
  COLLECTION_REMOVE_REFS,
  (collectionId, refs) => ({ refs }),
  createCollectionIdMeta,
);

/**
 * Removes all entities from a collection
 * @function collectionClearAll
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 */
export const collectionClearAll = createAction(
  COLLECTION_CLEAR_ALL,
  () => null,
  createCollectionIdMeta,
);

/**
 * Removes all entities from a collection if the given entity is in the collection data
 * @function collectionClearIfContainsRef
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param ref {Object} An `{ id, type }` reference to an entity. If this entity exists in the
 * collection, the collection will be cleared
 */
export const collectionClearIfContainsRef = createAction(
  COLLECTION_CLEAR_IF_CONTAINS_REF,
  (collectionId, ref) => ({ ref }),
  createCollectionIdMeta,
);

/**
 * Adds the given entities to the start of the collection, before all other entries.
 * @function collectionUnshift
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array|Object} An array of new `{ id, type }` references to entities
 */
export const collectionUnshift = createAction(
  COLLECTION_UNSHIFT,
  (collectionId, refs) => ({ refs: Array.isArray(refs) ? refs : [refs] }),
  createCollectionIdMeta,
);

/**
 * Adds the given entities to collection before all other entries. To be used for collections
 * with pagination type `PAGINATION_PARTITION`. This is usually for cursor-based pagination
 * @function collectionPartitionSetBefore
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array|Object} An array of new `{ id, type }` references to entities
 * @param expectedCount {number} The number of expected results. If the number of refs is less
 * than this, we know we have reached the start of the list
 * @param [beforeRef] {Object} An `{ id, type }` pair of the ref before which these refs should
 * be inserted. If omitted it is assumed that the current state refs should be replaced. If given,
 * but the ref does not exist in the current state, this action will be ignored.
 */
export const collectionPartitionSetBefore = createAction(
  COLLECTION_PARTITION_SET_BEFORE,
  (collectionId, refs, expectedCount, beforeRef) => ({ refs, expectedCount, beforeRef }),
  createCollectionIdMeta,
);

/**
 * Adds the given entities to collection after all other entries. To be used for collections
 * with pagination type `PAGINATION_PARTITION`. This is usually for cursor-based pagination
 * @function collectionPartitionSetAfter
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param refs {Array|Object} An array of new `{ id, type }` references to entities
 * @param expectedCount {number} The number of expected results. If the number of refs is less
 * than this, we know we have reached the end of the list
 * @param [afterRef] {Object} An `{ id, type }` pair of the ref after which these refs should
 * be inserted. If omitted it is assumed that the current state refs should be replaced. If given,
 * but the ref does not exist in the current state, this action will be ignored.
 * @param assumeAtBegin {bool} If `true` and no afterRef is given, the collection reducer will
 * assume that this is the begin of the list and set `atBegin` to `true`. Default to `true`. When
 * getting deeplinked data (providing a specific cursor to an api call) set this parameter to
 * `false`
 */
export const collectionPartitionSetAfter = createAction(
  COLLECTION_PARTITION_SET_AFTER,
  (collectionId, refs, expectedCount, afterRef, assumeAtBegin) => ({
    refs,
    expectedCount,
    afterRef,
    assumeAtBegin,
  }),
  createCollectionIdMeta,
);

/**
 * Clears all pagination information from a collection
 * @function collectionClearPagination
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 */
export const collectionClearPagination = createAction(
  COLLECTION_SET_PAGINATION,
  () => ({ type: PAGINATION_NONE }),
  createCollectionIdMeta,
);

/**
 * Checks if a partition collection is 'complete'. That is, the number of entities in the collection
 * is as big as the given total. In that case, this action will set both the `atBegin` and the
 * `atEnd` flags to `true`. Otherwise, this action has no effect.
 * @function collectionPartitionCheckComplete
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param total {number} The expected total number of items in the collection
 */
export const collectionPartitionCheckComplete = createAction(
  COLLECTION_PARTITION_CHECK_COMPLETE,
  (collectionId, total) => ({ total }),
  createCollectionIdMeta,
);

/**
 * Sets the `total` field of a collection's `pagination`. This should be set to the total items
 * available on the server and does not necessarily equal the total items currently in state.
 * @function collectionSetTotal
 * @param collectionId {string} The id of the collection to update. Should be obtained from
 * {@link module:collectionIds}
 * @param total {number} The new total
 */
export const collectionSetTotal = createAction(
  COLLECTION_SET_TOTAL,
  (collectionId, total) => ({ total }),
  createCollectionIdMeta,
);