├── 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 |
--------------------------------------------------------------------------------