<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import reactMixin from 'react-mixin';
import autoBind from 'react-autobind';
import Reflux from 'reflux';
import alertify from 'alertifyjs';
import Select from 'react-select';
import Dropzone from 'react-dropzone';
import TextBox from 'js/components/common/textBox';
import Checkbox from 'js/components/common/checkbox';
import {bem} from 'js/bem';
import {LoadingSpinner} from 'js/ui';
import assetUtils from 'js/assetUtils';
import TextareaAutosize from 'react-autosize-textarea';
import {stores} from 'js/stores';
import {hashHistory} from 'react-router';
import mixins from 'js/mixins';
import TemplatesList from 'js/components/templatesList';
import {actions} from 'js/actions';
import {dataInterface} from 'js/dataInterface';
import {
  validFileTypes,
  isAValidUrl,
  escapeHtml,
} from 'utils';
import {
  NAME_MAX_LENGTH,
  PROJECT_SETTINGS_CONTEXTS,
  ROUTES,
} from 'js/constants';
import {LOCKING_RESTRICTIONS} from 'js/components/locking/lockingConstants';
import {hasAssetRestriction} from 'js/components/locking/lockingUtils';

const VIA_URL_SUPPORT_URL = 'xls_url.html';

/*
This is used for multiple different purposes:

1. When creating new project
2. When replacing project with new one
3. When editing project in /settings
4. When editing or creating asset in Form Builder

Identifying the purpose is done by checking `context` and `formAsset`.

You can listen to field changes by `onProjectDetailsChange` prop function.
*/
class ProjectSettings extends React.Component {
  constructor(props) {
    super(props);

    this.STEPS = {
      FORM_SOURCE: 'form-source',
      CHOOSE_TEMPLATE: 'choose-template',
      UPLOAD_FILE: 'upload-file',
      IMPORT_URL: 'import-url',
      PROJECT_DETAILS: 'project-details'
    };

    this.unlisteners = [];

    const formAsset = this.props.formAsset;

    this.state = {
      isSessionLoaded: !!stores.session.currentAccount,
      isSubmitPending: false,
      formAsset: formAsset,
      // project details
      name: formAsset ? formAsset.name : '',
      description: formAsset ? formAsset.settings.description : '',
      sector: formAsset ? formAsset.settings.sector : null,
      country: formAsset ? formAsset.settings.country : null,
      'share-metadata': formAsset ? formAsset.settings['share-metadata'] : false,
      // steps
      currentStep: null,
      previousStep: null,
      // importing url
      isImportFromURLPending: false,
      importUrl: '',
      importUrlButtonEnabled: false,
      importUrlButton: t('Import'),
      // template
      isApplyTemplatePending: false,
      applyTemplateButton: t('Next'),
      chosenTemplateUid: null,
      // upload files
      isUploadFilePending: false,
      // archive flow
      isAwaitingArchiveCompleted: false,
      isAwaitingUnarchiveCompleted: false
    };

    autoBind(this);
  }

  /*
   * setup
   */

  componentDidMount() {
    this.setInitialStep();
    this.listenTo(stores.session, () => {
      this.setState({
        isSessionLoaded: true,
      });
    });
    this.unlisteners.push(
      actions.resources.updateAsset.completed.listen(this.onUpdateAssetCompleted.bind(this)),
      actions.resources.updateAsset.failed.listen(this.onUpdateAssetFailed.bind(this)),
      actions.resources.cloneAsset.completed.listen(this.onCloneAssetCompleted.bind(this)),
      actions.resources.cloneAsset.failed.listen(this.onCloneAssetFailed.bind(this)),
      actions.resources.setDeploymentActive.failed.listen(this.onSetDeploymentActiveFailed.bind(this)),
      actions.resources.setDeploymentActive.completed.listen(this.onSetDeploymentActiveCompleted.bind(this)),
      hashHistory.listen(this.onRouteChange.bind(this))
    );
  }

  componentWillUnmount() {
    this.unlisteners.forEach((clb) => {clb();});
  }

  setInitialStep() {
    switch (this.props.context) {
      case PROJECT_SETTINGS_CONTEXTS.NEW:
      case PROJECT_SETTINGS_CONTEXTS.REPLACE:
        return this.displayStep(this.STEPS.FORM_SOURCE);
      case PROJECT_SETTINGS_CONTEXTS.EXISTING:
      case PROJECT_SETTINGS_CONTEXTS.BUILDER:
        return this.displayStep(this.STEPS.PROJECT_DETAILS);
      default:
        throw new Error(`Unknown context: ${this.props.context}!`);
    }
  }

