"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireWildcard(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _reactRouter = require("react-router");

var _immutable = _interopRequireDefault(require("immutable"));

var _get = _interopRequireDefault(require("lodash/get"));

var _Dock = _interopRequireDefault(require("../sections/Dock"));

var _RecordButtonBar = _interopRequireDefault(require("./RecordButtonBar"));

var _RecordHeader = _interopRequireDefault(require("./RecordHeader"));

var _ConfirmRecordNavigationModal = _interopRequireDefault(require("./ConfirmRecordNavigationModal"));

var _ConfirmRecordDeleteModal = _interopRequireDefault(require("./ConfirmRecordDeleteModal"));

var _LockRecordModal = _interopRequireDefault(require("./LockRecordModal"));

var _HierarchyReparentNotifier = _interopRequireDefault(require("./HierarchyReparentNotifier"));

var _RecordFormContainer = _interopRequireDefault(require("../../containers/record/RecordFormContainer"));

var _permissionHelpers = require("../../helpers/permissionHelpers");

var _recordDataHelpers = require("../../helpers/recordDataHelpers");

var _workflowStateHelpers = require("../../helpers/workflowStateHelpers");

var _RecordEditor = _interopRequireDefault(require("../../../styles/cspace-ui/RecordEditor.css"));

var _modalNames = require("../../constants/modalNames");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

const propTypes = {
  config: _propTypes.default.shape({
    recordTypes: _propTypes.default.object,
    termDeprecationEnabled: _propTypes.default.bool
  }),
  recordType: _propTypes.default.string.isRequired,
  vocabulary: _propTypes.default.string,
  csid: _propTypes.default.string,
  cloneCsid: _propTypes.default.string,
  data: _propTypes.default.instanceOf(_immutable.default.Map),
  dockTop: _propTypes.default.number,
  formName: _propTypes.default.string,
  perms: _propTypes.default.instanceOf(_immutable.default.Map),
  roleNames: _propTypes.default.instanceOf(_immutable.default.List),
  subrecordData: _propTypes.default.instanceOf(_immutable.default.Map),
  validationErrors: _propTypes.default.instanceOf(_immutable.default.Map),
  vocabularyWorkflowState: _propTypes.default.string,
  isModified: _propTypes.default.bool,
  isReadPending: _propTypes.default.bool,
  isSavePending: _propTypes.default.bool,
  isSidebarOpen: _propTypes.default.bool,
  isHardDelete: _propTypes.default.bool,
  // The workflow state of the related subject (aka primary) record when we're in a secondary tab.
  relatedSubjectWorkflowState: _propTypes.default.string,
  openModalName: _propTypes.default.string,
  checkDeletable: _propTypes.default.func,
  checkForRelations: _propTypes.default.func,
  checkForUses: _propTypes.default.func,
  checkForRoleUses: _propTypes.default.func,
  createNewRecord: _propTypes.default.func,
  readRecord: _propTypes.default.func,
  onRecordCreated: _propTypes.default.func,
  onRecordSaved: _propTypes.default.func,
  onSaveCancelled: _propTypes.default.func,
  closeModal: _propTypes.default.func,
  openModal: _propTypes.default.func,
  deleteRecord: _propTypes.default.func,
  save: _propTypes.default.func,
  saveWithTransition: _propTypes.default.func,
  revert: _propTypes.default.func,
  clone: _propTypes.default.func,
  transitionRecord: _propTypes.default.func,
  removeNotification: _propTypes.default.func,
  removeValidationNotification: _propTypes.default.func,
  setForm: _propTypes.default.func,
  validateRecordData: _propTypes.default.func,
  onRecordReadComplete: _propTypes.default.func,
  onRecordDeleted: _propTypes.default.func,
  onRecordTransitioned: _propTypes.default.func,
  onRunButtonClick: _propTypes.default.func
};
const defaultProps = {
  data: _immutable.default.Map(),
  isSidebarOpen: true
};

