├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── logo512.png ├── manifest.json └── index.html ├── src ├── setupTests.js ├── index.css ├── reportWebVitals.js ├── index.js ├── components │ ├── AddTaskForm.jsx │ ├── UpdateForm.jsx │ └── ToDo.jsx ├── App.css └── App.js ├── .gitignore ├── README.md ├── .codesandbox └── tasks.json ├── .devcontainer └── devcontainer.json ├── package.json └── LICENSE /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webstylepress/to-do-list-app-react-wsp/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webstylepress/to-do-list-app-react-wsp/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webstylepress/to-do-list-app-react-wsp/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/AddTaskForm.jsx: -------------------------------------------------------------------------------- 1 | const AddTaskForm = ({ newTask, setNewTask, addTask }) => { 2 | return( 3 | <> 4 | {/* Add Task */} 5 |
6 |
7 | setNewTask(e.target.value)} 10 | className="form-control form-control-lg" 11 | /> 12 |
13 |
14 | 18 |
19 |
20 |
21 | 22 | ) 23 | } 24 | 25 | export default AddTaskForm; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # To Do List App React (V1) 2 | 3 | To Do List App React JS by WebStylePress (Add, Edit, Update, Delete, Toggle Tasks) 4 | 5 | ## How to Use 6 | 7 | Clone or download repo 8 | NodeJS / NPM / Yarn should be installed in your PC 9 | 10 | Open terminal or Git for Windows (Git Bash) 11 | Run these commands: 12 | 13 | ### Install Dependencies 14 | 15 | yarn install 16 | 17 | OR 18 | 19 | npm install 20 | 21 | ### Run app 22 | 23 | yarn start 24 | 25 | OR 26 | 27 | npm start 28 | 29 | ### YouTube Tutorial URL 30 | 31 | Title: To Do List App Project in ReactJS | Full React JS Project for Beginners from Scratch 32 | 33 | https://youtu.be/TmDNBEdHzVs 34 | 35 | ### To Do List App React (V2) [Update] 36 | 37 | Tutorial: https://youtu.be/E2CWxv5hOso 38 | 39 | Code: https://github.com/webstylepress/To-Do-List-App-React-V2- 40 | -------------------------------------------------------------------------------- /src/components/UpdateForm.jsx: -------------------------------------------------------------------------------- 1 | const UpdateForm = ({ updateData, changeTask, updateTask, cancelUpdate }) => { 2 | return( 3 | <> 4 | {/* Update Task */} 5 |
6 |
7 | changeTask(e)} 10 | className="form-control form-control-lg" 11 | /> 12 |
13 |
14 | 18 | 22 |
23 |
24 |
25 | 26 | ) 27 | } 28 | 29 | export default UpdateForm; -------------------------------------------------------------------------------- /.codesandbox/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // These tasks will run in order when initializing your CodeSandbox project. 3 | "setupTasks": [ 4 | { 5 | "name": "Install Dependencies", 6 | "command": "npm install" 7 | } 8 | ], 9 | 10 | // These tasks can be run from CodeSandbox. Running one will open a log in the app. 11 | "tasks": { 12 | "start": { 13 | "name": "start", 14 | "command": "npm run start", 15 | "runAtStart": true 16 | }, 17 | "build": { 18 | "name": "build", 19 | "command": "npm run build", 20 | "runAtStart": false 21 | }, 22 | "test": { 23 | "name": "test", 24 | "command": "npm run test", 25 | "runAtStart": false 26 | }, 27 | "eject": { 28 | "name": "eject", 29 | "command": "npm run eject", 30 | "runAtStart": false 31 | }, 32 | "npm start": { 33 | "name": "npm start", 34 | "command": "npm start", 35 | "runAtStart": true 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node 3 | { 4 | "name": "Node.js", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye" 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | // "forwardPorts": [], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | // "postCreateCommand": "yarn install", 16 | 17 | // Configure tool-specific properties. 18 | // "customizations": {}, 19 | 20 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 21 | // "remoteUser": "root" 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "to-do", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/free-solid-svg-icons": "^6.1.1", 7 | "@fortawesome/react-fontawesome": "^0.1.18", 8 | "@testing-library/jest-dom": "^5.16.4", 9 | "@testing-library/react": "^13.1.1", 10 | "@testing-library/user-event": "^13.5.0", 11 | "bootstrap": "^5.1.3", 12 | "react": "^18.0.0", 13 | "react-dom": "^18.0.0", 14 | "react-scripts": "5.0.1", 15 | "web-vitals": "^2.1.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 WebStylePress 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #333; 3 | color: #fff; 4 | } 5 | 6 | .App { 7 | text-align: center; 8 | } 9 | 10 | .taskBg { 11 | background-color: #555; 12 | border-radius: 6px; 13 | margin-bottom: 20px; 14 | padding: 10px 140px 10px 15px; 15 | text-align: left; 16 | font-size: 22px; 17 | position: relative; 18 | } 19 | 20 | .taskBg div { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .taskNumber { 26 | color: #999; 27 | border: 1px solid #999; 28 | border-radius: 50%; 29 | width: 26px; 30 | height: 26px; 31 | display: flex; 32 | text-align: center; 33 | font-size: 14px; 34 | margin-right: 8px; 35 | align-items: center; 36 | justify-content: center; 37 | } 38 | 39 | .taskBg .taskText { 40 | flex: 1; 41 | } 42 | 43 | .taskBg .done .taskText { 44 | text-decoration: line-through; 45 | opacity: 0.3; 46 | } 47 | 48 | .taskBg .iconsWrap { 49 | position: absolute; 50 | top: 50%; 51 | transform: translateY(-50%); 52 | right: 15px; 53 | width: auto; 54 | display: inline-block; 55 | } 56 | 57 | .taskBg .iconsWrap span { 58 | display: inline-block; 59 | margin: 0px 10px 0 10px; 60 | cursor: pointer; 61 | color: #00ff89; 62 | } 63 | 64 | .taskBg .iconsWrap span:hover { 65 | color: yellow; 66 | } 67 | 68 | .mr-20 { 69 | margin-right: 20px; 70 | } 71 | -------------------------------------------------------------------------------- /src/components/ToDo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import { 5 | faCircleCheck, faPen, faTrashCan 6 | } from '@fortawesome/free-solid-svg-icons' 7 | 8 | const ToDo = ({ toDo, markDone, setUpdateData, deleteTask }) => { 9 | return( 10 | <> 11 | {toDo && toDo 12 | .sort((a, b) => a.id > b.id ? 1 : -1) 13 | .map( (task, index) => { 14 | return( 15 | 16 |
17 |
18 | {index + 1} 19 | {task.title} 20 |
21 |
22 | markDone(task.id) } 24 | > 25 | 26 | 27 | 28 | {task.status ? null : ( 29 | setUpdateData({ 31 | id: task.id, 32 | title: task.title, 33 | status: task.status ? true : false 34 | }) } 35 | > 36 | 37 | 38 | )} 39 | 40 | deleteTask(task.id)} 42 | > 43 | 44 | 45 |
46 |
47 |
48 | ) 49 | }) 50 | } 51 | 52 | ) 53 | } 54 | 55 | export default ToDo; -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import {useState} from 'react'; 2 | import AddTaskForm from './components/AddTaskForm.jsx'; 3 | import UpdateForm from './components/UpdateForm.jsx'; 4 | import ToDo from './components/ToDo.jsx'; 5 | 6 | import 'bootstrap/dist/css/bootstrap.min.css'; 7 | 8 | import './App.css'; 9 | 10 | function App() { 11 | 12 | // Tasks (ToDo List) State 13 | const [toDo, setToDo] = useState([]); 14 | 15 | // Temp State 16 | const [newTask, setNewTask] = useState(''); 17 | const [updateData, setUpdateData] = useState(''); 18 | 19 | // Add task 20 | /////////////////////////// 21 | const addTask = () => { 22 | if(newTask) { 23 | let num = toDo.length + 1; 24 | let newEntry = { id: num, title: newTask, status: false } 25 | setToDo([...toDo, newEntry]) 26 | setNewTask(''); 27 | } 28 | } 29 | 30 | // Delete task 31 | /////////////////////////// 32 | const deleteTask = (id) => { 33 | let newTasks = toDo.filter( task => task.id !== id) 34 | setToDo(newTasks); 35 | } 36 | 37 | // Mark task as done or completed 38 | /////////////////////////// 39 | const markDone = (id) => { 40 | let newTask = toDo.map( task => { 41 | if( task.id === id ) { 42 | return ({ ...task, status: !task.status }) 43 | } 44 | return task; 45 | }) 46 | setToDo(newTask); 47 | } 48 | 49 | // Cancel update 50 | /////////////////////////// 51 | const cancelUpdate = () => { 52 | setUpdateData(''); 53 | } 54 | 55 | // Change task for update 56 | /////////////////////////// 57 | const changeTask = (e) => { 58 | let newEntry = { 59 | id: updateData.id, 60 | title: e.target.value, 61 | status: updateData.status ? true : false 62 | } 63 | setUpdateData(newEntry); 64 | } 65 | 66 | // Update task 67 | /////////////////////////// 68 | const updateTask = () => { 69 | let filterRecords = [...toDo].filter( task => task.id !== updateData.id ); 70 | let updatedObject = [...filterRecords, updateData] 71 | setToDo(updatedObject); 72 | setUpdateData(''); 73 | } 74 | 75 | return ( 76 |
77 | 78 |

79 |

To Do List App (ReactJS)

80 |

81 | 82 | {updateData && updateData ? ( 83 | 89 | ) : ( 90 | 95 | )} 96 | 97 | {/* Display ToDos */} 98 | 99 | {toDo && toDo.length ? '' : 'No Tasks...'} 100 | 101 | 107 | 108 |
109 | ); 110 | } 111 | 112 | export default App; 113 | --------------------------------------------------------------------------------