diff --git a/package-lock.json b/package-lock.json index e6a160a..742324e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,11 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "uuid": "^9.0.1", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "tailwindcss": "^3.4.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -15998,6 +16002,14 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -17325,9 +17337,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 88a269e..2833951 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "uuid": "^9.0.1", "web-vitals": "^2.1.4" }, "scripts": { @@ -34,5 +35,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "tailwindcss": "^3.4.1" } } diff --git a/src/App.css b/src/App.css index 13088c2..e4b8a7a 100644 --- a/src/App.css +++ b/src/App.css @@ -25,7 +25,7 @@ } .App-header { - background-color: #282c34; + background-color: #151b25; min-height: 100vh; display: flex; flex-direction: column; diff --git a/src/App.js b/src/App.js index 0ff7d8a..1d11d9d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,11 +1,13 @@ import "./App.css"; +import TodoList from "./components/TodoList"; // TODO: Import the todoData and pass it as a prop to the TodoList component +import todoData from "./todoData"; function App() { return (
- {/* Call the TodoList Component Here */} +
); diff --git a/src/components/ToDoItem.js b/src/components/ToDoItem.js new file mode 100644 index 0000000..6516123 --- /dev/null +++ b/src/components/ToDoItem.js @@ -0,0 +1,48 @@ +import React from "react"; +import { useState } from "react"; +export const ToDoItem = ({ todo, handleDelete, handleEdit }) => { + const [isEditing, setIsEditing] = useState(false); + const [editedTitle, setEditedTitle] = useState(todo.title); + + const handleChange = (event) => { + setEditedTitle(event.target.value); + }; + const handleIsEditing = () => { + setIsEditing(!isEditing); + }; + + return ( +
+ + + ) : ( + + )} + + {isEditing ? ( + + ) : ( +

{todo.title}

+ )} +
+ ); +}; diff --git a/src/components/TodoList.js b/src/components/TodoList.js new file mode 100644 index 0000000..a6c631a --- /dev/null +++ b/src/components/TodoList.js @@ -0,0 +1,120 @@ +import React from "react"; +import { useState, useEffect, useRef } from "react"; +import { v4 as uuidv4 } from "uuid"; +import { ToDoItem } from "./ToDoItem"; + +function TodoList({ todoData }) { + const [todoList, setTodoList] = useState(todoData); + const [newTodo, setNewTodo] = useState(""); + const [error, setError] = useState(""); + const [filtered, setFiltered] = useState([]); + // Create + const handleTextChange = (event) => { + setNewTodo(event.target.value); + }; + const clear = useRef(); + const handleTodoCreate = () => { + let errors = ""; + if (!newTodo.trim()) { + errors = "write something"; + } else if (/\d+/.test(newTodo)) { + errors = "must not contain numbers"; + } else if (/\W+/.test(newTodo)) { + errors = "must not contain symbols"; + } else { + const newTodoObj = { + id: uuidv4(), + title: newTodo, + done: false, + }; + // Update the array to add the new item + setTodoList([...todoList, newTodoObj]); + } + setError(errors); + if (errors.length === 0) { + clear.current.value = ""; + } + }; + + // Delete + const handleDelete = (todoId) => { + setTodoList(todoList.filter((todo) => todo.id !== todoId)); + }; + + // Edit + const handleEdit = (todoId, editedTitle) => { + setTodoList( + todoList.map((todo) => { + return todo.id === todoId ? { ...todo, title: editedTitle } : todo; + }) + ); + }; + + // Search + useEffect(() => { + setFiltered(todoList); + }, [todoList]); + const handleSearch = (e) => { + const filter = todoList.filter((todo) => + todo.title.toLowerCase().includes(e.target.value) + ); + setFiltered(filter); + }; + + return ( +
+ +
+ {filtered.map((todo) => ( + + ))} +
+
+
+ + {error && ( + + {error} + + )} +
+
+ +
+
+
+ ); +} + +export default TodoList; diff --git a/src/index.css b/src/index.css index ec2585e..651ed53 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,6 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..a930689 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./src/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: {}, + }, + plugins: [], +} +