class RecordEditor extends _react.Component {
  constructor() {
    super(); // Confirm delete modal button handlers.

    this.handleConfirmDeleteButtonClick = this.handleConfirmDeleteButtonClick.bind(this); // Confirm navigation modal button handlers.

    this.handleConfirmNavigationSaveButtonClick = this.handleConfirmNavigationSaveButtonClick.bind(this);
    this.handleConfirmNavigationRevertButtonClick = this.handleConfirmNavigationRevertButtonClick.bind(this); // Lock modal button handlers.

    this.handleSaveOnlyButtonClick = this.handleSaveOnlyButtonClick.bind(this);
    this.handleSaveLockButtonClick = this.handleSaveLockButtonClick.bind(this); // Shared modal handlers.

    this.handleModalCancelButtonClick = this.handleModalCancelButtonClick.bind(this); // Button bar handlers.

    this.handleDeprecateButtonClick = this.handleDeprecateButtonClick.bind(this);
    this.handleSaveButtonClick = this.handleSaveButtonClick.bind(this);
    this.handleSaveButtonErrorBadgeClick = this.handleSaveButtonErrorBadgeClick.bind(this);
    this.handleRevertButtonClick = this.handleRevertButtonClick.bind(this);
    this.handleCloneButtonClick = this.handleCloneButtonClick.bind(this);
    this.handleDeleteButtonClick = this.handleDeleteButtonClick.bind(this);
    this.handleRecordFormSelectorCommit = this.handleRecordFormSelectorCommit.bind(this);
    this.handleUndeprecateButtonClick = this.handleUndeprecateButtonClick.bind(this);
  }

  componentDidMount() {
    this.initRecord();
  }

  componentDidUpdate(prevProps) {
    const {
      recordType,
      vocabulary,
      csid,
      cloneCsid,
      data
    } = this.props;
    const {
      recordType: prevRecordType,
      vocabulary: prevVocabulary,
      csid: prevCsid,
      cloneCsid: prevCloneCsid,
      data: prevData
    } = prevProps;

    if (recordType !== prevRecordType || vocabulary !== prevVocabulary || csid !== prevCsid || cloneCsid !== prevCloneCsid // DRYD-859: Re-init when data is reset but other props stay the same.
    || prevData.size > 0 && data.size === 0) {
      this.initRecord();
    }
  }

  componentWillUnmount() {
    const {
      removeNotification,
      removeValidationNotification
    } = this.props;

    if (removeValidationNotification) {
      removeValidationNotification();
    }

    if (removeNotification) {
      removeNotification(_HierarchyReparentNotifier.default.notificationID);
    }
  }

  initRecord() {
    const {
      csid,
      cloneCsid,
      createNewRecord,
      readRecord,
      removeValidationNotification,
      onRecordReadComplete
    } = this.props;

    if (removeValidationNotification) {
      removeValidationNotification();
    }

    if (csid) {
      if (readRecord) {
        readRecord().then(() => {
          if (onRecordReadComplete) {
            onRecordReadComplete();
          }
        });
      }
    } else if (createNewRecord) {
      createNewRecord(cloneCsid);
    }
  }

  save(onRecordCreated) {
    const {
      config,
      data,
      recordType,
      openModal,
      save,
      saveWithTransition,
      onRecordSaved
    } = this.props;
    const recordTypeConfig = config.recordTypes[recordType];
    const {
      lockOnSave
    } = recordTypeConfig;

    if (lockOnSave === 'prompt' && openModal) {
      openModal(_modalNames.MODAL_LOCK_RECORD);
      return false;
    }

    let savePromise;

    if (lockOnSave === true && saveWithTransition) {
      savePromise = saveWithTransition('lock', onRecordCreated);
    } else if (save) {
      savePromise = save(onRecordCreated);
    }

    if (savePromise) {
      savePromise.then(() => {
        if (recordTypeConfig.onRecordSaved) {
          // TODO: Pass in the post-save data (which could have been modified due to services layer
          // event handlers) instead of the pre-save data. The save action would need to resolve
          // with the data instead of a csid.
          recordTypeConfig.onRecordSaved({
            data,
            recordEditor: this
          });
        }

        if (onRecordSaved) {
          onRecordSaved();
        }
      });
    }

    return true;
  }

