"use strict";

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

var _debounce2 = _interopRequireDefault(require("lodash/debounce"));

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

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

var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes"));

var _reactPolyglot = require("react-polyglot");

var _reactRedux = require("react-redux");

var _auth = require("../../actions/auth");

var _deploys = require("../../actions/deploys");

var _editorialWorkflow = require("../../actions/editorialWorkflow");

var _entries = require("../../actions/entries");

var _scroll = require("../../actions/scroll");

var _publishModes = require("../../constants/publishModes");

var _reducers = require("../../reducers");

var _collections = require("../../reducers/collections");

var _history = require("../../routing/history");

var _ui = require("../../ui");

var _Alert = _interopRequireDefault(require("../UI/Alert"));

var _Confirm = _interopRequireDefault(require("../UI/Confirm"));

var _EditorInterface = _interopRequireDefault(require("./EditorInterface"));

var _withWorkflow = _interopRequireDefault(require("./withWorkflow"));

var _react2 = require("@emotion/react");

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

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

class Editor extends _react.default.Component {
  constructor() {
    var _this;

    super(...arguments);
    _this = this;

    _defineProperty(this, "createBackup", (0, _debounce2.default)(function (entry, collection) {
      this.props.persistLocalBackup(entry, collection);
    }, 2000));

    _defineProperty(this, "handleChangeDraftField", (field, value, metadata, i18n) => {
      const entries = [this.props.unPublishedEntry, this.props.publishedEntry].filter(Boolean);
      this.props.changeDraftField({
        field,
        value,
        metadata,
        entries,
        i18n
      });
    });

    _defineProperty(this, "handleChangeStatus", newStatusName => {
      const {
        entryDraft,
        updateUnpublishedEntryStatus,
        collection,
        slug,
        currentStatus
      } = this.props;

      if (entryDraft.get('hasChanged')) {
        (0, _Alert.default)({
          title: 'editor.editor.onUpdatingWithUnsavedChangesTitle',
          body: 'editor.editor.onUpdatingWithUnsavedChangesBody'
        });
        return;
      }

      const newStatus = _publishModes.status.get(newStatusName);

      updateUnpublishedEntryStatus(collection.get('name'), slug, currentStatus, newStatus);
    });

    _defineProperty(this, "handlePersistEntry", async function () {
      let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      const {
        createNew = false,
        duplicate = false
      } = opts;
      const {
        persistEntry,
        collection,
        currentStatus,
        hasWorkflow,
        loadEntry,
        slug,
        createDraftDuplicateFromEntry,
        entryDraft
      } = _this.props;
      await persistEntry(collection);

      _this.deleteBackup();

      if (createNew) {
        (0, _history.navigateToNewEntry)(collection.get('name'));
        duplicate && createDraftDuplicateFromEntry(entryDraft.get('entry'));
      } else if (slug && hasWorkflow && !currentStatus) {
        loadEntry(collection, slug);
      }
    });

    _defineProperty(this, "handlePublishEntry", async function () {
      let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      const {
        createNew = false,
        duplicate = false
      } = opts;
      const {
        publishUnpublishedEntry,
        createDraftDuplicateFromEntry,
        entryDraft,
        collection,
        slug,
        currentStatus
      } = _this.props;

      if (currentStatus !== _publishModes.status.last()) {
        (0, _Alert.default)({
          title: 'editor.editor.onPublishingNotReadyTitle',
          body: 'editor.editor.onPublishingNotReadyBody'
        });
        return;
      } else if (entryDraft.get('hasChanged')) {
        (0, _Alert.default)({
          title: 'editor.editor.onPublishingWithUnsavedChangesTitle',
          body: 'editor.editor.onPublishingWithUnsavedChangesBody'
        });
        return;
      } else if (!(await (0, _Confirm.default)({
        title: 'editor.editor.onPublishingTitle',
        body: 'editor.editor.onPublishingBody'
      }))) {
        return;
      }

      await publishUnpublishedEntry(collection.get('name'), slug);

      _this.deleteBackup();

      if (createNew) {
        (0, _history.navigateToNewEntry)(collection.get('name'));
      }

      duplicate && createDraftDuplicateFromEntry(entryDraft.get('entry'));
    });

    _defineProperty(this, "handleUnpublishEntry", async () => {
      const {
        unpublishPublishedEntry,
        collection,
        slug
      } = this.props;

      if (!(await (0, _Confirm.default)({
        title: 'editor.editor.onUnpublishingTitle',
        body: 'editor.editor.onUnpublishingBody',
        color: 'error'
      }))) {
        return;
      }

      await unpublishPublishedEntry(collection, slug);
      return (0, _history.navigateToCollection)(collection.get('name'));
    });

    _defineProperty(this, "handleDuplicateEntry", () => {
      const {
        createDraftDuplicateFromEntry,
        collection,
        entryDraft
      } = this.props;
      (0, _history.navigateToNewEntry)(collection.get('name'));
      createDraftDuplicateFromEntry(entryDraft.get('entry'));
    });

    _defineProperty(this, "handleDeleteEntry", async () => {
      const {
        entryDraft,
        newEntry,
        collection,
        deleteEntry,
        slug
      } = this.props;

      if (entryDraft.get('hasChanged')) {
        if (!(await (0, _Confirm.default)({
          title: 'editor.editor.onDeleteWithUnsavedChangesTitle',
          body: 'editor.editor.onDeleteWithUnsavedChangesBody',
          color: 'error'
        }))) {
          return;
        }
      } else if (!(await (0, _Confirm.default)({
        title: 'editor.editor.onDeletePublishedEntryTitle',
        body: 'editor.editor.onDeletePublishedEntryBody',
        color: 'error'
      }))) {
        return;
      }

      if (newEntry) {
        return (0, _history.navigateToCollection)(collection.get('name'));
      }

      setTimeout(async () => {
        await deleteEntry(collection, slug);
        this.deleteBackup();
        return (0, _history.navigateToCollection)(collection.get('name'));
      }, 0);
    });

    _defineProperty(this, "handleDeleteUnpublishedChanges", async () => {
      const {
        entryDraft,
        collection,
        slug,
        deleteUnpublishedEntry,
        loadEntry,
        isModification
      } = this.props;

      if (entryDraft.get('hasChanged') && !(await (0, _Confirm.default)({
        title: 'editor.editor.onDeleteUnpublishedChangesWithUnsavedChangesTitle',
        body: 'editor.editor.onDeleteUnpublishedChangesWithUnsavedChangesBody',
        color: 'error'
      }))) {
        return;
      } else if (!(await (0, _Confirm.default)({
        title: 'editor.editor.onDeleteUnpublishedChangesTitle',
        body: 'editor.editor.onDeleteUnpublishedChangesBody',
        color: 'error'
      }))) {
        return;
      }

      await deleteUnpublishedEntry(collection.get('name'), slug);
      this.deleteBackup();

      if (isModification) {
        loadEntry(collection, slug);
      } else {
        (0, _history.navigateToCollection)(collection.get('name'));
      }
    });
  }

