huridocs/uwazi

View on GitHub
app/react/Relationships/actions/actions.js

Summary

Maintainability
A
1 hr
Test Coverage
B
85%
import api from 'app/utils/api';
import { actions } from 'app/BasicReducer';
import debounce from 'app/utils/debounce';
import { createSelector } from 'reselect';
import { notificationActions } from 'app/Notifications';
import { referencesActions } from 'app/Viewer';
import { RequestParams } from 'app/utils/RequestParams';
import SearchApi from 'app/Search/SearchAPI';
import { t } from 'app/I18N';
import EntitiesApi from '../../Entities/EntitiesAPI';
import * as types from './actionTypes';
import * as uiActions from './uiActions';
import * as routeUtils from '../utils/routeUtils';

function parseResults(results, parentEntity, editing) {
  return { type: types.PARSE_RELATIONSHIPS_RESULTS, results, parentEntity, editing };
}

function edit(value, results, parentEntity) {
  return { type: types.EDIT_RELATIONSHIPS, value, results, parentEntity, editing: value };
}

function addHub() {
  return { type: types.ADD_RELATIONSHIPS_HUB };
}

function toggelRemoveLeftRelationship(index) {
  return { type: types.TOGGLE_REMOVE_RELATIONSHIPS_LEFT, index };
}

function toggleRemoveRightRelationshipGroup(index, rightIndex) {
  return { type: types.TOGGLE_REMOVE_RELATIONSHIPS_RIGHT_GROUP, index, rightIndex };
}

function updateLeftRelationshipType(index, _id) {
  return { type: types.UPDATE_RELATIONSHIPS_LEFT_TYPE, index, _id };
}

function setAddToData(index, rightIndex) {
  return { type: types.SET_RELATIONSHIPS_ADD_TO_DATA, index, rightIndex };
}

function updateRelationshipEntityData(entity) {
  return { type: types.UPDATE_RELATIONSHIP_ENTITY_DATA, entity };
}

function updateRightRelationshipType(index, rightIndex, _id) {
  return (dispatch, getState) => {
    const { hubs } = getState().relationships;
    const newRightRelationshipType =
      rightIndex === hubs.getIn([index, 'rightRelationships']).size - 1;

    dispatch({
      type: types.UPDATE_RELATIONSHIPS_RIGHT_TYPE,
      index,
      rightIndex,
      _id,
      newRightRelationshipType,
    });

    if (newRightRelationshipType) {
      dispatch(setAddToData(index, rightIndex));
      dispatch(uiActions.openPanel());
    }
  };
}

function addEntity(index, rightIndex, entity, errors = []) {
  return dispatch => {
    const title = entity.title.length > 75 ? `${entity.title.slice(0, 75)}(...)` : entity.title;
    let message = t('System', 'added to hub.', null, false);

    if (errors.length) {
      message = `${t(
        'System',
        'added to hub with the following errors:',
        null,
        false
      )} ${JSON.stringify(errors, null)}.`;
    }

    const notificationMessage = `${title} ${message}\n${t(
      'System',
      'Save your work to make change permanent',
      null,
      false
    )}.`;

    dispatch(
      notificationActions.notify(notificationMessage, errors.length ? 'warning' : 'success')
    );
    dispatch({ type: types.ADD_RELATIONSHIPS_ENTITY, index, rightIndex, entity });
  };
}

function toggleRemoveEntity(index, rightIndex, relationshipIndex) {
  return { type: types.TOGGLE_REMOVE_RELATIONSHIPS_ENTITY, index, rightIndex, relationshipIndex };
}

function toggleMoveEntity(index, rightIndex, relationshipIndex) {
  return { type: types.TOGGLE_MOVE_RELATIONSHIPS_ENTITY, index, rightIndex, relationshipIndex };
}

function moveEntities(index, rightRelationshipIndex) {
  return { type: types.MOVE_RELATIONSHIPS_ENTITY, index, rightRelationshipIndex };
}

function reloadRelationships(sharedId) {
  return (dispatch, getState) =>
    routeUtils
      .requestState(new RequestParams({ sharedId }), getState())
      .then(([connectionsGroups, searchResults]) => {
        dispatch(actions.set('relationships/list/connectionsGroups', connectionsGroups));
        dispatch(actions.set('relationships/list/searchResults', searchResults));
      });
}

