diff --git a/README.md b/README.md
index a8d3593..20a7fff 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ The Team Management App is a web-based application designed to facilitate team c
## Live Links
- [Frontend](https://team-manager-eight.vercel.app)
-- [Backend](https://team-management-app-server-with-redis.onrender.com)
+- [Backend](https://api-team-manager.onrender.com)
###### Login to website
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index fd28bf5..b2321ba 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -26,6 +26,7 @@
"react-icons": "^4.10.1",
"react-redux": "^9.1.0",
"react-select": "^5.8.0",
+ "socket.io-client": "^4.7.5",
"sweetalert2": "^11.7.18",
"swiper": "^11.0.5",
"tailwind-scrollbar": "^3.0.5"
@@ -1569,6 +1570,12 @@
"integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==",
"dev": true
},
+ "node_modules/@socket.io/component-emitter": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
+ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
+ "license": "MIT"
+ },
"node_modules/@swc/helpers": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
@@ -2671,7 +2678,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
"dependencies": {
"ms": "2.1.2"
},
@@ -2800,6 +2806,28 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
+ "node_modules/engine.io-client": {
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
+ "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.17.1",
+ "xmlhttprequest-ssl": "~2.0.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
+ "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.15.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
@@ -4811,8 +4839,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/mz": {
"version": "2.7.0",
@@ -6073,6 +6100,34 @@
"node": ">=8"
}
},
+ "node_modules/socket.io-client": {
+ "version": "4.7.5",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
+ "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.2",
+ "engine.io-client": "~6.5.2",
+ "socket.io-parser": "~4.2.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/socket.io-parser": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -6996,6 +7051,35 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
+ "node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xmlhttprequest-ssl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
+ "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index bddb525..42934c8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -27,6 +27,7 @@
"react-icons": "^4.10.1",
"react-redux": "^9.1.0",
"react-select": "^5.8.0",
+ "socket.io-client": "^4.7.5",
"sweetalert2": "^11.7.18",
"swiper": "^11.0.5",
"tailwind-scrollbar": "^3.0.5"
diff --git a/frontend/src/components/pages/dashboard/invitation/PendingInvitation.tsx b/frontend/src/components/pages/dashboard/invitation/PendingInvitation.tsx
index 561208f..8a6c980 100644
--- a/frontend/src/components/pages/dashboard/invitation/PendingInvitation.tsx
+++ b/frontend/src/components/pages/dashboard/invitation/PendingInvitation.tsx
@@ -27,7 +27,7 @@ const PendingInvitation = () => {
memberId: user?.id,
});
if (result?.data?.success) {
- // socket.emit("notification", result?.data?.data);
+ socket.emit("notification", result?.data?.data);
Swal.fire({
position: "center",
icon: "success",
@@ -45,7 +45,7 @@ const PendingInvitation = () => {
});
if (result?.data?.success) {
// send notification viw socket
- // socket.emit("notification", result?.data?.data);
+ socket.emit("notification", result?.data?.data);
Swal.fire({
position: "center",
diff --git a/frontend/src/components/pages/dashboard/leaveRequest/ProjectLeaveRequest.tsx b/frontend/src/components/pages/dashboard/leaveRequest/ProjectLeaveRequest.tsx
index 739d2b0..d3f2a4f 100644
--- a/frontend/src/components/pages/dashboard/leaveRequest/ProjectLeaveRequest.tsx
+++ b/frontend/src/components/pages/dashboard/leaveRequest/ProjectLeaveRequest.tsx
@@ -12,8 +12,6 @@ const ProjectLeaveRequest = () => {
);
const requests = requestsData?.data;
- console.log("project", requests);
-
return (
{requests?.length > 0 &&
diff --git a/frontend/src/components/pages/projects/desktop/AddMemberToProject.tsx b/frontend/src/components/pages/projects/desktop/AddMemberToProject.tsx
index 5bf6055..71b94cb 100644
--- a/frontend/src/components/pages/projects/desktop/AddMemberToProject.tsx
+++ b/frontend/src/components/pages/projects/desktop/AddMemberToProject.tsx
@@ -40,7 +40,7 @@ const AddMemberToProject = ({ isOpen, setIsOpen, projectId, team }: Props) => {
const result: any = await addNewMember(memberData);
if (result?.data?.success) {
- // socket.emit("notification", result?.data?.data);
+ socket.emit("notification", result?.data?.data);
Swal.fire({
position: "center",
icon: "success",
diff --git a/frontend/src/components/pages/projects/desktop/ProjectPage.tsx b/frontend/src/components/pages/projects/desktop/ProjectPage.tsx
index 8c2db5a..c4f3f27 100644
--- a/frontend/src/components/pages/projects/desktop/ProjectPage.tsx
+++ b/frontend/src/components/pages/projects/desktop/ProjectPage.tsx
@@ -34,8 +34,6 @@ const Projects = () => {
user?.id
);
- console.log("Project for task", project);
-
const handleLeaveRequest = async () => {
Swal.fire({
title: "So sad",
@@ -69,9 +67,9 @@ const Projects = () => {
}, [query?.id]);
// connect to socket team room
- // useEffect(() => {
- // socket.emit("task-room", project?.id);
- // }, [socket, project?.id]);
+ useEffect(() => {
+ socket.emit("task-room", project?.id);
+ }, [socket, project?.id]);
return (
diff --git a/frontend/src/components/pages/tasks/CreateTaskModal.tsx b/frontend/src/components/pages/tasks/CreateTaskModal.tsx
index aabab65..eebe5e0 100644
--- a/frontend/src/components/pages/tasks/CreateTaskModal.tsx
+++ b/frontend/src/components/pages/tasks/CreateTaskModal.tsx
@@ -31,9 +31,9 @@ const CreateTaskModal = ({ isOpen, setIsOpen, project, status }: any) => {
data.project = project.id;
const result: any = await createTask(data);
if (result?.data?.success) {
- // window.location.reload();
- // socket.emit("task", result?.data?.data?.data);
- // socket.emit("notification", result?.data?.data?.notification);
+ window.location.reload();
+ socket.emit("task", result?.data?.data?.data);
+ socket.emit("notification", result?.data?.data?.notification);
Swal.fire({
position: "center",
icon: "success",
diff --git a/frontend/src/components/pages/tasks/ParentTask.tsx b/frontend/src/components/pages/tasks/ParentTask.tsx
index 52d9d46..aab0eec 100644
--- a/frontend/src/components/pages/tasks/ParentTask.tsx
+++ b/frontend/src/components/pages/tasks/ParentTask.tsx
@@ -94,12 +94,7 @@ const ParentTask = ({ project }: Props) => {
// Fetch tasks only if project id is available
if (project?.id) {
fetch(
- `https://api-team-manager.onrender.com/task/by-project/${project.id}`,
- {
- headers: {
- authorization: token || "",
- },
- }
+ `https://api-team-manager.onrender.com/task/by-project/${project.id}`
)
.then((res) => res.json())
.then((data: any) => {
@@ -163,16 +158,15 @@ const ParentTask = ({ project }: Props) => {
};
// Listen for new tasks from socket
- // useEffect(() => {
- // socket.on("task", (newTask: any) => {
- // console.log("New task data", newTask);
- // addNewTask(newTask);
- // });
-
- // return () => {
- // socket.off("task");
- // };
- // }, [socket]);
+ useEffect(() => {
+ socket.on("task", (newTask: any) => {
+ addNewTask(newTask);
+ });
+
+ return () => {
+ socket.off("task");
+ };
+ }, [socket]);
return (
diff --git a/frontend/src/components/pages/teams/addMember/AddMemberModal.tsx b/frontend/src/components/pages/teams/addMember/AddMemberModal.tsx
index ab7a42e..9b21974 100644
--- a/frontend/src/components/pages/teams/addMember/AddMemberModal.tsx
+++ b/frontend/src/components/pages/teams/addMember/AddMemberModal.tsx
@@ -53,7 +53,7 @@ const AddMemberModal = ({ isOpen, setIsOpen, team }: any) => {
if (result?.data?.success) {
closeModal();
// send invitation notification
- // socket.emit("notification", result?.data?.data);
+ socket.emit("notification", result?.data?.data);
Swal.fire({
position: "center",
icon: "success",
diff --git a/frontend/src/components/pages/teams/collaborations/common/MessageForm.tsx b/frontend/src/components/pages/teams/collaborations/common/MessageForm.tsx
index 9275026..1db1d59 100644
--- a/frontend/src/components/pages/teams/collaborations/common/MessageForm.tsx
+++ b/frontend/src/components/pages/teams/collaborations/common/MessageForm.tsx
@@ -83,7 +83,7 @@ const MessageForm = ({ teamId, type }: Props) => {
};
const emitData: IMessage = { ...message, poster };
- // socket.emit("message", emitData);
+ socket.emit("message", emitData);
setRealTimeMessages((prev: IMessage[]) => [...prev, emitData]);
setImagePreview([]);
diff --git a/frontend/src/components/pages/teams/collaborations/common/ShowMessages.tsx b/frontend/src/components/pages/teams/collaborations/common/ShowMessages.tsx
index 8d14eb2..62c4b0d 100644
--- a/frontend/src/components/pages/teams/collaborations/common/ShowMessages.tsx
+++ b/frontend/src/components/pages/teams/collaborations/common/ShowMessages.tsx
@@ -26,7 +26,6 @@ const ShowMessages = ({ messages }: Props) => {
const [editedMessage, setEditedMessage] = useState("");
const [imageModalOpen, setImageModalOpen] = useState(false);
const [selectedImage, setSelectedImage] = useState("");
- const [onlineUsers, setOnlineUsers] = useState({});
const [isEditMessage, setIsEditMessage] = useState<{
id: string | undefined;
status: boolean;
@@ -67,30 +66,30 @@ const ShowMessages = ({ messages }: Props) => {
}
};
- // useEffect(() => {
- // const handleMessage = (data: IMessage) => {
- // setRealTimeMessages((prev: IMessage[]) => [...prev, data]);
- // };
+ useEffect(() => {
+ const handleMessage = (data: IMessage) => {
+ setRealTimeMessages((prev: IMessage[]) => [...prev, data]);
+ };
- // socket.on("message", handleMessage);
+ socket?.on("message", handleMessage);
- // return () => {
- // socket.off("message", handleMessage);
- // };
- // }, [setRealTimeMessages, socket]);
+ return () => {
+ socket?.off("message", handleMessage);
+ };
+ }, [setRealTimeMessages, socket]);
// keep updated message in state
- // useEffect(() => {
- // setRealTimeMessages(messages);
- // }, [messages, setRealTimeMessages]);
+ useEffect(() => {
+ setRealTimeMessages(messages);
+ }, [messages, setRealTimeMessages]);
// keep user in the bottom of the message
- // useEffect(() => {
- // if (messagesContainerRef.current) {
- // messagesContainerRef.current.scrollTop =
- // messagesContainerRef.current.scrollHeight;
- // }
- // }, [realTimeMessages, socket]);
+ useEffect(() => {
+ if (messagesContainerRef.current) {
+ messagesContainerRef.current.scrollTop =
+ messagesContainerRef.current.scrollHeight;
+ }
+ }, [realTimeMessages, socket]);
return (
{
};
// connect to socket team room
- // useEffect(() => {
- // socket.emit("join-room", team?.id);
- // }, [socket, team?.id]);
+ useEffect(() => {
+ socket?.emit("join-room", team?.id);
+ }, [socket, team?.id]);
useEffect(() => {
setActiveNav(router?.query?.collaborate);
diff --git a/frontend/src/components/shared/Navbar.tsx b/frontend/src/components/shared/Navbar.tsx
index ab2c705..bde9768 100644
--- a/frontend/src/components/shared/Navbar.tsx
+++ b/frontend/src/components/shared/Navbar.tsx
@@ -18,7 +18,6 @@ const Navbar = () => {
const { theme, setTheme } = useTheme();
const { data }: any = useLoggedInUserQuery({});
const user: IUser = data?.data;
- console.log("User from navbar", user);
const [isOpen, setIsOpen] = useState(false);
const [toggle, setToggle] = useState(false);
const { data: notifiedData } = useGetNotificationQuery(user?.id);
@@ -32,16 +31,15 @@ const Navbar = () => {
window.location.replace("/");
};
- // useEffect(() => {
- // const handleNotification = (data: INotification) => {
- // console.log("New notification", data);
- // setUnreadNotifications((prev: INotification[]) => [...prev, data]);
- // };
- // socket.on("notification", handleNotification);
- // return () => {
- // socket.off("notification", handleNotification);
- // };
- // }, [socket]);
+ useEffect(() => {
+ const handleNotification = (data: INotification) => {
+ setUnreadNotifications((prev: INotification[]) => [...prev, data]);
+ };
+ socket?.on("notification", handleNotification);
+ return () => {
+ socket?.off("notification", handleNotification);
+ };
+ }, [socket]);
useEffect(() => {
const unread = notifications.filter((notified) => !notified.read);
diff --git a/frontend/src/context/SocketContext.tsx b/frontend/src/context/SocketContext.tsx
index 157fba6..914c927 100644
--- a/frontend/src/context/SocketContext.tsx
+++ b/frontend/src/context/SocketContext.tsx
@@ -1,14 +1,14 @@
-import useGetLoggedInUser from "@/hooks/useGetLoggedInUser";
import { IContext } from "@/interfaces/context.interface";
import { IMessage } from "@/interfaces/message.interface";
-import { IUser } from "@/interfaces/user.interface";
import { ReactNode, createContext, useEffect, useState } from "react";
+import { io } from "socket.io-client";
const initValues: IContext = {
realTimeMessages: [],
setRealTimeMessages: (messages: IMessage[]) => {},
refetchTask: false,
setRefetchTask: () => false,
+ socket: "",
};
export const SocketContext = createContext
(initValues);
@@ -18,35 +18,42 @@ type Props = {
};
const SocketProvider = ({ children }: Props) => {
- const socket: any = {};
+ const socket: any = io("https://api-team-manager.onrender.com");
const [realTimeMessages, setRealTimeMessages] = useState([]);
+ const [user, setUser] = useState({});
const [refetchTask, setRefetchTask] = useState(false);
- const user: IUser = useGetLoggedInUser();
- const [activeUsers, setActiveUsers] = useState([]);
-
- // connect to socket notification room
- // useEffect(() => {
- // socket.emit("notification-room", user?.id);
- // }, [socket, user?.id]);
-
- // // connect to socket active
- // useEffect(() => {
- // socket.emit("active", user?.id);
- // }, [socket, user?.id]);
-
- // // connect to socket active
- // useEffect(() => {
- // socket.on("activeUsers", (data: any) => {
- // setActiveUsers(data);
- // console.log("Active users", data);
- // });
- // }, [socket]);
+
+ useEffect(() => {
+ const fetchUser = async () => {
+ try {
+ const res = await fetch(
+ "https://api-team-manager.onrender.com/user/auth",
+ {
+ method: "GET",
+ credentials: "include",
+ }
+ );
+ const data = await res.json();
+ setUser(data?.data);
+ } catch (error) {
+ console.log("Failed to fetch user");
+ }
+ };
+ fetchUser();
+ }, []);
+
+ useEffect(() => {
+ if (user?.id) {
+ socket.emit("notification-room", user.id);
+ }
+ }, [user]);
const values: IContext = {
realTimeMessages,
setRealTimeMessages,
refetchTask,
setRefetchTask,
+ socket,
};
return (
diff --git a/frontend/src/hooks/useGetLoggedInUser.ts b/frontend/src/hooks/useGetLoggedInUser.ts
deleted file mode 100644
index a2e3743..0000000
--- a/frontend/src/hooks/useGetLoggedInUser.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useEffect, useState } from "react";
-import { IUser, userInitData } from "@/interfaces/user.interface";
-
-const useGetLoggedInUser = () => {
- const [user, setUser] = useState(userInitData);
- useEffect(() => {
- const fetchUser = async () => {
- try {
- const res = await fetch(
- "https://api-team-manager.onrender.com/user/auth",
- {
- method: "GET",
- credentials: "include",
- }
- );
- const data = await res.json();
- console.log("User from useGetLoggedInUser hook", data);
- setUser(data?.data);
- } catch (error) {
- console.log("Failed to fetch user");
- }
- console.log("Will call");
- };
- fetchUser();
- }, []);
-
- return user;
-};
-
-export default useGetLoggedInUser;
diff --git a/frontend/src/interfaces/context.interface.ts b/frontend/src/interfaces/context.interface.ts
index e0202ef..878fb43 100644
--- a/frontend/src/interfaces/context.interface.ts
+++ b/frontend/src/interfaces/context.interface.ts
@@ -5,4 +5,5 @@ export type IContext = {
setRealTimeMessages: (messages: IMessage[]) => void;
refetchTask: false;
setRefetchTask: (status: boolean) => void;
+ socket: any;
};