  componentDidMount() {
    const {
      newEntry,
      collection,
      slug,
      loadEntry,
      createEmptyDraft,
      loadEntries,
      retrieveLocalBackup,
      collectionEntriesLoaded,
      t
    } = this.props;
    retrieveLocalBackup(collection, slug);

    if (newEntry) {
      createEmptyDraft(collection, this.props.location.search);
    } else {
      loadEntry(collection, slug);
    }

    const leaveMessage = t('editor.editor.onLeavePage');

    this.exitBlocker = event => {
      if (this.props.entryDraft.get('hasChanged')) {
        // This message is ignored in most browsers, but its presence
        // triggers the confirmation dialog
        event.returnValue = leaveMessage;
        return leaveMessage;
      }
    };

    window.addEventListener('beforeunload', this.exitBlocker);

    const navigationBlocker = (location, action) => {
      /**
       * New entry being saved and redirected to it's new slug based url.
       */
      const isPersisting = this.props.entryDraft.getIn(['entry', 'isPersisting']);
      const newRecord = this.props.entryDraft.getIn(['entry', 'newRecord']);
      const newEntryPath = `/collections/${collection.get('name')}/new`;

      if (isPersisting && newRecord && this.props.location.pathname === newEntryPath && action === 'PUSH') {
        return;
      }

      if (this.props.hasChanged) {
        return leaveMessage;
      }
    };

    const unblock = _history.history.block(navigationBlocker);
    /**
     * This will run as soon as the location actually changes, unless creating
     * a new post. The confirmation above will run first.
     */


    this.unlisten = _history.history.listen((location, action) => {
      const newEntryPath = `/collections/${collection.get('name')}/new`;
      const entriesPath = `/collections/${collection.get('name')}/entries/`;
      const {
        pathname
      } = location;

      if (pathname.startsWith(newEntryPath) || pathname.startsWith(entriesPath) && action === 'PUSH') {
        return;
      }

      this.deleteBackup();
      unblock();
      this.unlisten();
    });

    if (!collectionEntriesLoaded) {
      loadEntries(collection);
    }
  }

  async checkLocalBackup(prevProps) {
    const {
      t,
      hasChanged,
      localBackup,
      loadLocalBackup,
      entryDraft,
      collection
    } = this.props;

    if (!prevProps.localBackup && localBackup) {
      const confirmLoadBackup = await (0, _Confirm.default)({
        title: 'editor.editor.confirmLoadBackupTitle',
        body: 'editor.editor.confirmLoadBackupBody'
      });

      if (confirmLoadBackup) {
        loadLocalBackup();
      } else {
        this.deleteBackup();
      }
    }

    if (hasChanged) {
      this.createBackup(entryDraft.get('entry'), collection);
    }
  }

  componentDidUpdate(prevProps) {
    this.checkLocalBackup(prevProps);

    if (prevProps.entry === this.props.entry) {
      return;
    }

    const {
      newEntry,
      collection
    } = this.props;

    if (newEntry) {
      prevProps.createEmptyDraft(collection, this.props.location.search);
    }
  }

  componentWillUnmount() {
    this.createBackup.flush();
    this.props.discardDraft();
    window.removeEventListener('beforeunload', this.exitBlocker);
  }

  deleteBackup() {
    const {
      deleteLocalBackup,
      collection,
      slug,
      newEntry
    } = this.props;
    this.createBackup.cancel();
    deleteLocalBackup(collection, !newEntry && slug);
  }

