Skip to content
Open
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
2 changes: 2 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LoadingPage from "./loading.jsx";
import { BrowserRouter as Router, Routes, Route, useNavigate } from "react-router-dom";
import PrivateRoutes from "./router_utils/PrivateRoutes";
import ProfilePage from "./screens/profile.js";
import MyQuizzes from "./screens/myquizzes";

import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
Expand Down Expand Up @@ -90,6 +91,7 @@ const App = () => {
<Route element={<PrivateRoutes />}>
<Route element={<Dashboard />} path="dashboard" exact />
<Route element={<ProfilePage />} path="profile" exact />
<Route element={<MyQuizzes />} path="myquizzes" exact />
</Route>
<Route element={<BrowseScreen />} path="browse">
<Route element={<BrowseScreen />} path=":code">
Expand Down
144 changes: 144 additions & 0 deletions client/src/api/Quiz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { toast } from "react-toastify";
import server from "./server";
import { getUser } from "./User";
import { getCourse } from "./Course";

export const createQuizEvent = async (eventName, eventDate, course) => {
try {
const response = await fetch(`${server}/api/quiz/create`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
eventName,
eventDate,
course,
})
});

const data = await response.json();

if (!response.ok) {
throw new Error(data.message || 'Failed to create quiz event');
}

return data;
} catch (error) {
throw error;
}
};
export const getAllQuizEvents = async () => {
try {
const response = await fetch(`${server}/api/quiz/events`, {
method: 'GET',
credentials: 'include'
});

const data = await response.json();

if (!response.ok) {
throw new Error(data.message || 'Failed to fetch quiz events');
}
const events = data.data.filter(event => {
const currDate = new Date();
const eventDate = new Date(event.eventDate);
if (eventDate.getTime() >= currDate.getTime()){
return true;
}
else{
deleteQuizEvent(event._id);
return false;
}
})
return events || [];
} catch (error) {
throw error;
}
};

export const getQuizEvents = async () => {
try {
console.log("Getting Quizzes")
const { data: user } = await getUser();
if(!user) {
throw new Error('User not found');
}
const response = await fetch(`${server}/api/quiz/events`, {
method: 'GET',
credentials: 'include'
});

const data = await response.json();

if (!response.ok) {
throw new Error(data.message || 'Failed to fetch quiz events');
}
if(data.data) {
// const userEvents = data.data.filter(event =>
// user?.courses?.some(course => course.code === event.course)
// );
const userEvents = data.data.filter(event =>{
if (user?.courses?.some(course => course.code === event.course)){
const currDate = new Date();
const eventDate = new Date(event.eventDate);
if(eventDate.getTime() >= currDate.getTime()){
return true;
}
else{
deleteQuizEvent(event._id);
return false;
}
}
})
return userEvents;
} else {
throw new Error(data.message || 'Failed to fetch quiz events data');
}
} catch (error) {
throw error;
}
};