  getBaseTitle() {
    switch (this.props.context) {
      case PROJECT_SETTINGS_CONTEXTS.NEW:
        return t('Create project');
      case PROJECT_SETTINGS_CONTEXTS.REPLACE:
        return t('Replace form');
      case PROJECT_SETTINGS_CONTEXTS.EXISTING:
      case PROJECT_SETTINGS_CONTEXTS.BUILDER:
      default:
        return t('Project settings');
    }
  }

  getStepTitle(step) {
    switch (step) {
      case this.STEPS.FORM_SOURCE: return t('Choose a source');
      case this.STEPS.CHOOSE_TEMPLATE: return t('Choose template');
      case this.STEPS.UPLOAD_FILE: return t('Upload XLSForm');
      case this.STEPS.IMPORT_URL: return t('Import XLSForm');
      case this.STEPS.PROJECT_DETAILS: return t('Project details');
      default: return '';
    }
  }

  getFilenameFromURI(url) {
    return decodeURIComponent(new URL(url).pathname.split('/').pop().split('.')[0]);
  }

  isReplacingFormLocked() {
    return (
      this.props.context === PROJECT_SETTINGS_CONTEXTS.REPLACE &&
      this.props.formAsset?.content &&
      hasAssetRestriction(this.props.formAsset.content, LOCKING_RESTRICTIONS.form_repace.name)
    );
  }

  /*
   * handling user input
   */

  onAnyDataChange(fieldName, fieldValue) {
    if (typeof this.props.onProjectDetailsChange === 'function') {
      this.props.onProjectDetailsChange({fieldName, fieldValue});
    }
  }

  onNameChange(evt) {
    this.setState({name: removeInvalidChars(evt.target.value)});
    this.onAnyDataChange('name', removeInvalidChars(evt.target.value));
  }

  onDescriptionChange(evt) {
    this.setState({description: removeInvalidChars(evt.target.value)});
    this.onAnyDataChange('description', removeInvalidChars(evt.target.value));
  }

  onCountryChange(val) {
    this.setState({country: val});
    this.onAnyDataChange('country', val);
  }

