diff --git a/peerprep/backend/question-service/src/models/testcaseModel.ts b/peerprep/backend/question-service/src/models/testcaseModel.ts new file mode 100644 index 0000000000..43187838d5 --- /dev/null +++ b/peerprep/backend/question-service/src/models/testcaseModel.ts @@ -0,0 +1,21 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +export interface ITestcase extends Document { + questionId: number; + title: string; + input1: string; + output1: string; + input2: string; + output2: string; +} + +const TestcaseSchema: Schema = new Schema({ + questionId: { type: Number, unique: true }, + title: { type: String, unique: true }, + input1: { type: String, required: true }, + output1: { type: String, required: true }, + input2: { type: String, required: true }, + output2: { type: String, required: true }, +}); + +export default mongoose.model('Testcase', TestcaseSchema); diff --git a/peerprep/backend/question-service/src/routes/testcaseRoutes.ts b/peerprep/backend/question-service/src/routes/testcaseRoutes.ts new file mode 100644 index 0000000000..b9c179c3d6 --- /dev/null +++ b/peerprep/backend/question-service/src/routes/testcaseRoutes.ts @@ -0,0 +1,20 @@ +import express, { Request, Response } from 'express'; +import Testcase, { ITestcase } from '../models/testcaseModel'; + +const router = express.Router(); + +router.get('/testcases/:title', async (req: Request, res: Response) => { + const { title } = req.params; + try { + const testcase: ITestcase | null = await Testcase.findOne({ title }); + if (!testcase) { + return res.status(404).json({ message: 'Testcases not found' }); + } + res.json(testcase); + } catch (error) { + console.error('Error fetching testcases:', error); + res.status(500).json({ message: 'Server error' }); + } +}); + +export default router; diff --git a/peerprep/backend/question-service/src/sampleData.ts b/peerprep/backend/question-service/src/sampleData.ts index d8c53a250e..79c2e59338 100644 --- a/peerprep/backend/question-service/src/sampleData.ts +++ b/peerprep/backend/question-service/src/sampleData.ts @@ -141,13 +141,6 @@ const sampleQuestions = [ description: `Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection. Design an algorithm to serialize and deserialize a binary tree.`, categories: 'data-structures, algorithms', difficulty: 'hard', - }, - { - title: 'Trips and Users', - description: `Given table Trips with columns id, client_id, driver_id, city_id, status, request_at, and table Users with columns users_id, banned, role, write a solution to find the cancellation rate of requests with unbanned users (both client and driver must not be banned) between specific dates.`, - categories: 'data-structures, graphs, strings, algorithms', - difficulty: 'hard', - }, ]; // Create a helper function to simulate the Express request-response cycle diff --git a/peerprep/backend/question-service/src/server.ts b/peerprep/backend/question-service/src/server.ts index 3ed070789b..c8155d59d8 100644 --- a/peerprep/backend/question-service/src/server.ts +++ b/peerprep/backend/question-service/src/server.ts @@ -7,6 +7,7 @@ import connectDB from '../config/db'; import questionRoutes from './routes/questionRoutes'; import databaseRoutes from './routes/databaseRoutes'; import gptRoutes from './routes/gptRoutes'; +import testcaseRoutes from './routes/testcaseRoutes'; import loadSampleData from './sampleData'; connectDB() // Initialize MongoDB connection @@ -51,6 +52,8 @@ app.use('/api', databaseRoutes); app.use('/api', gptRoutes); +app.use('/api', testcaseRoutes); + // Health check route app.get('/hello', (req, res) => { res.json({ message: 'Hello World' }); diff --git a/peerprep/frontend/src/api/testcaseApi.ts b/peerprep/frontend/src/api/testcaseApi.ts new file mode 100644 index 0000000000..6a60381d06 --- /dev/null +++ b/peerprep/frontend/src/api/testcaseApi.ts @@ -0,0 +1,23 @@ +import axios from 'axios'; + +const API_URL = 'http://localhost:8080/api/testcases'; + +export interface Testcase { + questionId: number; + title: string; + input1: string; + output1: string; + input2: string; + output2: string; +} + +export const getTestcasesByTitle = async (title: string): Promise => { + try { + const response = await axios.get(`${API_URL}/${title}`); + console.log('Fetched testcases:', response.data); + return response.data; + } catch (error) { + console.error('Error fetching testcases:', error); + throw error; + } +}; diff --git a/peerprep/frontend/src/styles/App.css b/peerprep/frontend/src/styles/App.css index 0a70a493c8..25fbfdeb3d 100644 --- a/peerprep/frontend/src/styles/App.css +++ b/peerprep/frontend/src/styles/App.css @@ -22,7 +22,6 @@ h2 { color: black; } - /* Container uses flexbox for split layout */ .container { display: flex; @@ -503,9 +502,17 @@ h2 { height: 85vh; /* Full height of the viewport */ width: 80vw; /* Full width of the viewport */ + overflow-y: scroll; + overflow-x: hidden; background-color: white; padding: 20px; box-sizing: border-box; /* Include padding in width and height calculations */ + scrollbar-width: none; +} + +/* Hide scrollbar for Webkit browsers (Chrome, Safari) */ +.editor-container-parent::-webkit-scrollbar { + display: none; } .CodeMirror { @@ -518,7 +525,8 @@ h2 { width: 100%; height: 100%; max-width: 900px; - min-height: 300px; + max-height: 200px; + min-height: 200px; flex-grow: 1; position: relative; } @@ -527,7 +535,8 @@ h2 { width: 70%; height: 100%; max-width: 900px; - min-height: 300px; + max-height: 200px; + min-height: 200px; flex-grow: 1; border: 2px solid #ccc; border-radius: 10px; @@ -541,11 +550,23 @@ h2 { vertical-align: top; /* Ensures text starts from the top */ } +/* Hide scrollbar for Webkit browsers (Chrome, Safari) */ +.editor-container::-webkit-scrollbar { + display: none; +} + +/* Hide scrollbar for Firefox */ +.editor-container { + scrollbar-width: none; /* Firefox */ +} + .chat-box { width: 30%; display: flex; flex-direction: column; height: 100%; + max-height: 200px; + min-height: 100px; border: 2px solid #ccc; border-radius: 10px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); @@ -623,7 +644,7 @@ input { .editor-header { text-align: center; margin-bottom: -10px; - margin-top: -60px; + margin-top: -45px; } .leave-btn, @@ -692,13 +713,13 @@ input { display: flex; flex-direction: row; /* Arrange items in a vertical stack */ align-items: center; /* Align items to the left */ - gap: 100px; /* Add vertical spacing between items */ + gap: 60px; /* Add vertical spacing between items */ } .matching-form2 { padding: 0px; max-width: 40%; - min-width: 10%; + min-width: 18%; margin: 0 auto; /* Center the form */ border-radius: 10px; /* Rounded corners for the form */ background-color: white; @@ -774,4 +795,45 @@ input { .output-container{ overflow-y: scroll; -} \ No newline at end of file + min-height: 50px; + max-height: 100px; + max-width: 900px; +} + +/* Hide scrollbar for Webkit browsers (Chrome, Safari) */ +.output-container::-webkit-scrollbar { + display: none; +} + +/* Hide scrollbar for Firefox */ +.output-container { + scrollbar-width: none; /* Firefox */ +} + +.testcases-table { + margin: 20px auto; /* Center the table horizontally */ + max-width: 900px; /* Set max width */ + width: 100%; /* Allow the table to expand to max-width */ +} + +.testcases-table table { + border-collapse: collapse; + border: 2px solid #333 !important; /* Outer border around the table */ + text-align: center; + width: 100%; /* Ensure the table fills the container width */ +} + + +.testcases-table th, .testcases-table td { + border: 1px solid #333 !important; /* Border around each cell */ + padding: 8px; +} + +.testcases-table th { + background-color: #f2f2f2; + font-weight: bold; +} + +.testcases-table td { + background-color: #fff; +} diff --git a/peerprep/frontend/src/views/CollabServiceViews/CollabServiceIntegratedView.tsx b/peerprep/frontend/src/views/CollabServiceViews/CollabServiceIntegratedView.tsx index 20914d3597..2d9aa49707 100644 --- a/peerprep/frontend/src/views/CollabServiceViews/CollabServiceIntegratedView.tsx +++ b/peerprep/frontend/src/views/CollabServiceViews/CollabServiceIntegratedView.tsx @@ -24,7 +24,7 @@ import { WebsocketProvider } from 'y-websocket'; import { deleteMatchedSession} from "../../api/matchingApi.ts"; import { getQuestionById } from '../../api/questionApi.ts'; - +import { getTestcasesByTitle, Testcase } from '../../api/testcaseApi.ts'; const CollaborationServiceIntegratedView: React.FC = () => { const { sessionId } = useParams<{ sessionId: string; }>(); @@ -36,6 +36,15 @@ const CollaborationServiceIntegratedView: React.FC = () => { const navigate = useNavigate(); const [yText, setYText] = useState(null); const [commentoutput, setCommentOutput] = useState(null); + const [testcases, setTestcases] = useState({ + questionId: 0, + title: "N/A", + input1: "N/A", + output1: "N/A", + input2: "N/A", + output2: "N/A" + }); + console.log(commentoutput); //let topic = 'topic'; //let difficulty = 'difficulty'; @@ -74,7 +83,6 @@ const CollaborationServiceIntegratedView: React.FC = () => { useEffect(() => { console.log(`Session ID: ${sessionId}, Topics: ${topics}, Difficulty: ${difficulty}`); - console.log(`Question: ${questionId}`); }, [sessionId, topics, difficulty, questionId]); useEffect(() => { @@ -101,6 +109,44 @@ const CollaborationServiceIntegratedView: React.FC = () => { } }, [sessionId]); + useEffect(() => { + const fetchTestcases = async () => { + try { + const response = await getTestcasesByTitle(questionTitle); + if (response) { + console.log('Setting fetched testcases:', response); + setTestcases(response); + } else { + console.log('No testcases found, setting default values'); + setTestcases({ + questionId: 0, + title: "N/A", + input1: "N/A", + output1: "N/A", + input2: "N/A", + output2: "N/A" + }); + } + } catch (error) { + console.error('Error fetching testcases:', error); + setTestcases({ + questionId: 0, + title: "N/A", + input1: "N/A", + output1: "N/A", + input2: "N/A", + output2: "N/A" + }); + } + }; + + if (questionTitle && questionTitle !== 'N/A') { + fetchTestcases(); + } + }, [questionTitle]); + + + const handleLeaveSession = () => { // Call the API to delete the session try { @@ -212,8 +258,7 @@ const CollaborationServiceIntegratedView: React.FC = () => {

Collaboration Session

-

Topics: {topics} | Difficulty: {difficulty}

-

Question: {questionTitle}

+

Topics: {topics} | Difficulty: {difficulty} | Question: {questionTitle}

Description: {questionDescription}

@@ -303,9 +348,33 @@ const CollaborationServiceIntegratedView: React.FC = () => {
{/*
{commentoutput}
-
*/} - - ); + */} + +{testcases && ( +
+

Test Cases

+ + + + + + + + + + + + + + + + + +
Input 1Output 1Input 2Output 2
{testcases.input1}{testcases.output1}{testcases.input2}{testcases.output2}
+
+)} + + ); }; export default CollaborationServiceIntegratedView;