diff --git a/quizeek/src/app/(app)/auth/quiz/[quizId]/attempt/[attemptId]/page.tsx b/quizeek/src/app/(app)/auth/quiz/[quizId]/attempt/[attemptId]/page.tsx index b5503b0..3558803 100644 --- a/quizeek/src/app/(app)/auth/quiz/[quizId]/attempt/[attemptId]/page.tsx +++ b/quizeek/src/app/(app)/auth/quiz/[quizId]/attempt/[attemptId]/page.tsx @@ -1,5 +1,8 @@ import { QuizAttempt } from '@/components/quiz/quiz-attempt'; -import { getQuizAttemptById, getQuizWithQuestionsById } from '@/db/queries'; +import { + getQuizAttemptById, + getQuizWithPublicQuestionsById, +} from '@/db/queries'; import { notFound, redirect } from 'next/navigation'; import React from 'react'; @@ -21,7 +24,7 @@ const Page = async ({ params }: AttemptPageProps) => { notFound(); } - const quiz = await getQuizWithQuestionsById(routeParams.quizId); + const quiz = await getQuizWithPublicQuestionsById(routeParams.quizId); const attempt = await getQuizAttemptById(routeParams.attemptId); if (!quiz || !attempt) { diff --git a/quizeek/src/app/(app)/auth/quiz/[quizId]/view/[attemptId]/page.tsx b/quizeek/src/app/(app)/auth/quiz/[quizId]/view/[attemptId]/page.tsx index c2843d9..4c0b34e 100644 --- a/quizeek/src/app/(app)/auth/quiz/[quizId]/view/[attemptId]/page.tsx +++ b/quizeek/src/app/(app)/auth/quiz/[quizId]/view/[attemptId]/page.tsx @@ -1,9 +1,41 @@ +import { QuizAttempt } from '@/components/quiz/quiz-attempt'; +import { + getQuizAttemptWithAnswers, + getQuizWithQuestionsById, +} from '@/db/queries'; +import { notFound } from 'next/navigation'; + +type PageProps = { + params?: Promise<{ + quizId?: string; + attemptId?: string; + }>; +}; + export const metadata = { title: 'View Results', }; -const Page = async () => { - return

Quiz view

; +const Page = async ({ params }: PageProps) => { + const routeParams = await params; + + if (!routeParams?.quizId || !routeParams.attemptId) { + notFound(); + } + + const quiz = await getQuizWithQuestionsById(routeParams.quizId); + const attempt = await getQuizAttemptWithAnswers(routeParams.attemptId); + + if (!quiz || !attempt) { + return notFound(); + } + + return ( + <> +

{quiz.title}

+ + + ); }; export default Page; diff --git a/quizeek/src/components/profile/update-user-form.tsx b/quizeek/src/components/profile/update-user-form.tsx index ba1f778..f16ff7c 100644 --- a/quizeek/src/components/profile/update-user-form.tsx +++ b/quizeek/src/components/profile/update-user-form.tsx @@ -1,7 +1,7 @@ 'use client'; import { UpdateUser, updateUserSchema } from '@/db/schema/user'; -import { useUpdateUserMutation } from '@/hooks/user'; +import { useUpdateUserMutation } from '@/hooks'; import { cn } from '@/lib/utils'; import { zodResolver } from '@hookform/resolvers/zod'; import { SessionContextValue } from 'next-auth/react'; diff --git a/quizeek/src/components/quiz/attempt/quiz-attempt-save-dialog.tsx b/quizeek/src/components/quiz/attempt/quiz-attempt-save-dialog.tsx index a401fb4..caac869 100644 --- a/quizeek/src/components/quiz/attempt/quiz-attempt-save-dialog.tsx +++ b/quizeek/src/components/quiz/attempt/quiz-attempt-save-dialog.tsx @@ -21,7 +21,7 @@ export const QuizAttemptSaveDialog = ({ }: QuizAttemptSaveDialogProps) => { return ( - + diff --git a/quizeek/src/components/quiz/detail/quiz-activate-dialog.tsx b/quizeek/src/components/quiz/detail/quiz-activate-dialog.tsx index d8e7b88..183f5af 100644 --- a/quizeek/src/components/quiz/detail/quiz-activate-dialog.tsx +++ b/quizeek/src/components/quiz/detail/quiz-activate-dialog.tsx @@ -9,7 +9,7 @@ import { DialogTrigger, } from '@/components/ui/dialog'; import { QuizWithUser } from '@/db/schema/quiz'; -import { useActivateQuizMutation } from '@/hooks/quiz'; +import { useActivateQuizMutation } from '@/hooks'; import React from 'react'; import { toast } from 'sonner'; diff --git a/quizeek/src/components/quiz/detail/quiz-detail-my-attempts.tsx b/quizeek/src/components/quiz/detail/quiz-detail-my-attempts.tsx index f1956b8..c5457f9 100644 --- a/quizeek/src/components/quiz/detail/quiz-detail-my-attempts.tsx +++ b/quizeek/src/components/quiz/detail/quiz-detail-my-attempts.tsx @@ -1,7 +1,7 @@ import { Card, CardContent, CardTitle } from '@/components/ui/card'; import { getMyQuizAttempts } from '@/db/queries'; import { QuizWithUser } from '@/db/schema/quiz'; -import { toLocalDateTimeString } from '@/utils/date'; +import { toLocalDateTimeString } from '@/utils'; import { SquareArrowRight } from 'lucide-react'; import Link from 'next/link'; import React from 'react'; diff --git a/quizeek/src/components/quiz/detail/quiz-detail-other-attempts.tsx b/quizeek/src/components/quiz/detail/quiz-detail-other-attempts.tsx index 8ebe820..7d15047 100644 --- a/quizeek/src/components/quiz/detail/quiz-detail-other-attempts.tsx +++ b/quizeek/src/components/quiz/detail/quiz-detail-other-attempts.tsx @@ -1,7 +1,7 @@ import { Card, CardContent, CardTitle } from '@/components/ui/card'; import { getOtherQuizAttempts } from '@/db/queries'; import { QuizWithUser } from '@/db/schema/quiz'; -import { toLocalDateTimeString } from '@/utils/date'; +import { toLocalDateTimeString } from '@/utils'; import { CircleUserRound } from 'lucide-react'; import Image from 'next/image'; import React from 'react'; diff --git a/quizeek/src/components/quiz/question/choice/choice.tsx b/quizeek/src/components/quiz/question/choice/choice.tsx index 28577eb..aa41e43 100644 --- a/quizeek/src/components/quiz/question/choice/choice.tsx +++ b/quizeek/src/components/quiz/question/choice/choice.tsx @@ -1,11 +1,39 @@ import { Card } from '@/components/ui/card'; +import { cn } from '@/lib/utils'; import { PropsWithChildren } from 'react'; -export type ChoiceProps = PropsWithChildren; +export type ChoiceProps = { + enableHiglighting: boolean; + isCorrect: boolean; + wasSelected: boolean; +} & PropsWithChildren; -export const Choice = ({ children }: ChoiceProps) => { +export const Choice = ({ + enableHiglighting, + isCorrect, + wasSelected, + children, + ...props +}: ChoiceProps) => { return ( - + {children} ); diff --git a/quizeek/src/components/quiz/question/choice/multi-choice-list.tsx b/quizeek/src/components/quiz/question/choice/multi-choice-list.tsx index e9a0de8..022acaa 100644 --- a/quizeek/src/components/quiz/question/choice/multi-choice-list.tsx +++ b/quizeek/src/components/quiz/question/choice/multi-choice-list.tsx @@ -1,16 +1,22 @@ import { ScrollArea } from '@/components/ui/scroll-area'; import { Choice, PublicChoice } from '@/db/schema/choice'; +import { + type QuizAttempt as QuizAttemptType, + QuizAttemptWithAnswers, +} from '@/db/schema/quiz-attempt'; import { MultiChoice } from './multi-choice'; export type MultiChoiceListProps = { questionId: string; choices: (Choice | PublicChoice)[]; + attempt: QuizAttemptType | QuizAttemptWithAnswers; }; export const MultiChoiceList = ({ questionId, choices, + attempt, }: MultiChoiceListProps) => { return ( {choices.map((choice) => ( - + ))} ); diff --git a/quizeek/src/components/quiz/question/choice/multi-choice.tsx b/quizeek/src/components/quiz/question/choice/multi-choice.tsx index 62c9f70..7981a85 100644 --- a/quizeek/src/components/quiz/question/choice/multi-choice.tsx +++ b/quizeek/src/components/quiz/question/choice/multi-choice.tsx @@ -2,6 +2,10 @@ import { Checkbox } from '@/components/ui/checkbox'; import { FormControl, FormField, FormItem } from '@/components/ui/form'; import { Label } from '@/components/ui/label'; import { Choice as ChoiceType, PublicChoice } from '@/db/schema/choice'; +import { + type QuizAttempt as QuizAttemptType, + QuizAttemptWithAnswers, +} from '@/db/schema/quiz-attempt'; import { useFormContext } from 'react-hook-form'; import { Choice } from './choice'; @@ -9,13 +13,29 @@ import { Choice } from './choice'; export type MultiChoiceProps = { questionId: string; choice: ChoiceType | PublicChoice; + attempt: QuizAttemptType | QuizAttemptWithAnswers; }; -export const MultiChoice = ({ questionId, choice }: MultiChoiceProps) => { +export const MultiChoice = ({ + questionId, + choice, + attempt, +}: MultiChoiceProps) => { const form = useFormContext(); + const enableHiglighting = + attempt.type === 'with_answers' && choice.type === 'private'; + const wasSelected = + enableHiglighting && + !!attempt.answers.find((a) => a.choiceId === choice.id); + const isCorrect = enableHiglighting && choice.isCorrect; + return ( - + { { diff --git a/quizeek/src/components/quiz/question/choice/single-choice-list.tsx b/quizeek/src/components/quiz/question/choice/single-choice-list.tsx index cf0030d..698560a 100644 --- a/quizeek/src/components/quiz/question/choice/single-choice-list.tsx +++ b/quizeek/src/components/quiz/question/choice/single-choice-list.tsx @@ -2,6 +2,10 @@ import { FormControl, FormField, FormItem } from '@/components/ui/form'; import { RadioGroup } from '@/components/ui/radio-group'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Choice, PublicChoice } from '@/db/schema/choice'; +import { + type QuizAttempt as QuizAttemptType, + QuizAttemptWithAnswers, +} from '@/db/schema/quiz-attempt'; import { useFormContext } from 'react-hook-form'; import { SingleChoice } from './single-choice'; @@ -9,11 +13,13 @@ import { SingleChoice } from './single-choice'; export type SingleChoiceListProps = { questionId: string; choices: (Choice | PublicChoice)[]; + attempt: QuizAttemptType | QuizAttemptWithAnswers; }; export const SingleChoiceList = ({ questionId, choices, + attempt, }: SingleChoiceListProps) => { const form = useFormContext(); @@ -30,10 +36,15 @@ export const SingleChoiceList = ({ field.onChange([v])} - defaultValue={field.value} + value={field.value?.[0]} + defaultValue={field.value?.[0]} > {choices.map((choice) => ( - + ))} diff --git a/quizeek/src/components/quiz/question/choice/single-choice.tsx b/quizeek/src/components/quiz/question/choice/single-choice.tsx index 41bdda7..32b9c20 100644 --- a/quizeek/src/components/quiz/question/choice/single-choice.tsx +++ b/quizeek/src/components/quiz/question/choice/single-choice.tsx @@ -2,18 +2,38 @@ import { FormControl } from '@/components/ui/form'; import { Label } from '@/components/ui/label'; import { RadioGroupItem } from '@/components/ui/radio-group'; import { Choice as ChoiceType, PublicChoice } from '@/db/schema/choice'; +import { + type QuizAttempt as QuizAttemptType, + QuizAttemptWithAnswers, +} from '@/db/schema/quiz-attempt'; import { Choice } from './choice'; export type SingleChoiceProps = { choice: ChoiceType | PublicChoice; + attempt: QuizAttemptType | QuizAttemptWithAnswers; }; -export const SingleChoice = ({ choice }: SingleChoiceProps) => { +export const SingleChoice = ({ choice, attempt }: SingleChoiceProps) => { + const enableHiglighting = + attempt.type === 'with_answers' && choice.type === 'private'; + const wasSelected = + enableHiglighting && + !!attempt.answers.find((a) => a.choiceId === choice.id); + const isCorrect = enableHiglighting && choice.isCorrect; + return ( - + - +