diff --git a/src/context api/context.jsx b/src/context api/context.jsx
index 66c1dcf..5b0682f 100644
--- a/src/context api/context.jsx
+++ b/src/context api/context.jsx
@@ -20,6 +20,7 @@ export const AllconversProvider = ({ children }) => {
const [assigntask, setAssigntask] = useState(false);
const [viewchanneltasks, setViewchanneltask] = useState(false);
const [viewtask, setViewtask] = useState(false);
+ const [assigntaskself, setassigntaskself] = useState(false);
// Fetch user data once on component mount
useEffect(() => {
const fetchUserData = async () => {
@@ -80,6 +81,8 @@ export const AllconversProvider = ({ children }) => {
setViewchanneltask,
viewtask,
setViewtask,
+ assigntaskself,
+ setassigntaskself,
};
return (
diff --git a/src/homepage/ToDo_list/mytododlist.jsx b/src/homepage/ToDo_list/mytododlist.jsx
new file mode 100644
index 0000000..f154901
--- /dev/null
+++ b/src/homepage/ToDo_list/mytododlist.jsx
@@ -0,0 +1,188 @@
+import supabase from "../../supabase";
+import assigntaskselfCSS from "./mytodolist.module.css";
+import { Allconvers } from "../../context api/context";
+import { useContext, useState, useEffect } from "react";
+import { ImCross } from "react-icons/im";
+import { fetchusertodo } from "../../database.jsx"; // Import your utility functions
+import { v4 as uuid } from "uuid";
+
+const Assigntaskself = () => {
+ const { setassigntaskself, currentUser } = useContext(Allconvers);
+ const [taskName, setTaskName] = useState("");
+ const [dueDateTime, setDueDateTime] = useState("");
+ const [noDueDate, setNoDueDate] = useState(false); // State to track if "No Due Date" option is selected
+ const [taskDescription, setTaskDescription] = useState("");
+ const [user_todo, setUserTodo] = useState([]);
+ const [refreshuserlist, setrefreshuserlist] = useState(false);
+ // Notification states
+ const [showNotification, setShowNotification] = useState(false);
+ const [showSuccessNotification, setShowSuccessNotification] = useState(false);
+
+ useEffect(() => {
+ const fetchUserTodoList = async () => {
+ const receivedUserTodo = await fetchusertodo(currentUser[0].id);
+ setUserTodo(receivedUserTodo);
+ setrefreshuserlist(false);
+ };
+ fetchUserTodoList();
+ }, [currentUser[0].id, refreshuserlist]);
+
+ useEffect(() => {
+ console.log(refreshuserlist), [refreshuserlist];
+ });
+ useEffect(() => {
+ const userlistupd = () => {
+ const userlistupds = supabase
+ .channel("user_list")
+ .on(
+ "postgres_changes",
+ {
+ event: "*", //channels are used to listen to real time changes
+ schema: "public", //here we listen to the changes in realtime and update the postgres changes here
+ table: "Todo_list",
+ select: "todo_list",
+ filter: `id=eq.${currentUser[0].id}`,
+ },
+ (payload) => {
+ setrefreshuserlist(true);
+ }
+ )
+ .subscribe();
+
+ // Cleanup function to unsubscribe from the channel to avoid data leakage
+ return () => {
+ supabase.removeChannel(userlistupds);
+ };
+ };
+ userlistupd();
+ }, [currentUser[0].id]);
+
+ const handleSubmit = async () => {
+ try {
+ // Check if required fields are filled
+ if (!taskName || (!noDueDate && !dueDateTime) || !taskDescription) {
+ setShowNotification(true);
+ // Hide notification after 2.5 seconds
+ setTimeout(() => {
+ setShowNotification(false);
+ }, 2500);
+ return;
+ }
+
+ const assignedOn = new Date().toISOString(); // Current timestamp
+ const task_id = uuid(); // Generate a random UUID
+
+ let todoListData = {};
+
+ todoListData = [
+ ...user_todo,
+ {
+ task_id,
+ taskname: taskName,
+ duedate: noDueDate ? null : dueDateTime || null,
+ assignedon: assignedOn,
+ task_description: taskDescription,
+ taskdone: false,
+ assigned_by: currentUser[0].username,
+ assigned_byid: currentUser[0].id,
+ },
+ ];
+
+ await supabase
+ .from("Todo_list")
+ .update({ todo_list: todoListData })
+ .eq("id", currentUser[0].id);
+
+ // Clear input fields and reset states after successful submission
+ setTaskName("");
+ setDueDateTime("");
+ setNoDueDate(false);
+ setTaskDescription("");
+ setShowSuccessNotification(true);
+ // Hide success notification after 3 seconds
+ setTimeout(() => {
+ setShowSuccessNotification(false);
+ }, 3000);
+ } catch (error) {
+ console.error("Error assigning task:", error.message);
+ }
+ };
+
+ return (
+
+
+
{
+ setassigntaskself(false);
+ }}
+ className={assigntaskselfCSS.closeIcon}
+ />
+
+
Add my Tasks
+
+
+ Task Name:
+ setTaskName(e.target.value)}
+ required // Ensure task name is compulsory
+ />
+ * Required
+
+
+
+ Task Description:
+
+
+ Assign
+
+ {showNotification && (
+
+ "Please fill all required details."
+
+ )}
+ {showSuccessNotification && (
+
+ Task added successfully!
+
+ )}
+
+
+ );
+};
+
+export default Assigntaskself;
diff --git a/src/homepage/ToDo_list/mytodolist.module.css b/src/homepage/ToDo_list/mytodolist.module.css
new file mode 100644
index 0000000..670ab41
--- /dev/null
+++ b/src/homepage/ToDo_list/mytodolist.module.css
@@ -0,0 +1,101 @@
+.body {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background-color: rgba(0, 0, 0, 0.8);
+ width: 100%;
+ height: 100%;
+ z-index: 1000;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.box {
+ background-color: white;
+ padding: 20px;
+ width: 400px;
+ border-radius: 8px;
+ box-shadow: 0 0 10px rgba(31, 30, 30, 0.1);
+ position: relative;
+}
+
+.closeIcon {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ cursor: pointer;
+}
+
+.head {
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.head h1 {
+ font-size: 1.5rem;
+ margin: 0;
+}
+
+.taskName,
+.dueDateTime,
+.taskDescription {
+ margin-bottom: 20px;
+}
+
+.taskName label,
+.dueDateTime label,
+.taskDescription label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+
+.taskName input,
+.dueDateTime input[type="datetime-local"],
+.taskDescription textarea {
+ width: 100%;
+ padding: 8px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+
+.dueDateTimeOptions {
+ display: flex;
+ align-items: center;
+}
+
+.dueDateTimeOptions label {
+ margin-left: 10px;
+}
+
+.submitButton {
+ text-align: center;
+}
+
+.submitButton button {
+ padding: 10px 20px;
+ background-color: #007bff;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+}
+
+.notification {
+ background-color: #28a745;
+ color: white;
+ text-align: center;
+ padding: 10px;
+ border-radius: 4px;
+ margin-top: 10px;
+ animation: fadeInOut 5s ease-in-out; /* Apply fadeInOut animation for notifications */
+}
+
+.requiredLabel {
+ display: block;
+ color: red;
+ font-size: 0.8rem;
+ margin-top: 5px;
+}
diff --git a/src/homepage/ToDo_list/vieusertask.module.css b/src/homepage/ToDo_list/vieusertask.module.css
deleted file mode 100644
index e69de29..0000000
diff --git a/src/homepage/ToDo_list/viewchanneltask.jsx b/src/homepage/ToDo_list/viewchanneltask.jsx
index 717350f..6d5fb27 100644
--- a/src/homepage/ToDo_list/viewchanneltask.jsx
+++ b/src/homepage/ToDo_list/viewchanneltask.jsx
@@ -144,7 +144,10 @@ const Viewchanneltask = () => {
Due Date: {dueDateDisplay}
- Assigned By: {task.assigned_by}
+ Assigned By:{" "}
+ {task.assigned_byid === currentUser[0].id
+ ? `${task.assigned_by} (You)`
+ : `${task.assigned_by}`}
Assigned on:{" "}
@@ -196,7 +199,10 @@ const Viewchanneltask = () => {
: "None"}
- Assigned By: {task.assigned_by}
+ Assigned By:{" "}
+ {task.assigned_byid === currentUser[0].id
+ ? `${task.assigned_by} (You)`
+ : `${task.assigned_by}`}
Assigned on:{" "}
diff --git a/src/homepage/ToDo_list/viewusertask.jsx b/src/homepage/ToDo_list/viewusertask.jsx
index e69de29..7e12d6d 100644
--- a/src/homepage/ToDo_list/viewusertask.jsx
+++ b/src/homepage/ToDo_list/viewusertask.jsx
@@ -0,0 +1,232 @@
+import React, { useContext, useState, useEffect } from "react";
+import { ImCross } from "react-icons/im";
+import supabase from "../../supabase";
+import viewusertaskCSS from "./viewusertask.module.css";
+import { Allconvers } from "../../context api/context";
+import { fetchusertodo } from "../../database";
+
+const Viewutask = () => {
+ const { currentUser, setViewtask } = useContext(Allconvers);
+ const [isAdmin, setIsAdmin] = useState(false);
+ const [tasks, setTasks] = useState([]);
+
+ useEffect(() => {
+ if (currentUser) {
+ setIsAdmin(true);
+ }
+ const fetchTasks = async () => {
+ const fetchedTasks = await fetchusertodo(currentUser[0].id);
+ setTasks(fetchedTasks);
+ };
+ fetchTasks();
+ // Refresh tasks every minute to update time remaining
+ const interval = setInterval(fetchTasks, 60000); // Update every minute
+ return () => clearInterval(interval); // Clean up interval on component unmount
+ }, [currentUser]);
+
+ // Function to calculate time remaining until due date
+ const calculateTimeRemaining = (dueDate) => {
+ if (!dueDate)
+ return {
+ days: null,
+ hours: null,
+ minutes: null,
+ seconds: null,
+ distance: null,
+ };
+ const now = new Date().getTime();
+ const dueTime = new Date(dueDate).getTime();
+ const distance = dueTime - now;
+ // Calculate days, hours, minutes, and seconds
+ const days = Math.floor(distance / (1000 * 60 * 60 * 24));
+ const hours = Math.floor(
+ (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
+ );
+ const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
+ const seconds = Math.floor((distance % (1000 * 60)) / 1000);
+ return { days, hours, minutes, seconds, distance };
+ };
+ const markAsDone = async (task_id) => {
+ const updatedTasks = tasks.map(
+ (
+ task //to set the tasks done
+ ) => (task.task_id === task_id ? { ...task, taskdone: true } : task)
+ );
+ setTasks(updatedTasks);
+ await updateTasks(updatedTasks);
+ };
+ const removeTask = async (task_id) => {
+ //to remove the tasks from the db
+ const updatedTasks = tasks.filter((task) => task.task_id !== task_id);
+ setTasks(updatedTasks);
+ await updateTasks(updatedTasks);
+ };
+ const undoTask = async (task_id) => {
+ //to bring back tasks back into To Do
+ const updatedTasks = tasks.map((task) =>
+ task.task_id === task_id ? { ...task, taskdone: false } : task
+ );
+ setTasks(updatedTasks);
+ await updateTasks(updatedTasks);
+ };
+ const updateTasks = async (updatedTasks) => {
+ await supabase
+ .from("Todo_list")
+ .update({ todo_list: updatedTasks })
+ .eq("id", currentUser[0].id);
+ };
+ // Sort tasks by due date (nearest due date first), with "None" due date at the bottom
+ const sortedTasks = tasks.slice().sort((a, b) => {
+ //slice is used so that a new copy be created which decreses the risk of db data changing
+ if (!a.duedate && !b.duedate) return 0; // Both have no due date
+ if (!a.duedate) return 1; // a has no due date, place it after b
+ if (!b.duedate) return -1; // b has no due date, place it after a
+
+ const dueDateA = new Date(a.duedate).getTime();
+ const dueDateB = new Date(b.duedate).getTime();
+ return dueDateA - dueDateB; // Ascending order (nearest due date first)
+ });
+
+ return (
+ <>
+
+
+
+
My Tasks
+ {
+ setViewtask(false);
+ }}
+ className={viewusertaskCSS.closeIcon}
+ />
+
+
+
+
To Do
+
+ {sortedTasks //calls the sorting function for the filtered tasks
+ .filter((task) => !task.taskdone)
+ .map((task) => {
+ const { days, hours, minutes, seconds, distance } =
+ calculateTimeRemaining(task.duedate); //time left is calculated to change the due date color accordingly
+ const isPastDue = distance < 0;
+ const dueDateDisplay = task.duedate
+ ? new Date(task.duedate).toLocaleDateString() //to show date according to local date string
+ : "None";
+
+ return (
+ //now returning the filtered and then sorted tasks
+
+
+
+
{task.taskname}
+
{task.task_description}
+
+ Due Date: {dueDateDisplay}
+
+
+ Assigned By:{" "}
+ {task.assigned_byid === currentUser[0].id
+ ? `${task.assigned_by} (You)`
+ : `${task.assigned_by}`}
+
+
+ Assigned on:{" "}
+ {new Date(task.assignedon).toLocaleDateString()}
+
+
+
+ {isAdmin && (
+ <>
+ markAsDone(task.task_id)}
+ className={viewusertaskCSS.button}
+ >
+ Done
+
+ removeTask(task.task_id)}
+ className={viewusertaskCSS.removebutton}
+ >
+ Remove
+
+ >
+ )}
+
+
+
+ );
+ })}
+
+
+
+
Done
+
+ {sortedTasks
+ .filter((task) => task.taskdone)
+ .map((task) => (
+
+
+
+
{task.taskname}
+
{task.task_description}
+
+ Due Date:{" "}
+ {task.duedate
+ ? new Date(task.duedate).toLocaleDateString()
+ : "None"}
+
+
+ Assigned By:{" "}
+ {task.assigned_byid === currentUser[0].id
+ ? `${task.assigned_by} (You)`
+ : `${task.assigned_by}`}
+
+
+ Assigned on:{" "}
+ {new Date(task.assignedon).toLocaleDateString()}
+
+
+
+ {isAdmin && (
+ <>
+ undoTask(task.task_id)}
+ className={viewusertaskCSS.button}
+ >
+ Undone
+
+ removeTask(task.task_id)}
+ className={viewusertaskCSS.removebutton}
+ >
+ Remove
+
+ >
+ )}
+
+
+
+ ))}
+
+
+
+
+
+ >
+ );
+};
+
+export default Viewutask;
diff --git a/src/homepage/ToDo_list/viewusertask.module.css b/src/homepage/ToDo_list/viewusertask.module.css
new file mode 100644
index 0000000..799ee3c
--- /dev/null
+++ b/src/homepage/ToDo_list/viewusertask.module.css
@@ -0,0 +1,143 @@
+.body {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ height: 100vh;
+ background-color: #f0f0f085;
+ position: absolute;
+ z-index: 5;
+ top: 0;
+ left: 0;
+}
+
+.box {
+ width: 80%;
+ max-width: 800px;
+ background-color: #fff;
+ border-radius: 8px;
+ box-shadow: 0 0 10px rgba(29, 29, 29, 0.1);
+ padding: 20px;
+ height: 80vh;
+ overflow: hidden;
+ position: relative;
+}
+
+.head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ height: 10%;
+}
+
+.heading {
+ color: #333;
+ font-size: 1.5rem;
+ margin-bottom: 10px;
+}
+
+.closeIcon {
+ cursor: pointer;
+}
+
+.tasks {
+ display: flex;
+ height: 90%;
+ width: 100%;
+ position: relative;
+}
+
+.todo,
+.done {
+ flex: 1;
+ margin: 10px;
+ padding: 10px;
+ background-color: #f5f5f5;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.sectionHeading {
+ color: #333;
+ font-size: 1.2rem;
+ margin-bottom: 10px;
+}
+
+.taskList {
+ list-style-type: none;
+ padding: 0;
+ overflow-y: auto;
+ height: calc(100% - 30px);
+}
+
+.taskItem {
+ margin-bottom: 10px;
+ padding: 10px;
+ border-radius: 8px;
+ height: 130px;
+ width: 100%;
+ background-color: #f0dbc7;
+}
+
+.taskContainer {
+ padding: 5px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.taskInfo {
+ flex: 1;
+}
+
+.taskMeta {
+ margin: 5px 0;
+}
+
+.taskActions {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.button,
+.removebutton {
+ color: #fff;
+ border: none;
+ padding: 8px 12px;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-right: 5px;
+ height: 30px;
+ width: 70px;
+}
+
+.button {
+ background-color: #007bff;
+ margin-bottom: 3px;
+}
+
+.button:hover {
+ background-color: #0056b3;
+}
+
+.removebutton {
+ background-color: #ff1100;
+ margin-top: 2px;
+}
+
+.removebutton:hover {
+ background-color: #b32400;
+}
+
+.taskMetaNotPastDue {
+ color: green;
+}
+
+.taskMetaPastDue {
+ color: red;
+}
+.taskMetaNone {
+ color: rgb(128, 31, 240);
+}
diff --git a/src/homepage/homepage.jsx b/src/homepage/homepage.jsx
index f3bd5e5..ad45202 100644
--- a/src/homepage/homepage.jsx
+++ b/src/homepage/homepage.jsx
@@ -25,6 +25,10 @@ import Addmember from "./channels/addchannelmember";
import Showmembers from "./channels/membersofchannel";
import Assigntask from "./ToDo_list/assigntask";
import Viewchanneltask from "./ToDo_list/viewchanneltask";
+import { MdAssignmentAdd } from "react-icons/md";
+import { FaTasks } from "react-icons/fa";
+import Viewutask from "./ToDo_list/viewusertask";
+import Assigntaskself from "./ToDo_list/mytododlist";
function Home(data) {
const {
@@ -50,9 +54,10 @@ function Home(data) {
assigntask,
setAssigntask,
viewchanneltasks,
-
viewtask,
setViewtask,
+ assigntaskself,
+ setassigntaskself,
} = useContext(Allconvers);
const { dispatch } = useContext(Chatcontext);
const { channel_data, dispatchchannel } = useContext(Channelcontext);
@@ -224,7 +229,9 @@ function Home(data) {
return (
<>
{viewchanneltasks ? : <>>}
+ {viewtask ? : <>>}
{assigntask ? : <>>}
+ {assigntaskself ? : <>>}
{showmembers ? : <>>}
{addchannelmember ? : <>>}
{addchannel ? : <>>}
@@ -344,6 +351,18 @@ function Home(data) {
className={homepaseCSS.poweroff}
onClick={() => signout()}
/>
+ setViewtask(true)}
+ size={30}
+ color="white"
+ style={{ cursor: "pointer" }}
+ />
+ setassigntaskself(true)}
+ size={30}
+ color="white"
+ style={{ cursor: "pointer" }}
+ />
diff --git a/src/homepage/homepage.module.css b/src/homepage/homepage.module.css
index 145747c..de5ae91 100644
--- a/src/homepage/homepage.module.css
+++ b/src/homepage/homepage.module.css
@@ -162,38 +162,45 @@
font-size: 15px;
}
.schannel {
- height: 40px;
- width: 90%;
- background-color: rgb(96, 15, 109);
- display: flex;
- cursor: pointer;
- border-bottom: solid thin black;
- border-radius: 10px;
- margin-bottom: 2px;
- display: flex;
- align-items: center;
- overflow: hidden;
- }
- .schannel:hover {
- background-color: rgb(77, 5, 88);
- }
- .sdmimg {
- height: 25px;
- width: 25px;
- border-radius: 50%;
- background-color: azure;
- }
- .schannelinfo {
- color: rgb(222, 225, 228);
- display: flex;
- align-items: center;
- margin-left: 8px;
- }
- .schannelname {
- font-size: 20px;
- font-weight: 500;
- margin-left: 10px;
- }
- .schannelmail {
- font-size: 15px;
- }
\ No newline at end of file
+ height: 40px;
+ width: 90%;
+ background-color: rgb(96, 15, 109);
+ display: flex;
+ cursor: pointer;
+ border-bottom: solid thin black;
+ border-radius: 10px;
+ margin-bottom: 2px;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+}
+.schannel:hover {
+ background-color: rgb(77, 5, 88);
+}
+.sdmimg {
+ height: 25px;
+ width: 25px;
+ border-radius: 50%;
+ background-color: azure;
+}
+.schannelinfo {
+ color: rgb(222, 225, 228);
+ display: flex;
+ align-items: center;
+ margin-left: 8px;
+}
+.schannelname {
+ font-size: 20px;
+ font-weight: 500;
+ margin-left: 10px;
+}
+.schannelmail {
+ font-size: 15px;
+}
+.allcom {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ height: 140px;
+}