diff --git a/frontend/src/Components/DashBoard/PomodoroTimer.jsx b/frontend/src/Components/DashBoard/PomodoroTimer.jsx index a5961af..9e0461b 100644 --- a/frontend/src/Components/DashBoard/PomodoroTimer.jsx +++ b/frontend/src/Components/DashBoard/PomodoroTimer.jsx @@ -1,7 +1,8 @@ import { useContext } from "react"; -import ThemeContext from "../ui/theme-provider.jsx"; +import ThemeContext from "../ui/theme-provider.jsx"; import { useTimer } from "../../context/TimerContext.jsx"; -import Topbar from './Topbar'; +import Topbar from "./Topbar"; +import Sidebar from "./Sidebar"; // βœ… Added Sidebar // Circular Timer Component function CircularTimer({ value, max, label, size = 140, isDarkMode }) { @@ -16,7 +17,14 @@ function CircularTimer({ value, max, label, size = 140, isDarkMode }) { return (
- + - + {String(value).padStart(2, "0")} - + {label}
@@ -59,7 +84,7 @@ function CircularTimer({ value, max, label, size = 140, isDarkMode }) { const sessionLabels = { work: "Focus Time πŸ’»", shortBreak: "Short Break β˜•", - longBreak: "Long Break πŸšΆβ€β™‚οΈ" + longBreak: "Long Break πŸšΆβ€β™‚οΈ", }; export default function PomodoroTimer() { @@ -69,68 +94,176 @@ export default function PomodoroTimer() { const { timeLeft, isRunning, - sessionType, + sessionType, sessions, - startTimer, - pauseTimer, - resetTimer, + startTimer, + pauseTimer, + resetTimer, workTime, shortBreak, longBreak, updateWorkTime, updateShortBreak, updateLongBreak, - SESSIONS_BEFORE_LONG_BREAK + SESSIONS_BEFORE_LONG_BREAK, } = useTimer(); const minutes = Math.floor(timeLeft / 60); const seconds = timeLeft % 60; return ( -
- -
-

- {sessionLabels[sessionType]} -

+
+ +
+ {/* βœ… Sidebar added (same as Dashboard) */} + -
- - : - -
+ {/* Main Pomodoro Area */} +
+

+ {sessionLabels[sessionType]} +

-
- {[ - { label: "Work", value: Math.floor(workTime / 60), onChange: e => updateWorkTime(Number(e.target.value)) }, - { label: "Short Break", value: Math.floor(shortBreak / 60), onChange: e => updateShortBreak(Number(e.target.value)) }, - { label: "Long Break", value: Math.floor(longBreak / 60), onChange: e => updateLongBreak(Number(e.target.value)) } - ].map(input => ( -
- - -
- ))} -
+ {/* Circular Timer */} +
+ + + : + + +
-
- {!isRunning ? ( - - ) : ( - - )} - -
+ {/* Session Settings */} +
+ {[ + { + label: "Work", + value: Math.floor(workTime / 60), + onChange: (e) => updateWorkTime(Number(e.target.value)), + }, + { + label: "Short Break", + value: Math.floor(shortBreak / 60), + onChange: (e) => updateShortBreak(Number(e.target.value)), + }, + { + label: "Long Break", + value: Math.floor(longBreak / 60), + onChange: (e) => updateLongBreak(Number(e.target.value)), + }, + ].map((input) => ( +
+ + +
+ ))} +
-
- {[...Array(SESSIONS_BEFORE_LONG_BREAK)].map((_, i) => ( -
- ))} + {/* Control Buttons */} +
+ {!isRunning ? ( + + ) : ( + + )} + +
+ + {/* Session Dots */} +
+ {[...Array(SESSIONS_BEFORE_LONG_BREAK)].map((_, i) => ( +
+ ))} +
+ +

+ {sessionType === "work" + ? `Session ${sessions + 1} of ${SESSIONS_BEFORE_LONG_BREAK}` + : "Break Time"} +

-

- {sessionType === 'work' ? `Session ${sessions + 1} of ${SESSIONS_BEFORE_LONG_BREAK}` : "Break Time"} -

); -} \ No newline at end of file +} diff --git a/frontend/src/Components/DashBoard/Todo.jsx b/frontend/src/Components/DashBoard/Todo.jsx index 0ea261c..a685af5 100644 --- a/frontend/src/Components/DashBoard/Todo.jsx +++ b/frontend/src/Components/DashBoard/Todo.jsx @@ -1,7 +1,15 @@ import React, { useEffect, useMemo, useState } from "react"; import Topbar from "./Topbar"; import BackButton from "../ui/backbutton"; -import { Plus, Pencil, Trash2, CheckCircle2, Circle, Filter } from "lucide-react"; +import { + Plus, + Pencil, + Trash2, + CheckCircle2, + Circle, + Filter, +} from "lucide-react"; +import Sidebar from "./Sidebar"; // βœ… Add this after Topbar import // Mock-only UI for GSSOC To-Do page. Uses local state; backend wiring will follow. export default function Todo() { @@ -9,18 +17,37 @@ export default function Todo() { const [loading, setLoading] = useState(true); const API = `${import.meta.env.VITE_API_URL}/api/tasks`; - const [form, setForm] = useState({ title: "", description: "", deadline: "" }); + const [form, setForm] = useState({ + title: "", + description: "", + deadline: "", + }); const [editingId, setEditingId] = useState(null); const [filter, setFilter] = useState("all"); // all | upcoming | completed const [showModal, setShowModal] = useState(false); - const [modalData, setModalData] = useState({ title: "", description: "", status: "pending", deadline: "" }); + const [modalData, setModalData] = useState({ + title: "", + description: "", + status: "pending", + deadline: "", + }); - const pendingTasks = useMemo(() => tasks.filter(t => t.status === "pending"), [tasks]); - const completedTasks = useMemo(() => tasks.filter(t => t.status === "completed"), [tasks]); + const pendingTasks = useMemo( + () => tasks.filter((t) => t.status === "pending"), + [tasks] + ); + const completedTasks = useMemo( + () => tasks.filter((t) => t.status === "completed"), + [tasks] + ); const filtered = (items) => { - if (filter === "completed") return items.filter(t => t.status === "completed"); - if (filter === "upcoming") return items.filter(t => t.status === "pending").sort((a,b)=> new Date(a.deadline) - new Date(b.deadline)); + if (filter === "completed") + return items.filter((t) => t.status === "completed"); + if (filter === "upcoming") + return items + .filter((t) => t.status === "pending") + .sort((a, b) => new Date(a.deadline) - new Date(b.deadline)); return items; }; @@ -34,7 +61,8 @@ export default function Todo() { fetch(API, { headers: { "x-auth-token": token } }) .then(async (res) => { const data = await res.json(); - if (!res.ok) throw new Error(data?.errors?.[0]?.msg || "Failed to fetch tasks"); + if (!res.ok) + throw new Error(data?.errors?.[0]?.msg || "Failed to fetch tasks"); setTasks(data); }) .catch((e) => console.error(e)) @@ -43,12 +71,22 @@ export default function Todo() { function resetForm() { setForm({ title: "", description: "", deadline: "" }); - setModalData({ title: "", description: "", status: "pending", deadline: "" }); + setModalData({ + title: "", + description: "", + status: "pending", + deadline: "", + }); setEditingId(null); } function openAddModal() { - setModalData({ title: "", description: "", status: "pending", deadline: "" }); + setModalData({ + title: "", + description: "", + status: "pending", + deadline: "", + }); setEditingId(null); setShowModal(true); } @@ -67,12 +105,15 @@ export default function Todo() { description: modalData.description, status: modalData.status, deadline: modalData.deadline || null, - }) + }), }) .then(async (res) => { const data = await res.json(); - if (!res.ok) throw new Error(data?.errors?.[0]?.msg || "Failed to update task"); - setTasks(prev => prev.map(t => (t._id || t.id) === taskId ? data : t)); + if (!res.ok) + throw new Error(data?.errors?.[0]?.msg || "Failed to update task"); + setTasks((prev) => + prev.map((t) => ((t._id || t.id) === taskId ? data : t)) + ); setShowModal(false); resetForm(); }) @@ -86,12 +127,13 @@ export default function Todo() { description: modalData.description, status: modalData.status, deadline: modalData.deadline || null, - }) + }), }) .then(async (res) => { const data = await res.json(); - if (!res.ok) throw new Error(data?.errors?.[0]?.msg || "Failed to create task"); - setTasks(prev => [data, ...prev]); + if (!res.ok) + throw new Error(data?.errors?.[0]?.msg || "Failed to create task"); + setTasks((prev) => [data, ...prev]); setShowModal(false); resetForm(); }) @@ -101,35 +143,41 @@ export default function Todo() { function toggleComplete(id) { const token = localStorage.getItem("token"); - const task = tasks.find(t => t._id === id || t.id === id); + const task = tasks.find((t) => t._id === id || t.id === id); if (!task) return; const newStatus = task.status === "pending" ? "completed" : "pending"; const taskId = task._id || task.id; fetch(`${API}/${taskId}`, { method: "PUT", headers: { "Content-Type": "application/json", "x-auth-token": token }, - body: JSON.stringify({ status: newStatus }) + body: JSON.stringify({ status: newStatus }), }) .then(async (res) => { const data = await res.json(); - if (!res.ok) throw new Error(data?.errors?.[0]?.msg || "Failed to update task"); - setTasks(prev => prev.map(t => (t._id || t.id) === taskId ? data : t)); + if (!res.ok) + throw new Error(data?.errors?.[0]?.msg || "Failed to update task"); + setTasks((prev) => + prev.map((t) => ((t._id || t.id) === taskId ? data : t)) + ); }) .catch((e) => console.error(e)); } function removeTask(id) { const token = localStorage.getItem("token"); - const task = tasks.find(t => t._id === id || t.id === id); + const task = tasks.find((t) => t._id === id || t.id === id); if (!task) return; const taskId = task._id || task.id; - fetch(`${API}/${taskId}`, { method: "DELETE", headers: { "x-auth-token": token } }) + fetch(`${API}/${taskId}`, { + method: "DELETE", + headers: { "x-auth-token": token }, + }) .then(async (res) => { if (!res.ok) { const data = await res.json(); throw new Error(data?.errors?.[0]?.msg || "Failed to delete task"); } - setTasks(prev => prev.filter(t => (t._id || t.id) !== taskId)); + setTasks((prev) => prev.filter((t) => (t._id || t.id) !== taskId)); }) .catch((e) => console.error(e)); } @@ -140,7 +188,7 @@ export default function Todo() { title: task.title, description: task.description, status: task.status, - deadline: task.deadline ? task.deadline.slice(0,16) : "", + deadline: task.deadline ? task.deadline.slice(0, 16) : "", }); setShowModal(true); } @@ -153,13 +201,22 @@ export default function Todo() { return (
-

Goals

- {done}/{total} completed +

+ Goals +

+ + {done}/{total} completed +
-
+
-

Track milestones like "Solve X LeetCode" or "Finish project".

+

+ Track milestones like "Solve X LeetCode" or "Finish project". +

); } @@ -168,7 +225,11 @@ export default function Todo() {
-
-

{task.title}

- {task.description &&

{task.description}

} +

+ {task.title} +

+ {task.description && ( +

+ {task.description} +

+ )} {task.deadline && ( -

Due {new Date(task.deadline).toLocaleString()}

+

+ Due {new Date(task.deadline).toLocaleString()} +

)}
- -
@@ -202,133 +279,220 @@ export default function Todo() { return (
-

Weekly Goals

- {weeklyDone}/{weeklyTarget} this week +

+ Weekly Goals +

+ + {weeklyDone}/{weeklyTarget} this week +
-
+
-

Set targets like "Solve 7 problems" weekly.

+

+ Set targets like "Solve 7 problems" weekly. +

); } return ( -
+
+ {" "} -
-
-
- -

To-Do List

-
-
- - +
+ {" "} + {/* sidebar stays left */} +
+
+
+ +

+ To-Do List +

+
+
+ + +
+
-
-
- {/* Add / Edit Modal */} - {showModal && ( -
-
-
-

{editingId ? "Edit Task" : "Add Task"}

- -
-
- setModalData({ ...modalData, title: e.target.value })} placeholder="Title" className="px-3 py-2 rounded-lg bg-[var(--background)] dark:bg-gray-900 text-[var(--card-foreground)] dark:text-gray-100 border border-[var(--input)] dark:border-gray-600" /> -