  onSectorChange(val) {
    this.setState({sector: val});<commit_msg>fix post duplicate import removal issue<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import reactMixin from 'react-mixin';
import autoBind from 'react-autobind';
import Reflux from 'reflux';
import alertify from 'alertifyjs';
import Select from 'react-select';
import Dropzone from 'react-dropzone';
import TextBox from 'js/components/common/textBox';
import Checkbox from 'js/components/common/checkbox';
import {bem} from 'js/bem';
import {LoadingSpinner} from 'js/ui';
import assetUtils from 'js/assetUtils';
import TextareaAutosize from 'react-autosize-textarea';
import {stores} from 'js/stores';
import {hashHistory} from 'react-router';
import mixins from 'js/mixins';
import TemplatesList from 'js/components/templatesList';
import {actions} from 'js/actions';
import {dataInterface} from 'js/dataInterface';
import {
  validFileTypes,
  isAValidUrl,
  escapeHtml,
} from 'utils';
import {
  NAME_MAX_LENGTH,
  PROJECT_SETTINGS_CONTEXTS,
  ROUTES,
} from 'js/constants';
import {LOCKING_RESTRICTIONS} from 'js/components/locking/lockingConstants';
import {hasAssetRestriction} from 'js/components/locking/lockingUtils';

const VIA_URL_SUPPORT_URL = 'xls_url.html';

/*
This is used for multiple different purposes:

1. When creating new project
2. When replacing project with new one
3. When editing project in /settings
4. When editing or creating asset in Form Builder

Identifying the purpose is done by checking `context` and `formAsset`.

You can listen to field changes by `onProjectDetailsChange` prop function.
*/
class ProjectSettings extends React.Component {
  constructor(props) {
    super(props);

    this.STEPS = {
      FORM_SOURCE: 'form-source',
      CHOOSE_TEMPLATE: 'choose-template',
      UPLOAD_FILE: 'upload-file',
      IMPORT_URL: 'import-url',
      PROJECT_DETAILS: 'project-details'
    };

    this.unlisteners = [];

    const formAsset = this.props.formAsset;

    this.state = {
      isSessionLoaded: !!stores.session.currentAccount,
      isSubmitPending: false,
      formAsset: formAsset,
      // project details
      name: formAsset ? formAsset.name : '',
      description: formAsset ? formAsset.settings.description : '',
      sector: formAsset ? formAsset.settings.sector : null,
      country: formAsset ? formAsset.settings.country : null,
      'share-metadata': formAsset ? formAsset.settings['share-metadata'] : false,
      // steps
      currentStep: null,
      previousStep: null,
      // importing url
      isImportFromURLPending: false,
      importUrl: '',
      importUrlButtonEnabled: false,
      importUrlButton: t('Import'),
      // template
      isApplyTemplatePending: false,
      applyTemplateButton: t('Next'),
      chosenTemplateUid: null,
      // upload files
      isUploadFilePending: false,
      // archive flow
      isAwaitingArchiveCompleted: false,
      isAwaitingUnarchiveCompleted: false
    };

    autoBind(this);
  }

  /*
   * setup
   */

  componentDidMount() {
    this.setInitialStep();
    this.listenTo(stores.session, () => {
      this.setState({
        isSessionLoaded: true,
      });
    });
    this.unlisteners.push(
      actions.resources.updateAsset.completed.listen(this.onUpdateAssetCompleted.bind(this)),
      actions.resources.updateAsset.failed.listen(this.onUpdateAssetFailed.bind(this)),
      actions.resources.cloneAsset.completed.listen(this.onCloneAssetCompleted.bind(this)),
      actions.resources.cloneAsset.failed.listen(this.onCloneAssetFailed.bind(this)),
      actions.resources.setDeploymentActive.failed.listen(this.onSetDeploymentActiveFailed.bind(this)),
      actions.resources.setDeploymentActive.completed.listen(this.onSetDeploymentActiveCompleted.bind(this)),
      hashHistory.listen(this.onRouteChange.bind(this))
    );
  }

  componentWillUnmount() {
    this.unlisteners.forEach((clb) => {clb();});
  }

  setInitialStep() {
    switch (this.props.context) {
      case PROJECT_SETTINGS_CONTEXTS.NEW:
      case PROJECT_SETTINGS_CONTEXTS.REPLACE:
        return this.displayStep(this.STEPS.FORM_SOURCE);
      case PROJECT_SETTINGS_CONTEXTS.EXISTING:
      case PROJECT_SETTINGS_CONTEXTS.BUILDER:
        return this.displayStep(this.STEPS.PROJECT_DETAILS);
      default:
        throw new Error(`Unknown context: ${this.props.context}!`);
    }
  }

  getBaseTitle() {
    switch (this.props.context) {
      case PROJECT_SETTINGS_CONTEXTS.NEW:
        return t('Create project');
      case PROJECT_SETTINGS_CONTEXTS.REPLACE:
        return t('Replace form');
      case PROJECT_SETTINGS_CONTEXTS.EXISTING:
      case PROJECT_SETTINGS_CONTEXTS.BUILDER:
      default:
        return t('Project settings');
    }
  }

  getStepTitle(step) {
    switch (step) {
      case this.STEPS.FORM_SOURCE: return t('Choose a source');
      case this.STEPS.CHOOSE_TEMPLATE: return t('Choose template');
      case this.STEPS.UPLOAD_FILE: return t('Upload XLSForm');
      case this.STEPS.IMPORT_URL: return t('Import XLSForm');
      case this.STEPS.PROJECT_DETAILS: return t('Project details');
      default: return '';
    }
  }

  getFilenameFromURI(url) {
    return decodeURIComponent(new URL(url).pathname.split('/').pop().split('.')[0]);
  }

  isReplacingFormLocked() {
    return (
      this.props.context === PROJECT_SETTINGS_CONTEXTS.REPLACE &&
      this.props.formAsset?.content &&
      hasAssetRestriction(this.props.formAsset.content, LOCKING_RESTRICTIONS.form_repace.name)
    );
  }

  /*
   * handling user input
   */

  onAnyDataChange(fieldName, fieldValue) {
    if (typeof this.props.onProjectDetailsChange === 'function') {
      this.props.onProjectDetailsChange({fieldName, fieldValue});
    }
  }

  onNameChange(evt) {
    this.setState({name: assetUtils.removeInvalidChars(evt.target.value)});
    this.onAnyDataChange('name', assetUtils.removeInvalidChars(evt.target.value));
  }

  onDescriptionChange(evt) {
    this.setState({description: assetUtils.removeInvalidChars(evt.target.value)});
    this.onAnyDataChange('description', assetUtils.removeInvalidChars(evt.target.value));
  }

  onCountryChange(val) {
    this.setState({country: val});
    this.onAnyDataChange('country', val);
  }

  onSectorChange(val) {
    this.setState({sector: val});
{'fraction_non_alphanumeric': 0.1171648987463838, 'fraction_numerical': 0.0008036001285760206, 'mean_word_length': 3.79022324865281, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4037081', 'n_tokens_mistral': 3842, 'n_tokens_neox': 3823, 'n_words': 740}