'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var icons = require('@transferwise/icons');
var clsx = require('clsx');
var React = require('react');
var reactIntl = require('react-intl');
var Title = require('../title/Title.js');
var Upload_messages = require('./Upload.messages.js');
var uploadImageStep = require('./steps/uploadImageStep/uploadImageStep.js');
var processingStep = require('./steps/processingStep/processingStep.js');
var completeStep = require('./steps/completeStep/completeStep.js');
var postData = require('./utils/postData/postData.js');
var asyncFileRead = require('./utils/asyncFileRead/asyncFileRead.js');
var isSizeValid = require('./utils/isSizeValid/isSizeValid.js');
var isTypeValid = require('./utils/isTypeValid/isTypeValid.js');
var getFileType = require('./utils/getFileType/getFileType.js');
var jsxRuntime = require('react/jsx-runtime');
var typography = require('../common/propsValues/typography.js');

const ANIMATION_FIX = 10;
const MAX_SIZE_DEFAULT = 5000000;
exports.UploadStep = void 0;
(function (UploadStep) {
  UploadStep["UPLOAD_IMAGE_STEP"] = "uploadImageStep";
})(exports.UploadStep || (exports.UploadStep = {}));
class Upload extends React.Component {
  static defaultProps = {
    animationDelay: 700,
    maxSize: MAX_SIZE_DEFAULT,
    psButtonDisabled: false,
    size: 'md',
    usAccept: 'image/*',
    usDisabled: false,
    usLabel: ''
  };
  dragCounter = 0;
  timeouts = 0;
  constructor(props) {
    super(props);
    this.state = {
      fileName: '',
      isDroppable: false,
      isComplete: false,
      isError: false,
      isImage: false,
      isProcessing: false,
      isSuccess: false,
      response: undefined,
      uploadedImage: undefined
    };
  }
  getErrorMessage(status) {
    const {
      csFailureText,
      csTooLargeMessage,
      csWrongTypeMessage,
      maxSize,
      intl
    } = this.props;
    switch (status) {
      case 413:
        return csTooLargeMessage || intl.formatMessage(Upload_messages.csTooLargeMessage, {
          maxSize: maxSize / 1000000
        });
      case 415:
        return csWrongTypeMessage || intl.formatMessage(Upload_messages.csWrongTypeMessage);
      default:
        return csFailureText || intl.formatMessage(Upload_messages.csFailureText);
    }
  }
  onDragLeave(event) {
    event.preventDefault();
    this.dragCounter -= 1;
    if (this.dragCounter === 0) {
      this.setState({
        isDroppable: false
      });
    }
  }
  onDragEnter(event) {
    event.preventDefault();
    this.dragCounter += 1;
    const {
      usDisabled
    } = this.props;
    const {
      isProcessing
    } = this.state;
    if (this.dragCounter === 1 && !usDisabled && !isProcessing) {
      this.setState({
        isDroppable: true
      });
    }
  }
  async onDrop(event) {
    const {
      isProcessing
    } = this.state;
    event.preventDefault();
    if (!isProcessing) {
      this.reset();
    }
    if (event.dataTransfer?.files?.[0]) {
      await this.fileDropped(event.dataTransfer.files[0]);
    }
  }
  onAnimationCompleted = async status => {
    const {
      response,
      isProcessing,
      fileName
    } = this.state;
    const {
      animationDelay
    } = this.props;
    if (isProcessing && status === 'succeeded') {
      const {
        onSuccess
      } = this.props;
      this.timeouts = window.setTimeout(() => {
        this.setState({
          isProcessing: false,
          isComplete: true
        }, onSuccess ? () => onSuccess(response, fileName) : undefined);
      }, animationDelay);
    }
    if (isProcessing && status === 'failed') {
      const {
        onFailure
      } = this.props;
      this.timeouts = window.setTimeout(() => {
        this.setState({
          isProcessing: false,
          isComplete: true
        }, onFailure ? () => onFailure(response) : undefined);
      }, animationDelay);
    }
  };
  asyncPost = async file => {
    const {
      httpOptions,
      fetcher
    } = this.props;
    if (httpOptions == null) {
      throw new Error('Cannot find HTTP options');
    }
    const {
      fileInputName = file.name,
      data = {}
    } = httpOptions;
    const formData = new FormData();
    formData.append(fileInputName, file);
    Object.keys(data).forEach(key => formData.append(key, data[key]));
    return postData.postData(httpOptions, formData, fetcher);
  };
  asyncResponse = (response, type) => {
    // Gives time to the animation callback to fire.
    this.timeouts = window.setTimeout(() => {
      this.setState({
        response,
        isError: type === 'error',
        isSuccess: type === 'success'
      });
    }, ANIMATION_FIX);
  };
  handleOnClear = event => {
    event.preventDefault();
    const {
      onCancel
    } = this.props;
    onCancel?.();
    this.reset();
  };
  reset = () => {
    this.dragCounter = 0;
    window.clearTimeout(this.timeouts);
    this.setState({
      isComplete: false,
      isError: false,
      isProcessing: false,
      isSuccess: false
    });
  };
  showDataImage = dataUrl => {
    const {
      isImage
    } = this.state;
    if (isImage) {
      this.setState({
        uploadedImage: dataUrl
      });
    }
  };
  fileDropped = async file => {
    const {
      httpOptions,
      maxSize,
      onStart,
      usDisabled,
      usAccept
    } = this.props;
    const {
      isProcessing
    } = this.state;
    if (usDisabled || isProcessing) {
      return false;
    }
    if (!file) {
      throw new Error('Could not retrieve file');
    }
    this.setState({
      fileName: file.name,
      isDroppable: false,
      isProcessing: true
    });
    onStart?.(file);
    let file64 = null;
    try {
      file64 = await asyncFileRead.asyncFileRead(file);
    } catch (error) {
      this.asyncResponse(error, 'error');
    }
    if (!file64) {
      return false;
    }
    this.setState({
      isImage: getFileType.getFileType(file, file64).includes('image')
    });
    if (!isTypeValid.isTypeValid(file, usAccept, file64)) {
      this.asyncResponse(new postData.ResponseError(new Response(null, {
        status: 415,
        statusText: 'Unsupported Media Type'
      })), 'error');
      return false;
    }
    if (!isSizeValid.isSizeValid(file, maxSize)) {
      this.asyncResponse(new postData.ResponseError(new Response(null, {
        status: 413,
        statusText: 'Request Entity Too Large'
      })), 'error');
      return false;
    }
    if (httpOptions) {
      // Post the file to provided endpoint
      let response;
      try {
        response = await this.asyncPost(file);
      } catch (error) {
        this.asyncResponse(error, 'error');
        return false;
      }
      this.asyncResponse(response, 'success');
      this.showDataImage(file64);
      return true;
    }
    // Post on form submit. And return the encoded image.
    this.showDataImage(file64);
    this.asyncResponse(file64, 'success');
    return true;
  };
  render() {
    const {
      maxSize,
      usDropMessage,
      usAccept,
      usButtonText,
      usButtonRetryText,
      usDisabled,
      usHelpImage,
      usLabel,
      usPlaceholder,
      psButtonText,
      psProcessingText,
      psButtonDisabled,
      csButtonText,
      csSuccessText,
      size,
      intl,
      errorIconLabel
    } = this.props;
    const {
      response,
      fileName,
      isComplete,
      isDroppable,
      isError,
      isImage,
      isProcessing,
      isSuccess,
      uploadedImage
    } = this.state;
    return /*#__PURE__*/jsxRuntime.jsxs("div", {
      className: clsx.clsx('droppable-area', {
        droppable: true,
        'tw-droppable-sm droppable-sm': size === 'sm',
        'tw-droppable-md droppable-md': size === 'md' || !size,
        'tw-droppable-lg droppable-lg': size === 'lg',
        'droppable-dropping': isDroppable,
        'droppable-processing': isProcessing,
        'droppable-complete': isComplete && !isError,
        'droppable-negative': isError && !isProcessing
      }),
      onDragEnter: event => this.onDragEnter(event),
      onDragLeave: event => this.onDragLeave(event),
      onDrop: async event => this.onDrop(event),
      onDragOver: event => event.preventDefault(),
      children: [!isProcessing && !isComplete && /*#__PURE__*/jsxRuntime.jsx(uploadImageStep, {
        fileDropped: async file => this.fileDropped(file),
        isComplete: isComplete,
        usAccept: usAccept,
        usButtonText: usButtonText || intl.formatMessage(Upload_messages.usButtonText),
        usDisabled: usDisabled,
        usHelpImage: usHelpImage,
        usLabel: usLabel,
        usPlaceholder: usPlaceholder || intl.formatMessage(Upload_messages.usPlaceholder, {
          maxSize: maxSize / 1000000
        })
      }), (isSuccess || isComplete) && !isError && /*#__PURE__*/jsxRuntime.jsx(completeStep, {
        fileName: fileName,
        isComplete: isComplete,
        isImage: isImage,
        csButtonText: csButtonText || intl.formatMessage(Upload_messages.csButtonText),
        csSuccessText: csSuccessText || intl.formatMessage(Upload_messages.csSuccessText),
        uploadedImage: uploadedImage,
        onClear: event => this.handleOnClear(event)
      }), isError && !isProcessing && /*#__PURE__*/jsxRuntime.jsx(uploadImageStep, {
        fileDropped: async file => {
          this.reset();
          await this.fileDropped(file);
        },
        isComplete: !isError,
        usAccept: usAccept,
        usButtonText: usButtonRetryText || intl.formatMessage(Upload_messages.retry),
        usDisabled: usDisabled,
        usHelpImage: null,
        usLabel: usLabel,
        usPlaceholder: usPlaceholder || intl.formatMessage(Upload_messages.usPlaceholder, {
          maxSize: maxSize / 1000000
        }),
        errorMessage: this.getErrorMessage(response != null && typeof response === 'object' && 'status' in response && typeof response.status === 'number' ? response.status : undefined),
        errorIconLabel: errorIconLabel
      }), isProcessing && /*#__PURE__*/jsxRuntime.jsx(processingStep, {
        isComplete: isComplete,
        isError: isError,
        isSuccess: isSuccess,
        psButtonText: psButtonText || intl.formatMessage(Upload_messages.psButtonText),
        psProcessingText: psProcessingText || intl.formatMessage(Upload_messages.psProcessingText),
        psButtonDisabled: psButtonDisabled,
        onAnimationCompleted: async status => this.onAnimationCompleted(status),
        onClear: event => this.handleOnClear(event)
      }), !isProcessing && /*#__PURE__*/jsxRuntime.jsx("div", {
        className: "droppable-dropping-card droppable-card",
        "aria-live": "polite",
        children: /*#__PURE__*/jsxRuntime.jsxs("div", {
          className: "droppable-card-content",
          children: [/*#__PURE__*/jsxRuntime.jsx("div", {
            className: "circle circle-sm text-primary",
            children: /*#__PURE__*/jsxRuntime.jsx(icons.Plus, {
              size: "16"
            })
          }), /*#__PURE__*/jsxRuntime.jsx(Title, {
            type: typography.Typography.TITLE_BODY,
            className: "m-t-3",
            children: usDropMessage || intl.formatMessage(Upload_messages.usDropMessage)
          })]
        })
      })]
    });
  }
}
var Upload$1 = reactIntl.injectIntl(Upload);

exports.MAX_SIZE_DEFAULT = MAX_SIZE_DEFAULT;
exports.Upload = Upload;
exports.default = Upload$1;
//# sourceMappingURL=Upload.js.map