  render() {
    const {
      entry,
      entryDraft,
      fields,
      collection,
      changeDraftFieldValidation,
      user,
      hasChanged,
      displayUrl,
      hasWorkflow,
      useOpenAuthoring,
      unpublishedEntry,
      newEntry,
      isModification,
      currentStatus,
      logoutUser,
      deployPreview,
      loadDeployPreview,
      draftKey,
      slug,
      t,
      editorBackLink,
      toggleScroll,
      scrollSyncEnabled,
      loadScroll
    } = this.props;
    const isPublished = !newEntry && !unpublishedEntry;

    if (entry && entry.get('error')) {
      return (0, _react2.jsx)("div", null, (0, _react2.jsx)("h3", null, entry.get('error')));
    } else if (entryDraft == null || entryDraft.get('entry') === undefined || entry && entry.get('isFetching')) {
      return (0, _react2.jsx)(_ui.Loader, {
        active: true
      }, t('editor.editor.loadingEntry'));
    }

    return (0, _react2.jsx)(_EditorInterface.default, {
      draftKey: draftKey,
      entry: entryDraft.get('entry'),
      collection: collection,
      fields: fields,
      fieldsMetaData: entryDraft.get('fieldsMetaData'),
      fieldsErrors: entryDraft.get('fieldsErrors'),
      onChange: this.handleChangeDraftField,
      onValidate: changeDraftFieldValidation,
      onPersist: this.handlePersistEntry,
      onDelete: this.handleDeleteEntry,
      onDeleteUnpublishedChanges: this.handleDeleteUnpublishedChanges,
      onChangeStatus: this.handleChangeStatus,
      onPublish: this.handlePublishEntry,
      unPublish: this.handleUnpublishEntry,
      onDuplicate: this.handleDuplicateEntry,
      showDelete: this.props.showDelete,
      user: user,
      hasChanged: hasChanged,
      displayUrl: displayUrl,
      hasWorkflow: hasWorkflow,
      useOpenAuthoring: useOpenAuthoring,
      hasUnpublishedChanges: unpublishedEntry,
      isNewEntry: newEntry,
      isModification: isModification,
      currentStatus: currentStatus,
      onLogoutClick: logoutUser,
      deployPreview: deployPreview,
      loadDeployPreview: opts => loadDeployPreview(collection, slug, entry, isPublished, opts),
      editorBackLink: editorBackLink,
      toggleScroll: toggleScroll,
      scrollSyncEnabled: scrollSyncEnabled,
      loadScroll: loadScroll,
      t: t
    });
  }

}

exports.Editor = Editor;

_defineProperty(Editor, "propTypes", {
  changeDraftField: _propTypes.default.func.isRequired,
  changeDraftFieldValidation: _propTypes.default.func.isRequired,
  collection: _reactImmutableProptypes.default.map.isRequired,
  createDraftDuplicateFromEntry: _propTypes.default.func.isRequired,
  createEmptyDraft: _propTypes.default.func.isRequired,
  discardDraft: _propTypes.default.func.isRequired,
  entry: _reactImmutableProptypes.default.map,
  entryDraft: _reactImmutableProptypes.default.map.isRequired,
  loadEntry: _propTypes.default.func.isRequired,
  persistEntry: _propTypes.default.func.isRequired,
  deleteEntry: _propTypes.default.func.isRequired,
  showDelete: _propTypes.default.bool.isRequired,
  fields: _reactImmutableProptypes.default.list.isRequired,
  slug: _propTypes.default.string,
  newEntry: _propTypes.default.bool.isRequired,
  displayUrl: _propTypes.default.string,
  hasWorkflow: _propTypes.default.bool,
  useOpenAuthoring: _propTypes.default.bool,
  unpublishedEntry: _propTypes.default.bool,
  isModification: _propTypes.default.bool,
  collectionEntriesLoaded: _propTypes.default.bool,
  updateUnpublishedEntryStatus: _propTypes.default.func.isRequired,
  publishUnpublishedEntry: _propTypes.default.func.isRequired,
  deleteUnpublishedEntry: _propTypes.default.func.isRequired,
  logoutUser: _propTypes.default.func.isRequired,
  loadEntries: _propTypes.default.func.isRequired,
  deployPreview: _propTypes.default.object,
  loadDeployPreview: _propTypes.default.func.isRequired,
  currentStatus: _propTypes.default.string,
  user: _propTypes.default.object,
  location: _propTypes.default.shape({
    pathname: _propTypes.default.string,
    search: _propTypes.default.string
  }),
  hasChanged: _propTypes.default.bool,
  t: _propTypes.default.func.isRequired,
  retrieveLocalBackup: _propTypes.default.func.isRequired,
  localBackup: _reactImmutableProptypes.default.map,
  loadLocalBackup: _propTypes.default.func,
  persistLocalBackup: _propTypes.default.func.isRequired,
  deleteLocalBackup: _propTypes.default.func,
  toggleScroll: _propTypes.default.func.isRequired,
  scrollSyncEnabled: _propTypes.default.bool.isRequired,
  loadScroll: _propTypes.default.func.isRequired
});

