From 3d172412f3420bd003c8a2cdbef5cd6a8bbd825e Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 18 May 2018 17:04:55 +0300 Subject: [PATCH 01/14] Migrate EmailVerificationForm to Final Form --- .../EmailVerificationForm.js | 162 +++++++++--------- 1 file changed, 80 insertions(+), 82 deletions(-) diff --git a/src/forms/EmailVerificationForm/EmailVerificationForm.js b/src/forms/EmailVerificationForm/EmailVerificationForm.js index 0048d3e3ef..8e5bad8d94 100644 --- a/src/forms/EmailVerificationForm/EmailVerificationForm.js +++ b/src/forms/EmailVerificationForm/EmailVerificationForm.js @@ -1,8 +1,8 @@ import React from 'react'; -import PropTypes from 'prop-types'; +import { bool } from 'prop-types'; import { compose } from 'redux'; import { FormattedMessage, injectIntl } from 'react-intl'; -import { reduxForm, Field, propTypes as formPropTypes } from 'redux-form'; +import { Form as FinalForm, Field } from 'react-final-form'; import { Form, NamedLink, @@ -14,79 +14,84 @@ import { propTypes } from '../../util/types'; import css from './EmailVerificationForm.css'; -const EmailVerificationFormComponent = props => { - const { currentUser, inProgress, handleSubmit, verificationError } = props; - - const { email, emailVerified, pendingEmail, profile } = currentUser.attributes; - const emailToVerify = {pendingEmail || email}; - const name = profile.firstName; - - const errorMessage = ( -
- -
- ); - - const submitInProgress = inProgress; - const submitDisabled = submitInProgress; - - const verifyEmail = ( -
-
- -

- -

- -

- -

- - {verificationError ? errorMessage : null} -
- -
- - -
- - {inProgress ? ( - - ) : ( - - )} - +const EmailVerificationFormComponent = props => ( + { + const { currentUser, inProgress, handleSubmit, verificationError } = fieldRenderProps; + + const { email, emailVerified, pendingEmail, profile } = currentUser.attributes; + const emailToVerify = {pendingEmail || email}; + const name = profile.firstName; + + const errorMessage = ( +
+
- -
- ); - - const alreadyVerified = ( -
-
- -

- -

- -

- -

-
- -
- - - -
-
- ); - - return emailVerified && !pendingEmail ? alreadyVerified : verifyEmail; -}; + ); + + const submitInProgress = inProgress; + const submitDisabled = submitInProgress; + + const verifyEmail = ( +
+
+ +

+ +

+ +

+ +

+ + {verificationError ? errorMessage : null} +
+ +
+ + +
+ + {inProgress ? ( + + ) : ( + + )} + +
+ +
+ ); + + const alreadyVerified = ( +
+
+ +

+ +

+ +

+ +

+
+ +
+ + + +
+
+ ); + + return emailVerified && !pendingEmail ? alreadyVerified : verifyEmail; + }} + /> +); EmailVerificationFormComponent.defaultProps = { currentUser: null, @@ -94,19 +99,12 @@ EmailVerificationFormComponent.defaultProps = { verificationError: null, }; -const { bool } = PropTypes; - EmailVerificationFormComponent.propTypes = { - ...formPropTypes, inProgress: bool, currentUser: propTypes.currentUser.isRequired, verificationError: propTypes.error, }; -const defaultFormName = 'EmailVerificationForm'; - -const EmailVerificationForm = compose(reduxForm({ form: defaultFormName }), injectIntl)( - EmailVerificationFormComponent -); +const EmailVerificationForm = compose(injectIntl)(EmailVerificationFormComponent); export default EmailVerificationForm; From 2a305cf4568357a7a3dd458174911a095f807da3 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Mon, 21 May 2018 17:27:09 +0300 Subject: [PATCH 02/14] Migrate SendMessageForm to Final Form --- .../TransactionPanel/TransactionPanel.js | 7 +- .../TransactionPage/TransactionPage.js | 5 - .../TransactionPage.test.js.snap | 2 - .../SendMessageForm.example.js | 9 +- src/forms/SendMessageForm/SendMessageForm.js | 111 +++++++++--------- 5 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/components/TransactionPanel/TransactionPanel.js b/src/components/TransactionPanel/TransactionPanel.js index 86e5756c7b..89fefc72c1 100644 --- a/src/components/TransactionPanel/TransactionPanel.js +++ b/src/components/TransactionPanel/TransactionPanel.js @@ -73,9 +73,9 @@ export class TransactionPanelComponent extends Component { this.setState({ sendMessageFormFocused: false }); } - onMessageSubmit(values) { + onMessageSubmit(values, form) { const message = values.message ? values.message.trim() : null; - const { transaction, onResetForm, onSendMessage } = this.props; + const { transaction, onSendMessage } = this.props; const ensuredTransaction = ensureTransaction(transaction); if (!message) { @@ -83,7 +83,7 @@ export class TransactionPanelComponent extends Component { } onSendMessage(ensuredTransaction.id, message) .then(messageId => { - onResetForm(this.sendMessageFormName); + form.reset(); this.scrollToMessage(messageId); }) .catch(e => { @@ -387,7 +387,6 @@ TransactionPanelComponent.propTypes = { onShowMoreMessages: func.isRequired, onSendMessage: func.isRequired, onSendReview: func.isRequired, - onResetForm: func.isRequired, // Sale related props onAcceptSale: func.isRequired, diff --git a/src/containers/TransactionPage/TransactionPage.js b/src/containers/TransactionPage/TransactionPage.js index b3014723a2..02cc4a4fd6 100644 --- a/src/containers/TransactionPage/TransactionPage.js +++ b/src/containers/TransactionPage/TransactionPage.js @@ -4,7 +4,6 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import classNames from 'classnames'; import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; -import { reset as resetForm } from 'redux-form'; import { propTypes } from '../../util/types'; import { ensureListing, ensureTransaction } from '../../util/data'; import { getMarketplaceEntities } from '../../ducks/marketplaceData.duck'; @@ -48,7 +47,6 @@ export const TransactionPageComponent = props => { intl, messages, onManageDisableScrolling, - onResetForm, onSendMessage, onSendReview, onShowMoreMessages, @@ -153,7 +151,6 @@ export const TransactionPageComponent = props => { onShowMoreMessages={onShowMoreMessages} onSendMessage={onSendMessage} onSendReview={onSendReview} - onResetForm={onResetForm} transactionRole={transactionRole} onAcceptSale={onAcceptSale} onDeclineSale={onDeclineSale} @@ -221,7 +218,6 @@ TransactionPageComponent.propTypes = { sendMessageError: propTypes.error, onShowMoreMessages: func.isRequired, onSendMessage: func.isRequired, - onResetForm: func.isRequired, // from injectIntl intl: intlShape.isRequired, @@ -279,7 +275,6 @@ const mapDispatchToProps = dispatch => { onDeclineSale: transactionId => dispatch(declineSale(transactionId)), onShowMoreMessages: txId => dispatch(fetchMoreMessages(txId)), onSendMessage: (txId, message) => dispatch(sendMessage(txId, message)), - onResetForm: formName => dispatch(resetForm(formName)), onManageDisableScrolling: (componentId, disableScrolling) => dispatch(manageDisableScrolling(componentId, disableScrolling)), onSendReview: (role, tx, reviewRating, reviewContent) => diff --git a/src/containers/TransactionPage/__snapshots__/TransactionPage.test.js.snap b/src/containers/TransactionPage/__snapshots__/TransactionPage.test.js.snap index 8c2fb326fe..c969f6a5c1 100644 --- a/src/containers/TransactionPage/__snapshots__/TransactionPage.test.js.snap +++ b/src/containers/TransactionPage/__snapshots__/TransactionPage.test.js.snap @@ -53,7 +53,6 @@ exports[`TransactionPage - Order matches snapshot 1`] = ` oldestMessagePageFetched={0} onAcceptSale={[Function]} onDeclineSale={[Function]} - onResetForm={[Function]} onSendMessage={[Function]} onShowMoreMessages={[Function]} sendMessageError={null} @@ -250,7 +249,6 @@ exports[`TransactionPage - Sale matches snapshot 1`] = ` oldestMessagePageFetched={0} onAcceptSale={[Function]} onDeclineSale={[Function]} - onResetForm={[Function]} onSendMessage={[Function]} onShowMoreMessages={[Function]} sendMessageError={null} diff --git a/src/forms/SendMessageForm/SendMessageForm.example.js b/src/forms/SendMessageForm/SendMessageForm.example.js index e1a8cb798a..dc97878519 100644 --- a/src/forms/SendMessageForm/SendMessageForm.example.js +++ b/src/forms/SendMessageForm/SendMessageForm.example.js @@ -3,7 +3,6 @@ import SendMessageForm from './SendMessageForm'; export const Empty = { component: SendMessageForm, props: { - form: 'Styleguide_SendMessageForm_Empty', messagePlaceholder: 'Send message to Juho…', onChange: values => { console.log('values changed to:', values); @@ -24,9 +23,11 @@ export const Empty = { export const InProgress = { component: SendMessageForm, props: { - form: 'Styleguide_SendMessageForm_InProgress', messagePlaceholder: 'Send message to Juho…', inProgress: true, + onSubmit: values => { + console.log('submit values:', values); + }, }, group: 'forms', }; @@ -34,9 +35,11 @@ export const InProgress = { export const Error = { component: SendMessageForm, props: { - form: 'Styleguide_SendMessageForm_Error', messagePlaceholder: 'Send message to Juho…', sendMessageError: { type: 'error', name: 'ExampleError' }, + onSubmit: values => { + console.log('submit values:', values); + }, }, group: 'forms', }; diff --git a/src/forms/SendMessageForm/SendMessageForm.js b/src/forms/SendMessageForm/SendMessageForm.js index 71146dd6bb..a86e7ec66d 100644 --- a/src/forms/SendMessageForm/SendMessageForm.js +++ b/src/forms/SendMessageForm/SendMessageForm.js @@ -2,9 +2,9 @@ import React, { Component } from 'react'; import { string, bool, func } from 'prop-types'; import { compose } from 'redux'; import { FormattedMessage, injectIntl, intlShape } from 'react-intl'; -import { reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { Form as FinalForm } from 'react-final-form'; import classNames from 'classnames'; -import { Form, TextInputField, SecondaryButton } from '../../components'; +import { Form, FieldTextInput, SecondaryButton } from '../../components'; import { propTypes } from '../../util/types'; import css from './SendMessageForm.css'; @@ -36,10 +36,12 @@ class SendMessageFormComponent extends Component { this.handleBlur = this.handleBlur.bind(this); this.blurTimeoutId = null; } + handleFocus() { this.props.onFocus(); window.clearTimeout(this.blurTimeoutId); } + handleBlur() { // We only trigger a blur if another focus event doesn't come // within a timeout. This enables keeping the focus synced when @@ -49,53 +51,60 @@ class SendMessageFormComponent extends Component { this.props.onBlur(); }, BLUR_TIMEOUT_MS); } - render() { - const { - rootClassName, - className, - messagePlaceholder, - form, - handleSubmit, - inProgress, - sendMessageError, - invalid, - } = this.props; - - const classes = classNames(rootClassName || css.root, className); - const submitInProgress = inProgress; - const submitDisabled = invalid || submitInProgress; + render() { return ( -
- -
-
- {sendMessageError ? ( -

- -

- ) : null} -
- - - - -
- + { + const { + rootClassName, + className, + messagePlaceholder, + handleSubmit, + inProgress, + sendMessageError, + invalid, + form, + } = fieldRenderProps; + + const classes = classNames(rootClassName || css.root, className); + const submitInProgress = inProgress; + const submitDisabled = invalid || submitInProgress; + return ( +
handleSubmit(values, form)}> + +
+
+ {sendMessageError ? ( +

+ +

+ ) : null} +
+ + + + +
+ + ); + }} + /> ); } } @@ -111,12 +120,12 @@ SendMessageFormComponent.defaultProps = { }; SendMessageFormComponent.propTypes = { - ...formPropTypes, rootClassName: string, className: string, inProgress: bool, messagePlaceholder: string, + onSubmit: func.isRequired, onFocus: func, onBlur: func, sendMessageError: propTypes.error, @@ -125,11 +134,7 @@ SendMessageFormComponent.propTypes = { intl: intlShape.isRequired, }; -const defaultFormName = 'SendMessageForm'; - -const SendMessageForm = compose(reduxForm({ form: defaultFormName }), injectIntl)( - SendMessageFormComponent -); +const SendMessageForm = compose(injectIntl)(SendMessageFormComponent); SendMessageForm.displayName = 'SendMessageForm'; From 7ab64c7df7290a3d6d1fcc11bb489425b18a1bad Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Tue, 22 May 2018 13:50:46 +0300 Subject: [PATCH 03/14] Migrate LocationAutocompleteInput example --- .../LocationAutocompleteInput.example.js | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.example.js b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.example.js index 01f9a53a92..183dd688ba 100644 --- a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.example.js +++ b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.example.js @@ -1,30 +1,28 @@ import React, { Component } from 'react'; -import { Field, reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { Form as FinalForm, Field } from 'react-final-form'; import { propTypes } from '../../util/types'; import { Button } from '../../components'; import LocationAutocompleteInput from './LocationAutocompleteInput'; -const FormComponent = props => { - const { handleSubmit, pristine, submitting } = props; +const Form = props => { return ( -
- - - - + { + return ( +
+ + + + + ); + }} + /> ); }; -FormComponent.propTypes = formPropTypes; - -const defaultFormName = 'Styleguide.LocationAutocompleteInput.Form'; - -const Form = reduxForm({ - form: defaultFormName, -})(FormComponent); - const PlaceInfo = props => { const { place } = props; const { address, country, origin, bounds } = place; From e90d7d2add341ec25f1b3174f4247404e1667bcb Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Tue, 22 May 2018 15:52:06 +0300 Subject: [PATCH 04/14] Migrate TopbarSearchForm --- .../LocationAutocompleteInput.js | 17 ++-- .../TopbarSearchForm/TopbarSearchForm.js | 83 +++++++++++-------- 2 files changed, 59 insertions(+), 41 deletions(-) diff --git a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js index 78c2d54cfe..ccec79b2e4 100644 --- a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js +++ b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import { any, arrayOf, bool, func, number, object, shape, string, oneOfType } from 'prop-types'; import { Field } from 'react-final-form'; import debounce from 'lodash/debounce'; import classNames from 'classnames'; @@ -93,8 +93,6 @@ const LocationPredictionsList = props => { ); }; -const { any, arrayOf, bool, func, number, object, shape, string } = PropTypes; - LocationPredictionsList.defaultProps = { rootClassName: null, className: null, @@ -475,11 +473,14 @@ LocationAutocompleteInput.propTypes = { placeholder: string, input: shape({ name: string.isRequired, - value: shape({ - search: string, - predictions: any, - selectedPlace: propTypes.place, - }), + value: oneOfType([ + shape({ + search: string, + predictions: any, + selectedPlace: propTypes.place, + }), + string, + ]), onChange: func.isRequired, onFocus: func.isRequired, onBlur: func.isRequired, diff --git a/src/forms/TopbarSearchForm/TopbarSearchForm.js b/src/forms/TopbarSearchForm/TopbarSearchForm.js index 2127ff82d0..5a95cf3522 100644 --- a/src/forms/TopbarSearchForm/TopbarSearchForm.js +++ b/src/forms/TopbarSearchForm/TopbarSearchForm.js @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import PropTypes 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 { intlShape, injectIntl } from 'react-intl'; import classNames from 'classnames'; import { Form, LocationAutocompleteInput } from '../../components'; @@ -30,33 +29,57 @@ class TopbarSearchFormComponent extends Component { } render() { - const { rootClassName, className, desktopInputRoot, intl, isMobile } = this.props; + return ( + { + const classes = classNames(rootClassName, className); + const desktopInputRootClass = desktopInputRoot || css.desktopInputRoot; - const classes = classNames(rootClassName, className); - const desktopInputRootClass = desktopInputRoot || css.desktopInputRoot; + // Allow form submit only when the place has changed + const preventFormSubmit = e => e.preventDefault(); - // Allow form submit only when the place has changed - const preventFormSubmit = e => e.preventDefault(); + return ( +
+ { + const { onChange, ...restInput } = input; - return ( - - { - this.searchInput = node; - }} - /> - + // Merge the standard onChange function with custom behaviur. A better solution would + // be to use the FormSpy component from Final Form and pass this.onChange to the + // onChange prop but that breaks due to insufficient subscription handling. + // See: https://github.com/final-form/react-final-form/issues/159 + const searchOnChange = value => { + onChange(value); + this.onChange(value); + }; + + const searchInput = { ...restInput, onChange: searchOnChange }; + return ( + { + this.searchInput = node; + }} + input={searchInput} + meta={meta} + /> + ); + }} + /> + + ); + }} + /> ); } } @@ -71,8 +94,6 @@ TopbarSearchFormComponent.defaultProps = { }; TopbarSearchFormComponent.propTypes = { - ...formPropTypes, - rootClassName: string, className: string, desktopInputRoot: string, @@ -83,10 +104,6 @@ TopbarSearchFormComponent.propTypes = { intl: intlShape.isRequired, }; -const defaultFormName = 'TopbarSearchForm'; - -const TopbarSearchForm = compose(reduxForm({ form: defaultFormName }), injectIntl)( - TopbarSearchFormComponent -); +const TopbarSearchForm = injectIntl(TopbarSearchFormComponent); export default TopbarSearchForm; From c5b08ab737f50d77409c802fddf6958aecb6b668 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Wed, 23 May 2018 11:45:09 +0300 Subject: [PATCH 05/14] Migrate LocationSearchForm to Final Form --- .../__snapshots__/NotFoundPage.test.js.snap | 2 +- .../LocationSearchForm/LocationSearchForm.js | 79 +++++++++++-------- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/containers/NotFoundPage/__snapshots__/NotFoundPage.test.js.snap b/src/containers/NotFoundPage/__snapshots__/NotFoundPage.test.js.snap index 764c0e66fc..7e38d3ebb0 100644 --- a/src/containers/NotFoundPage/__snapshots__/NotFoundPage.test.js.snap +++ b/src/containers/NotFoundPage/__snapshots__/NotFoundPage.test.js.snap @@ -36,7 +36,7 @@ exports[`NotFoundPageComponent matches snapshot 1`] = ` values={Object {}} />

-
diff --git a/src/forms/LocationSearchForm/LocationSearchForm.js b/src/forms/LocationSearchForm/LocationSearchForm.js index b703168556..6cb6567082 100644 --- a/src/forms/LocationSearchForm/LocationSearchForm.js +++ b/src/forms/LocationSearchForm/LocationSearchForm.js @@ -1,7 +1,6 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { compose } from 'redux'; -import { Field, reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { func, string } from 'prop-types'; +import { Form as FinalForm, Field } from 'react-final-form'; import { intlShape, injectIntl } from 'react-intl'; import classNames from 'classnames'; import { Form, LocationAutocompleteInput } from '../../components'; @@ -9,47 +8,65 @@ import { Form, LocationAutocompleteInput } from '../../components'; import css from './LocationSearchForm.css'; const LocationSearchFormComponent = props => { - const { rootClassName, className, intl, onSubmit } = props; - - const onChange = location => { + const handleChange = location => { if (location.selectedPlace) { // Note that we use `onSubmit` instead of the conventional // `handleSubmit` prop for submitting. We want to autosubmit // when a place is selected, and don't require any extra // validations for the form. - onSubmit({ location }); + props.onSubmit({ location }); } }; - const classes = classNames(rootClassName || css.root, className); + return ( + { + const classes = classNames(rootClassName || css.root, className); + + // Allow form submit only when the place has changed + const preventFormSubmit = e => e.preventDefault(); - // Allow form submit only when the place has changed - const preventFormSubmit = e => e.preventDefault(); + return ( +
+ { + const { onChange, ...restInput } = input; - return ( - - - + // Merge the standard onChange function with custom behaviur. A better solution would + // be to use the FormSpy component from Final Form and pass this.onChange to the + // onChange prop but that breaks due to insufficient subscription handling. + // See: https://github.com/final-form/react-final-form/issues/159 + const searchOnChange = value => { + onChange(value); + handleChange(value); + }; + + const searchInput = { ...restInput, onChange: searchOnChange }; + return ( + + ); + }} + /> + + ); + }} + /> ); }; -const { func, string } = PropTypes; - LocationSearchFormComponent.defaultProps = { rootClassName: null, className: null }; LocationSearchFormComponent.propTypes = { - ...formPropTypes, - rootClassName: string, className: string, onSubmit: func.isRequired, @@ -58,10 +75,6 @@ LocationSearchFormComponent.propTypes = { intl: intlShape.isRequired, }; -const defaultFormName = 'TopbarSearchForm'; - -const LocationSearchForm = compose(reduxForm({ form: defaultFormName }), injectIntl)( - LocationSearchFormComponent -); +const LocationSearchForm = injectIntl(LocationSearchFormComponent); export default LocationSearchForm; From 5321c9e454c03b1f8195b11eb48370cfffdd1cad Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 31 May 2018 16:48:18 +0300 Subject: [PATCH 06/14] Migrate SelectMultipleFilterPlainForm --- .../FieldGroupCheckbox/FieldCheckbox.js | 4 +- src/components/PropertyGroup/PropertyGroup.js | 2 +- .../SelectMultipleFilterPlain.example.js | 1 + .../SelectMultipleFilterPlain.js | 8 ++- .../SelectMultipleFilterPlainForm.js | 50 ++++++++++++------- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/components/FieldGroupCheckbox/FieldCheckbox.js b/src/components/FieldGroupCheckbox/FieldCheckbox.js index 13a94036ed..cad10ef69b 100644 --- a/src/components/FieldGroupCheckbox/FieldCheckbox.js +++ b/src/components/FieldGroupCheckbox/FieldCheckbox.js @@ -1,7 +1,7 @@ import React from 'react'; import { any, node, string, object, shape } from 'prop-types'; import classNames from 'classnames'; -import { Field } from 'redux-form'; +import { Field } from 'react-final-form'; import { ValidationError } from '../../components'; import css from './FieldCheckbox.css'; @@ -79,7 +79,7 @@ FieldCheckboxComponent.propTypes = { id: string.isRequired, label: node, - // redux-form Field params + // FieldRenderProps input: shape({ value: any }).isRequired, meta: object.isRequired, }; diff --git a/src/components/PropertyGroup/PropertyGroup.js b/src/components/PropertyGroup/PropertyGroup.js index 0c5356351a..15bb254296 100644 --- a/src/components/PropertyGroup/PropertyGroup.js +++ b/src/components/PropertyGroup/PropertyGroup.js @@ -2,7 +2,7 @@ * Renders a set of options with selected and non-selected values. * * The corresponding component when selecting the values is - * FieldGroupCheckbox. + * FieldCheckboxGroup. * */ diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.example.js b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.example.js index 986e843387..d96a6cdc45 100644 --- a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.example.js +++ b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.example.js @@ -41,6 +41,7 @@ const options = [ ]; const handleSelect = (urlParam, values, history) => { + console.log(`handle select`, values); const queryParams = values ? `?${stringify({ [urlParam]: values.join(',') })}` : ''; history.push(`${window.location.pathname}${queryParams}`); }; diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js index 1e4a47c3ab..25ba8c44b8 100644 --- a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js +++ b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js @@ -4,7 +4,6 @@ import classNames from 'classnames'; import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; import SelectMultipleFilterPlainForm from './SelectMultipleFilterPlainForm'; -import { arrayToFormValues, formValuesToArray } from '../../util/data'; import css from './SelectMultipleFilterPlain.css'; @@ -20,8 +19,8 @@ class SelectMultipleFilterPlainComponent extends Component { handleSelect(values) { const { urlParam, name, onSelect } = this.props; - const selectedKeys = formValuesToArray(values[name]); - onSelect(urlParam, selectedKeys); + const paramValues = values[name]; + onSelect(urlParam, paramValues); } handleClear() { @@ -64,8 +63,7 @@ class SelectMultipleFilterPlainComponent extends Component { [css.columnLayout]: twoColumns, }); - const initialValuesObj = arrayToFormValues(initialValues); - const namedInitialValues = { [name]: initialValuesObj }; + const namedInitialValues = { [name]: initialValues }; return (
diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js index f2775bbb61..6be5a3baf7 100644 --- a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js +++ b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js @@ -1,31 +1,46 @@ import React from 'react'; -import { arrayOf, bool, node, shape, string } from 'prop-types'; -import { reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { arrayOf, bool, node, shape, string, func } from 'prop-types'; +import { Form as FinalForm, FormSpy } from 'react-final-form'; +import arrayMutators from 'final-form-arrays'; -import { FieldGroupCheckbox, Form } from '../../components'; +import { FieldCheckboxGroup, Form } from '../../components'; -const SelectMultipleFilterPlainFormComponent = props => { - const { form, className, name, options, twoColumns } = props; +const SelectMultipleFilterPlainForm = props => { + const { onChange, ...rest } = props; + + const handleChange = formState => { + if (formState.dirty) { + onChange(formState.values); + } + } return ( -
- - + console.log('SelectMultipleFilterPlainForm', vals)} + render={({ className, name, options, twoColumns, onChange }) => +
+ + + + } + /> ); }; -SelectMultipleFilterPlainFormComponent.defaultProps = { +SelectMultipleFilterPlainForm.defaultProps = { className: null, twoColumns: false, + onChange: () => null, }; -SelectMultipleFilterPlainFormComponent.propTypes = { - ...formPropTypes, +SelectMultipleFilterPlainForm.propTypes = { className: string, name: string.isRequired, options: arrayOf( @@ -35,8 +50,7 @@ SelectMultipleFilterPlainFormComponent.propTypes = { }) ).isRequired, twoColumns: bool, + onChange: func, }; -const SelectMultipleFilterPlainForm = reduxForm({})(SelectMultipleFilterPlainFormComponent); - export default SelectMultipleFilterPlainForm; From 0fe23cc60bc55e854b98f61f4fe0e8be6e3e3659 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 31 May 2018 16:51:41 +0300 Subject: [PATCH 07/14] Migrate SelectMultipleFilterForm --- .../SelectMultipleFilter.js | 11 +- .../SelectMultipleFilterForm.js | 117 +++++++++--------- .../SelectMultipleFilterPlainForm.js | 8 +- 3 files changed, 66 insertions(+), 70 deletions(-) diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js index 85934121ff..ae80055e0c 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.js +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -3,7 +3,6 @@ import { array, arrayOf, func, number, string } from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape } from 'react-intl'; -import { arrayToFormValues, formValuesToArray } from '../../util/data'; import SelectMultipleFilterForm from './SelectMultipleFilterForm'; import css from './SelectMultipleFilter.css'; @@ -28,9 +27,9 @@ class SelectMultipleFilter extends Component { handleSubmit(values) { const { name, onSelect, urlParam } = this.props; - const selectedKeys = formValuesToArray(values[name]); + const paramValues = values[name]; this.setState({ isOpen: false }); - onSelect(urlParam, selectedKeys); + onSelect(urlParam, paramValues); } handleClear() { @@ -107,13 +106,9 @@ class SelectMultipleFilter extends Component { const contentStyle = this.positionStyleForContent(); - // turn a list of values into a map that can be passed to - // a redux form - const initialValuesObj = arrayToFormValues(initialValues); - // pass the initial values with the name key so that // they can be passed to the correct field - const namedInitialValues = { [name]: initialValuesObj }; + const namedInitialValues = { [name]: initialValues }; return (
{ - const { - form, - destroy, - reset, - handleSubmit, - name, - onClear, - onCancel, - options, - isOpen, - contentRef, - style, - intl, - } = props; - const classes = classNames(css.root, { [css.isOpen]: isOpen }); - - const handleClear = () => { - // clear the redux form state - destroy(); - onClear(); - }; - - const handleCancel = () => { - // reset the redux form to initialValues - reset(); - onCancel(); - }; + return ( + { + const { + form, + handleSubmit, + name, + onClear, + onCancel, + options, + isOpen, + contentRef, + style, + intl, + } = formProps; + const classes = classNames(css.root, { [css.isOpen]: isOpen }); - const clear = intl.formatMessage({ id: 'SelectMultipleFilterForm.clear' }); - const cancel = intl.formatMessage({ id: 'SelectMultipleFilterForm.cancel' }); - const submit = intl.formatMessage({ id: 'SelectMultipleFilterForm.submit' }); + const handleCancel = () => { + // reset the final form to initialValues + form.reset(); + onCancel(); + }; - return ( -
- -
- - - -
- + const clear = intl.formatMessage({ id: 'SelectMultipleFilterForm.clear' }); + const cancel = intl.formatMessage({ id: 'SelectMultipleFilterForm.cancel' }); + const submit = intl.formatMessage({ id: 'SelectMultipleFilterForm.submit' }); + return ( +
+ +
+ + + +
+ + ); + }} + /> ); }; @@ -71,7 +75,6 @@ SelectMultipleFilterFormComponent.defaultProps = { }; SelectMultipleFilterFormComponent.propTypes = { - ...formPropTypes, name: string.isRequired, onClear: func.isRequired, onCancel: func.isRequired, @@ -89,8 +92,6 @@ SelectMultipleFilterFormComponent.propTypes = { intl: intlShape.isRequired, }; -const SelectMultipleFilterForm = compose(reduxForm({}), injectIntl)( - SelectMultipleFilterFormComponent -); +const SelectMultipleFilterForm = injectIntl(SelectMultipleFilterFormComponent); export default SelectMultipleFilterForm; diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js index 6be5a3baf7..81e22c302f 100644 --- a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js +++ b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js @@ -12,16 +12,16 @@ const SelectMultipleFilterPlainForm = props => { if (formState.dirty) { onChange(formState.values); } - } + }; return ( console.log('SelectMultipleFilterPlainForm', vals)} - render={({ className, name, options, twoColumns, onChange }) => + render={({ className, name, options, twoColumns, onChange }) => (
- + { twoColumns={twoColumns} /> - } + )} /> ); }; From 2cf223fbe83bd6c5b1f2b91795834e88bb93e146 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 31 May 2018 17:05:30 +0300 Subject: [PATCH 08/14] Remove unused code --- .../FieldGroupCheckbox/FieldCheckbox.css | 68 ---------- .../FieldGroupCheckbox/FieldCheckbox.js | 91 -------------- .../FieldGroupCheckbox/FieldGroupCheckbox.css | 28 ----- .../FieldGroupCheckbox.example.js | 108 ---------------- .../FieldGroupCheckbox/FieldGroupCheckbox.js | 92 -------------- src/components/SelectField/SelectField.css | 18 --- .../SelectField/SelectField.example.js | 47 ------- src/components/SelectField/SelectField.js | 72 ----------- .../TextInputField/TextInputField.css | 19 --- .../TextInputField/TextInputField.example.css | 7 -- .../TextInputField/TextInputField.example.js | 81 ------------ .../TextInputField/TextInputField.js | 117 ------------------ src/components/index.js | 3 - src/ducks/index.js | 2 - src/examples.js | 6 - src/util/data.js | 37 ------ src/util/data.test.js | 34 ----- 17 files changed, 830 deletions(-) delete mode 100644 src/components/FieldGroupCheckbox/FieldCheckbox.css delete mode 100644 src/components/FieldGroupCheckbox/FieldCheckbox.js delete mode 100644 src/components/FieldGroupCheckbox/FieldGroupCheckbox.css delete mode 100644 src/components/FieldGroupCheckbox/FieldGroupCheckbox.example.js delete mode 100644 src/components/FieldGroupCheckbox/FieldGroupCheckbox.js delete mode 100644 src/components/SelectField/SelectField.css delete mode 100644 src/components/SelectField/SelectField.example.js delete mode 100644 src/components/SelectField/SelectField.js delete mode 100644 src/components/TextInputField/TextInputField.css delete mode 100644 src/components/TextInputField/TextInputField.example.css delete mode 100644 src/components/TextInputField/TextInputField.example.js delete mode 100644 src/components/TextInputField/TextInputField.js diff --git a/src/components/FieldGroupCheckbox/FieldCheckbox.css b/src/components/FieldGroupCheckbox/FieldCheckbox.css deleted file mode 100644 index a295dbf02c..0000000000 --- a/src/components/FieldGroupCheckbox/FieldCheckbox.css +++ /dev/null @@ -1,68 +0,0 @@ -@import '../../marketplace.css'; - -.root { - position: relative; -} - -.input { - position: absolute; - opacity: 0; - height: 0; - width: 0; - - /* Highlight the borders if the checkbox is hovered, focused or checked */ - &:hover + label .box, - &:focus + label .box, - &:checked + label .box { - stroke: var(--marketplaceColor); - } - - /* Display the "check" when checked */ - &:checked + label .checked { - display: inline; - stroke: var(--marketplaceColor); - stroke-width: 1px; - } - - /* Hightlight the text on checked, hover and focus */ - &:focus + label .text, - &:hover + label .text, - &:checked + label .text { - color: var(--matterColorDark); - } -} - -.label { - display: flex; - align-items: center; - padding: 0; -} - -.checkboxWrapper { - /* This should follow line-height */ - height: 32px; - margin-top: -1px; - margin-right: 12px; - align-self: baseline; - - display: inline-flex; - align-items: center; - cursor: pointer; -} - -.checked { - display: none; - fill: var(--marketplaceColor); -} - -.box { - stroke: var(--matterColorAnti); -} - -.text { - @apply --marketplaceListingAttributeFontStyles; - color: var(--matterColor); - margin-top: -1px; - margin-bottom: 1px; - cursor: pointer; -} diff --git a/src/components/FieldGroupCheckbox/FieldCheckbox.js b/src/components/FieldGroupCheckbox/FieldCheckbox.js deleted file mode 100644 index cad10ef69b..0000000000 --- a/src/components/FieldGroupCheckbox/FieldCheckbox.js +++ /dev/null @@ -1,91 +0,0 @@ -import React from 'react'; -import { any, node, string, object, shape } from 'prop-types'; -import classNames from 'classnames'; -import { Field } from 'react-final-form'; -import { ValidationError } from '../../components'; - -import css from './FieldCheckbox.css'; - -const IconCheckbox = props => { - return ( - - - - - - - - - - ); -}; - -IconCheckbox.defaultProps = { className: null }; - -IconCheckbox.propTypes = { className: string }; - -const FieldCheckboxComponent = props => { - const { rootClassName, className, svgClassName, id, label, input, meta, ...rest } = props; - - const classes = classNames(rootClassName || css.root, className); - - const { value, ...inputProps } = input; - const checked = value === true; - - const checkboxProps = { - id, - className: css.input, - type: 'checkbox', - checked, - ...inputProps, - ...rest, - }; - - return ( - - - - - - ); -}; - -FieldCheckboxComponent.defaultProps = { - className: null, - rootClassName: null, - svgClassName: null, - label: null, -}; - -FieldCheckboxComponent.propTypes = { - className: string, - rootClassName: string, - svgClassName: string, - id: string.isRequired, - label: node, - - // FieldRenderProps - input: shape({ value: any }).isRequired, - meta: object.isRequired, -}; - -const FieldCheckbox = props => { - return ; -}; - -export default FieldCheckbox; diff --git a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.css b/src/components/FieldGroupCheckbox/FieldGroupCheckbox.css deleted file mode 100644 index 0550ae37c9..0000000000 --- a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.css +++ /dev/null @@ -1,28 +0,0 @@ -@import '../../marketplace.css'; - -.root { - margin: 0; - padding: 0; - border: none; -} - -.list { - margin: 0; -} - -.twoColumns { - @media (--viewportMedium) { - columns: 2; - } -} - -.item { - padding: 2px 0; - - /* Fix broken multi-column layout in Chrome */ - page-break-inside: avoid; - - @media (--viewportMedium) { - padding: 4px 0; - } -} diff --git a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.example.js b/src/components/FieldGroupCheckbox/FieldGroupCheckbox.example.js deleted file mode 100644 index 54c43adcd9..0000000000 --- a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.example.js +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react'; -import { reduxForm, propTypes as formPropTypes } from 'redux-form'; -import { Button } from '../../components'; -import FieldGroupCheckbox from './FieldGroupCheckbox'; -import { requiredFieldArrayCheckbox } from '../../util/validators'; - -const formName = 'Styleguide.FieldGroupCheckboxForm'; -const formNameRequired = 'Styleguide.FieldGroupCheckboxFormRequired'; - -const label =

Amenities

; - -const commonProps = { - label: label, - options: [ - { - key: 'towels', - label: 'Towels', - }, - { - key: 'bathroom', - label: 'Bathroom', - }, - { - key: 'swimming_pool', - label: 'Swimming pool', - }, - { - key: 'own_drinks', - label: 'Own drinks allowed', - }, - { - key: 'jacuzzi', - label: 'Jacuzzi', - }, - { - key: 'audiovisual_entertainment', - label: 'Audiovisual entertainment', - }, - { - key: 'barbeque', - label: 'Barbeque', - }, - { - key: 'own_food_allowed', - label: 'Own food allowed', - }, - ], - twoColumns: true, -}; - -const optionalProps = { - name: 'amenities-optional', - id: `${formName}.amenities-optional`, - ...commonProps, -}; - -const requiredProps = { - name: 'amenities-required', - id: `${formNameRequired}.amenities-required`, - ...commonProps, - validate: requiredFieldArrayCheckbox('this is required'), -}; - -const FormComponent = props => { - const { handleSubmit, invalid, submitting, componentProps } = props; - - const submitDisabled = invalid || submitting; - - return ( -
- - - - - ); -}; - -FormComponent.propTypes = formPropTypes; - -const Form = formName => { - return reduxForm({ - form: formName, - })(FormComponent); -}; - -export const Optional = { - component: Form(formName), - props: { - onSubmit: values => { - console.log('Submit values: ', values); - }, - componentProps: optionalProps, - }, - group: 'inputs', -}; - -export const Required = { - component: Form(formNameRequired), - props: { - onSubmit: values => { - console.log('Submit values: ', values); - }, - componentProps: requiredProps, - }, - group: 'inputs', -}; diff --git a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.js b/src/components/FieldGroupCheckbox/FieldGroupCheckbox.js deleted file mode 100644 index 14876e968d..0000000000 --- a/src/components/FieldGroupCheckbox/FieldGroupCheckbox.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Renders a group of checkboxes that can be used to select - * multiple values from a set of options. - * - * The corresponding component when rendering the selected - * values is PropertyGroup. - * - */ - -import React, { Component } from 'react'; -import { arrayOf, bool, node, shape, string } from 'prop-types'; -import classNames from 'classnames'; -import { FieldArray } from 'redux-form'; -import { ValidationError } from '../../components'; - -import FieldCheckbox from './FieldCheckbox'; -import css from './FieldGroupCheckbox.css'; - -class FieldCheckboxRenderer extends Component { - constructor(props) { - super(props); - this.state = { touched: false }; - } - - componentWillReceiveProps(nextProps) { - // FieldArray doesn't have touched prop, so we'll keep track of it - if (!this.state.touched) { - this.setState({ touched: nextProps.meta.dirty }); - } - } - - render() { - const { className, rootClassName, label, twoColumns, id, options, meta, name } = this.props; - - const touched = this.state.touched; - - const classes = classNames(rootClassName || css.root, className); - const listClasses = twoColumns ? classNames(css.list, css.twoColumns) : css.list; - - return ( -
- {label ? {label} : null} -
    - {options.map(option => { - const fieldId = `${id}.${option.key}`; - return ( -
  • - -
  • - ); - })} -
- -
- ); - } -} - -FieldCheckboxRenderer.defaultProps = { - rootClassName: null, - className: null, - label: null, - twoColumns: false, -}; - -FieldCheckboxRenderer.propTypes = { - rootClassName: string, - className: string, - id: string.isRequired, - label: node, - options: arrayOf( - shape({ - key: string.isRequired, - label: node.isRequired, - }) - ).isRequired, - twoColumns: bool, -}; - -// Redux Form: the name of FieldArray must be unique -// https://github.com/erikras/redux-form/issues/2740 -const FieldGroupCheckbox = props => ( - -); - -// Name and component are required fields for FieldArray. -// Component-prop we define in this file, name needs to be passed in -FieldGroupCheckbox.propTypes = { - name: string.isRequired, -}; - -export default FieldGroupCheckbox; diff --git a/src/components/SelectField/SelectField.css b/src/components/SelectField/SelectField.css deleted file mode 100644 index 0aa58c74ce..0000000000 --- a/src/components/SelectField/SelectField.css +++ /dev/null @@ -1,18 +0,0 @@ -@import '../../marketplace.css'; - -.root { -} - -.select { - color: var(--matterColorAnti); - border-bottom-color: var(--attentionColor); -} - -.selectSuccess { - color: var(--matterColor); - border-bottom-color: var(--successColor); -} - -.selectError { - border-bottom-color: var(--failColor); -} diff --git a/src/components/SelectField/SelectField.example.js b/src/components/SelectField/SelectField.example.js deleted file mode 100644 index a348c25d25..0000000000 --- a/src/components/SelectField/SelectField.example.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable no-console */ -import React from 'react'; -import { reduxForm, propTypes as formPropTypes } from 'redux-form'; -import * as validators from '../../util/validators'; -import { Button } from '../../components'; -import SelectField from './SelectField'; - -const formName = 'Styleguide.SelectField.Form'; - -const FormComponent = props => { - const { form, handleSubmit, invalid, pristine, submitting } = props; - const required = validators.required('This field is required'); - const submitDisabled = invalid || pristine || submitting; - return ( -
- - - - - - -
- ); -}; - -FormComponent.propTypes = formPropTypes; - -const Form = reduxForm({ - form: formName, -})(FormComponent); - -export const Select = { - component: Form, - props: { - onSubmit: values => { - console.log('submit values:', values); - }, - }, - group: 'inputs', -}; diff --git a/src/components/SelectField/SelectField.js b/src/components/SelectField/SelectField.js deleted file mode 100644 index c733916cba..0000000000 --- a/src/components/SelectField/SelectField.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * DEPRECATED: this component is part of Redux Form - we are migrating to react-final-form. - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { Field } from 'redux-form'; -import classNames from 'classnames'; -import { ValidationError } from '../../components'; - -import css from './SelectField.css'; - -const SelectFieldComponent = props => { - const { rootClassName, className, id, label, input, meta, children, ...rest } = props; - - if (label && !id) { - throw new Error('id required when a label is given'); - } - - const { valid, invalid, touched, error } = meta; - - // Error message and input error styles are only shown if the - // field has been touched and the validation has failed. - const hasError = touched && invalid && error; - - const selectClasses = classNames(css.select, { - [css.selectSuccess]: valid, - [css.selectError]: hasError, - }); - const selectProps = { className: selectClasses, id, ...input, ...rest }; - - const classes = classNames(rootClassName || css.root, className); - return ( -
- {label ? : null} - - -
- ); -}; - -SelectFieldComponent.defaultProps = { - rootClassName: null, - className: null, - id: null, - label: null, - children: null, -}; - -const { string, object, node } = PropTypes; - -SelectFieldComponent.propTypes = { - rootClassName: string, - className: string, - - // Label is optional, but if it is given, an id is also required so - // the label can reference the input in the `for` attribute - id: string, - label: string, - - // Generated by redux-form's Field component - input: object.isRequired, - meta: object.isRequired, - - children: node, -}; - -const SelectField = props => { - return ; -}; - -export default SelectField; diff --git a/src/components/TextInputField/TextInputField.css b/src/components/TextInputField/TextInputField.css deleted file mode 100644 index 2294a88d4d..0000000000 --- a/src/components/TextInputField/TextInputField.css +++ /dev/null @@ -1,19 +0,0 @@ -@import '../../marketplace.css'; - -.root { -} - -.input { - border-bottom-color: var(--attentionColor); -} - -.inputSuccess { - border-bottom-color: var(--successColor); -} - -.inputError { - border-bottom-color: var(--failColor); -} - -.textarea { -} diff --git a/src/components/TextInputField/TextInputField.example.css b/src/components/TextInputField/TextInputField.example.css deleted file mode 100644 index 9fe2d13d28..0000000000 --- a/src/components/TextInputField/TextInputField.example.css +++ /dev/null @@ -1,7 +0,0 @@ -.field { - margin-top: 24px; -} - -.submit { - margin-top: 24px; -} diff --git a/src/components/TextInputField/TextInputField.example.js b/src/components/TextInputField/TextInputField.example.js deleted file mode 100644 index 4007f50d41..0000000000 --- a/src/components/TextInputField/TextInputField.example.js +++ /dev/null @@ -1,81 +0,0 @@ -/* eslint-disable no-console */ -import React from 'react'; -import { reduxForm, propTypes as formPropTypes } from 'redux-form'; -import * as validators from '../../util/validators'; -import { Button } from '../../components'; -import TextInputField from './TextInputField'; - -import css from './TextInputField.example.css'; - -const formName = 'Styleguide.TextInputField.Form'; - -const FormComponent = props => { - const { handleSubmit, invalid, pristine, submitting } = props; - const required = validators.required('This field is required'); - const submitDisabled = invalid || pristine || submitting; - return ( -
- - - - - - - - - ); -}; - -FormComponent.propTypes = formPropTypes; - -const Form = reduxForm({ - form: formName, -})(FormComponent); - -export const Inputs = { - component: Form, - props: { - onSubmit: values => { - console.log('submit values:', values); - }, - }, - group: 'inputs', -}; diff --git a/src/components/TextInputField/TextInputField.js b/src/components/TextInputField/TextInputField.js deleted file mode 100644 index 0014a58cef..0000000000 --- a/src/components/TextInputField/TextInputField.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * DEPRECATED: this component is part of Redux Form - we are migrating to react-final-form. - */ - -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { Field } from 'redux-form'; -import classNames from 'classnames'; -import { ValidationError, ExpandingTextarea } from '../../components'; - -import css from './TextInputField.css'; - -const CONTENT_MAX_LENGTH = 5000; - -class TextInputFieldComponent extends Component { - componentWillUnmount() { - if (this.props.clearOnUnmount) { - this.props.input.onChange(''); - } - } - render() { - /* eslint-disable no-unused-vars */ - const { - rootClassName, - className, - inputRootClass, - clearOnUnmount, - customErrorText, - id, - label, - type, - input, - meta, - ...rest - } = this.props; - /* eslint-enable no-unused-vars */ - - if (label && !id) { - throw new Error('id required when a label is given'); - } - - const { valid, invalid, touched, error } = meta; - const isTextarea = type === 'textarea'; - - const errorText = customErrorText || error; - - // Error message and input error styles are only shown if the - // field has been touched and the validation has failed. - const hasError = touched && invalid && errorText; - - const fieldMeta = { touched, error: errorText }; - - const inputClasses = - inputRootClass || - classNames(css.input, { - [css.inputSuccess]: valid, - [css.inputError]: hasError, - [css.textarea]: isTextarea, - }); - const inputProps = isTextarea - ? { className: inputClasses, id, rows: 1, maxLength: CONTENT_MAX_LENGTH, ...input, ...rest } - : { className: inputClasses, id, type, ...input, ...rest }; - - const classes = classNames(rootClassName || css.root, className); - return ( -
- {label ? : null} - {isTextarea ? : } - -
- ); - } -} - -TextInputFieldComponent.defaultProps = { - rootClassName: null, - className: null, - inputRootClass: null, - clearOnUnmount: false, - customErrorText: null, - id: null, - label: null, -}; - -const { string, bool, shape, func, object } = PropTypes; - -TextInputFieldComponent.propTypes = { - rootClassName: string, - className: string, - inputRootClass: string, - - clearOnUnmount: bool, - - // Error message that can be manually passed to input field, - // overrides default validation message - customErrorText: string, - - // Label is optional, but if it is given, an id is also required so - // the label can reference the input in the `for` attribute - id: string, - label: string, - - // Either 'textarea' or something that is passed to the input element - type: string.isRequired, - - // Generated by redux-form's Field component - input: shape({ - onChange: func.isRequired, - }).isRequired, - meta: object.isRequired, -}; - -const TextInputField = props => { - return ; -}; - -export default TextInputField; diff --git a/src/components/index.js b/src/components/index.js index 3d5a5b8dcd..5710804942 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -36,7 +36,6 @@ export { default as FieldCheckboxGroup } from './FieldCheckboxGroup/FieldCheckbo export { default as FieldCurrencyInput } from './FieldCurrencyInput/FieldCurrencyInput'; export { default as FieldDateInput } from './FieldDateInput/FieldDateInput'; export { default as FieldDateRangeInput } from './FieldDateRangeInput/FieldDateRangeInput'; -export { default as FieldGroupCheckbox } from './FieldGroupCheckbox/FieldGroupCheckbox'; export { default as FieldPhoneNumberInput } from './FieldPhoneNumberInput/FieldPhoneNumberInput'; export { default as FieldReviewRating } from './FieldReviewRating/FieldReviewRating'; export { default as FieldSelect } from './FieldSelect/FieldSelect'; @@ -115,7 +114,6 @@ export { default as SectionHero } from './SectionHero/SectionHero'; export { default as SectionHowItWorks } from './SectionHowItWorks/SectionHowItWorks'; export { default as SectionLocations } from './SectionLocations/SectionLocations'; export { default as SectionThumbnailLinks } from './SectionThumbnailLinks/SectionThumbnailLinks'; -export { default as SelectField } from './SelectField/SelectField'; export { default as SelectMultipleFilter } from './SelectMultipleFilter/SelectMultipleFilter'; export { default as SelectMultipleFilterPlain, @@ -131,7 +129,6 @@ export { default as TabNav } from './TabNav/TabNav'; export { LinkTabNavHorizontal, ButtonTabNavHorizontal } from './TabNavHorizontal/TabNavHorizontal'; export { default as Tabs } from './Tabs/Tabs'; export { default as TermsOfService } from './TermsOfService/TermsOfService'; -export { default as TextInputField } from './TextInputField/TextInputField'; export { default as Topbar } from './Topbar/Topbar'; export { default as TopbarDesktop } from './TopbarDesktop/TopbarDesktop'; export { default as TopbarMobileMenu } from './TopbarMobileMenu/TopbarMobileMenu'; diff --git a/src/ducks/index.js b/src/ducks/index.js index 0f451fe7e9..9987e5c137 100644 --- a/src/ducks/index.js +++ b/src/ducks/index.js @@ -4,7 +4,6 @@ * https://github.com/erikras/ducks-modular-redux */ -import { reducer as form } from 'redux-form'; import Auth from './Auth.duck'; import EmailVerification from './EmailVerification.duck'; import FlashNotification from './FlashNotification.duck'; @@ -21,7 +20,6 @@ export { LocationFilter, Routing, UI, - form, marketplaceData, user, }; diff --git a/src/examples.js b/src/examples.js index 846be7576d..c8c5994e95 100644 --- a/src/examples.js +++ b/src/examples.js @@ -12,7 +12,6 @@ import * as FieldCheckboxGroup from './components/FieldCheckboxGroup/FieldCheckb import * as FieldCurrencyInput from './components/FieldCurrencyInput/FieldCurrencyInput.example'; import * as FieldDateInput from './components/FieldDateInput/FieldDateInput.example'; import * as FieldDateRangeInput from './components/FieldDateRangeInput/FieldDateRangeInput.example'; -import * as FieldGroupCheckbox from './components/FieldGroupCheckbox/FieldGroupCheckbox.example'; import * as FieldPhoneNumberInput from './components/FieldPhoneNumberInput/FieldPhoneNumberInput.example'; import * as FieldReviewRating from './components/FieldReviewRating/FieldReviewRating.example'; import * as FieldSelect from './components/FieldSelect/FieldSelect.example'; @@ -49,14 +48,12 @@ import * as ResponsiveImage from './components/ResponsiveImage/ResponsiveImage.e import * as ReviewRating from './components/ReviewRating/ReviewRating.example'; import * as Reviews from './components/Reviews/Reviews.example'; import * as SectionThumbnailLinks from './components/SectionThumbnailLinks/SectionThumbnailLinks.example'; -import * as SelectField from './components/SelectField/SelectField.example'; import * as SelectMultipleFilter from './components/SelectMultipleFilter/SelectMultipleFilter.example'; import * as SelectMultipleFilterPlain from './components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.example'; import * as StripeBankAccountTokenInputField from './components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example'; import * as TabNav from './components/TabNav/TabNav.example'; import * as TabNavHorizontal from './components/TabNavHorizontal/TabNavHorizontal.example'; import * as Tabs from './components/Tabs/Tabs.example'; -import * as TextInputField from './components/TextInputField/TextInputField.example'; import * as TopbarDesktop from './components/TopbarDesktop/TopbarDesktop.example'; import * as UserCard from './components/UserCard/UserCard.example'; @@ -107,7 +104,6 @@ export { FieldCurrencyInput, FieldDateInput, FieldDateRangeInput, - FieldGroupCheckbox, FieldPhoneNumberInput, FieldReviewRating, FieldSelect, @@ -149,7 +145,6 @@ export { ReviewRating, Reviews, SectionThumbnailLinks, - SelectField, SelectMultipleFilter, SelectMultipleFilterPlain, SendMessageForm, @@ -159,7 +154,6 @@ export { TabNav, TabNavHorizontal, Tabs, - TextInputField, TopbarDesktop, Typography, UserCard, diff --git a/src/util/data.js b/src/util/data.js index bca9bd2176..45595c7bf6 100644 --- a/src/util/data.js +++ b/src/util/data.js @@ -1,6 +1,5 @@ import isArray from 'lodash/isArray'; import reduce from 'lodash/reduce'; -import toPairs from 'lodash/toPairs'; /** * Combine the given relationships objects @@ -283,39 +282,3 @@ export const overrideArrays = (objValue, srcValue, key, object, source, stack) = return srcValue; } }; - -/** - * Converts an array of strings into an object where the array items - * are keys and values in all fields are true. This kind of object - * can be passed as initialValues parameter to a ReduxForm that contains - * checkbox inputs. - * - * @param {Array} array An array of strings - * - * @return {Object} An object containing the array items as keys and all - * the values set to true - * - * A complementary function to formValuesToArray. - * - */ -export const arrayToFormValues = array => { - return array.reduce((map, key) => { - map[key] = true; - return map; - }, {}); -}; - -/** - * Converts a values object received form a Redux Form containing - * checkboxes into an array that contains only the values. - * - * @param {Object} formValues A values object received from a Redux Form - * - * @return {Array} An array containing the keys of the formValues parameter - * - * A complementary function to arrayToFormValues. - */ -export const formValuesToArray = formValues => { - const entries = toPairs(formValues); - return entries.filter(entry => entry[1] === true).map(entry => entry[0]); -}; diff --git a/src/util/data.test.js b/src/util/data.test.js index aa9ed9df14..f19e5e7310 100644 --- a/src/util/data.test.js +++ b/src/util/data.test.js @@ -328,38 +328,4 @@ describe('data utils', () => { ]); }); }); - - describe('arrayToFormValues()', () => { - it('converts an empty array', () => { - expect(arrayToFormValues([])).toEqual({}); - }); - it('converts multiple values', () => { - const array = ['one', 'two', 'three']; - const formValues = { one: true, two: true, three: true }; - expect(arrayToFormValues(array)).toEqual(formValues); - }); - }); - - describe('formValuesToArray()', () => { - it('converts an empty object', () => { - expect(formValuesToArray({})).toEqual([]); - }); - it('converts multiple values', () => { - const formValues = { one: true, two: true, three: true }; - const array = ['one', 'two', 'three']; - expect(formValuesToArray(formValues)).toEqual(array); - }); - it('it skips non-true values form input object', () => { - const formValues = { - one: true, - two: null, - three: 'true', - four: false, - five: '', - six: true, - }; - const array = ['one', 'six']; - expect(formValuesToArray(formValues)).toEqual(array); - }); - }); }); From 085935beb673bbff3e69f76755707b9baa30a7af Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 31 May 2018 17:22:56 +0300 Subject: [PATCH 09/14] Move rest of the forms to forms folder Move SelectMultipleFilterForm and SelectMultipleFilterPlainForm to the forms folder. --- src/components/SelectMultipleFilter/SelectMultipleFilter.js | 2 +- .../SelectMultipleFilterPlain/SelectMultipleFilterPlain.js | 2 +- .../SelectMultipleFilterForm}/SelectMultipleFilterForm.css | 0 .../SelectMultipleFilterForm}/SelectMultipleFilterForm.js | 0 .../SelectMultipleFilterPlainForm.js | 0 src/forms/index.js | 2 ++ 6 files changed, 4 insertions(+), 2 deletions(-) rename src/{components/SelectMultipleFilter => forms/SelectMultipleFilterForm}/SelectMultipleFilterForm.css (100%) rename src/{components/SelectMultipleFilter => forms/SelectMultipleFilterForm}/SelectMultipleFilterForm.js (100%) rename src/{components/SelectMultipleFilterPlain => forms/SelectMultipleFilterPlainForm}/SelectMultipleFilterPlainForm.js (100%) diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js index ae80055e0c..3becf3b9aa 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.js +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -3,7 +3,7 @@ import { array, arrayOf, func, number, string } from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape } from 'react-intl'; -import SelectMultipleFilterForm from './SelectMultipleFilterForm'; +import { SelectMultipleFilterForm } from '../../forms'; import css from './SelectMultipleFilter.css'; const KEY_CODE_ESCAPE = 27; diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js index 25ba8c44b8..22790e8ec6 100644 --- a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js +++ b/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlain.js @@ -3,7 +3,7 @@ import { array, bool, func, string } from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; -import SelectMultipleFilterPlainForm from './SelectMultipleFilterPlainForm'; +import { SelectMultipleFilterPlainForm } from '../../forms'; import css from './SelectMultipleFilterPlain.css'; diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilterForm.css b/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.css similarity index 100% rename from src/components/SelectMultipleFilter/SelectMultipleFilterForm.css rename to src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.css diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilterForm.js b/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js similarity index 100% rename from src/components/SelectMultipleFilter/SelectMultipleFilterForm.js rename to src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js diff --git a/src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js b/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js similarity index 100% rename from src/components/SelectMultipleFilterPlain/SelectMultipleFilterPlainForm.js rename to src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js diff --git a/src/forms/index.js b/src/forms/index.js index 1d2a9979a8..e25116d724 100644 --- a/src/forms/index.js +++ b/src/forms/index.js @@ -17,6 +17,8 @@ export { default as PayoutDetailsForm } from './PayoutDetailsForm/PayoutDetailsF export { default as ProfileSettingsForm } from './ProfileSettingsForm/ProfileSettingsForm'; export { default as ReviewForm } from './ReviewForm/ReviewForm'; export { default as SendMessageForm } from './SendMessageForm/SendMessageForm'; +export { default as SelectMultipleFilterForm } from './SelectMultipleFilterForm/SelectMultipleFilterForm'; +export { default as SelectMultipleFilterPlainForm } from './SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm'; export { default as SignupForm } from './SignupForm/SignupForm'; export { default as StripePaymentForm } from './StripePaymentForm/StripePaymentForm'; export { default as TopbarSearchForm } from './TopbarSearchForm/TopbarSearchForm'; From 51d8c2b6c6987fb702e0c3539f7cea6d73d54ab4 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 1 Jun 2018 01:07:10 +0300 Subject: [PATCH 10/14] Add empty onSubmit to SelectMultipleFilterPlainForm --- .../SelectMultipleFilterPlainForm.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js b/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js index 81e22c302f..706271d263 100644 --- a/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js +++ b/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js @@ -17,17 +17,12 @@ const SelectMultipleFilterPlainForm = props => { return ( null} mutators={{ ...arrayMutators }} - onSubmit={vals => console.log('SelectMultipleFilterPlainForm', vals)} render={({ className, name, options, twoColumns, onChange }) => (
- + )} /> From 729439ad691c63fc3399c03651c0a1d1432a77b0 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 31 May 2018 23:36:39 +0300 Subject: [PATCH 11/14] Remove textual references to Redux Form --- docs/folder-structure.md | 4 ---- src/components/FieldBirthdayInput/FieldBirthdayInput.js | 4 ---- src/components/FieldCheckbox/FieldCheckbox.js | 4 ---- src/components/FieldCheckboxGroup/FieldCheckboxGroup.js | 4 ---- src/components/FieldCurrencyInput/FieldCurrencyInput.js | 4 ---- .../FieldPhoneNumberInput/FieldPhoneNumberInput.js | 4 ---- src/components/FieldReviewRating/FieldReviewRating.js | 2 +- src/components/FieldSelect/FieldSelect.js | 4 ---- src/components/FieldTextInput/FieldTextInput.js | 6 +----- .../LocationAutocompleteInput.js | 9 ++++----- .../StripeBankAccountTokenInputField.js | 6 +----- src/components/ValidationError/ValidationError.js | 2 +- src/util/validators.js | 4 ++-- 13 files changed, 10 insertions(+), 47 deletions(-) diff --git a/docs/folder-structure.md b/docs/folder-structure.md index 5a7e22f18f..66dfe1723b 100644 --- a/docs/folder-structure.md +++ b/docs/folder-structure.md @@ -79,10 +79,6 @@ this folder contains only page-level components and one common component: Topbar Forms are in their own folder since they are using a special library to handle validations, errors, internal state, etc. -_**NOTE:** Currently, we are migrating to -[🏁 Final Form](https://github.com/final-form/react-final-form) (away from -[Redux Form](http://redux-form.com/))._ - ## server/ * `server/index.js` handles server-side rendering (SSR). Built with [Express](http://expressjs.com) diff --git a/src/components/FieldBirthdayInput/FieldBirthdayInput.js b/src/components/FieldBirthdayInput/FieldBirthdayInput.js index 2510e410ba..aa0709a4c4 100644 --- a/src/components/FieldBirthdayInput/FieldBirthdayInput.js +++ b/src/components/FieldBirthdayInput/FieldBirthdayInput.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - import React, { Component } from 'react'; import { func, instanceOf, object, node, string, bool } from 'prop-types'; import { Field } from 'react-final-form'; diff --git a/src/components/FieldCheckbox/FieldCheckbox.js b/src/components/FieldCheckbox/FieldCheckbox.js index 2084bbde02..5904e5a652 100644 --- a/src/components/FieldCheckbox/FieldCheckbox.js +++ b/src/components/FieldCheckbox/FieldCheckbox.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - import React from 'react'; import { node, string } from 'prop-types'; import classNames from 'classnames'; diff --git a/src/components/FieldCheckboxGroup/FieldCheckboxGroup.js b/src/components/FieldCheckboxGroup/FieldCheckboxGroup.js index 5660f45439..b46dbf16c1 100644 --- a/src/components/FieldCheckboxGroup/FieldCheckboxGroup.js +++ b/src/components/FieldCheckboxGroup/FieldCheckboxGroup.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - /* * Renders a group of checkboxes that can be used to select * multiple values from a set of options. diff --git a/src/components/FieldCurrencyInput/FieldCurrencyInput.js b/src/components/FieldCurrencyInput/FieldCurrencyInput.js index 998227b076..19050c2e4d 100644 --- a/src/components/FieldCurrencyInput/FieldCurrencyInput.js +++ b/src/components/FieldCurrencyInput/FieldCurrencyInput.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - /** * CurrencyInput renders an input field that format it's value according to currency formatting rules * onFocus: renders given value in unformatted manner: "9999,99" diff --git a/src/components/FieldPhoneNumberInput/FieldPhoneNumberInput.js b/src/components/FieldPhoneNumberInput/FieldPhoneNumberInput.js index 6a44b4a5bc..f1c127c5bd 100644 --- a/src/components/FieldPhoneNumberInput/FieldPhoneNumberInput.js +++ b/src/components/FieldPhoneNumberInput/FieldPhoneNumberInput.js @@ -1,7 +1,3 @@ -/** - * DEPRECATED: this component is part of Redux Form - we are migrating to react-final-form. - */ - /** * A text field with phone number formatting. By default uses formatting * rules defined in the fiFormatter.js file. To change the formatting diff --git a/src/components/FieldReviewRating/FieldReviewRating.js b/src/components/FieldReviewRating/FieldReviewRating.js index 72b4f34a68..25698b1618 100644 --- a/src/components/FieldReviewRating/FieldReviewRating.js +++ b/src/components/FieldReviewRating/FieldReviewRating.js @@ -114,7 +114,7 @@ FieldReviewRatingComponent.propTypes = { // overrides default validation message customErrorText: string, - // Generated by redux-form's Field component + // Generated by final-form's Field component input: shape({ onChange: func.isRequired, }).isRequired, diff --git a/src/components/FieldSelect/FieldSelect.js b/src/components/FieldSelect/FieldSelect.js index dd13589d7a..d480cd6e41 100644 --- a/src/components/FieldSelect/FieldSelect.js +++ b/src/components/FieldSelect/FieldSelect.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - import React from 'react'; import PropTypes from 'prop-types'; import { Field } from 'react-final-form'; diff --git a/src/components/FieldTextInput/FieldTextInput.js b/src/components/FieldTextInput/FieldTextInput.js index 9af3262c9c..878738ee6c 100644 --- a/src/components/FieldTextInput/FieldTextInput.js +++ b/src/components/FieldTextInput/FieldTextInput.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - import React, { Component } from 'react'; import { func, object, shape, string } from 'prop-types'; import { Field } from 'react-final-form'; @@ -96,7 +92,7 @@ FieldTextInputComponent.propTypes = { // Either 'textarea' or something that is passed to the input element type: string.isRequired, - // Generated by redux-form's Field component + // Generated by final-form's Field component input: shape({ onChange: func.isRequired, }).isRequired, diff --git a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js index ccec79b2e4..a501ed136c 100644 --- a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js +++ b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js @@ -126,14 +126,13 @@ const currentValue = props => { /* Location auto completion input component - This component can work as the `component` prop to Redux Form's - component. it takes a custom input value shape, and - controls the onChanged callback that is called with the value to - syncronise to the form's Redux store. + This component can work as the `component` prop to Final Form's + component. It takes a custom input value shape, and + controls the onChange callback that is called with the input value. The component works by listening to the underlying input component and calling the Google Maps Places API for predictions. When the - predictions arrive, those are passed to Redux Form in the onChange + predictions arrive, those are passed to Final Form in the onChange callback. See the LocationAutocompleteInput.example.js file for a usage diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js index 43ec5197ed..3046759c55 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js @@ -1,7 +1,3 @@ -/** - * NOTE this component is part of react-final-form instead of Redux Form. - */ - /* eslint-disable no-underscore-dangle */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -23,7 +19,7 @@ import { import StripeBankAccountRequiredInput from './StripeBankAccountRequiredInput'; import css from './StripeBankAccountTokenInputField.css'; -// Since redux-form tracks the onBlur event for marking the field as +// Since final-form tracks the onBlur event for marking the field as // touched (which triggers possible error validation rendering), only // trigger the event asynchronously when no other input within this // component has received focus. diff --git a/src/components/ValidationError/ValidationError.js b/src/components/ValidationError/ValidationError.js index cfda30b501..b9b3545bce 100644 --- a/src/components/ValidationError/ValidationError.js +++ b/src/components/ValidationError/ValidationError.js @@ -6,7 +6,7 @@ import css from './ValidationError.css'; /** * This component can be used to show validation errors next to form - * input fields. The component takes the redux-form Field component + * input fields. The component takes the final-form Field component * `meta` object as a prop and infers if an error message should be * shown. */ diff --git a/src/util/validators.js b/src/util/validators.js index dc91a7ee70..07fe966033 100644 --- a/src/util/validators.js +++ b/src/util/validators.js @@ -12,10 +12,10 @@ const isNonEmptyString = val => { }; /** - * Validator functions and helpers for Redux Forms + * Validator functions and helpers for Final Forms */ -// Redux Form expects and undefined value for a successful validation +// Final Form expects and undefined value for a successful validation const VALID = undefined; export const required = message => value => { From 867167536da7261e3c5ee66f17adb92ddcdca52e Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 1 Jun 2018 00:37:23 +0300 Subject: [PATCH 12/14] Remove the redux-form dependency --- package.json | 1 - yarn.lock | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/package.json b/package.json index cea7037363..874012c99b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "react-redux": "^5.0.7", "react-router-dom": "^4.2.2", "redux": "^3.7.2", - "redux-form": "^7.3.0", "redux-thunk": "^2.2.0", "sanitize.css": "^5.0.0", "sharetribe-scripts": "1.1.2", diff --git a/yarn.lock b/yarn.lock index 4608ed5041..28d73ec4fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2579,10 +2579,6 @@ es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-symbol "~3.1.1" next-tick "1" -es6-error@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" - es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" @@ -4001,12 +3997,6 @@ invariant@^2.0.0, invariant@^2.1.1, invariant@^2.2.1, invariant@^2.2.2: dependencies: loose-envify "^1.0.0" -invariant@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - dependencies: - loose-envify "^1.0.0" - invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -7072,19 +7062,6 @@ reduce-function-call@^1.0.1, reduce-function-call@^1.0.2: dependencies: balanced-match "^0.4.2" -redux-form@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-7.3.0.tgz#b92ef1639c86a6009b0821aacfc80ad8b5ac8c05" - dependencies: - deep-equal "^1.0.1" - es6-error "^4.1.1" - hoist-non-react-statics "^2.5.0" - invariant "^2.2.3" - is-promise "^2.1.0" - lodash "^4.17.5" - lodash-es "^4.17.5" - prop-types "^15.6.1" - redux-thunk@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" From 3a7dc5ad1389d0b3c5c7f2f1b21c4f88a2e07d5e Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 1 Jun 2018 01:11:52 +0300 Subject: [PATCH 13/14] Update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f2f9a73be..c7c540e12f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,11 @@ way to update this template, but currently, we follow a pattern: --- -## Upcoming version +## v1.0.0 +* [change] Migrate remaining Redux Forms to Final Form. Also now all the form components can be + found in the src/forms folder. Remove redux-form from the dependencies. + [#845](https://github.com/sharetribe/flex-template-web/pull/845) * [fix] Extract and fix missing information reminder modal from Topbar [#846](https://github.com/sharetribe/flex-template-web/pull/846) * [fix] Add missing styles for ModalMissingInformation from Topbar From cdfd6e088604c830fba7c5d2f0bb31a7055084b1 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 1 Jun 2018 12:42:08 +0300 Subject: [PATCH 14/14] Change final form props spreading Change props spreading so that the whole props object is available to the form and required props can be destructured from that. --- .../EmailVerificationForm.js | 4 ++-- .../LocationSearchForm/LocationSearchForm.js | 3 ++- .../SelectMultipleFilterForm.js | 4 ++-- .../SelectMultipleFilterPlainForm.js | 15 +++++++++------ src/forms/SendMessageForm/SendMessageForm.js | 4 ++-- src/forms/TopbarSearchForm/TopbarSearchForm.js | 4 +++- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/forms/EmailVerificationForm/EmailVerificationForm.js b/src/forms/EmailVerificationForm/EmailVerificationForm.js index 8e5bad8d94..41b670fbb1 100644 --- a/src/forms/EmailVerificationForm/EmailVerificationForm.js +++ b/src/forms/EmailVerificationForm/EmailVerificationForm.js @@ -17,8 +17,8 @@ import css from './EmailVerificationForm.css'; const EmailVerificationFormComponent = props => ( { - const { currentUser, inProgress, handleSubmit, verificationError } = fieldRenderProps; + render={formRenderProps => { + const { currentUser, inProgress, handleSubmit, verificationError } = formRenderProps; const { email, emailVerified, pendingEmail, profile } = currentUser.attributes; const emailToVerify = {pendingEmail || email}; diff --git a/src/forms/LocationSearchForm/LocationSearchForm.js b/src/forms/LocationSearchForm/LocationSearchForm.js index 6cb6567082..b65704c081 100644 --- a/src/forms/LocationSearchForm/LocationSearchForm.js +++ b/src/forms/LocationSearchForm/LocationSearchForm.js @@ -21,7 +21,8 @@ const LocationSearchFormComponent = props => { return ( { + render={formRenderProps => { + const { rootClassName, className, intl } = formRenderProps; const classes = classNames(rootClassName || css.root, className); // Allow form submit only when the place has changed diff --git a/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js b/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js index 00dd13ce33..517b5f2159 100644 --- a/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js +++ b/src/forms/SelectMultipleFilterForm/SelectMultipleFilterForm.js @@ -13,7 +13,7 @@ const SelectMultipleFilterFormComponent = props => { { + render={formRenderProps => { const { form, handleSubmit, @@ -25,7 +25,7 @@ const SelectMultipleFilterFormComponent = props => { contentRef, style, intl, - } = formProps; + } = formRenderProps; const classes = classNames(css.root, { [css.isOpen]: isOpen }); const handleCancel = () => { diff --git a/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js b/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js index 706271d263..6bc44ee018 100644 --- a/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js +++ b/src/forms/SelectMultipleFilterPlainForm/SelectMultipleFilterPlainForm.js @@ -19,12 +19,15 @@ const SelectMultipleFilterPlainForm = props => { {...rest} onSubmit={() => null} mutators={{ ...arrayMutators }} - render={({ className, name, options, twoColumns, onChange }) => ( -
- - - - )} + render={formRenderProps => { + const { className, name, options, twoColumns } = formRenderProps; + return ( +
+ + + + ); + }} /> ); }; diff --git a/src/forms/SendMessageForm/SendMessageForm.js b/src/forms/SendMessageForm/SendMessageForm.js index a86e7ec66d..c0e55d17e2 100644 --- a/src/forms/SendMessageForm/SendMessageForm.js +++ b/src/forms/SendMessageForm/SendMessageForm.js @@ -56,7 +56,7 @@ class SendMessageFormComponent extends Component { return ( { + render={formRenderProps => { const { rootClassName, className, @@ -66,7 +66,7 @@ class SendMessageFormComponent extends Component { sendMessageError, invalid, form, - } = fieldRenderProps; + } = formRenderProps; const classes = classNames(rootClassName || css.root, className); const submitInProgress = inProgress; diff --git a/src/forms/TopbarSearchForm/TopbarSearchForm.js b/src/forms/TopbarSearchForm/TopbarSearchForm.js index 5a95cf3522..eb15e5afca 100644 --- a/src/forms/TopbarSearchForm/TopbarSearchForm.js +++ b/src/forms/TopbarSearchForm/TopbarSearchForm.js @@ -32,7 +32,9 @@ class TopbarSearchFormComponent extends Component { return ( { + render={formRenderProps => { + const { rootClassName, className, desktopInputRoot, intl, isMobile } = formRenderProps; + const classes = classNames(rootClassName, className); const desktopInputRootClass = desktopInputRoot || css.desktopInputRoot;