text: import React, { Component } from 'react';
  import { array, bool, func, shape, string } from 'prop-types';
  import { compose } from 'redux';
  import { Form as FinalForm, Field, FormSpy } from 'react-final-form';
  import { FormattedMessage, intlShape, injectIntl } from '../../util/reactIntl';
  import isEqual from 'lodash/isEqual';
  import classNames from 'classnames';
  import { MAIN_PHOTO_TYPE, OTHER_PHOTO_TYPE, propTypes } from '../../util/types';
  import { nonEmptyArray, composeValidators } from '../../util/validators';
  import { isUploadImageOverLimitError } from '../../util/errors';
  import { AddImages, Button, Form, ValidationError } from '../../components';
  
  import css from './EditListingPhotosForm.module.css';
  import _ from 'lodash';
  
  const ACCEPT_IMAGES = 'image/*';
  
  export class EditListingPhotosFormComponent extends Component {
    constructor(props) {
      super(props);
      this.state = { imageUploadRequested: false };
      this.onImageUploadHandler = this.onImageUploadHandler.bind(this);
      this.submittedImages = [];
    }
  
    onImageUploadHandler(file, type) {
      if (file) {
        this.setState({ imageUploadRequested: true });
        this.props
          .onImageUpload({ id: `${type}_${file.name}_${Date.now()}`, file })
          .then(() => {
            this.setState({ imageUploadRequested: false });
          })
          .catch(() => {
            this.setState({ imageUploadRequested: false });
          });
      }
    }
  
    render() {
      return (
        <FinalForm
          {...this.props}
          onImageUploadHandler={this.onImageUploadHandler}
          imageUploadRequested={this.state.imageUploadRequested}
          initialValues={{ images: this.props.images }}
          render={formRenderProps => {
            const {
              form,
              className,
              fetchErrors,
              handleSubmit,
              images,
              imageUploadRequested,
              intl,
              invalid,
              onImageUploadHandler,
              onRemoveImage,
              disabled,
              ready,
              saveActionMsg,
              updated,
              updateInProgress,
              mainPhotos,
              otherPhotos,
              subTitle
            } = formRenderProps;
  
            const chooseImageText = (
              <span className={css.chooseImageText}>
                <span className={css.chooseImage}>
                  <FormattedMessage id="EditListingPhotosForm.chooseImage" />
                </span>
                <span className={css.imageTypes}>
                  <FormattedMessage id="EditListingPhotosForm.imageTypes" />
                </span>
              </span>
            );
  
            const imageRequiredMessage = intl.formatMessage({
              id: 'EditListingPhotosForm.imageRequired',
            });
  
            const { publishListingError, showListingsError, updateListingError, uploadImageError } =
              fetchErrors || {};
            const uploadOverLimit = isUploadImageOverLimitError(uploadImageError);
  
            let uploadImageFailed = null;
  
            if (uploadOverLimit) {
              uploadImageFailed = (
                <p className={css.error}>
                  <FormattedMessage id="EditListingPhotosForm.imageUploadFailed.uploadOverLimit" />
                </p>
              );
            } else if (uploadImageError) {
              uploadImageFailed = (
                <p className={css.error}>
                  <FormattedMessage id="EditListingPhotosForm.imageUploadFailed.uploadFailed" />
                </p>
              );
            }
  
            const subTitlePanel = subTitle ? <FormattedMessage id={subTitle} /> : null;
  
            // NOTE: These error messages are here since Photos panel is the last visible panel
            // before creating a new listing. If that order is changed, these should be changed too.
            // Create and show listing errors are shown above submit button
            const publishListingFailed = publishListingError ? (
              <p className={css.error}>
                <FormattedMessage id="EditListingPhotosForm.publishListingFailed" />
              </p>
            ) : null;
            const showListingFailed = showListingsError ? (
              <p className={css.error}>
                <FormattedMessage id="EditListingPhotosForm.showListingFailed" />
              </p>
            ) : null;
  
            const submittedOnce = this.submittedImages.length > 0;
            // imgs can contain added images (with temp ids) and submitted images with uniq ids.
            const arrayOfImgIds = imgs =>
              imgs.map(i => (typeof i.id === 'string' ? i.imageId : i.id));
            const imageIdsFromProps = arrayOfImgIds(images);
            const imageIdsFromPreviousSubmit = arrayOfImgIds(this.submittedImages);
            const imageArrayHasSameImages = isEqual(imageIdsFromProps, imageIdsFromPreviousSubmit);
            const pristineSinceLastSubmit = submittedOnce && imageArrayHasSameImages;
  
            const submitReady = (updated && pristineSinceLastSubmit) || ready;
            const submitInProgress = updateInProgress;
            const submitDisabled =
              invalid || disabled || submitInProgress || imageUploadRequested || ready;
  
            const classes = classNames(css.root, className);
  
            const getPhotosByMainType = () => {
              const localImages = images.filter(img => img.imageId);
              const publishImages = images.filter(img => !img.imageId);
  
              if (mainPhotos && mainPhotos.length) {
                const tempLocalMainImage = localImages.filter(img => img.id.split('_')[0] === MAIN_PHOTO_TYPE) || [];
                const lookup = _.keyBy(mainPhotos, main => main);
                const tempPublishMainImage = publishImages.filter(img => lookup.hasOwnProperty(img.id.uuid)) || [];
  
                return [...tempPublishMainImage, ...tempLocalMainImage];
              } else {
                return images.filter(img => img.id.split('_')[0] === MAIN_PHOTO_TYPE) || [];
              }
            }
  
            const getPhotosByOtherType = () => {
              const localImages = images.filter(img => img.imageId);
              const publishImages = images.filter(img => !img.imageId);
  
              if (otherPhotos && otherPhotos.length) {
                const tempLocalOtherImage = localImages.filter(img => img.id.split('_')[0] === OTHER_PHOTO_TYPE) || [];
                const lookup = _.keyBy(otherPhotos, other => other);
                const tempPublishOtherImage = publishImages.filter(img => lookup.hasOwnProperty(img.id.uuid)) || [];
  
                return [...tempPublishOtherImage, ...tempLocalOtherImage];
              } else {
                return images.filter(img => img.id.split('_')[0] === OTHER_PHOTO_TYPE) || [];
              }
            }
  
            return (
              <Form
                className={classes}
                onSubmit={e => {
                  this.submittedImages = images;
                  handleSubmit(e);
                }}
              >
                {updateListingError ? (
                  <p className={css.error}>
                    <FormattedMessage id="EditListingPhotosForm.updateFailed" />
                  </p>
                ) : null}
                <AddImages
                  className={css.imagesField}
                  images={getPhotosByMainType()}
                  thumbnailClassName={css.thumbnail}
                  savedImageAltText={intl.formatMessage({
                    id: 'EditListingPhotosForm.savedImageAltText',
                  })}
                  onRemoveImage={onRemoveImage}
                >
                  <FormSpy subscription={{ values: true }}>
                    {({ values }) => {
                      return getPhotosByMainType().length > 0 && subTitle ? null : (
                        <Field
                          id="addImage"
                          name="addImage"
                          accept={ACCEPT_IMAGES}
                          form={null}
                          label={chooseImageText}
                          type="file"
                          disabled={imageUploadRequested}
                        >
                          {fieldprops => {
                            const { accept, input, label, disabled: fieldDisabled } = fieldprops;
                            const { name, type } = input;
                            const onChange = e => {
                              const file = e.target.files[0];
                              form.change(`addImage`, file);
                              form.blur(`addImage`);
  
                              onImageUploadHandler(file, MAIN_PHOTO_TYPE);
                            };
                            const inputProps = { accept, id: name, name, onChange, type };
                            return (
                              <div className={css.addImageWrapper}>
                                <div className={css.aspectRatioWrapper}>
                                  {fieldDisabled ? null : (
                                    <input {...inputProps} className={css.addImageInput} />
                                  )}
                                  <label htmlFor={name} className={css.addImage}>
                                    {label}
                                  </label>
                                </div>
                              </div>
                            );
                          }}
                        </Field>
                      )
                    }
                    }
                  </FormSpy>
  
                  <Field
                    component={props => {
                      const { input, meta } = props;
                      return (
                        <div className={css.imageRequiredWrapper}>
                          <input {...input} />
                          <ValidationError fieldMeta={meta} />
                        </div>
                      );
                    }}
                    name="images"
                    type="hidden"
                    validate={composeValidators(nonEmptyArray(imageRequiredMessage))}
                  />
                </AddImages>
                {uploadImageFailed}
  
                { subTitle ? (
                  <div>
                    <h1 className={css.title}>{subTitlePanel}</h1>
                    <AddImages
                      className={css.imagesField}
                      images={getPhotosByOtherType()}
                      thumbnailClassName={css.thumbnail}
                      savedImageAltText={intl.formatMessage({
                        id: 'EditListingPhotosForm.savedImageAltText',
                      })}
                      onRemoveImage={onRemoveImage}
                    >
                      <Field
                        id="addSubImage"
                        name="addSubImage"
                        accept={ACCEPT_IMAGES}
                        form={null}
                        label={chooseImageText}
                        type="file"
                        disabled={imageUploadRequested}
                      >
                        {fieldprops => {
                          const { accept, input, label, disabled: fieldDisabled } = fieldprops;
                          const { name, type } = input;
                          const onChange = e => {
                            const file = e.target.files[0];
                            form.change(`addImage`, file);
                            form.blur(`addImage`);
  
                            onImageUploadHandler(file, OTHER_PHOTO_TYPE);
                          };
                          const inputProps = { accept, id: name, name, onChange, type };
                          return (
                            <div className={css.addImageWrapper}>
                              <div className={css.aspectRatioWrapper}>
                                {fieldDisabled ? null : (
                                  <input {...inputProps} className={css.addImageInput} />
                                )}
                                <label htmlFor={name} className={css.addImage}>
                                  {label}
                                </label>
                              </div>
                            </div>
                          );
                        }}
                      </Field>
  
                      <Field
                        component={props => {
                          const { input, meta } = props;
                          return (
                            <div className={css.imageRequiredWrapper}>
                              <input {...input} />
                              <ValidationError fieldMeta={meta} />
                            </div>
                          );
                        }}
                        name="images"
                        type="hidden"
                        validate={composeValidators(nonEmptyArray(imageRequiredMessage))}
                      />
                    </AddImages>
                  </div>
                ) : null}
  
                {publishListingFailed}
                {showListingFailed}
  
                <Button
                  className={css.submitButton}
                  type="submit"
                  inProgress={submitInProgress}
                  disabled={submitDisabled}
                  ready={submitReady}
                >
                  {saveActionMsg}
                </Button>
              </Form>
            );
          }}
        />
      );
    }
  }
  
  EditListingPhotosFormComponent.defaultProps = { fetchErrors: null, images: [] };
  
  EditListingPhotosFormComponent.propTypes = {
    fetchErrors: shape({
      publishListingError: propTypes.error,
      showListingsError: propTypes.error,
      uploadImageError: propTypes.error,
      updateListingError: propTypes.error,
    }),
    images: array,
    intl: intlShape.isRequired,
    onImageUpload: func.isRequired,
    onUpdateImageOrder: func.isRequired,
    onSubmit: func.isRequired,
    saveActionMsg: string.isRequired,
    disabled: bool.isRequired,
    ready: bool.isRequired,
    updated: bool.isRequired,
    updateInProgress: bool.isRequired,
    onRemoveImage: func.isRequired,
  };
  
  export default compose(injectIntl)(EditListingPhotosFormComponent);
  