function mapStateToProps(state, ownProps) {
  const {
    collections,
    entryDraft,
    auth,
    config,
    entries,
    globalUI,
    scroll
  } = state;
  const slug = ownProps.match.params[0];
  const collection = collections.get(ownProps.match.params.name);
  const collectionName = collection.get('name');
  const newEntry = ownProps.newRecord === true;
  const fields = (0, _collections.selectFields)(collection, slug);
  const entry = newEntry ? null : (0, _reducers.selectEntry)(state, collectionName, slug);
  const user = auth.user;
  const hasChanged = entryDraft.get('hasChanged');
  const displayUrl = config.display_url;
  const hasWorkflow = config.publish_mode === _publishModes.EDITORIAL_WORKFLOW;
  const useOpenAuthoring = globalUI.useOpenAuthoring;
  const isModification = entryDraft.getIn(['entry', 'isModification']);
  const collectionEntriesLoaded = !!entries.getIn(['pages', collectionName]);
  const unPublishedEntry = (0, _reducers.selectUnpublishedEntry)(state, collectionName, slug);
  const publishedEntry = (0, _reducers.selectEntry)(state, collectionName, slug);
  const currentStatus = unPublishedEntry && unPublishedEntry.get('status');
  const deployPreview = (0, _reducers.selectDeployPreview)(state, collectionName, slug);
  const localBackup = entryDraft.get('localBackup');
  const draftKey = entryDraft.get('key');
  let editorBackLink = `/collections/${collectionName}`;

  if (new URLSearchParams(ownProps.location.search).get('ref') === 'workflow') {
    editorBackLink = `/workflow`;
  }

  if (collection.has('files') && collection.get('files').size === 1) {
    editorBackLink = '/';
  }

  if (collection.has('nested') && slug) {
    const pathParts = slug.split('/');

    if (pathParts.length > 2) {
      editorBackLink = `${editorBackLink}/filter/${pathParts.slice(0, -2).join('/')}`;
    }
  }

  const scrollSyncEnabled = scroll.isScrolling;
  return {
    collection,
    collections,
    newEntry,
    entryDraft,
    fields,
    slug,
    entry,
    user,
    hasChanged,
    displayUrl,
    hasWorkflow,
    useOpenAuthoring,
    isModification,
    collectionEntriesLoaded,
    currentStatus,
    deployPreview,
    localBackup,
    draftKey,
    publishedEntry,
    unPublishedEntry,
    editorBackLink,
    scrollSyncEnabled
  };
}

const mapDispatchToProps = {
  changeDraftField: _entries.changeDraftField,
  changeDraftFieldValidation: _entries.changeDraftFieldValidation,
  loadEntry: _entries.loadEntry,
  loadEntries: _entries.loadEntries,
  loadDeployPreview: _deploys.loadDeployPreview,
  loadLocalBackup: _entries.loadLocalBackup,
  retrieveLocalBackup: _entries.retrieveLocalBackup,
  persistLocalBackup: _entries.persistLocalBackup,
  deleteLocalBackup: _entries.deleteLocalBackup,
  createDraftDuplicateFromEntry: _entries.createDraftDuplicateFromEntry,
  createEmptyDraft: _entries.createEmptyDraft,
  discardDraft: _entries.discardDraft,
  persistEntry: _entries.persistEntry,
  deleteEntry: _entries.deleteEntry,
  updateUnpublishedEntryStatus: _editorialWorkflow.updateUnpublishedEntryStatus,
  publishUnpublishedEntry: _editorialWorkflow.publishUnpublishedEntry,
  unpublishPublishedEntry: _editorialWorkflow.unpublishPublishedEntry,
  deleteUnpublishedEntry: _editorialWorkflow.deleteUnpublishedEntry,
  logoutUser: _auth.logoutUser,
  toggleScroll: _scroll.toggleScroll,
  loadScroll: _scroll.loadScroll
};

var _default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withWorkflow.default)((0, _reactPolyglot.translate)()(Editor)));

exports.default = _default;