Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

History #191

Merged
merged 6 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions collab-service/app/controller/collab-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getAllRooms,
fetchRoomChatHistory,
getQuestionIdByRoomId,
getAllRoomsByUserId,
} from "../model/repository.js";
import crypto from "crypto";

Expand All @@ -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)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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}` });
}
}
}
16 changes: 11 additions & 5 deletions collab-service/app/model/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -35,7 +32,6 @@ export async function getRoomId(user) {
}
}


export async function getAllRooms() {
try {
const rooms = await UsersSession.find({});
Expand All @@ -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
Expand Down Expand Up @@ -113,4 +119,4 @@ export async function getQuestionIdByRoomId(roomId) {
console.error(`Error finding questionId for roomId ${roomId}:`, error);
return null;
}
}
}
5 changes: 4 additions & 1 deletion collab-service/app/routes/collab-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
createRoom,
getRoomByUser,
getAllRoomsController,
getAllRoomsByUser,
getRoomChatHistory,
getQuestionId
getQuestionId,
} from "../controller/collab-controller.js";

const router = express.Router();
Expand All @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions frontend/app/app/history/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<AuthPageWrapper requireLoggedIn>
<Suspense>
<UserRooms />
</Suspense>
</AuthPageWrapper>
);
}
11 changes: 7 additions & 4 deletions frontend/components/collab/collab-room.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div className="h-full flex flex-col mx-4 p-4">
<header className="flex justify-between border-b">
<h1 className="text-2xl font-bold mb-4">Collab Room {roomId}</h1>
<Button variant="destructive">
Leave Room
<X className="ml-2" />
</Button>
<Link href="/app/history">
<Button variant="destructive">
Leave Room
<X className="ml-2" />
</Button>
</Link>
</header>
<div className="flex flex-1">
<div className="w-2/5 p-4 flex flex-col space-y-4">
Expand Down
28 changes: 21 additions & 7 deletions frontend/components/collab/question-display.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import React, { useEffect, useState } from "react";
import clsx from "clsx";
import {
Card,
CardContent,
Expand All @@ -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<Question | null>(null);
Expand Down Expand Up @@ -66,16 +75,21 @@ export default function QuestionDisplay({ roomId }: { roomId: string }) {
if (!question) {
return <div>Question not found</div>;
}
date && console.log(date.toLocaleString());
date && console.log(date.toLocaleString("en-GB"));

return (
<Card className="flex-shrink-0">
<Card className={clsx("flex-shrink-0", className)}>
<CardHeader>
<CardTitle>{question.title}</CardTitle>
<CardDescription className="flex items-center space-x-2">
<span>{question.categories}</span>
<Badge className={`${difficultyColors[question.complexity]}`}>
{question.complexity}
</Badge>
<CardDescription className="flex items-center justify-between">
<div className="flex space-x-2">
<span>{question.categories}</span>
<Badge className={`${difficultyColors[question.complexity]}`}>
{question.complexity}
</Badge>
</div>
{date && <span>{new Date(date).toLocaleString()}</span>}
</CardDescription>
</CardHeader>
<CardContent>
Expand Down
78 changes: 78 additions & 0 deletions frontend/components/collab/user-rooms.tsx
Original file line number Diff line number Diff line change
@@ -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<Room[] | null>(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 <LoadingScreen />;
}

return (
<Card className="w-full max-w-4xl mx-auto my-4">
<CardHeader>
<CardTitle>Historical Rooms</CardTitle>
<CardDescription>Look at rooms you have joined before</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-y-2">
{rooms?.map((room) => (
<Link
href={`/app/collab/${room.roomId}`}
className="w-full my-2"
key={room.roomId}
>
<QuestionDisplay
roomId={room.roomId}
className="hover:bg-accent"
date={room.lastUpdated}
/>
</Link>
))}
</CardContent>
</Card>
);
}
21 changes: 20 additions & 1 deletion frontend/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -72,6 +80,17 @@ export function Navbar() {
<Users className="mr-2 h-4 w-4" />
Matching
</Link>
<Link
href="/app/history"
className={`inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium ${
isActive("/app/history")
? "border-primary"
: "border-transparent"
}`}
>
<History className="mr-2 h-4 w-4" />
History
</Link>
</div>
</div>
<div className="hidden sm:ml-6 sm:flex sm:items-center">
Expand Down
14 changes: 14 additions & 0 deletions frontend/lib/api/collab-service/get-rooms-by-users.ts
Original file line number Diff line number Diff line change
@@ -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;
};