diff --git a/frontend/src/components/Dashboard/DashboardTasks.jsx b/frontend/src/components/Dashboard/DashboardTasks.jsx index 480498f1..c3a2cf39 100644 --- a/frontend/src/components/Dashboard/DashboardTasks.jsx +++ b/frontend/src/components/Dashboard/DashboardTasks.jsx @@ -1,12 +1,54 @@ import { useNavigate } from "react-router-dom"; -import { Plus, ArrowRight, CheckCircle2 } from "lucide-react"; -import { useState } from "react"; +import { ArrowRight } from "lucide-react"; +import { useState, useCallback, useRef, useEffect } from "react"; +// Toast popup component - shows at bottom right +function Toast({ message, type }) { + if (!message) return null; + return ( +
+ {message} +
+ ); +} export default function DashboardTasks({ tasks, updateTask }) { const navigate = useNavigate(); const [durationModalTask, setDurationModalTask] = useState(null); const [actualDuration, setActualDuration] = useState(""); + const [toast, setToast] = useState({ message: "", type: "success" }); + const toastTimer = useRef(null); + + const showToast = useCallback((message, type = "success") => { + clearTimeout(toastTimer.current); + setToast({ message, type }); + toastTimer.current = setTimeout(() => setToast({ message: "", type: "success" }), 3000); + }, []); + + const handleActualDurationSubmit = async () => { + const durationValue = Number(actualDuration); + + if (Number.isNaN(durationValue) || durationValue <= 0) { + showToast("Please enter a valid duration in minutes", "error"); + return; + } + + try { + await updateTask(durationModalTask._id, { + status: "Completed", + actualDuration: durationValue, + }); + + setDurationModalTask(null); + setActualDuration(""); + } catch (error) { + console.error("Failed to update task:", error); + } + }; const priorityOrder = { High: 3, @@ -53,147 +95,131 @@ export default function DashboardTasks({ tasks, updateTask }) { } }; - const handleActualDurationSubmit = async () => { - const durationValue = Number(actualDuration); - - if (Number.isNaN(durationValue) || durationValue <= 0) { - alert("Please enter a valid duration in minutes"); - return; - } - - try { - await updateTask(durationModalTask._id, { - status: "Completed", - actualDuration: durationValue, - }); - - setDurationModalTask(null); - setActualDuration(""); - } catch (error) { - console.error("Failed to update task:", error); - } - }; + useEffect(() => () => clearTimeout(toastTimer.current), []); return ( -
- {/* Header */} -
-
-

Today’s Focus

-

Top priorities for today

+ <> + +
+ {/* Header */} +
+
+

Today's Focus

+

Top priorities for today

+
+ +
- -
+ {todayTasks?.length ? ( +
+ {todayTasks.map((task) => ( +
+ {/* Checkbox */} + handleCheckboxChange(task)} + /> + + {/* Task content */} +
+

+ {task.title} +

+ +
+ + {task.priority} + + + {task.status === "Completed" && ( + Completed + )} +
+
- {todayTasks?.length ? ( -
- {todayTasks.map((task) => ( -
+ ✓ + +
+ ))} +
+ ) : ( +
+ No tasks for today. + + +
+ )} + + {durationModalTask && ( +
+
+

+ Complete Task +

+ +

+ How long did you actually take to complete " + {durationModalTask.title}"? +

handleCheckboxChange(task)} + type="number" + min="1" + value={actualDuration} + onChange={(e) => setActualDuration(e.target.value)} + className="w-full p-2 border border-soft rounded-lg text-black dark:text-white dark:bg-slate-800 dark:placeholder-slate-500" + placeholder="Actual duration in minutes" /> - - {/* Task content */} -
-

+ +

- - {/* Hover affordance */} - - ✓ - -
- ))} -
- ) : ( -
- No tasks for today. - - -
- )} - - {durationModalTask && ( -
-
-

- Complete Task -

- -

- How long did you actually take to complete " - {durationModalTask.title}"? -

- setActualDuration(e.target.value)} - className="w-full p-2 border border-soft rounded-lg text-black dark:placeholder-slate-500" - placeholder="Actual duration in minutes" - /> -
- -
-
- )} -
+ )} +
+ ); }