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 ? ( + ) : ( + + ); +}