Entony 5 年之前
父節點
當前提交
dd6159d21e

+ 39 - 0
package-lock.json

@@ -4532,6 +4532,11 @@
         "is-symbol": "^1.0.2"
       }
     },
+    "es6-error": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="
+    },
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -6197,6 +6202,12 @@
       "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
       "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg=="
     },
+    "immutable": {
+      "version": "3.8.2",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz",
+      "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=",
+      "optional": true
+    },
     "import-cwd": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@@ -8003,6 +8014,11 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
       "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
     },
+    "lodash-es": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
+      "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+    },
     "lodash._reinterpolate": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -10610,6 +10626,11 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
       "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
     },
+    "react-lifecycles-compat": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+      "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+    },
     "react-redux": {
       "version": "7.1.0",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.1.0.tgz",
@@ -10816,6 +10837,24 @@
         "symbol-observable": "^1.2.0"
       }
     },
+    "redux-form": {
+      "version": "8.2.6",
+      "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-8.2.6.tgz",
+      "integrity": "sha512-krmF7wl1C753BYpEpWIVJ5NM4lUJZFZc5GFUVgblT+jprB99VVBDyBcgrZM3gWWLOcncFyNsHcKNQQcFg8Uanw==",
+      "requires": {
+        "@babel/runtime": "^7.2.0",
+        "es6-error": "^4.1.1",
+        "hoist-non-react-statics": "^3.2.1",
+        "immutable": "*",
+        "invariant": "^2.2.4",
+        "is-promise": "^2.1.0",
+        "lodash": "^4.17.15",
+        "lodash-es": "^4.17.15",
+        "prop-types": "^15.6.1",
+        "react-is": "^16.7.0",
+        "react-lifecycles-compat": "^3.0.4"
+      }
+    },
     "redux-logger": {
       "version": "3.0.6",
       "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "react-router-dom": "^5.0.1",
     "react-scripts": "3.0.1",
     "redux": "^4.0.4",
+    "redux-form": "^8.2.6",
     "redux-logger": "^3.0.6",
     "redux-saga": "^1.0.5",
     "redux-thunk": "^2.3.0"

+ 2 - 0
src/actionTypes/index.js

@@ -32,3 +32,5 @@ export const REGISTRATION_REQUEST_FAIL = "REGISTRATION_REQUEST_FAIL";
 export const GET_USER_BY_ID = "GET_USER_BY_ID";
 export const GET_USER_BY_ID_SUCCESS = "GET_USER_BY_ID_SUCCESS";
 export const GET_USER_BY_ID_FAIL = "GET_USER_BY_ID_FAIL";
+
+export const SET_INITIAL_VALUES_REDUX_FORM = "SET_INITIAL_VALUES_REDUX_FORM";

+ 6 - 1
src/actions/todo.js

@@ -1,6 +1,6 @@
 import * as types from "../actionTypes";
 import axios from "axios";
-import rmFFromObject from "../utils/rmPropFromObject";
+// import rmFFromObject from "../utils/rmPropFromObject";
 
 export const addItem = () => {
 	return {
@@ -157,3 +157,8 @@ export const setInitialValue = payload => ({
 	type: types.SET_INITIAL_VALUES,
 	payload
 });
+
+export const setInitialValueReduxForm = payload => ({
+	type: types.SET_INITIAL_VALUES_REDUX_FORM,
+	payload
+});

+ 39 - 0
src/components/form-elements/index.js

@@ -0,0 +1,39 @@
+import React from "react";
+
+export const renderField = ({
+	input: { ...inputProps },
+	meta: { touched, error, ...rest },
+	label,
+	type = "text"
+}) => {
+	return (
+		<div>
+			{label && <label>{label}</label>}
+			<div>
+				<input type={type} {...inputProps} />
+				{touched && error && <span>{error}</span>}
+			</div>
+		</div>
+	);
+};
+
+export const renderSelect = ({
+	input: { ...inputProps },
+	meta: { touched, error, ...rest },
+	label,
+	option
+}) => {
+	return (
+		<div>
+			{label && <label>{label}</label>}
+			<select {...inputProps}>
+				{option.map(el => (
+					<option key={el.value} value={el.value}>
+						{el.title}
+					</option>
+				))}
+			</select>
+			{touched && error && <span>{error}</span>}
+		</div>
+	);
+};

+ 3 - 3
src/components/header/index.js

@@ -25,9 +25,9 @@ class Header extends React.Component {
 
 	togglePortal = () => this.setState(prevState => ({ modal: !prevState.modal }));
 
-	componentDidMount() {
-		console.log("componentDidMount HEADER", this.context);
-	}
+	// componentDidMount() {
+	// 	console.log("componentDidMount HEADER", this.context);
+	// }
 
 	logIn = () =>
 		new Promise(resolve => {

+ 1 - 1
src/components/layout/index.js

@@ -22,7 +22,7 @@ class Layout extends React.Component {
 	// }
 
 	async componentDidMount() {
-		console.log("componentDidMount", this.state);
+		// console.log("componentDidMount", this.state);
 		fetch("https://jsonplaceholder.typicode.com/todos/1")
 			.then(response => response.json())
 			.then(json => this.setState({ user: json }));

+ 1 - 1
src/components/menu/index.js

@@ -15,7 +15,7 @@ export default class Menu extends Component {
 				i am nemu component
 				<div className="main__list-wrapper">
 					{posts.map(post => (
-						<div className="main__list-item">
+						<div key={post.id} className="main__list-item">
 							<h4 className="main__item-title">
 								<Link to={`/item/${post.id}`}>{post.title}</Link>
 							</h4>

+ 58 - 0
src/components/redux-form/index.js

@@ -0,0 +1,58 @@
+import React from "react";
+import { reduxForm, Field } from "redux-form";
+
+import { renderField, renderSelect } from "../form-elements";
+import { validate } from "../../utils/validation";
+
+const OPTIONS = [
+	{
+		value: "male",
+		title: "Male"
+	},
+	{
+		value: "female",
+		title: "Female"
+	}
+];
+
+const Form = props => {
+	const { handleSubmit, mock, setInitialValueReduxForm, reset } = props;
+
+	const submit = values => console.log(values);
+
+	console.log("props", props);
+	return (
+		<div>
+			<form onSubmit={handleSubmit(submit)}>
+				<Field name="name" component={renderField} />
+				<Field name="age" type="number" component={renderField} />
+				<Field name="sex" option={OPTIONS} component={renderSelect} />
+
+				<button>Submit</button>
+				{/* <button onClick={reset} type="button">
+					Clear
+				</button> */}
+			</form>
+
+			<div>
+				{mock.map(el => (
+					<div key={el.id}>
+						<h3>{el.name}</h3>
+						<h5>{el.age}</h5>
+						<p>{el.sex}</p>
+
+						<button onClick={setInitialValueReduxForm.bind(null, el.id)} type="button">
+							Edit
+						</button>
+					</div>
+				))}
+			</div>
+		</div>
+	);
+};
+
+export default reduxForm({
+	form: "todo",
+	validate: (values, props) => validate(values),
+	enableReinitialize: true
+})(Form);

+ 2 - 2
src/containers/main.js

@@ -33,7 +33,7 @@ class Main extends Component {
 		const params = new URLSearchParams(this.props.location.search);
 
 		params.forEach(el => console.log("el", el));
-		console.log("params/", params.get("name"));
+		// console.log("params/", params.get("name"));
 
 		const request = await fetch("https://jsonplaceholder.typicode.com/posts");
 		const json = await request.json();
@@ -69,7 +69,7 @@ class Main extends Component {
 	render() {
 		const { posts, post, loading } = this.state;
 
-		console.log("this", this.props);
+		// console.log("this", this.props);
 
 		return (
 			<>

+ 29 - 0
src/containers/redux-form.js

@@ -0,0 +1,29 @@
+import React, { Component } from "react";
+import { reset } from "redux-form";
+import { connect } from "react-redux";
+import { setInitialValueReduxForm } from "../actions/todo";
+
+import Form from "../components/redux-form";
+
+class ReduxForm extends Component {
+	render() {
+		const { mock, initialValues, setInitialValueReduxForm, reset } = this.props;
+		return (
+			<div>
+				ReduxForm
+				<button onClick={() => reset("todo")}>Clear</button>
+				<Form mock={mock} initialValues={initialValues} setInitialValueReduxForm={setInitialValueReduxForm} />
+			</div>
+		);
+	}
+}
+
+const mapStateToProps = state => ({
+	mock: state.todo.MOCK,
+	initialValues: state.todo.initialValues
+});
+
+export default connect(
+	mapStateToProps,
+	{ setInitialValueReduxForm, reset }
+)(ReduxForm);

+ 0 - 1
src/containers/todoRedux.js

@@ -33,7 +33,6 @@ export class TodoRedux extends Component {
 
 	render() {
 		const { name, updateName, addItem, list, removeItem, editMode, setItemToUpdate } = this.props;
-		console.log("this.props", this.props);
 		return (
 			<div>
 				<div>

+ 1 - 1
src/reducers/auth.js

@@ -17,7 +17,7 @@ export default (state = initialState, { type, payload }) => {
 		}
 
 		case types.GET_USER_BY_ID: {
-			console.log("GET_USER_BY_ID, REDUCER");
+			// console.log("GET_USER_BY_ID, REDUCER");
 			return { ...state, isFetching: false };
 		}
 

+ 2 - 0
src/reducers/index.js

@@ -1,9 +1,11 @@
 import { combineReducers } from "redux";
+import { reducer as formReducer } from "redux-form";
 
 import todo from "./todo";
 import auth from "./auth";
 
 export default combineReducers({
+	form: formReducer,
 	todo,
 	auth
 });

+ 49 - 1
src/reducers/todo.js

@@ -1,5 +1,26 @@
 import * as types from "../actionTypes";
 
+const MOCK = [
+	{
+		id: 1,
+		name: "Tony",
+		age: 23,
+		sex: "male"
+	},
+	{
+		id: 2,
+		name: "John",
+		age: 33,
+		sex: "male"
+	},
+	{
+		id: 3,
+		name: "Monika",
+		age: 23,
+		sex: "female"
+	}
+];
+
 const initilalState = {
 	list: [],
 	item: {
@@ -10,7 +31,10 @@ const initilalState = {
 	remoteTodo: { fistName: "", lastName: "", age: "", editable: false },
 	remoteList: [],
 	removeId: "",
-	updateId: ""
+	updateId: "",
+	MOCK,
+	initialValues: {},
+	updatedValues: {}
 };
 
 export default (state = initilalState, action) => {
@@ -170,6 +194,30 @@ export default (state = initilalState, action) => {
 			};
 		}
 
+		case "@@redux-form/CHANGE": {
+			const { meta, payload } = action;
+			if (meta.form === "todo") {
+				return {
+					...state,
+					updatedValues: {
+						...state.updatedValues,
+						[meta.field]: payload
+					}
+				};
+			}
+			console.log("action", action);
+			return state;
+		}
+
+		case types.SET_INITIAL_VALUES_REDUX_FORM: {
+			const { payload } = action;
+
+			return {
+				...state,
+				initialValues: state.MOCK.find(el => el.id === payload)
+			};
+		}
+
 		default: {
 			return state;
 		}

+ 13 - 0
src/router.js

@@ -10,6 +10,7 @@ import Todo from "./containers/todo";
 import Auth from "./containers/auth";
 import TodoRedux from "./containers/todoRedux";
 import ThunkTodo from "./containers/thunkTodo";
+import ReduxForm from "./containers/redux-form";
 import { Hooks } from "./containers/hooks";
 
 import { LocalContext, setLanguage } from "./utils/localContext";
@@ -68,6 +69,18 @@ export const ROUTERS = [
 		protected: false,
 		component: Todo
 	},
+	{
+		id: 10,
+		link: {
+			path: "/redux-form",
+			title: "Redux Form"
+		},
+		hasAccess: [0, 1],
+		exact: true,
+		path: "/redux-form",
+		protected: false,
+		component: ReduxForm
+	},
 	{
 		id: 5,
 		link: {

+ 1 - 1
src/sagas/user.js

@@ -7,7 +7,7 @@ import axios from "axios";
 const userUrl = "http://subdomain.entony.fs.a-level.com.ua/api/users/";
 
 function* getUserById({ payload }) {
-	console.log("USERS TYPES SAGA");
+	// console.log("USERS TYPES SAGA");
 	try {
 		const { data } = yield call(axios, {
 			method: "GET",

+ 15 - 0
src/utils/validation.js

@@ -0,0 +1,15 @@
+export const validate = ({ firstName, lastName }) => {
+	const errors = {};
+
+	if (!firstName) {
+		errors.firstName = "Required";
+	}
+
+	if (!lastName) {
+		errors.lastName = "Required";
+	} else if (lastName.lenght > 10) {
+		errors.lastName = "Should be more than 10";
+	}
+
+	return errors;
+};