export const modifyQuizEvent = async (eventId, eventData) => {
try {
const response = await fetch(`${server}/api/quiz/modify/${eventId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(eventData)
});
const data = await response.json();
if(!response.ok) {
toast.error(data.message || 'Failed to modify quiz event');
return null;
}
return data;
}
catch (error) {
toast.error(error.message || 'Failed to modify quiz event');
return null;
}
}
export const deleteQuizEvent = async (eventId) => {
try {
console.log("deleting Quizzes")
const response = await fetch(`${server}/api/quiz/delete/${eventId}`, {
method: 'DELETE',
credentials: 'include'
});
const data = await response.json();
if(!response.ok) {
toast.error(data.message || 'Failed to delete quiz event');
return null;
}
return data;
}
catch (error) {
toast.error(error.message || 'Failed to delete quiz event');
return null;
}
}
11 changes: 10 additions & 1 deletion client/src/api/Year.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ API.interceptors.request.use((req) => {
return req;
});

export const addYear = async ({ name, course }) => {
export const addYear = async ({ name, course, profName }) => {
const { data } = await API.post("/year", {
name,
course,
profName,
childType: "Folder",
Children: [],
});
Expand All @@ -31,3 +32,11 @@ export const deleteYear = async ({ folder, courseCode }) => {
});
return data;
};

export const editProfName = async ({ yearId, profName }) => {
const { data } = await API.put("/year/edit-prof", {
yearId,
profName,
});
return data;
};
2 changes: 2 additions & 0 deletions client/src/api/profName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import axios from "axios";
import serverRoot from "./server";
1 change: 1 addition & 0 deletions client/src/components/container/styles.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.container {
position: relative;
flex: 1;

.container-content {
max-width: 1400px;
Expand Down
2 changes: 2 additions & 0 deletions client/src/screens/browse/components/folder-info/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const FolderInfo = ({
isBR,
path,
name,
prof,
canDownload,
contributionHandler,
folderId,
Expand Down Expand Up @@ -243,6 +244,7 @@ const FolderInfo = ({
<p className="path">{path}</p>
<div className="curr-folder">
<p className="folder-name">{name}</p>
{prof && (<p className="prof-name">Prof. {prof}</p>)}
<div className="folder-actions">
{folderId && courseCode && (
<>
Expand Down
10 changes: 9 additions & 1 deletion client/src/screens/browse/components/folder-info/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
.folder-name {
font-family: "Bold";
font-size: 1.5rem;

}

.prof-name {
font-family: "Regular";
font-size: 1rem;
padding-left: 5px;
color: #333;
}

.folder-actions {
Expand Down Expand Up @@ -216,4 +224,4 @@

#bottommarginneeded {
margin-bottom: 2rem;
}
}
107 changes: 107 additions & 0 deletions client/src/screens/browse/components/quiz-schedule-modal/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState } from "react";
import { createQuizEvent } from "../../../../api/Quiz";
import { toast } from "react-toastify";
import "./styles.scss";

const QuizScheduleModal = ({ isOpen, onClose, courseCode }) => {
const [eventName, setEventName] = useState("");
const [eventDate, setEventDate] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();

if (!eventName.trim() || !eventDate) {
toast.error("Please fill in all fields");
return;
}

setIsSubmitting(true);

try {
await createQuizEvent(eventName, eventDate, courseCode);
toast.success("Quiz event scheduled successfully!");
setEventName("");
setEventDate("");
onClose();
} catch (error) {
toast.error(error.message || "Failed to schedule quiz event");
} finally {
setIsSubmitting(false);
}
};

const handleClose = () => {
if (!isSubmitting) {
setEventName("");
setEventDate("");
onClose();
}
};

if (!isOpen) return null;

return (
<div className="quiz-modal-overlay" onClick={handleClose}>
<div className="quiz-modal" onClick={(e) => e.stopPropagation()}>
<div className="quiz-modal-header">
<h3>Schedule Quiz</h3>
<button
className="close-button"
onClick={handleClose}
disabled={isSubmitting}
>
×
</button>
</div>

<form onSubmit={handleSubmit} className="quiz-modal-form">
<div className="form-group">
<label htmlFor="eventName">Event Name:</label>
<input
type="text"
id="eventName"
value={eventName}
onChange={(e) => setEventName(e.target.value)}
placeholder="Enter quiz name"
disabled={isSubmitting}
required
/>
</div>

<div className="form-group">
<label htmlFor="eventDate">Event Date:</label>
<input
type="datetime-local"
id="eventDate"
value={eventDate}
onChange={(e) => setEventDate(e.target.value)}
disabled={isSubmitting}
required
/>
</div>

<div className="form-actions">
<button
type="button"
className="btn btn-secondary"
onClick={handleClose}
disabled={isSubmitting}
>
Cancel
</button>
<button
type="submit"
className="btn btn-primary"
disabled={isSubmitting}
>
{isSubmitting ? "Scheduling..." : "Schedule Quiz"}
</button>
</div>
</form>
</div>
</div>
);
};

export default QuizScheduleModal;
Loading