diff --git a/collab-service/app/controller/collab-controller.js b/collab-service/app/controller/collab-controller.js index 87f3f807b8..0d72e5bedf 100644 --- a/collab-service/app/controller/collab-controller.js +++ b/collab-service/app/controller/collab-controller.js @@ -4,6 +4,7 @@ import { getAllRooms, fetchRoomChatHistory, getQuestionIdByRoomId, + getAllRoomsByUserId, } from "../model/repository.js"; import crypto from "crypto"; @@ -12,11 +13,13 @@ export async function createRoom(req, res) { const { user1, user2, question_id } = req.body; if (!user1 || !user2 || !question_id) { - return res.status(400).json({ error: "user1,user2 and question_id are required" }); + return res + .status(400) + .json({ error: "user1,user2 and question_id are required" }); } // Generate a unique room ID by hashing the two user IDs - const timeSalt = new Date().toISOString().slice(0, 13); + const timeSalt = new Date().toISOString().slice(0, 19); const roomId = crypto .createHash("sha256") .update(user1 + user2 + timeSalt) @@ -58,6 +61,17 @@ export async function getAllRoomsController(req, res) { } } +// Get all rooms by user +export async function getAllRoomsByUser(req, res) { + const { user } = req.params; + const rooms = await getAllRoomsByUserId(user); + + if (rooms) { + res.status(200).json(rooms); + } else { + res.status(500).json({ error: "Failed to retrieve rooms" }); + } +} export async function getRoomChatHistory(req, res) { const { roomId } = req.params; @@ -86,6 +100,8 @@ export async function getQuestionId(req, res) { if (questionId) { res.status(200).json({ questionId }); } else { - res.status(404).json({ error: `Question ID not found for room ID: ${roomId}` }); + res + .status(404) + .json({ error: `Question ID not found for room ID: ${roomId}` }); } -} \ No newline at end of file +} diff --git a/collab-service/app/model/repository.js b/collab-service/app/model/repository.js index 73073a855b..9c304a819a 100644 --- a/collab-service/app/model/repository.js +++ b/collab-service/app/model/repository.js @@ -7,9 +7,6 @@ export async function connectToMongo() { export async function newRoom(user1, user2, roomId, questionId) { try { - // Remove any existing rooms where either user1 or user2 is a participant - await UsersSession.deleteMany({ users: { $in: [user1, user2] } }); - const newRoom = new UsersSession({ users: [user1, user2], roomId: roomId, @@ -35,7 +32,6 @@ export async function getRoomId(user) { } } - export async function getAllRooms() { try { const rooms = await UsersSession.find({}); @@ -46,6 +42,16 @@ export async function getAllRooms() { } } +export async function getAllRoomsByUserId(user) { + try { + const rooms = await UsersSession.find({ users: user }); + return rooms; + } catch (error) { + console.error("Error getting all rooms of user:", error); + return null; + } +} + // Function to add a new message to chatHistory with transaction support export async function addMessageToChat(roomId, userId, text) { // Start a session for the transaction @@ -113,4 +119,4 @@ export async function getQuestionIdByRoomId(roomId) { console.error(`Error finding questionId for roomId ${roomId}:`, error); return null; } -} \ No newline at end of file +} diff --git a/collab-service/app/routes/collab-routes.js b/collab-service/app/routes/collab-routes.js index 088321b041..08a324508f 100644 --- a/collab-service/app/routes/collab-routes.js +++ b/collab-service/app/routes/collab-routes.js @@ -3,8 +3,9 @@ import { createRoom, getRoomByUser, getAllRoomsController, + getAllRoomsByUser, getRoomChatHistory, - getQuestionId + getQuestionId, } from "../controller/collab-controller.js"; const router = express.Router(); @@ -15,6 +16,8 @@ router.get("/user/:user", getRoomByUser); router.get("/rooms", getAllRoomsController); +router.get("/rooms/:user", getAllRoomsByUser); + router.get("/chat-history/:roomId", getRoomChatHistory); router.get("/rooms/:roomId/questionId", getQuestionId); diff --git a/frontend/app/app/history/page.tsx b/frontend/app/app/history/page.tsx new file mode 100644 index 0000000000..d1b0616f63 --- /dev/null +++ b/frontend/app/app/history/page.tsx @@ -0,0 +1,13 @@ +import AuthPageWrapper from "@/components/auth/auth-page-wrapper"; +import UserRooms from "@/components/collab/user-rooms"; +import { Suspense } from "react"; + +export default function CollabPage() { + return ( + + + + + + ); +} diff --git a/frontend/components/collab/collab-room.tsx b/frontend/components/collab/collab-room.tsx index 474ee5c9ee..353ae304d5 100644 --- a/frontend/components/collab/collab-room.tsx +++ b/frontend/components/collab/collab-room.tsx @@ -4,16 +4,19 @@ import { X } from "lucide-react"; import Chat from "./chat"; import QuestionDisplay from "./question-display"; import CodeEditor from "./code-editor"; +import Link from "next/link"; export default function CollabRoom({ roomId }: { roomId: string }) { return (

Collab Room {roomId}

- + + +
diff --git a/frontend/components/collab/question-display.tsx b/frontend/components/collab/question-display.tsx index 3cff6b4ba2..d3e4fa9c7d 100644 --- a/frontend/components/collab/question-display.tsx +++ b/frontend/components/collab/question-display.tsx @@ -1,5 +1,6 @@ "use client"; import React, { useEffect, useState } from "react"; +import clsx from "clsx"; import { Card, CardContent, @@ -26,7 +27,15 @@ interface Question { description: string; } -export default function QuestionDisplay({ roomId }: { roomId: string }) { +export default function QuestionDisplay({ + roomId, + className, + date, +}: { + roomId: string; + className?: string; + date?: Date; +}) { const auth = useAuth(); const token = auth?.token; const [question, setQuestion] = useState(null); @@ -66,16 +75,21 @@ export default function QuestionDisplay({ roomId }: { roomId: string }) { if (!question) { return
Question not found
; } + date && console.log(date.toLocaleString()); + date && console.log(date.toLocaleString("en-GB")); return ( - + {question.title} - - {question.categories} - - {question.complexity} - + +
+ {question.categories} + + {question.complexity} + +
+ {date && {new Date(date).toLocaleString()}}
diff --git a/frontend/components/collab/user-rooms.tsx b/frontend/components/collab/user-rooms.tsx new file mode 100644 index 0000000000..4b0913ca99 --- /dev/null +++ b/frontend/components/collab/user-rooms.tsx @@ -0,0 +1,78 @@ +"use client"; +import React, { useEffect, useState } from "react"; +import { useAuth } from "@/app/auth/auth-context"; +import { getRoomsByUser } from "@/lib/api/collab-service/get-rooms-by-users"; +import Link from "next/link"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../ui/card"; +import QuestionDisplay from "./question-display"; +import LoadingScreen from "../common/loading-screen"; + +interface Room { + users: string[]; + roomId: string; + questionId: string; + lastUpdated: Date; +} +export default function UserRooms() { + const auth = useAuth(); + const [loading, setLoading] = useState(true); + const [rooms, setRooms] = useState(null); + + useEffect(() => { + async function fetchRoomsByUser() { + try { + if (!auth?.user?.id) { + console.error("User is not authenticated"); + return; + } + const response = await getRoomsByUser(auth?.user?.id); + const tempRooms = await response.json(); + const sortedRooms = tempRooms.sort((a: Room, b: Room) => { + return ( + new Date(b.lastUpdated).getTime() - + new Date(a.lastUpdated).getTime() + ); + }); + setRooms(sortedRooms); + } finally { + setLoading(false); + } + } + + fetchRoomsByUser(); + }, [auth]); + + if (loading) { + return ; + } + + return ( + + + Historical Rooms + Look at rooms you have joined before + + + {rooms?.map((room) => ( + + + + ))} + + + ); +} diff --git a/frontend/components/navbar.tsx b/frontend/components/navbar.tsx index 2a3ae9cf58..99eea09d30 100644 --- a/frontend/components/navbar.tsx +++ b/frontend/components/navbar.tsx @@ -3,7 +3,15 @@ import { useAuth } from "@/app/auth/auth-context"; import { usePathname } from "next/navigation"; -import { Book, BookUser, LogOut, Settings, User, Users } from "lucide-react"; +import { + Book, + BookUser, + History, + LogOut, + Settings, + User, + Users, +} from "lucide-react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { @@ -72,6 +80,17 @@ export function Navbar() { Matching + + + History +
diff --git a/frontend/lib/api/collab-service/get-rooms-by-users.ts b/frontend/lib/api/collab-service/get-rooms-by-users.ts new file mode 100644 index 0000000000..e61e8a9e1e --- /dev/null +++ b/frontend/lib/api/collab-service/get-rooms-by-users.ts @@ -0,0 +1,14 @@ +import { collabServiceUri } from "@/lib/api/api-uri"; + +export const getRoomsByUser = async (userId: string) => { + const response = await fetch( + `${collabServiceUri(window.location.hostname)}/collab/rooms/${userId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + return response; +};