Skip to content
Snippets Groups Projects
Commit a8c22cd0 authored by OUKASSOU Anas's avatar OUKASSOU Anas
Browse files

Merge branch 'feature/manage-tasks' into 'main'

Feature/manage tasks

See merge request !16
parents 1c913339 b003f8e5
No related branches found
No related tags found
1 merge request!16Feature/manage tasks
...@@ -2,76 +2,85 @@ import { useState } from "react"; ...@@ -2,76 +2,85 @@ import { useState } from "react";
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"; import "react-datepicker/dist/react-datepicker.css";
export default function Modal({ isOpen, closeModal, saveTask }) { export default function Modal({task, isOpen, closeModal, saveTask }) {
if (!isOpen) return null; if (!isOpen) return null;
const [taskName, setTaskName] = useState(""); const [editedTask, setEditedTask] = useState({...task});
const [dueDate, setDueDate] = useState(new Date());
const createTask = () => { const handleSave = () => {
return { saveTask(editedTask)
id: crypto.randomUUID(),
name: taskName,
isCompleted: false,
dueDate: dueDate
}
}
const handleSaveTask = () => {
const task = createTask()
saveTask(task)
closeModal() closeModal()
} }
const handleInputChange = (e) => { const handleChange = (e) => {
setTaskName(e.target.value); const { name, value, type, checked } = e.target;
setEditedTask({
...editedTask,
[name]: type === 'checkbox' ? checked : value
});
}; };
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-25 flex items-center justify-center z-50">
<div <div
className="absolute top-0 left-0 right-0 bottom-0 flex justify-center items-center z-50" className="bg-white rounded-lg shadow-xl p-6 w-full max-w-md mx-4"
style={{ pointerEvents: 'none' }}
> >
<div <div className="flex justify-between items-center mb-4">
className="absolute inset-0 bg-gray-500 bg-opacity-50" <h3 className="text-lg font-medium">Edit Task</h3>
style={{ pointerEvents: 'none' }} <button
></div> onClick={closeModal}
className="text-gray-400 hover:text-gray-500"
<div
className="relative bg-white p-6 rounded-lg shadow-lg w-1/3 z-10"
style={{ pointerEvents: 'auto' }}
> >
<h2 className="text-xl mb-4">Add a New Task</h2> <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<p className="mb-4">Enter the task details below:</p> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-1">
Task Name
</label>
<input <input
type="text" id="name"
className="w-full p-2 mb-4 border border-gray-300 rounded-md" name="name"
placeholder="Task Name" className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500"
value={taskName} value={editedTask.name}
onChange={handleInputChange} onChange={handleChange}
/> />
</div>
<div> <div>
<DatePicker <label htmlFor="dueDate" className="block text-sm font-medium text-gray-700 mb-1">
showIcon Due Date
selected={dueDate} </label>
onChange={(date) => setDueDate(date)} <input
id="dueDate"
name="dueDate"
type="date"
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500"
value={editedTask.dueDate}
onChange={handleChange}
/> />
</div> </div>
</div>
<div className="flex justify-between"> <div className="mt-6 flex justify-end space-x-3">
<button <button
type="button"
className="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
onClick={closeModal} onClick={closeModal}
className="px-4 py-2 bg-red-500 text-white rounded-md"
> >
Close Cancel
</button> </button>
<button <button
className="px-4 py-2 bg-blue-500 text-white rounded-md" type="button"
onClick={handleSaveTask} className="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
onClick={handleSave}
> >
Save Task Save
</button> </button>
</div> </div>
</div> </div>
......
...@@ -22,6 +22,28 @@ export default function TaskItem({ task }) { ...@@ -22,6 +22,28 @@ export default function TaskItem({ task }) {
? new Date(task.dueDate).toLocaleDateString() ? new Date(task.dueDate).toLocaleDateString()
: "No due date"; : "No due date";
const getDateTextColor = (task) => {
if (task.isCompleted) {
return 'text-gray-400';
}
const now = new Date();
const due = new Date(task.dueDate);
const diffTime = due - now;
const diffDays = diffTime / (1000 * 60 * 60 * 24);
if (diffDays >= 0 && diffDays < 1) {
return 'text-orange-500';
}
if (now > due) {
return 'text-red-500';
}
return 'text-gray-500';
};
return ( return (
<li> <li>
<div className="flex items-start p-4 border rounded-lg shadow-sm bg-white my-2 hover:shadow-md transition-shadow"> <div className="flex items-start p-4 border rounded-lg shadow-sm bg-white my-2 hover:shadow-md transition-shadow">
...@@ -39,8 +61,14 @@ export default function TaskItem({ task }) { ...@@ -39,8 +61,14 @@ export default function TaskItem({ task }) {
<h3 className={`text-base font-medium ${task.isCompleted ? 'text-gray-400 line-through' : 'text-gray-900'}`}> <h3 className={`text-base font-medium ${task.isCompleted ? 'text-gray-400 line-through' : 'text-gray-900'}`}>
{task.name} {task.name}
</h3> </h3>
<p className={`text-sm mt-1 ${task.isCompleted ? 'text-gray-400' : 'text-gray-500'}`}> <p className={`text-sm mt-1 flex items-center gap-1 ${getDateTextColor(task)}`}>
Due: {formattedDate} <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
<line x1="16" y1="2" x2="16" y2="6"></line>
<line x1="8" y1="2" x2="8" y2="6"></line>
<line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
{formattedDate}
</p> </p>
</div> </div>
<button <button
......
...@@ -15,6 +15,15 @@ const Home = () => { ...@@ -15,6 +15,15 @@ const Home = () => {
const openModal = () => setIsModalOpen(true); const openModal = () => setIsModalOpen(true);
const closeModal = () => setIsModalOpen(false); const closeModal = () => setIsModalOpen(false);
const newTask = () => {
return {
id: crypto.randomUUID(),
name: "",
isCompleted: false,
dueDate: ""
}
}
// Fonction pour ajouter une nouvelle tâche // Fonction pour ajouter une nouvelle tâche
const saveTask = (task) => { const saveTask = (task) => {
const newTask = { const newTask = {
...@@ -70,7 +79,7 @@ const Home = () => { ...@@ -70,7 +79,7 @@ const Home = () => {
</div> </div>
<Modal isOpen={isModalOpen} closeModal={closeModal} saveTask={saveTask} /> <Modal task={newTask()} isOpen={isModalOpen} closeModal={closeModal} saveTask={saveTask} />
</div> </div>
); );
}; };
......
...@@ -6,6 +6,16 @@ import { useTasks } from "@context/TasksContext"; ...@@ -6,6 +6,16 @@ import { useTasks } from "@context/TasksContext";
export default function Todolist() { export default function Todolist() {
const { tasks, setTasks } = useTasks() const { tasks, setTasks } = useTasks()
const newTask = () => {
return {
id: crypto.randomUUID(),
name: "",
isCompleted: false,
dueDate: ""
}
}
const saveTask = (task) => { const saveTask = (task) => {
const newTask = { const newTask = {
...task, ...task,
...@@ -36,7 +46,7 @@ export default function Todolist() { ...@@ -36,7 +46,7 @@ export default function Todolist() {
</div> </div>
</div> </div>
<Modal isOpen={isModalOpen} closeModal={closeModal} saveTask={saveTask}/> <Modal task={newTask()} isOpen={isModalOpen} closeModal={closeModal} saveTask={saveTask}/>
</div> </div>
) )
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment