From 6c9fd914734daadaeac0814460196a9de293afc2 Mon Sep 17 00:00:00 2001
From: ErikaKK <491649804@qq.com>
Date: Wed, 23 Jul 2025 08:45:33 +0000
Subject: [PATCH 1/8] solve student view doesn't have sidebar
---
client/src/components/layout.tsx | 7 +------
server/api/quiz/urls.py | 4 ++--
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/client/src/components/layout.tsx b/client/src/components/layout.tsx
index 93d0b27..2a43b64 100644
--- a/client/src/components/layout.tsx
+++ b/client/src/components/layout.tsx
@@ -64,12 +64,7 @@ export function ProtectedPage({ children, requiredRoles }: ProtectedPageProps) {
);
case "authorized":
return (
-
- {children}
-
+ {children}
);
default:
return ;
diff --git a/server/api/quiz/urls.py b/server/api/quiz/urls.py
index 354e71f..8010859 100644
--- a/server/api/quiz/urls.py
+++ b/server/api/quiz/urls.py
@@ -9,8 +9,8 @@
)
router = DefaultRouter()
-router.register(r"admin-quizzes", AdminQuizViewSet, basename="")
-router.register(r"all-quizzes", QuizViewSet)
+router.register(r"admin-quizzes", AdminQuizViewSet, basename="") # all quizzes
+router.register(r"all-quizzes", QuizViewSet) # all visible quizzes
router.register(r"competition", CompetitionQuizViewSet, basename="competition")
router.register(r"quiz-slots", QuizSlotViewSet)
router.register(r"quiz-attempts", QuizAttemptViewSet)
From daa240556acf96ddb61a2a32a11d07646143d1a6 Mon Sep 17 00:00:00 2001
From: ErikaKK <491649804@qq.com>
Date: Wed, 23 Jul 2025 08:46:14 +0000
Subject: [PATCH 2/8] solve visitor can view competition
---
client/src/pages/quiz/index.tsx | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/client/src/pages/quiz/index.tsx b/client/src/pages/quiz/index.tsx
index e81d8bd..a98c46e 100644
--- a/client/src/pages/quiz/index.tsx
+++ b/client/src/pages/quiz/index.tsx
@@ -1,5 +1,6 @@
"use client";
+import Cookies from "js-cookie";
import { createContext, useContext, useEffect } from "react";
import { PublicPage } from "@/components/layout";
@@ -41,22 +42,24 @@ const QuizPage = () => {
endpoint: "/quiz/competition/",
});
+ const userRole = Cookies.get("user_role");
if (isQuizDataLoading || !quizData || isCompQuizDataLoading || !compQuizData)
return ;
if (isQuizDataError) return
Error Quiz: {QuizDataError?.message}
;
- if (isCompQuizDataError)
+ if (userRole && isCompQuizDataError)
return Error Competition: {compQuizDataError?.message}
;
return (
- {compQuizData.results.length > 0 ? (
-
- ) : (
-
- )}
+ {userRole &&
+ (compQuizData.results.length > 0 ? (
+
+ ) : (
+
+ ))}
);
From 2c5ea3348b876a35acbe79adea5b81f70e7903ce Mon Sep 17 00:00:00 2001
From: ErikaKK <491649804@qq.com>
Date: Wed, 23 Jul 2025 08:53:13 +0000
Subject: [PATCH 3/8] solve invalid access when competition has finished
---
client/src/components/ui/Quiz/quiz-intro.tsx | 14 +++++++++++---
client/src/pages/quiz/competition/[id].tsx | 13 +++++++++++++
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/client/src/components/ui/Quiz/quiz-intro.tsx b/client/src/components/ui/Quiz/quiz-intro.tsx
index f911441..f34e73d 100644
--- a/client/src/components/ui/Quiz/quiz-intro.tsx
+++ b/client/src/components/ui/Quiz/quiz-intro.tsx
@@ -7,6 +7,7 @@ interface Props {
startTime: string | Date;
quizDuration: number;
numberOfQuestions: number;
+ isFinished?: boolean;
}
export default function QuizIntro({
@@ -15,6 +16,7 @@ export default function QuizIntro({
startTime,
quizDuration,
numberOfQuestions,
+ isFinished,
}: Partial) {
let headingStyle = `text-xl sm:text-2xl md:text-3xl text-slate-800 font-bold`;
let generalInstructions =
@@ -48,9 +50,15 @@ export default function QuizIntro({
not be expected to be to scale.
-
+ {isFinished ? (
+
+ ) : (
+
+ )}
);
diff --git a/client/src/pages/quiz/competition/[id].tsx b/client/src/pages/quiz/competition/[id].tsx
index 38f9cbb..d3b1308 100644
--- a/client/src/pages/quiz/competition/[id].tsx
+++ b/client/src/pages/quiz/competition/[id].tsx
@@ -24,6 +24,7 @@ export default function CompetitionQuizPage() {
const router = useRouter();
const compId = router.query.id as string;
const [start, setStart] = useState(false);
+ const [isFinished, setIsFinished] = useState(false);
const handleStart = () => {
setStart(true);
// console.log(compId);
@@ -40,6 +41,17 @@ export default function CompetitionQuizPage() {
enabled: !!compId, // Only run the query if compId is defined
});
+ useEffect(() => {
+ if (compData) {
+ const endTime = new Date(compData.open_time_date);
+ endTime.setMinutes(endTime.getMinutes() + compData.time_limit);
+ const now = new Date();
+ if (now > endTime) {
+ setIsFinished(true);
+ }
+ }
+ }, [compData]);
+
if (!compId) return ;
console.log(compId);
@@ -51,6 +63,7 @@ export default function CompetitionQuizPage() {
quizDuration: compData?.time_limit,
startTime: compData?.open_time_date,
onStart: handleStart,
+ isFinished: isFinished,
}}
/>
);
From 1c997bcedb354b48a4d0cb37080dccc219b07d7a Mon Sep 17 00:00:00 2001
From: ErikaKK <491649804@qq.com>
Date: Wed, 23 Jul 2025 09:34:08 +0000
Subject: [PATCH 4/8] Solve mobile view doesn't show dashboard button
---
client/src/components/ui/mobilenav.tsx | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/client/src/components/ui/mobilenav.tsx b/client/src/components/ui/mobilenav.tsx
index 542909f..781dc13 100644
--- a/client/src/components/ui/mobilenav.tsx
+++ b/client/src/components/ui/mobilenav.tsx
@@ -1,12 +1,16 @@
import { AlignJustify, X } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
+import { useRouter } from "next/router";
import { Drawer } from "vaul";
import { Button } from "@/components/ui/button";
import { LoginModal } from "@/components/ui/Users/login-modal";
+import { useAuth } from "@/context/auth-provider";
export default function MobileNav() {
+ const router = useRouter();
+ const { isLoggedIn } = useAuth();
return (
@@ -42,15 +46,26 @@ export default function MobileNav() {
Awards
Quizzes
Contact us
-
+ {isLoggedIn ? (
-
+ ) : (
+
+
+
+ )}
{/* */}
From cc4828b95d3b95a2df49a88bfb4db900e864ad18 Mon Sep 17 00:00:00 2001
From: ErikaKK <491649804@qq.com>
Date: Wed, 23 Jul 2025 11:53:26 +0000
Subject: [PATCH 5/8] changed comp entry button to inactive button for
different users
---
client/src/components/ui/Quiz/quiz-intro.tsx | 19 ++++++++-
client/src/pages/quiz/competition/[id].tsx | 44 ++++++++++++++++++--
client/src/types/quiz.ts | 2 +
server/api/quiz/serializers.py | 8 +++-
server/api/users/serializers.py | 20 ++++++---
5 files changed, 81 insertions(+), 12 deletions(-)
diff --git a/client/src/components/ui/Quiz/quiz-intro.tsx b/client/src/components/ui/Quiz/quiz-intro.tsx
index f34e73d..a4479c6 100644
--- a/client/src/components/ui/Quiz/quiz-intro.tsx
+++ b/client/src/components/ui/Quiz/quiz-intro.tsx
@@ -5,18 +5,24 @@ interface Props {
onStart: () => void;
quizName: string;
startTime: string | Date;
+ timeWindow: number;
quizDuration: number;
numberOfQuestions: number;
- isFinished?: boolean;
+ isFinished: boolean;
+ isEntryClosed: boolean;
+ isSubmitted: boolean;
}
export default function QuizIntro({
onStart,
quizName,
startTime,
+ timeWindow,
quizDuration,
numberOfQuestions,
isFinished,
+ isEntryClosed,
+ isSubmitted,
}: Partial) {
let headingStyle = `text-xl sm:text-2xl md:text-3xl text-slate-800 font-bold`;
let generalInstructions =
@@ -36,6 +42,9 @@ export default function QuizIntro({
className="flex-row gap-1 font-bold"
/>
+
+ Competition will allow entering within {timeWindow} minutes
+
Individual Quiz
{quizDuration} minutes
@@ -54,6 +63,14 @@ export default function QuizIntro({
+ ) : isEntryClosed ? (
+
+ ) : isSubmitted ? (
+
) : (