Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"lottie-react": "^2.4.0",
"lottie-web": "^5.12.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-lottie": "^1.2.4",
"react-scripts": "5.0.1",
"uuid4": "^2.0.3",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand All @@ -34,5 +38,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"tailwindcss": "^3.4.1"
}
}
29 changes: 0 additions & 29 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,8 @@
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
6 changes: 3 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import "./App.css";
// TODO: Import the todoData and pass it as a prop to the TodoList component

import TodoList from "./components/TodoList";
// import DropdownMenu from "./components/DropdownMenu";
function App() {
return (
<div className="App">
<header className="App-header">
{/* Call the TodoList Component Here */}
<TodoList />
</header>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/a.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.4.3","fr":30,"ip":0,"op":31,"w":400,"h":400,"nm":"good","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[],"ip":0,"op":31,"st":0,"bm":0,"completed":true},{"ddd":0,"ind":2,"ty":4,"nm":"coche","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-12.249,-5.011,0],"ix":2},"a":{"a":0,"k":[-18,-78.5,0],"ix":1},"s":{"a":0,"k":[111.35,111.35,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-107.006,-69.99],[-19.597,2.505],[85.185,-123.056]],"o":[[-107.006,-69.99],[-19.597,2.505],[85.185,-123.056]],"v":[[-107.006,-69.99],[-19.597,2.505],[85.185,-123.056]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false,"_render":true},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.266],"y":[1]},"o":{"x":[0.807],"y":[0]},"n":["0p266_1_0p807_0"],"t":4,"s":[0],"e":[100]},{"t":19}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Raccorder les tracés 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true},{"ty":"st","c":{"a":0,"k":[1,0.5412,0.4902,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":25,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer ","_render":true}],"nm":"Forme 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":31,"st":0,"bm":0,"completed":true},{"ddd":0,"ind":3,"ty":4,"nm":"circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.281],"y":[1]},"o":{"x":[0.748],"y":[0]},"n":["0p281_1_0p748_0"],"t":0,"s":[-81.143],"e":[0]},{"t":10}],"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.309,0.309,0.667],"y":[1,1,1]},"o":{"x":[0.841,0.841,0.333],"y":[0,0,0]},"n":["0p309_1_0p841_0","0p309_1_0p841_0","0p667_1_0p333_0"],"t":0,"s":[41.198,41.198,100],"e":[89.36,89.36,100]},{"t":10}],"ix":6,"x":"var $bm_rt;\nvar amp, freq, decay, n, time_max, n, t, t, v;\namp = 0.5;\nfreq = 2;\ndecay = 3;\nn = 0;\n$bm_rt = time_max = 3;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n}\nif (n == 0) {\n $bm_rt = t = 0;\n} else {\n $bm_rt = t = sub(time, key(n).time);\n}\nif (n > 0 && t < time_max) {\n v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10)));\n $bm_rt = sum(value, div(mul(mul(v, amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))));\n} else {\n $bm_rt = value;\n}"}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[400,400],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false,"_render":true},{"ty":"st","c":{"a":0,"k":[1,0.5412,0.4902,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":25,"ix":5},"lc":2,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":8},"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[89.282,89.282],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer ","_render":true}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.281],"y":[1]},"o":{"x":[0.803],"y":[0]},"n":["0p281_1_0p803_0"],"t":0,"s":[0],"e":[100]},{"t":10}],"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":-46,"ix":3},"m":1,"ix":2,"nm":"Raccorder les tracés 1","mn":"ADBE Vector Filter - Trim","hd":false,"_render":true}],"ip":0,"op":31,"st":0,"bm":0,"completed":true}],"markers":[],"__complete":true}
7 changes: 7 additions & 0 deletions src/assignTo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const assignTo = [
{ value: "Hamza", label: "Hamza" },
{ value: "Umabass", label: "Umabass" },
{ value: "Jasimia", label: "Jasimia" },
{ value: "Stopha", label: "Stopha" },
];
export default assignTo;
1 change: 1 addition & 0 deletions src/b.json

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions src/components/Animation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import Lottie from "react-lottie";
import a from "../a.json";
import { useState } from "react";

const defaultOptions = {
loop: false,
autoplay: true,
animationData: a,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice",
},
};

const Animation = () => {
const [isStopped, setIsStopped] = useState(false);
const [isPaused, setIsPaused] = useState(false);
const animationCompleted = () => {
setIsStopped(true);
setIsPaused(true);
};

return (
<div className="absolute inset-0 mt-20">
<Lottie
options={defaultOptions}
height={400}
width={400}
isStopped={isStopped}
isPaused={isPaused}
eventListeners={[
{
eventName: "complete",
callback: animationCompleted,
},
]}
/>
</div>
);
};

