From d85425fd1b908c12bb1482e8ec7487e57f12a340 Mon Sep 17 00:00:00 2001 From: Valeriy Date: Wed, 4 Sep 2019 15:48:58 +0300 Subject: [PATCH] feat(client): use React Final Form instead of Redux Form (#36742) --- client/package-lock.json | 209 ++++++++++++++---- client/package.json | 6 +- client/src/components/formHelpers/Form.js | 92 +++----- .../src/components/formHelpers/Form.test.js | 93 ++++++-- .../src/components/formHelpers/FormFields.js | 82 ++++--- .../__snapshots__/Form.test.js.snap | 55 ----- client/src/components/formHelpers/index.js | 2 +- client/src/redux/rootReducer.js | 2 - .../src/templates/Challenges/redux/index.js | 22 -- 9 files changed, 310 insertions(+), 253 deletions(-) delete mode 100644 client/src/components/formHelpers/__snapshots__/Form.test.js.snap diff --git a/client/package-lock.json b/client/package-lock.json index f27988f03c..a9e76aae93 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2018,16 +2018,17 @@ "dev": true }, "@testing-library/dom": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.0.tgz", - "integrity": "sha512-nAsRvQLr/b6TGNjuHMEbWXCNPLrQYnzqa/KKQZL7wBOtfptUxsa4Ah9aqkHW0ZmCSFmUDj4nFUxWPVTeMu0iCw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.1.0.tgz", + "integrity": "sha512-qivqFvnbVIH3DyArFofEU/jlOhkGIioIemOy9A9M/NQTpPyDDQmtVkAfoB18RKN581f0s/RJMRBbq9WfMIhFTw==", "dev": true, "requires": { - "@babel/runtime": "^7.4.5", + "@babel/runtime": "^7.5.5", "@sheerun/mutationobserver-shim": "^0.3.2", + "@types/testing-library__dom": "^6.0.0", "aria-query": "3.0.0", "pretty-format": "^24.8.0", - "wait-for-expect": "^1.2.0" + "wait-for-expect": "^1.3.0" }, "dependencies": { "@babel/runtime": { @@ -2047,14 +2048,74 @@ } } }, - "@testing-library/react": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-8.0.5.tgz", - "integrity": "sha512-2EzVi7HjUUF8gKzB4s+oCJ1+F4VOrphO+DlUO6Ptgtcz1ko4J2zqnr0t7g+T7uedXXjJ0wdq70zQMhJXP3w37A==", + "@testing-library/jest-dom": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-4.1.0.tgz", + "integrity": "sha512-cKAONDmJKGJ2DSu6R/+lgA8i8uyZIx4CaOiiK0yMjp+2UecH6kfjunJiy5hfExKMtR74eyzFriqO1w9aTC8VyQ==", "dev": true, "requires": { - "@babel/runtime": "^7.5.4", - "@testing-library/dom": "^5.5.4" + "@babel/runtime": "^7.5.1", + "chalk": "^2.4.1", + "css": "^2.2.3", + "css.escape": "^1.5.1", + "jest-diff": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "lodash": "^4.17.11", + "pretty-format": "^24.0.0", + "redent": "^3.0.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + } + } + }, + "@testing-library/react": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-9.1.3.tgz", + "integrity": "sha512-qFVo6TsEbpEFpOmKjIxMHDujOKVdvVpcYFcUfJeWBqMO8eja5pN9SZnt6W6AzW3a1MRvRfw3X0Fhx3eXnBJxjA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@testing-library/dom": "^6.0.0", + "@types/testing-library__react": "^9.1.0" }, "dependencies": { "@babel/runtime": { @@ -2195,6 +2256,12 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-11.12.2.tgz", "integrity": "sha512-c82MtnqWB/CqqK7/zit74Ob8H1dBdV7bK+BcErwtXbe0+nUGkgzq5NTDmRW/pAv2lFtmeNmW95b0zK2hxpeklg==" }, + "@types/pretty-format": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/pretty-format/-/pretty-format-20.0.1.tgz", + "integrity": "sha512-Oh7wnvVUCtVIWnCHQWe9qDZKn0fGyk5AMq99jXml0x39K59P+z9qe31CNRtop9TceCpS7NmoK+J9eGeCnyFgnw==", + "dev": true + }, "@types/prop-types": { "version": "15.5.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz", @@ -2226,6 +2293,15 @@ "csstype": "^2.2.0" } }, + "@types/react-dom": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.0.tgz", + "integrity": "sha512-OL2lk7LYGjxn4b0efW3Pvf2KBVP0y1v3wip1Bp7nA79NkOpElH98q3WdCEdDj93b2b0zaeBG9DvriuKjIK5xDA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -2237,6 +2313,25 @@ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz", "integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==" }, + "@types/testing-library__dom": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.0.1.tgz", + "integrity": "sha512-j8wJmvER0VVrmDtab80SwA4MgF0vzFm6hSyk3j2bw9PXyJxgMjFDF8ihJDzo2gUOMP+HpEquHRZcUXOhLmYexA==", + "dev": true, + "requires": { + "@types/pretty-format": "*" + } + }, + "@types/testing-library__react": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__react/-/testing-library__react-9.1.1.tgz", + "integrity": "sha512-8/toTJaIlS3BC7JrK2ElTnbjH8tmFP7atdL2ZsIa1JDmH9RKSm/7Wp5oMDJzXoWr988Mv7ym/XZ8LRglyoGCGw==", + "dev": true, + "requires": { + "@types/react-dom": "*", + "@types/testing-library__dom": "*" + } + }, "@types/tmp": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.32.tgz", @@ -7731,6 +7826,29 @@ } } }, + "final-form": { + "version": "4.18.5", + "resolved": "https://registry.npmjs.org/final-form/-/final-form-4.18.5.tgz", + "integrity": "sha512-DH/I2W7fWxU8J8ZsbYJ5jLvUbhbatCvLhIKlsU17MvY6W3QnetPEyuX5mcxXgIGFNFKxfvqsG3pDy/1/VwOiTw==", + "requires": { + "@babel/runtime": "^7.3.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -13788,6 +13906,12 @@ "dom-walk": "^0.1.0" } }, + "min-indent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", + "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=", + "dev": true + }, "mini-css-extract-plugin": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz", @@ -16395,6 +16519,30 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, + "react-final-form": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.3.0.tgz", + "integrity": "sha512-jijhXR1fFGUBQwNOSqF4MK8XJO7Ynl1p8vcFsnQS0INSkGI52+4IagjUgtHj3w8EviIHPFK/Eflji6FELUl07w==", + "requires": { + "@babel/runtime": "^7.4.5", + "ts-essentials": "^2.0.8" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } + } + }, "react-ga": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.6.0.tgz", @@ -16529,14 +16677,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.2.tgz", "integrity": "sha512-rI3cGFj/obHbBz156PvErrS5xc6f1eWyTwyV4mo0vF2lGgXgS+mm7EKD5buLJq6jNgIagQescGSVG2YzgXt8Yg==" }, - "react-lazy-cache": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/react-lazy-cache/-/react-lazy-cache-3.0.1.tgz", - "integrity": "sha1-DcZNON8XZ+93Z4xclBkAZMsRsM0=", - "requires": { - "deep-equal": "^1.0.1" - } - }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -17133,26 +17273,6 @@ "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz", "integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==" }, - "redux-form": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-5.3.6.tgz", - "integrity": "sha1-93qB2/ONRNJupBEQCiPxninNGUY=", - "requires": { - "deep-equal": "^1.0.1", - "hoist-non-react-statics": "^1.0.5", - "invariant": "^2.0.0", - "is-promise": "^2.1.0", - "prop-types": "^15.5.8", - "react-lazy-cache": "^3.0.1" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", - "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=" - } - } - }, "redux-observable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/redux-observable/-/redux-observable-1.1.0.tgz", @@ -19417,6 +19537,11 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz", "integrity": "sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==" }, + "ts-essentials": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", + "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" + }, "ts-pnp": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz", @@ -20098,9 +20223,9 @@ } }, "wait-for-expect": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.2.0.tgz", - "integrity": "sha512-EJhKpA+5UHixduMBEGhTFuLuVgQBKWxkFbefOdj2bbk2/OpA5Opsc4aUTGmF+qJ+v3kTGxDRNYwKaT4j6g5n8Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.3.0.tgz", + "integrity": "sha512-8fJU7jiA96HfGPt+P/UilelSAZfhMBJ52YhKzlmZQvKEZU2EcD1GQ0yqGB6liLdHjYtYAoGVigYwdxr5rktvzA==", "dev": true }, "walker": { diff --git a/client/package.json b/client/package.json index 8713e6d051..0a9622f25d 100644 --- a/client/package.json +++ b/client/package.json @@ -24,6 +24,7 @@ "entities": "^1.1.2", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", + "final-form": "^4.18.5", "gatsby": "^2.13.67", "gatsby-cli": "^2.7.31", "gatsby-link": "^2.2.5", @@ -48,6 +49,7 @@ "react": "^16.9.0", "react-calendar-heatmap": "^1.8.1", "react-dom": "^16.9.0", + "react-final-form": "^6.3.0", "react-ga": "^2.6.0", "react-helmet": "^5.2.1", "react-identicons": "^1.1.7", @@ -64,7 +66,6 @@ "redux": "^4.0.4", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", - "redux-form": "^5.3.6", "redux-observable": "^1.1.0", "redux-saga": "^1.0.5", "reselect": "^3.0.1", @@ -92,7 +93,8 @@ "test": "jest" }, "devDependencies": { - "@testing-library/react": "^8.0.5", + "@testing-library/jest-dom": "^4.1.0", + "@testing-library/react": "^9.1.3", "autoprefixer": "^9.6.1", "babel-plugin-transform-imports": "^1.5.1", "chokidar": "^2.1.5", diff --git a/client/src/components/formHelpers/Form.js b/client/src/components/formHelpers/Form.js index a793640017..3a17e17e66 100644 --- a/client/src/components/formHelpers/Form.js +++ b/client/src/components/formHelpers/Form.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { reduxForm } from 'redux-form'; +import { Form } from 'react-final-form'; import { FormFields, @@ -12,16 +12,7 @@ import { const propTypes = { buttonText: PropTypes.string, enableSubmit: PropTypes.bool, - errors: PropTypes.object, - fields: PropTypes.objectOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - value: PropTypes.string.isRequired - }) - ), formFields: PropTypes.arrayOf(PropTypes.string).isRequired, - handleSubmit: PropTypes.func, hideButton: PropTypes.bool, id: PropTypes.string.isRequired, initialValues: PropTypes.object, @@ -33,67 +24,44 @@ const propTypes = { submit: PropTypes.func.isRequired }; -export function DynamicForm({ - // redux-form - errors, - fields, - handleSubmit, - fields: { - // eslint-disable-next-line react/prop-types - _meta: { allPristine } - }, - - // HOC +function DynamicForm({ + id, + formFields, + initialValues, + options, + submit, buttonText, enableSubmit, - hideButton, - id, - options, - submit + hideButton }) { return ( -
+ submit(formatUrlValues(values, options), ...args) - )} - style={{ width: '100%' }} + } > - - - {hideButton ? null : ( - errors[key]).length - } - > - {buttonText ? buttonText : null} - - )} - - + {({ handleSubmit, pristine, error }) => ( +
+ + + {hideButton ? null : ( + + {buttonText ? buttonText : null} + + )} + + + )} + ); } DynamicForm.displayName = 'DynamicForm'; DynamicForm.propTypes = propTypes; -const DynamicFormWithRedux = reduxForm()(DynamicForm); - -export default function Form(props) { - return ( - - ); -} - -Form.propTypes = propTypes; +export default DynamicForm; diff --git a/client/src/components/formHelpers/Form.test.js b/client/src/components/formHelpers/Form.test.js index cefc5f9ef2..e0cb43e723 100644 --- a/client/src/components/formHelpers/Form.test.js +++ b/client/src/components/formHelpers/Form.test.js @@ -1,30 +1,14 @@ -/* global expect */ +/* global jest, expect */ +import '@testing-library/jest-dom/extend-expect'; import React from 'react'; -import renderer from 'react-test-renderer'; -import Enzyme from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; +import { render, fireEvent } from '@testing-library/react'; -import { DynamicForm } from './Form'; - -Enzyme.configure({ adapter: new Adapter() }); +import Form from './Form'; const defaultTestProps = { - errors: {}, - fields: { - _meta: { - allPristine: true, - name: 'name', - onChange: () => {}, - value: '' - } - }, - handleSubmit: () => {}, - buttonText: 'Submit', - enableSubmit: true, formFields: ['name', 'website'], - hideButton: false, id: 'my-test-form', options: { types: { @@ -36,8 +20,69 @@ const defaultTestProps = { submit: () => {} }; -test(' snapshot', () => { - const component = renderer.create(); - let tree = component.toJSON(); - expect(tree).toMatchSnapshot(); +test('should render', () => { + const { getByLabelText, getByText } = render(
); + + const nameInput = getByLabelText(/name/i); + expect(nameInput).not.toBeRequired(); + expect(nameInput).toHaveAttribute('type', 'text'); + + const websiteInput = getByLabelText(/website/i); + expect(websiteInput).toBeRequired(); + expect(websiteInput).toHaveAttribute('type', 'url'); + + const button = getByText(/submit/i); + expect(button).toHaveAttribute('type', 'submit'); + expect(button).toBeDisabled(); +}); + +test('should render with default values', () => { + const websiteValue = 'http://mysite.com'; + const nameValue = 'John'; + + const { getByLabelText, getByText } = render( + + ); + + const nameInput = getByLabelText(/name/i); + expect(nameInput).toHaveValue(nameValue); + + const websiteInput = getByLabelText(/website/i); + expect(websiteInput).toHaveValue(websiteValue); + + const button = getByText(/submit/i); + expect(button).toBeEnabled(); +}); + +test('should submit', () => { + const submit = jest.fn(); + const props = { + ...defaultTestProps, + submit + }; + const websiteValue = 'http://mysite.com'; + + const { getByLabelText, getByText } = render(); + + const websiteInput = getByLabelText(/website/i); + fireEvent.change(websiteInput, { target: { value: websiteValue } }); + expect(websiteInput).toHaveValue(websiteValue); + + const button = getByText(/submit/i); + expect(button).toBeEnabled(); + + fireEvent.click(button); + expect(submit).toHaveBeenCalledTimes(1); + expect(submit.mock.calls[0][0]).toEqual({ website: websiteValue }); + + fireEvent.change(websiteInput, { target: { value: `${websiteValue}///` } }); + expect(websiteInput).toHaveValue(`${websiteValue}///`); + + fireEvent.click(button); + expect(submit).toHaveBeenCalledTimes(2); + expect(submit.mock.calls[1][0]).toEqual({ website: websiteValue }); }); diff --git a/client/src/components/formHelpers/FormFields.js b/client/src/components/formHelpers/FormFields.js index 930078e438..e2ae4195c9 100644 --- a/client/src/components/formHelpers/FormFields.js +++ b/client/src/components/formHelpers/FormFields.js @@ -9,20 +9,11 @@ import { FormGroup, HelpBlock } from '@freecodecamp/react-bootstrap'; +import { Field } from 'react-final-form'; const propTypes = { - errors: PropTypes.objectOf(PropTypes.string), - fields: PropTypes.objectOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - value: PropTypes.string.isRequired - }) - ).isRequired, + fields: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, options: PropTypes.shape({ - errors: PropTypes.objectOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(null)]) - ), ignored: PropTypes.arrayOf(PropTypes.string), placeholder: PropTypes.bool, required: PropTypes.arrayOf(PropTypes.string), @@ -31,7 +22,7 @@ const propTypes = { }; function FormFields(props) { - const { errors = {}, fields, options = {} } = props; + const { fields, options = {} } = props; const { ignored = [], placeholder = true, @@ -40,38 +31,43 @@ function FormFields(props) { } = options; return (
- {Object.keys(fields) + {fields .filter(field => !ignored.includes(field)) - .map(key => fields[key]) - .map(({ name, onChange, value, pristine }) => { - const key = kebabCase(name); - const type = name in types ? types[name] : 'text'; - return ( - - - {type === 'hidden' ? null : ( - {startCase(name)} - )} - - {name in errors && !pristine ? ( - - {errors[name]} - - ) : null} - - - ); - })} + .map(name => ( + + {({ input: { value, onChange }, meta: { pristine, error } }) => { + const key = kebabCase(name); + const type = name in types ? types[name] : 'text'; + return ( + + + {type === 'hidden' ? null : ( + + {startCase(name)} + + )} + + {error && !pristine ? ( + + {error} + + ) : null} + + + ); + }} + + ))}
); } diff --git a/client/src/components/formHelpers/__snapshots__/Form.test.js.snap b/client/src/components/formHelpers/__snapshots__/Form.test.js.snap deleted file mode 100644 index e315158b47..0000000000 --- a/client/src/components/formHelpers/__snapshots__/Form.test.js.snap +++ /dev/null @@ -1,55 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` snapshot 1`] = ` - -
-
-
- - -
-
-
-
- -
- -`; diff --git a/client/src/components/formHelpers/index.js b/client/src/components/formHelpers/index.js index 52c5b07b9b..9f4d8ccf11 100644 --- a/client/src/components/formHelpers/index.js +++ b/client/src/components/formHelpers/index.js @@ -18,7 +18,7 @@ export function callIfDefined(fn) { export function formatUrlValues(values, options) { return Object.keys(values).reduce((result, key) => { let value = values[key]; - if (options.types[key] === 'url') { + if (value && options.types[key] === 'url') { value = normalizeUrl(value, normalizeOptions); } return { ...result, [key]: value }; diff --git a/client/src/redux/rootReducer.js b/client/src/redux/rootReducer.js index 656547e918..961cf4a91e 100644 --- a/client/src/redux/rootReducer.js +++ b/client/src/redux/rootReducer.js @@ -1,5 +1,4 @@ import { combineReducers } from 'redux'; -import { reducer as formReducer } from 'redux-form'; import { reducer as app, ns as appNameSpace } from './'; import { @@ -25,7 +24,6 @@ export default combineReducers({ [challengeNameSpace]: challenge, [curriculumMapNameSpace]: curriculumMap, [flashNameSpace]: flash, - form: formReducer, [searchNameSpace]: search, [settingsNameSpace]: settings }); diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index 16e9e2cef2..6076fcd4a4 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -1,5 +1,4 @@ import { createAction, handleActions } from 'redux-actions'; -import { reducer as reduxFormReducer } from 'redux-form'; import { createTypes } from '../../../../utils/stateManagement'; @@ -353,24 +352,3 @@ export const reducer = handleActions( }, initialState ); - -const resetProjectFormValues = handleActions( - { - [types.updateProjectFormValues]: (state, { payload: { solution } }) => { - if (!solution) { - return { - ...state, - solution: {}, - githubLink: {} - }; - } - return state; - } - }, - {} -); - -export const formReducer = reduxFormReducer.plugin({ - 'frond-end-form': resetProjectFormValues, - 'back-end-form': resetProjectFormValues -});