+
+
+ {/* β
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() {
-
-
startEdit(task)} className="p-2 rounded-lg hover:bg-[var(--accent)] dark:hover:bg-gray-700/50" aria-label="edit">
+ startEdit(task)}
+ className="p-2 rounded-lg hover:bg-[var(--accent)] dark:hover:bg-gray-700/50"
+ aria-label="edit"
+ >
- removeTask(task._id || task.id)} className="p-2 rounded-lg hover:bg-[var(--accent)] dark:hover:bg-gray-700/50" aria-label="delete">
+ removeTask(task._id || task.id)}
+ className="p-2 rounded-lg hover:bg-[var(--accent)] dark:hover:bg-gray-700/50"
+ aria-label="delete"
+ >
@@ -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
+
-
-
- Add
-
-
- {/* Add / Edit Modal */}
- {showModal && (
-
-
-
-
{editingId ? "Edit Task" : "Add Task"}
- { setShowModal(false); resetForm(); }} className="px-2 py-1 rounded-md hover:bg-[var(--accent)] dark:hover:bg-gray-700/50 text-[var(--card-foreground)] dark:text-gray-100">β
-
-
-
-
);
-}
\ No newline at end of file
+}