  delete() {
    const {
      closeModal,
      isHardDelete,
      deleteRecord,
      onRecordDeleted,
      transitionRecord,
      onRecordTransitioned
    } = this.props;

    if (isHardDelete) {
      if (deleteRecord) {
        deleteRecord().then(() => {
          if (closeModal) {
            closeModal(true);
          }

          if (onRecordDeleted) {
            onRecordDeleted();
          }
        });
      }
    } else {
      const transitionName = 'delete';

      if (transitionRecord) {
        transitionRecord(transitionName).then(() => {
          if (closeModal) {
            closeModal(true);
          }

          if (onRecordTransitioned) {
            onRecordTransitioned(transitionName);
          }
        });
      }
    }
  }

  handleModalCancelButtonClick(event) {
    const {
      closeModal,
      onSaveCancelled
    } = this.props;

    if (closeModal) {
      event.stopPropagation();
      closeModal(false);
    }

    if (onSaveCancelled) {
      onSaveCancelled();
    }
  }

  handleUndeprecateButtonClick() {
    const {
      transitionRecord,
      onRecordTransitioned
    } = this.props;
    const transitionName = 'undeprecate';

    if (transitionRecord) {
      transitionRecord(transitionName).then(() => {
        if (onRecordTransitioned) {
          onRecordTransitioned(transitionName);
        }
      });
    }
  }

  handleDeprecateButtonClick() {
    const {
      transitionRecord,
      onRecordTransitioned
    } = this.props;
    const transitionName = 'deprecate';

    if (transitionRecord) {
      transitionRecord(transitionName).then(() => {
        if (onRecordTransitioned) {
          onRecordTransitioned(transitionName);
        }
      });
    }
  }

  handleConfirmDeleteButtonClick() {
    this.delete();
  }

  handleConfirmNavigationSaveButtonClick() {
    const {
      closeModal,
      onRecordCreated
    } = this.props; // Wrap the onRecordCreated callback in a function that sets isNavigating to true. This lets
    // the callback know that we're already navigating away, so it should not do any navigation
    // of its own.

    const callback = onRecordCreated ? newRecordCsid => {
      onRecordCreated(newRecordCsid, true);
    } : undefined;
    const saveCalled = this.save(callback);

    if (saveCalled && closeModal) {
      closeModal(true);
    }
  }

  handleConfirmNavigationRevertButtonClick() {
    const {
      closeModal,
      revert
    } = this.props;

    if (revert) {
      revert();
    }

    if (closeModal) {
      closeModal(true);
    }
  }

  handleCloneButtonClick() {
    const {
      clone,
      csid
    } = this.props;

    if (clone) {
      clone(csid);
    }
  }

  handleDeleteButtonClick() {
    const {
      openModal
    } = this.props;

    if (openModal) {
      openModal(_modalNames.MODAL_CONFIRM_RECORD_DELETE);
    }
  }

  handleRevertButtonClick() {
    const {
      revert
    } = this.props;

    if (revert) {
      revert();
    }
  }

  handleSaveButtonClick() {
    const {
      onRecordCreated
    } = this.props;
    this.save(onRecordCreated);
  }

  handleSaveButtonErrorBadgeClick() {
    const {
      validateRecordData
    } = this.props;

    if (validateRecordData) {
      validateRecordData();
    }
  }

  handleSaveOnlyButtonClick() {
    const {
      save,
      closeModal,
      onRecordCreated
    } = this.props;

    if (save) {
      save(onRecordCreated).then(() => {
        if (closeModal) {
          closeModal(true);
        }
      });
    }
  }

  handleSaveLockButtonClick() {
    const {
      saveWithTransition,
      closeModal,
      onRecordCreated
    } = this.props;

    if (saveWithTransition) {
      saveWithTransition('lock', onRecordCreated).then(() => {
        if (closeModal) {
          closeModal(true);
        }
      });
    }
  }

  handleRecordFormSelectorCommit(path, value) {
    const {
      setForm
    } = this.props;

    if (setForm) {
      setForm(value);
    }
  }

