feat(client): use React Final Form instead of Redux Form (#36742)
This commit is contained in:
209
client/package-lock.json
generated
209
client/package-lock.json
generated
@@ -2018,16 +2018,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@testing-library/dom": {
|
"@testing-library/dom": {
|
||||||
"version": "5.6.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.1.0.tgz",
|
||||||
"integrity": "sha512-nAsRvQLr/b6TGNjuHMEbWXCNPLrQYnzqa/KKQZL7wBOtfptUxsa4Ah9aqkHW0ZmCSFmUDj4nFUxWPVTeMu0iCw==",
|
"integrity": "sha512-qivqFvnbVIH3DyArFofEU/jlOhkGIioIemOy9A9M/NQTpPyDDQmtVkAfoB18RKN581f0s/RJMRBbq9WfMIhFTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.4.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"@sheerun/mutationobserver-shim": "^0.3.2",
|
"@sheerun/mutationobserver-shim": "^0.3.2",
|
||||||
|
"@types/testing-library__dom": "^6.0.0",
|
||||||
"aria-query": "3.0.0",
|
"aria-query": "3.0.0",
|
||||||
"pretty-format": "^24.8.0",
|
"pretty-format": "^24.8.0",
|
||||||
"wait-for-expect": "^1.2.0"
|
"wait-for-expect": "^1.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
@@ -2047,14 +2048,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@testing-library/react": {
|
"@testing-library/jest-dom": {
|
||||||
"version": "8.0.5",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-8.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-4.1.0.tgz",
|
||||||
"integrity": "sha512-2EzVi7HjUUF8gKzB4s+oCJ1+F4VOrphO+DlUO6Ptgtcz1ko4J2zqnr0t7g+T7uedXXjJ0wdq70zQMhJXP3w37A==",
|
"integrity": "sha512-cKAONDmJKGJ2DSu6R/+lgA8i8uyZIx4CaOiiK0yMjp+2UecH6kfjunJiy5hfExKMtR74eyzFriqO1w9aTC8VyQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.5.4",
|
"@babel/runtime": "^7.5.1",
|
||||||
"@testing-library/dom": "^5.5.4"
|
"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": {
|
"dependencies": {
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
@@ -2195,6 +2256,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.12.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.12.2.tgz",
|
||||||
"integrity": "sha512-c82MtnqWB/CqqK7/zit74Ob8H1dBdV7bK+BcErwtXbe0+nUGkgzq5NTDmRW/pAv2lFtmeNmW95b0zK2hxpeklg=="
|
"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": {
|
"@types/prop-types": {
|
||||||
"version": "15.5.5",
|
"version": "15.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
|
||||||
@@ -2226,6 +2293,15 @@
|
|||||||
"csstype": "^2.2.0"
|
"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": {
|
"@types/stack-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz",
|
||||||
"integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ=="
|
"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": {
|
"@types/tmp": {
|
||||||
"version": "0.0.32",
|
"version": "0.0.32",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.32.tgz",
|
"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": {
|
"finalhandler": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
@@ -13788,6 +13906,12 @@
|
|||||||
"dom-walk": "^0.1.0"
|
"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": {
|
"mini-css-extract-plugin": {
|
||||||
"version": "0.4.5",
|
"version": "0.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
"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": {
|
"react-ga": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.6.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.2.tgz",
|
||||||
"integrity": "sha512-rI3cGFj/obHbBz156PvErrS5xc6f1eWyTwyV4mo0vF2lGgXgS+mm7EKD5buLJq6jNgIagQescGSVG2YzgXt8Yg=="
|
"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": {
|
"react-lifecycles-compat": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz",
|
||||||
"integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg=="
|
"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": {
|
"redux-observable": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/redux-observable/-/redux-observable-1.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz",
|
||||||
"integrity": "sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q=="
|
"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": {
|
"ts-pnp": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz",
|
||||||
@@ -20098,9 +20223,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wait-for-expect": {
|
"wait-for-expect": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.3.0.tgz",
|
||||||
"integrity": "sha512-EJhKpA+5UHixduMBEGhTFuLuVgQBKWxkFbefOdj2bbk2/OpA5Opsc4aUTGmF+qJ+v3kTGxDRNYwKaT4j6g5n8Q==",
|
"integrity": "sha512-8fJU7jiA96HfGPt+P/UilelSAZfhMBJ52YhKzlmZQvKEZU2EcD1GQ0yqGB6liLdHjYtYAoGVigYwdxr5rktvzA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"walker": {
|
"walker": {
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
"entities": "^1.1.2",
|
"entities": "^1.1.2",
|
||||||
"enzyme": "^3.10.0",
|
"enzyme": "^3.10.0",
|
||||||
"enzyme-adapter-react-16": "^1.14.0",
|
"enzyme-adapter-react-16": "^1.14.0",
|
||||||
|
"final-form": "^4.18.5",
|
||||||
"gatsby": "^2.13.67",
|
"gatsby": "^2.13.67",
|
||||||
"gatsby-cli": "^2.7.31",
|
"gatsby-cli": "^2.7.31",
|
||||||
"gatsby-link": "^2.2.5",
|
"gatsby-link": "^2.2.5",
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
"react": "^16.9.0",
|
"react": "^16.9.0",
|
||||||
"react-calendar-heatmap": "^1.8.1",
|
"react-calendar-heatmap": "^1.8.1",
|
||||||
"react-dom": "^16.9.0",
|
"react-dom": "^16.9.0",
|
||||||
|
"react-final-form": "^6.3.0",
|
||||||
"react-ga": "^2.6.0",
|
"react-ga": "^2.6.0",
|
||||||
"react-helmet": "^5.2.1",
|
"react-helmet": "^5.2.1",
|
||||||
"react-identicons": "^1.1.7",
|
"react-identicons": "^1.1.7",
|
||||||
@@ -64,7 +66,6 @@
|
|||||||
"redux": "^4.0.4",
|
"redux": "^4.0.4",
|
||||||
"redux-actions": "^2.6.5",
|
"redux-actions": "^2.6.5",
|
||||||
"redux-devtools-extension": "^2.13.8",
|
"redux-devtools-extension": "^2.13.8",
|
||||||
"redux-form": "^5.3.6",
|
|
||||||
"redux-observable": "^1.1.0",
|
"redux-observable": "^1.1.0",
|
||||||
"redux-saga": "^1.0.5",
|
"redux-saga": "^1.0.5",
|
||||||
"reselect": "^3.0.1",
|
"reselect": "^3.0.1",
|
||||||
@@ -92,7 +93,8 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/react": "^8.0.5",
|
"@testing-library/jest-dom": "^4.1.0",
|
||||||
|
"@testing-library/react": "^9.1.3",
|
||||||
"autoprefixer": "^9.6.1",
|
"autoprefixer": "^9.6.1",
|
||||||
"babel-plugin-transform-imports": "^1.5.1",
|
"babel-plugin-transform-imports": "^1.5.1",
|
||||||
"chokidar": "^2.1.5",
|
"chokidar": "^2.1.5",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { reduxForm } from 'redux-form';
|
import { Form } from 'react-final-form';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormFields,
|
FormFields,
|
||||||
@@ -12,16 +12,7 @@ import {
|
|||||||
const propTypes = {
|
const propTypes = {
|
||||||
buttonText: PropTypes.string,
|
buttonText: PropTypes.string,
|
||||||
enableSubmit: PropTypes.bool,
|
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,
|
formFields: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
handleSubmit: PropTypes.func,
|
|
||||||
hideButton: PropTypes.bool,
|
hideButton: PropTypes.bool,
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
initialValues: PropTypes.object,
|
initialValues: PropTypes.object,
|
||||||
@@ -33,67 +24,44 @@ const propTypes = {
|
|||||||
submit: PropTypes.func.isRequired
|
submit: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export function DynamicForm({
|
function DynamicForm({
|
||||||
// redux-form
|
id,
|
||||||
errors,
|
formFields,
|
||||||
fields,
|
initialValues,
|
||||||
handleSubmit,
|
options,
|
||||||
fields: {
|
submit,
|
||||||
// eslint-disable-next-line react/prop-types
|
|
||||||
_meta: { allPristine }
|
|
||||||
},
|
|
||||||
|
|
||||||
// HOC
|
|
||||||
buttonText,
|
buttonText,
|
||||||
enableSubmit,
|
enableSubmit,
|
||||||
hideButton,
|
hideButton
|
||||||
id,
|
|
||||||
options,
|
|
||||||
submit
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<form
|
<Form
|
||||||
id={`dynamic-${id}`}
|
initialValues={initialValues}
|
||||||
onSubmit={handleSubmit((values, ...args) =>
|
onSubmit={(values, ...args) =>
|
||||||
submit(formatUrlValues(values, options), ...args)
|
submit(formatUrlValues(values, options), ...args)
|
||||||
)}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
>
|
|
||||||
<FormFields
|
|
||||||
errors={errors}
|
|
||||||
fields={fields}
|
|
||||||
formId={id}
|
|
||||||
options={options}
|
|
||||||
/>
|
|
||||||
<BlockSaveWrapper>
|
|
||||||
{hideButton ? null : (
|
|
||||||
<BlockSaveButton
|
|
||||||
disabled={
|
|
||||||
(allPristine && !enableSubmit) ||
|
|
||||||
!!Object.keys(errors).filter(key => errors[key]).length
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{({ handleSubmit, pristine, error }) => (
|
||||||
|
<form
|
||||||
|
id={`dynamic-${id}`}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<FormFields fields={formFields} options={options} />
|
||||||
|
<BlockSaveWrapper>
|
||||||
|
{hideButton ? null : (
|
||||||
|
<BlockSaveButton disabled={(pristine && !enableSubmit) || error}>
|
||||||
{buttonText ? buttonText : null}
|
{buttonText ? buttonText : null}
|
||||||
</BlockSaveButton>
|
</BlockSaveButton>
|
||||||
)}
|
)}
|
||||||
</BlockSaveWrapper>
|
</BlockSaveWrapper>
|
||||||
</form>
|
</form>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicForm.displayName = 'DynamicForm';
|
DynamicForm.displayName = 'DynamicForm';
|
||||||
DynamicForm.propTypes = propTypes;
|
DynamicForm.propTypes = propTypes;
|
||||||
|
|
||||||
const DynamicFormWithRedux = reduxForm()(DynamicForm);
|
export default DynamicForm;
|
||||||
|
|
||||||
export default function Form(props) {
|
|
||||||
return (
|
|
||||||
<DynamicFormWithRedux
|
|
||||||
{...props}
|
|
||||||
fields={props.formFields}
|
|
||||||
form={props.id}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Form.propTypes = propTypes;
|
|
||||||
|
@@ -1,30 +1,14 @@
|
|||||||
/* global expect */
|
/* global jest, expect */
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import { render, fireEvent } from '@testing-library/react';
|
||||||
import Enzyme from 'enzyme';
|
|
||||||
import Adapter from 'enzyme-adapter-react-16';
|
|
||||||
|
|
||||||
import { DynamicForm } from './Form';
|
import Form from './Form';
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
|
||||||
|
|
||||||
const defaultTestProps = {
|
const defaultTestProps = {
|
||||||
errors: {},
|
|
||||||
fields: {
|
|
||||||
_meta: {
|
|
||||||
allPristine: true,
|
|
||||||
name: 'name',
|
|
||||||
onChange: () => {},
|
|
||||||
value: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit: () => {},
|
|
||||||
|
|
||||||
buttonText: 'Submit',
|
buttonText: 'Submit',
|
||||||
enableSubmit: true,
|
|
||||||
formFields: ['name', 'website'],
|
formFields: ['name', 'website'],
|
||||||
hideButton: false,
|
|
||||||
id: 'my-test-form',
|
id: 'my-test-form',
|
||||||
options: {
|
options: {
|
||||||
types: {
|
types: {
|
||||||
@@ -36,8 +20,69 @@ const defaultTestProps = {
|
|||||||
submit: () => {}
|
submit: () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
test('<DynamicForm /> snapshot', () => {
|
test('should render', () => {
|
||||||
const component = renderer.create(<DynamicForm {...defaultTestProps} />);
|
const { getByLabelText, getByText } = render(<Form {...defaultTestProps} />);
|
||||||
let tree = component.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
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(
|
||||||
|
<Form
|
||||||
|
{...defaultTestProps}
|
||||||
|
enableSubmit={true}
|
||||||
|
initialValues={{ name: nameValue, website: websiteValue }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
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(<Form {...props} />);
|
||||||
|
|
||||||
|
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 });
|
||||||
});
|
});
|
||||||
|
@@ -9,20 +9,11 @@ import {
|
|||||||
FormGroup,
|
FormGroup,
|
||||||
HelpBlock
|
HelpBlock
|
||||||
} from '@freecodecamp/react-bootstrap';
|
} from '@freecodecamp/react-bootstrap';
|
||||||
|
import { Field } from 'react-final-form';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
errors: PropTypes.objectOf(PropTypes.string),
|
fields: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
|
||||||
fields: PropTypes.objectOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
value: PropTypes.string.isRequired
|
|
||||||
})
|
|
||||||
).isRequired,
|
|
||||||
options: PropTypes.shape({
|
options: PropTypes.shape({
|
||||||
errors: PropTypes.objectOf(
|
|
||||||
PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(null)])
|
|
||||||
),
|
|
||||||
ignored: PropTypes.arrayOf(PropTypes.string),
|
ignored: PropTypes.arrayOf(PropTypes.string),
|
||||||
placeholder: PropTypes.bool,
|
placeholder: PropTypes.bool,
|
||||||
required: PropTypes.arrayOf(PropTypes.string),
|
required: PropTypes.arrayOf(PropTypes.string),
|
||||||
@@ -31,7 +22,7 @@ const propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function FormFields(props) {
|
function FormFields(props) {
|
||||||
const { errors = {}, fields, options = {} } = props;
|
const { fields, options = {} } = props;
|
||||||
const {
|
const {
|
||||||
ignored = [],
|
ignored = [],
|
||||||
placeholder = true,
|
placeholder = true,
|
||||||
@@ -40,17 +31,20 @@ function FormFields(props) {
|
|||||||
} = options;
|
} = options;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{Object.keys(fields)
|
{fields
|
||||||
.filter(field => !ignored.includes(field))
|
.filter(field => !ignored.includes(field))
|
||||||
.map(key => fields[key])
|
.map(name => (
|
||||||
.map(({ name, onChange, value, pristine }) => {
|
<Field key={`${name}-field`} name={name}>
|
||||||
|
{({ input: { value, onChange }, meta: { pristine, error } }) => {
|
||||||
const key = kebabCase(name);
|
const key = kebabCase(name);
|
||||||
const type = name in types ? types[name] : 'text';
|
const type = name in types ? types[name] : 'text';
|
||||||
return (
|
return (
|
||||||
<Col key={key} xs={12}>
|
<Col key={key} xs={12}>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
{type === 'hidden' ? null : (
|
{type === 'hidden' ? null : (
|
||||||
<ControlLabel htmlFor={key}>{startCase(name)}</ControlLabel>
|
<ControlLabel htmlFor={key}>
|
||||||
|
{startCase(name)}
|
||||||
|
</ControlLabel>
|
||||||
)}
|
)}
|
||||||
<FormControl
|
<FormControl
|
||||||
componentClass={type === 'textarea' ? type : 'input'}
|
componentClass={type === 'textarea' ? type : 'input'}
|
||||||
@@ -63,15 +57,17 @@ function FormFields(props) {
|
|||||||
type={type}
|
type={type}
|
||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
{name in errors && !pristine ? (
|
{error && !pristine ? (
|
||||||
<HelpBlock>
|
<HelpBlock>
|
||||||
<Alert bsStyle='danger'>{errors[name]}</Alert>
|
<Alert bsStyle='danger'>{error}</Alert>
|
||||||
</HelpBlock>
|
</HelpBlock>
|
||||||
) : null}
|
) : null}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
})}
|
}}
|
||||||
|
</Field>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<DynamicForm /> snapshot 1`] = `
|
|
||||||
<form
|
|
||||||
id="dynamic-my-test-form"
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"width": "100%",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="col-xs-12"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="form-group"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
className="control-label"
|
|
||||||
htmlFor="name"
|
|
||||||
>
|
|
||||||
Name
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="form-control"
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
onChange={[Function]}
|
|
||||||
placeholder="name"
|
|
||||||
required={false}
|
|
||||||
rows={4}
|
|
||||||
type="text"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"padding": "0 15px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary btn-block"
|
|
||||||
disabled={false}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
`;
|
|
@@ -18,7 +18,7 @@ export function callIfDefined(fn) {
|
|||||||
export function formatUrlValues(values, options) {
|
export function formatUrlValues(values, options) {
|
||||||
return Object.keys(values).reduce((result, key) => {
|
return Object.keys(values).reduce((result, key) => {
|
||||||
let value = values[key];
|
let value = values[key];
|
||||||
if (options.types[key] === 'url') {
|
if (value && options.types[key] === 'url') {
|
||||||
value = normalizeUrl(value, normalizeOptions);
|
value = normalizeUrl(value, normalizeOptions);
|
||||||
}
|
}
|
||||||
return { ...result, [key]: value };
|
return { ...result, [key]: value };
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import { reducer as formReducer } from 'redux-form';
|
|
||||||
|
|
||||||
import { reducer as app, ns as appNameSpace } from './';
|
import { reducer as app, ns as appNameSpace } from './';
|
||||||
import {
|
import {
|
||||||
@@ -25,7 +24,6 @@ export default combineReducers({
|
|||||||
[challengeNameSpace]: challenge,
|
[challengeNameSpace]: challenge,
|
||||||
[curriculumMapNameSpace]: curriculumMap,
|
[curriculumMapNameSpace]: curriculumMap,
|
||||||
[flashNameSpace]: flash,
|
[flashNameSpace]: flash,
|
||||||
form: formReducer,
|
|
||||||
[searchNameSpace]: search,
|
[searchNameSpace]: search,
|
||||||
[settingsNameSpace]: settings
|
[settingsNameSpace]: settings
|
||||||
});
|
});
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
import { reducer as reduxFormReducer } from 'redux-form';
|
|
||||||
|
|
||||||
import { createTypes } from '../../../../utils/stateManagement';
|
import { createTypes } from '../../../../utils/stateManagement';
|
||||||
|
|
||||||
@@ -353,24 +352,3 @@ export const reducer = handleActions(
|
|||||||
},
|
},
|
||||||
initialState
|
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
|
|
||||||
});
|
|
||||||
|
Reference in New Issue
Block a user