export default Animation;
35 changes: 35 additions & 0 deletions src/components/DropdownMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import assignTo from "../assignTo";
function DropdownMenu({
isOpen,
selectedOption,
toggleDropdown,
handleOptionClick,
}) {
const options = assignTo;

return (
<div className="ml-2 ">
<button onClick={toggleDropdown}>
{selectedOption ? selectedOption.label : "Assign to:"}
</button>

{isOpen && (
<div className="absolute bg-veryLight">
<ul className="flex flex-col items-start">
{options.map((option) => (
<li
className="flex shadow-2xl bg-whatever pl-2 w-20 text-violet underline"
key={option.value}
onClick={() => handleOptionClick(option)}
>
{option.label}
</li>
))}
</ul>
</div>
)}
</div>
);
}

export default DropdownMenu;
27 changes: 27 additions & 0 deletions src/components/ListTabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";

const ListTabs = ({ handleShowAll, setShowCompleted }) => {
return (
<div className="flex m-2 mt-4">
<button
className="shadow-md bg-violet hover:brightness-75 hover:transition-all duration-300 w-16 p-2 text-veryLight rounded-l group focus:brightness-75 focus:outline-none "
onClick={handleShowAll}
>
All
</button>
<button
className="shadow-md bg-violet hover:brightness-75 hover:transition-all duration-300 w-auto p-2 text-veryLight focus:brightness-75 focus:outline-none "
onClick={() => setShowCompleted(false)}
>
Uncompleted
</button>
<button
className="shadow-md bg-violet hover:brightness-75 hover:transition-all duration-300 w-auto p-2 text-veryLight pr-6 rounded-r focus:brightness-75 focus:outline-none "
onClick={() => setShowCompleted(true)}
>
Completed
</button>
</div>
);
};
export default ListTabs;
96 changes: 96 additions & 0 deletions src/components/TodoItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState } from "react";
import trash from "../assets/trash.svg";
import edit from "../assets/edit.svg";
import Animation from "./Animation";
function TodoItem({ todo, handleDelete, Edit, handleToggle, toggleAnimation }) {
const [isEditing, setisEditing] = useState(false);
const [todoTitle, setTodoTitel] = useState(todo.title);
const [todoDescription, setTodoDescription] = useState(todo.details);
const [isChecked, setIsChecked] = useState(todo.isComplete);
///////////////////////////////////////////////////////////////

const handelEdit = () => {
setisEditing(true);
};

const handelEditChange = (e) => {
setTodoTitel(e.target.value);
};
const handelDescriptionChange = (e) => {
setTodoDescription(e.target.value);
};

const handelSave = () => {
const updatedTodo = { ...todo, title: todoTitle, details: todoDescription };
if (updatedTodo.title.trim() === "") {
return;
}

Edit(updatedTodo);

@AlhassanAli01 AlhassanAli01 Mar 22, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of naming the function Edit, I would suggest naming it onEdit.
That way it would be understood that this is supposed to be an event that should be handled.
This is a convention that you will often see when reading react code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same goes for handleDelete, since it's supposed to be passed as prop to the component itself naming it onDelete would be more appropriate.

if it were to be handled inside the component itself naming it handleDelete won't be an issue.

setisEditing(false);
};
/////////////////////////////////////////////////////////////////////////////////
return (
<div className="w-full bg-lightwhite p-2 w-full flex items-start justify-center rounded shadow-md">
{isEditing ? (
<div className="flex flex-col gap-2 items-start w-full">
<input
className="text-violet h-10 w-full p-1 rounded-full text-grey hover:brightness-95 hover:transition-all duration-300"
onChange={handelEditChange}
type="text"
value={todoTitle}
placeholder="What is the task?"
/>
<input
className="text-violet h-10 w-full p-1 rounded-full text-grey hover:brightness-95 hover:transition-all duration-300"
onChange={handelDescriptionChange}
type="text"
value={todoDescription}
placeholder="What is the description?"
/>
<div className="self-end flex justify-center aitems-center gap-6 p-4">
<button
className="text-sm bg-violet font-bold rounded-full p-2 text-white "
onClick={handelSave}
>
Save
</button>
<sub onClick={() => handleDelete(todo.id)}>
{" "}
<img className="w-6" src={trash} alt="trash-icon" />
</sub>
</div>
</div>
) : (
<div className="ml-4 flex flex-col items-start w-full justify-center gap-2">
<div onClick={toggleAnimation}>{isChecked && <Animation />}</div>
<h3 className="text-rose font-6xl">{todo.title}</h3>
<p className="text-grey">{todo.details}</p>
<p className="text-xs text-lightgrey italic">
Assigned to: {todo.assignedto.label}
</p>
<input
className="self-end mr-6 mb-4 w-6 h-6 border border-violet-300 rounded-md checked:bg-violet checked:border-transparent focus:outline-none focus:border-violet focus:ring-2 focus:ring-violet relative"
type="checkbox"
checked={isChecked}
onChange={() => {
handleToggle(todo.id);
setIsChecked(!isChecked);
}}
/>

<div className="self-end flex aitems-center gap-6 p-4">
<sub onClick={handelEdit}>
<img className="w-6" src={edit} alt="React Logo" />
</sub>

<sub onClick={() => handleDelete(todo.id)}>
<img className="w-6" src={trash} alt="trash-icon" />
</sub>
</div>
</div>
)}
</div>
);
}
export default TodoItem;
Loading