function saveRelationships() {
  return (dispatch, getState) => {
    dispatch({ type: types.SAVING_RELATIONSHIPS });
    const parentEntityId = getState().relationships.list.sharedId;
    const hubs = getState().relationships.hubs.toJS();

    const apiCall = hubs.reduce(
      (apiActions, hubData) => {
        if (!hubData.hub && !hubData.deleted) {
          const leftRelationship = { entity: parentEntityId, ...hubData.leftRelationship };
          const rightRelationships = hubData.rightRelationships.reduce(
            (relationships, rightGroup) => {
              if (!rightGroup.deleted) {
                const newRelationships = rightGroup.relationships.filter(r => !r.deleted);

                return relationships.concat(newRelationships);
              }
              return relationships;
            },
            []
          );
          const fullHubData = [leftRelationship].concat(rightRelationships);
          apiActions.save.push(fullHubData);
        }

        if (hubData.hub) {
          if (hubData.deleted) {
            apiActions.delete.push({ _id: hubData.leftRelationship._id, entity: parentEntityId });
          }

          if (hubData.modified && !hubData.deleted) {
            apiActions.save.push({
              entity: parentEntityId,
              hub: hubData.hub,
              ...hubData.leftRelationship,
            });
          }

          hubData.rightRelationships.forEach(rightGroup => {
            rightGroup.relationships.forEach(r => {
              const deleted = rightGroup.deleted || r.deleted || r.moved;

              if (deleted && r._id) {
                apiActions.delete.push({ _id: r._id, entity: r.entity });
              }

              const toSave = rightGroup.modified || !r._id;
              if (toSave && !deleted) {
                apiActions.save.push(
                  Object.assign(r, {
                    entity: r.entity,
                    hub: hubData.hub,
                    template: rightGroup.template,
                  })
                );
              }
            });
          });
        }
        return apiActions;
      },
      { save: [], delete: [] }
    );

    return api
      .post('relationships/bulk', new RequestParams(apiCall))
      .then(response =>
        Promise.all([
          response,
          EntitiesApi.get(new RequestParams({ sharedId: parentEntityId })).then(([r]) => r),
          reloadRelationships(parentEntityId)(dispatch, getState),
        ])
      )
      .then(([response, parentEntity]) => {
        dispatch(actions.set('entityView/entity', parentEntity));
        dispatch(actions.set('viewer/doc', parentEntity));

        dispatch(uiActions.closePanel());
        dispatch(
          edit(
            false,
            getState().relationships.list.searchResults,
            getState().relationships.list.entity
          )
        );
        dispatch(referencesActions.loadReferences(parentEntityId));
        dispatch({ type: types.SAVED_RELATIONSHIPS, response });
        dispatch(
          notificationActions.notify(t('System', 'Relationships saved', null, false), 'success')
        );
      })
      .catch(e => {
        dispatch({ type: types.SAVED_RELATIONSHIPS, e });
      });
  };
}

function immidiateSearch(dispatch, searchTerm) {
  dispatch(uiActions.searching());

  const requestParams = new RequestParams({
    searchTerm,
    fields: ['title'],
    includeUnpublished: true,
  });

  return SearchApi.search(requestParams).then(({ rows: results }) => {
    dispatch(actions.set('relationships/searchResults', results));
  });
}

const debouncedSearch = debounce(immidiateSearch, 400);

const selectRelationTypes = createSelector(
  state => state.translations,
  state => state.relationTypes,
  state => state.locale,
  (translations, relationTypes, locale) => {
    const translationContexts = translations.find(
      translation => translation.get('locale') === locale
    );
    const relations = relationTypes.toJS().map(rel => {
      const [translationContext] = translationContexts
        .get('contexts')
        .filter(context => context.get('id') === rel._id);
      const name = translationContext
        ? t(translationContext.get('id'), rel.name, null, false)
        : rel.name;
      return {
        ...rel,
        name,
      };
    });
    return [{ _id: null, name: t('System', 'No Label', null, false) }].concat(relations);
  }
);

function search(searchTerm) {
  return dispatch => {
    dispatch(actions.set('relationships/searchTerm', searchTerm));
    return debouncedSearch(dispatch, searchTerm);
  };
}

function selectConnection(connection) {
  return actions.set('relationships/connection', connection);
}

function unselectConnection() {
  return actions.set('relationships/connection', {});
}

export {
  unselectConnection,
  selectConnection,
  search,
  selectRelationTypes,
  immidiateSearch,
  saveRelationships,
  reloadRelationships,
  toggleRemoveEntity,
  toggleMoveEntity,
  moveEntities,
  addEntity,
  updateRightRelationshipType,
  updateRelationshipEntityData,
  setAddToData,
  parseResults,
  edit,
  addHub,
  toggelRemoveLeftRelationship,
  toggleRemoveRightRelationshipGroup,
  updateLeftRelationshipType,
};