From 9c1130b5197b46786eccba98f13d73b356fba704 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Mon, 16 Apr 2018 12:24:46 +0300 Subject: [PATCH] Refactor EditListingPhotosForm: use Form connector from Final Form --- .../EditListingPhotosForm.js | 348 +++++++++--------- .../EditListingPhotosForm.test.js.snap | 132 +++---- 2 files changed, 233 insertions(+), 247 deletions(-) diff --git a/src/containers/EditListingPhotosForm/EditListingPhotosForm.js b/src/containers/EditListingPhotosForm/EditListingPhotosForm.js index bd6009dc..49a57d22 100644 --- a/src/containers/EditListingPhotosForm/EditListingPhotosForm.js +++ b/src/containers/EditListingPhotosForm/EditListingPhotosForm.js @@ -1,51 +1,19 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import { bool, func, object, shape, string } from 'prop-types'; import { compose } from 'redux'; -import { Field, reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { Form as FinalForm, Field } from 'react-final-form'; import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; -import { isEqual } from 'lodash'; import { arrayMove } from 'react-sortable-hoc'; import classNames from 'classnames'; import { propTypes } from '../../util/types'; -import { nonEmptyArray } from '../../util/validators'; +import { nonEmptyArray, composeValidators } from '../../util/validators'; import { isUploadListingImageOverLimitError } from '../../util/errors'; -import { Form, AddImages, Button, ValidationError } from '../../components'; +import { AddImages, Button, Form, ValidationError } from '../../components'; import css from './EditListingPhotosForm.css'; const ACCEPT_IMAGES = 'image/*'; -// Add image wrapper. Label is the only visible element, file input is hidden. -const RenderAddImage = props => { - const { accept, input, label, type, disabled } = props; - const { name, onChange } = input; - const inputProps = { accept, id: name, name, onChange, type }; - return ( -
-
- {disabled ? null : } - -
-
- ); -}; - -const { bool, func, node, object, shape, string } = PropTypes; - -RenderAddImage.propTypes = { - accept: string.isRequired, - input: shape({ - value: object, - onChange: func.isRequired, - name: string.isRequired, - }).isRequired, - label: node.isRequired, - type: string.isRequired, - disabled: bool.isRequired, -}; - export class EditListingPhotosFormComponent extends Component { constructor(props) { super(props); @@ -54,14 +22,7 @@ export class EditListingPhotosFormComponent extends Component { this.onSortEnd = this.onSortEnd.bind(this); } - componentWillReceiveProps(nextProps) { - if (!isEqual(this.props.images, nextProps.images)) { - nextProps.change('images', nextProps.images); - } - } - - onImageUploadHandler(event) { - const file = event.target.files[0]; + onImageUploadHandler(file) { if (file) { this.setState({ imageUploadRequested: true }); this.props @@ -81,138 +42,176 @@ export class EditListingPhotosFormComponent extends Component { } render() { - const { - className, - disabled, - errors, - handleSubmit, - images, - intl, - invalid, - saveActionMsg, - submitting, - updated, - ready, - updateError, - updateInProgress, - onRemoveImage, - } = this.props; - - const chooseImageText = ( - - - - - - - - - ); - - const imageRequiredMessage = intl.formatMessage({ id: 'EditListingPhotosForm.imageRequired' }); - - const { createListingsError, showListingsError, uploadImageError } = errors; - const uploadOverLimit = isUploadListingImageOverLimitError(uploadImageError); - - let uploadImageFailed = null; - - if (uploadOverLimit) { - uploadImageFailed = ( -

- -

- ); - } else if (uploadImageError) { - uploadImageFailed = ( -

- -

- ); - } - - // 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 createListingFailed = createListingsError ? ( -

- -

- ) : null; - const showListingFailed = showListingsError ? ( -

- -

- ) : null; - - // Updating listing (edit mode) failed - const errorMessage = updateError ? ( -

- -

- ) : null; - - const classes = classNames(css.root, className); - - const submitReady = updated || ready; - const submitInProgress = submitting || updateInProgress; - const submitDisabled = - invalid || disabled || submitInProgress || this.state.imageUploadRequested || ready; - return ( -
- {errorMessage} - - + { + const { + blur, + change, + className, + disabled, + errors, + handleSubmit, + images, + imageUploadRequested, + intl, + invalid, + onImageUploadHandler, + onRemoveImage, + ready, + saveActionMsg, + submitting, + updated, + updateError, + updateInProgress, + } = fieldRenderProps; - { - const { input, type, meta } = props; - return ( -
- - -
- ); - }} - name="images" - type="hidden" - validate={[nonEmptyArray(imageRequiredMessage)]} - /> -
- {uploadImageFailed} + const chooseImageText = ( + + + + + + + + + ); -

- -

- {createListingFailed} - {showListingFailed} + const imageRequiredMessage = intl.formatMessage({ + id: 'EditListingPhotosForm.imageRequired', + }); - -
+ const { createListingsError, showListingsError, uploadImageError } = errors; + const uploadOverLimit = isUploadListingImageOverLimitError(uploadImageError); + + let uploadImageFailed = null; + + if (uploadOverLimit) { + uploadImageFailed = ( +

+ +

+ ); + } else if (uploadImageError) { + uploadImageFailed = ( +

+ +

+ ); + } + + // 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 createListingFailed = createListingsError ? ( +

+ +

+ ) : null; + const showListingFailed = showListingsError ? ( +

+ +

+ ) : null; + + const submitReady = updated || ready; + const submitInProgress = submitting || updateInProgress; + const submitDisabled = + invalid || disabled || submitInProgress || imageUploadRequested || ready; + + const classes = classNames(css.root, className); + + return ( +
+ {updateError ? ( +

+ +

+ ) : null} + + + {fieldprops => { + const { accept, input, label, type, disabled } = fieldprops; + const { name } = input; + const onChange = e => { + const file = e.target.files[0]; + change(`addImage`, file); + blur(`addImage`); + onImageUploadHandler(file); + }; + const inputProps = { accept, id: name, name, onChange, type }; + return ( +
+
+ {disabled ? null : ( + + )} + +
+
+ ); + }} +
+ + { + const { input, type, meta } = props; + return ( +
+ + +
+ ); + }} + name="images" + type="hidden" + validate={composeValidators(nonEmptyArray(imageRequiredMessage))} + /> +
+ {uploadImageFailed} + +

+ +

+ {createListingFailed} + {showListingFailed} + + +
+ ); + }} + /> ); } } @@ -220,7 +219,6 @@ export class EditListingPhotosFormComponent extends Component { EditListingPhotosFormComponent.defaultProps = { errors: {}, updateError: null }; EditListingPhotosFormComponent.propTypes = { - ...formPropTypes, errors: shape({ createListingsError: object, showListingsError: object, @@ -238,6 +236,4 @@ EditListingPhotosFormComponent.propTypes = { onRemoveImage: func.isRequired, }; -const formName = 'EditListingPhotosForm'; - -export default compose(reduxForm({ form: formName }), injectIntl)(EditListingPhotosFormComponent); +export default compose(injectIntl)(EditListingPhotosFormComponent); diff --git a/src/containers/EditListingPhotosForm/__snapshots__/EditListingPhotosForm.test.js.snap b/src/containers/EditListingPhotosForm/__snapshots__/EditListingPhotosForm.test.js.snap index 2f1f5ed6..33a2f361 100644 --- a/src/containers/EditListingPhotosForm/__snapshots__/EditListingPhotosForm.test.js.snap +++ b/src/containers/EditListingPhotosForm/__snapshots__/EditListingPhotosForm.test.js.snap @@ -1,76 +1,66 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`EditListingPhotosForm matches snapshot 1`] = ` -
- - - - - - - - - - } - name="addImage" - onChange={[Function]} - type="file" - /> - - -

- -

- -
+ onUpdateImageOrder={[Function]} + pristine={true} + pure={true} + ready={false} + render={[Function]} + reset={[Function]} + resetSection={[Function]} + saveActionMsg="Save photos" + stripeConnected={false} + submit={[Function]} + submitFailed={false} + submitSucceeded={false} + submitting={false} + touch={[Function]} + untouch={[Function]} + updateError={null} + updateInProgress={false} + updated={false} + valid={true} +/> `;