  renderConfirmNavigationModal() {
    const {
      isModified,
      isSavePending,
      openModalName,
      validationErrors
    } = this.props;
    return /*#__PURE__*/_react.default.createElement(_ConfirmRecordNavigationModal.default, {
      isOpen: openModalName === _modalNames.MODAL_CONFIRM_RECORD_NAVIGATION,
      isModified: isModified,
      isSavePending: isSavePending,
      validationErrors: validationErrors,
      onCancelButtonClick: this.handleModalCancelButtonClick,
      onCloseButtonClick: this.handleModalCancelButtonClick,
      onSaveButtonClick: this.handleConfirmNavigationSaveButtonClick,
      onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick,
      onRevertButtonClick: this.handleConfirmNavigationRevertButtonClick
    });
  }

  renderConfirmRecordDeleteModal() {
    const {
      config,
      csid,
      data,
      isSavePending,
      openModalName,
      recordType,
      vocabulary,
      checkForRelations,
      checkForUses,
      checkForRoleUses
    } = this.props;
    return /*#__PURE__*/_react.default.createElement(_ConfirmRecordDeleteModal.default, {
      config: config,
      csid: csid,
      data: data,
      isOpen: openModalName === _modalNames.MODAL_CONFIRM_RECORD_DELETE,
      isSavePending: isSavePending,
      recordType: recordType,
      vocabulary: vocabulary,
      checkForRelations: checkForRelations,
      checkForUses: checkForUses,
      checkForRoleUses: checkForRoleUses,
      onCancelButtonClick: this.handleModalCancelButtonClick,
      onCloseButtonClick: this.handleModalCancelButtonClick,
      onDeleteButtonClick: this.handleConfirmDeleteButtonClick
    });
  }

  renderLockRecordModal() {
    const {
      config,
      csid,
      isSavePending,
      openModalName,
      recordType
    } = this.props;
    const recordTypeConfig = config.recordTypes[recordType];
    const {
      lockOnSave
    } = recordTypeConfig;

    if (lockOnSave !== 'prompt') {
      return null;
    }

    return /*#__PURE__*/_react.default.createElement(_LockRecordModal.default, {
      csid: csid,
      isOpen: openModalName === _modalNames.MODAL_LOCK_RECORD,
      isSavePending: isSavePending,
      onCancelButtonClick: this.handleModalCancelButtonClick,
      onCloseButtonClick: this.handleModalCancelButtonClick,
      onSaveOnlyButtonClick: this.handleSaveOnlyButtonClick,
      onSaveLockButtonClick: this.handleSaveLockButtonClick
    });
  }

