11 changed files with 15532 additions and 0 deletions
@ -0,0 +1,23 @@ |
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |
||||||
|
|
||||||
|
# dependencies |
||||||
|
/node_modules |
||||||
|
/.pnp |
||||||
|
.pnp.js |
||||||
|
|
||||||
|
# testing |
||||||
|
/coverage |
||||||
|
|
||||||
|
# production |
||||||
|
/build |
||||||
|
|
||||||
|
# misc |
||||||
|
.DS_Store |
||||||
|
.env.local |
||||||
|
.env.development.local |
||||||
|
.env.test.local |
||||||
|
.env.production.local |
||||||
|
|
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
{ |
||||||
|
"name": "enhanced-reducer", |
||||||
|
"version": "0.1.0", |
||||||
|
"private": true, |
||||||
|
"dependencies": { |
||||||
|
"@testing-library/jest-dom": "^4.2.4", |
||||||
|
"@testing-library/react": "^9.5.0", |
||||||
|
"@testing-library/user-event": "^7.2.1", |
||||||
|
"react": "^16.13.1", |
||||||
|
"react-dom": "^16.13.1", |
||||||
|
"react-scripts": "3.4.1", |
||||||
|
"bootstrap": "4.4.1" |
||||||
|
}, |
||||||
|
"scripts": { |
||||||
|
"start": "react-scripts start", |
||||||
|
"build": "react-scripts build", |
||||||
|
"test": "react-scripts test", |
||||||
|
"eject": "react-scripts eject" |
||||||
|
}, |
||||||
|
"eslintConfig": { |
||||||
|
"extends": "react-app" |
||||||
|
}, |
||||||
|
"browserslist": { |
||||||
|
"production": [ |
||||||
|
">0.2%", |
||||||
|
"not dead", |
||||||
|
"not op_mini all" |
||||||
|
], |
||||||
|
"development": [ |
||||||
|
"last 1 chrome version", |
||||||
|
"last 1 firefox version", |
||||||
|
"last 1 safari version" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,43 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
||||||
|
<meta name="theme-color" content="#000000" /> |
||||||
|
<meta |
||||||
|
name="description" |
||||||
|
content="Web site created using create-react-app" |
||||||
|
/> |
||||||
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> |
||||||
|
<!-- |
||||||
|
manifest.json provides metadata used when your web app is installed on a |
||||||
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ |
||||||
|
--> |
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |
||||||
|
<!-- |
||||||
|
Notice the use of %PUBLIC_URL% in the tags above. |
||||||
|
It will be replaced with the URL of the `public` folder during the build. |
||||||
|
Only files inside the `public` folder can be referenced from the HTML. |
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will |
||||||
|
work correctly both with client-side routing and a non-root public URL. |
||||||
|
Learn how to configure a non-root public URL by running `npm run build`. |
||||||
|
--> |
||||||
|
<title>React App</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript> |
||||||
|
<div id="root"></div> |
||||||
|
<!-- |
||||||
|
This HTML file is a template. |
||||||
|
If you open it directly in the browser, you will see an empty page. |
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file. |
||||||
|
The build step will place the bundled scripts into the <body> tag. |
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`. |
||||||
|
To create a production bundle, use `npm run build` or `yarn build`. |
||||||
|
--> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"short_name": "React App", |
||||||
|
"name": "Create React App Sample", |
||||||
|
"icons": [ |
||||||
|
{ |
||||||
|
"src": "favicon.ico", |
||||||
|
"sizes": "64x64 32x32 24x24 16x16", |
||||||
|
"type": "image/x-icon" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"src": "logo192.png", |
||||||
|
"type": "image/png", |
||||||
|
"sizes": "192x192" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"src": "logo512.png", |
||||||
|
"type": "image/png", |
||||||
|
"sizes": "512x512" |
||||||
|
} |
||||||
|
], |
||||||
|
"start_url": ".", |
||||||
|
"display": "standalone", |
||||||
|
"theme_color": "#000000", |
||||||
|
"background_color": "#ffffff" |
||||||
|
} |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# https://www.robotstxt.org/robotstxt.html |
||||||
|
User-agent: * |
||||||
|
Disallow: |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
body { |
||||||
|
margin: 0; |
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', |
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', |
||||||
|
sans-serif; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
} |
||||||
|
|
||||||
|
code { |
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', |
||||||
|
monospace; |
||||||
|
} |
||||||
@ -0,0 +1,141 @@ |
|||||||
|
import * as React from "react"; |
||||||
|
import { render } from "react-dom"; |
||||||
|
import produce from "immer"; |
||||||
|
import { set, has } from "lodash"; |
||||||
|
import "bootstrap/dist/css/bootstrap.css"; |
||||||
|
|
||||||
|
function enhancedReducer(state, updateArg) { |
||||||
|
// check if the type of update argument is a callback function
|
||||||
|
if (updateArg.constructor === Function) { |
||||||
|
return { ...state, ...updateArg(state) }; |
||||||
|
} |
||||||
|
|
||||||
|
// if the type of update argument is an object
|
||||||
|
if (updateArg.constructor === Object) { |
||||||
|
// does the update object have _path and _value as it's keys
|
||||||
|
// if yes then use them to update deep object values
|
||||||
|
if (has(updateArg, "_path") && has(updateArg, "_value")) { |
||||||
|
const { _path, _value } = updateArg; |
||||||
|
|
||||||
|
return produce(state, (draft) => { |
||||||
|
set(draft, _path, _value); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
return { ...state, ...updateArg }; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const initialState = { |
||||||
|
firstName: "", |
||||||
|
lastName: "", |
||||||
|
address: { |
||||||
|
addressLine1: "", |
||||||
|
addressLine2: "", |
||||||
|
pinCode: "", |
||||||
|
}, |
||||||
|
isMember: false, |
||||||
|
}; |
||||||
|
|
||||||
|
function App() { |
||||||
|
const [state, updateState] = React.useReducer(enhancedReducer, initialState); |
||||||
|
|
||||||
|
const updateForm = React.useCallback(({ target: { value, name, type } }) => { |
||||||
|
const updatePath = name.split("."); |
||||||
|
|
||||||
|
// if the input is a checkbox then use callback function to update
|
||||||
|
// the toggle state based on previous state
|
||||||
|
if (type === "checkbox") { |
||||||
|
updateState((prevState) => ({ |
||||||
|
[name]: !prevState[name], |
||||||
|
})); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// if we have to update the root level nodes in the form
|
||||||
|
if (updatePath.length === 1) { |
||||||
|
const [key] = updatePath; |
||||||
|
|
||||||
|
updateState({ |
||||||
|
[key]: value, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// if we have to update nested nodes in the form object
|
||||||
|
// use _path and _value to update them.
|
||||||
|
if (updatePath.length === 2) { |
||||||
|
updateState({ |
||||||
|
_path: updatePath, |
||||||
|
_value: value, |
||||||
|
}); |
||||||
|
} |
||||||
|
}, []); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="App"> |
||||||
|
<h1>Hello, i'm your supposedly complex form.</h1> |
||||||
|
<input |
||||||
|
className="form-control" |
||||||
|
type="text" |
||||||
|
name="firstName" |
||||||
|
placeholder="First Name" |
||||||
|
onChange={updateForm} |
||||||
|
value={state.firstName} |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<input |
||||||
|
className="form-control" |
||||||
|
type="text" |
||||||
|
name="lastName" |
||||||
|
placeholder="Last Name" |
||||||
|
onChange={updateForm} |
||||||
|
value={state.lastName} |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<input |
||||||
|
className="form-control" |
||||||
|
type="text" |
||||||
|
name="address.addressLine1" |
||||||
|
placeholder="Address Line One" |
||||||
|
onChange={updateForm} |
||||||
|
value={state.address.addressLine1} |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<input |
||||||
|
className="form-control" |
||||||
|
type="text" |
||||||
|
name="address.addressLine2" |
||||||
|
placeholder="Address Line Two" |
||||||
|
onChange={updateForm} |
||||||
|
value={state.address.addressLine2} |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<input |
||||||
|
className="form-control" |
||||||
|
type="text" |
||||||
|
name="address.pinCode" |
||||||
|
placeholder="Pincode" |
||||||
|
onChange={updateForm} |
||||||
|
value={state.address.pinCode} |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<div className="form-check"> |
||||||
|
<input |
||||||
|
className="form-check-input" |
||||||
|
type="checkbox" |
||||||
|
name="isMember" |
||||||
|
onChange={updateForm} |
||||||
|
checked={state.isMember} |
||||||
|
id="exampleCheck1" |
||||||
|
/> |
||||||
|
<label className="form-check-label" htmlFor="exampleCheck1"> |
||||||
|
Are you a member already? |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const rootElement = document.getElementById("root"); |
||||||
|
render(<App />, rootElement); |
||||||
Loading…
Reference in new issue