  render() {
    const {
      config,
      csid,
      data,
      dockTop,
      formName,
      isModified,
      isReadPending,
      isSavePending,
      isSidebarOpen,
      perms,
      recordType,
      relatedSubjectWorkflowState,
      roleNames,
      subrecordData,
      validationErrors,
      vocabulary,
      vocabularyWorkflowState,
      checkDeletable,
      onRunButtonClick
    } = this.props;
    const recordTypeConfig = config.recordTypes[recordType];

    if (!data || !recordTypeConfig) {
      return null;
    }

    const serviceType = (0, _get.default)(recordTypeConfig, ['serviceConfig', 'serviceType']);
    const selectedFormName = formName || recordTypeConfig.defaultForm || 'default';
    const relatedSubjectLocked = (0, _workflowStateHelpers.isLocked)(relatedSubjectWorkflowState);
    const vocabularyLocked = (0, _workflowStateHelpers.isLocked)(vocabularyWorkflowState);
    const immutable = (0, _recordDataHelpers.isRecordImmutable)(data);
    const readOnly = isReadPending || immutable || !(csid ? (0, _permissionHelpers.canUpdate)(recordType, perms) : (0, _permissionHelpers.canCreate)(recordType, perms));
    const isRunnable = !!onRunButtonClick;
    const isCloneable = // The record must be saved.
    !!csid && !vocabularyLocked // If we're editing an object record in a secondary tab, and the primary record is locked,
    // a new cloned record would not be able to be related to the primary, so the clone
    // button should not appear.
    && !relatedSubjectLocked // We must have permission to create a new record of the type.
    && (0, _permissionHelpers.canCreate)(recordType, perms) // FIXME: Prevent cloning seeded authroles, since they may contain permissions that are not
    // normally creatable via the UI. Instead of hardcoding this, should be able to configure a
    // normalizeCloneData function that will clean up cloned data for a record type, and/or
    // a cloneable function that will determine if a record is cloneable based on its data.
    && !(recordType === 'authrole' && data.getIn(['ns2:role', 'permsProtection']) === 'immutable');
    const isDeletable = (checkDeletable ? checkDeletable(data) : true) && !!csid && !immutable && !vocabularyLocked // Security resources don't have soft-delete, so also need to check hard delete.
    && ((0, _permissionHelpers.canSoftDelete)(recordType, perms) || (0, _permissionHelpers.canDelete)(recordType, perms));
    const isDeprecatable = !!csid && config.termDeprecationEnabled && serviceType === 'authority' && !(0, _recordDataHelpers.isRecordDeprecated)(data);
    const isUndeprecatable = !!csid && config.termDeprecationEnabled && serviceType === 'authority' && (0, _recordDataHelpers.isRecordDeprecated)(data);
    const className = isSidebarOpen ? _RecordEditor.default.normal : _RecordEditor.default.full;
    return /*#__PURE__*/_react.default.createElement("form", {
      className: className,
      autoComplete: "off"
    }, /*#__PURE__*/_react.default.createElement(_Dock.default, {
      dockTop: dockTop,
      isSidebarOpen: isSidebarOpen
    }, /*#__PURE__*/_react.default.createElement(_RecordHeader.default, {
      config: config,
      data: data,
      formName: selectedFormName,
      isRunnable: isRunnable,
      isCloneable: isCloneable,
      isDeletable: isDeletable,
      isDeprecatable: isDeprecatable,
      isUndeprecatable: isUndeprecatable,
      isModified: isModified,
      isReadPending: isReadPending,
      isSavePending: isSavePending,
      readOnly: readOnly,
      recordType: recordType,
      validationErrors: validationErrors,
      onCloneButtonClick: this.handleCloneButtonClick,
      onCommit: this.handleRecordFormSelectorCommit,
      onDeprecateButtonClick: this.handleDeprecateButtonClick,
      onDeleteButtonClick: this.handleDeleteButtonClick,
      onSaveButtonClick: this.handleSaveButtonClick,
      onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick,
      onRevertButtonClick: this.handleRevertButtonClick,
      onUndeprecateButtonClick: this.handleUndeprecateButtonClick,
      onRunButtonClick: onRunButtonClick
    })), /*#__PURE__*/_react.default.createElement(_RecordFormContainer.default, {
      config: config,
      csid: csid,
      data: data,
      formName: selectedFormName,
      readOnly: readOnly,
      recordType: recordType,
      recordTypeConfig: recordTypeConfig,
      roleNames: roleNames,
      subrecordData: subrecordData,
      vocabulary: vocabulary
    }), /*#__PURE__*/_react.default.createElement("footer", null, /*#__PURE__*/_react.default.createElement(_RecordButtonBar.default, {
      isRunnable: isRunnable,
      isCloneable: isCloneable,
      isDeletable: isDeletable,
      isDeprecatable: isDeprecatable,
      isUndeprecatable: isUndeprecatable,
      isModified: isModified,
      isReadPending: isReadPending,
      isSavePending: isSavePending,
      readOnly: readOnly,
      validationErrors: validationErrors,
      onSaveButtonClick: this.handleSaveButtonClick,
      onSaveButtonErrorBadgeClick: this.handleSaveButtonErrorBadgeClick,
      onRevertButtonClick: this.handleRevertButtonClick,
      onCloneButtonClick: this.handleCloneButtonClick,
      onDeleteButtonClick: this.handleDeleteButtonClick,
      onRunButtonClick: onRunButtonClick
    })), /*#__PURE__*/_react.default.createElement(_reactRouter.Prompt, {
      when: isModified && !isSavePending,
      message: _modalNames.MODAL_CONFIRM_RECORD_NAVIGATION
    }), this.renderConfirmNavigationModal(), this.renderConfirmRecordDeleteModal(), this.renderLockRecordModal());
  }

}

exports.default = RecordEditor;
RecordEditor.propTypes = propTypes;
RecordEditor.defaultProps = defaultProps;