Skip to content

Commit fe02248

Browse files
refactor: quiz logic and add question edit dialog (#209)
* feat: refactor quiz question management with new form components and editing capabilities * feat: refactor quiz logic for improved session management and question navigation * feat: enhance quiz validation and error handling with new utility functions * refactor: update zod import syntax for consistency * refactor: consolidate quiz utility functions and improve guest mode handling * fix: edge case when deleting question would cause question card to disappear * refactor: improve layout structure in question form container * chore: apply review suggestions
1 parent deb16d4 commit fe02248

25 files changed

Lines changed: 1752 additions & 1207 deletions

package-lock.json

Lines changed: 128 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@radix-ui/react-checkbox": "^1.3.3",
3636
"@radix-ui/react-dialog": "^1.1.15",
3737
"@radix-ui/react-dropdown-menu": "^2.1.16",
38+
"@radix-ui/react-focus-scope": "^1.1.8",
3839
"@radix-ui/react-hover-card": "^1.1.15",
3940
"@radix-ui/react-label": "^2.1.8",
4041
"@radix-ui/react-navigation-menu": "^1.2.14",

src/app/quiz/[quizId]/client.tsx

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import { Icon } from "@iconify/react";
4+
import { FileQuestionMarkIcon } from "lucide-react";
45
import Link from "next/link";
56
import { ViewTransition, startTransition, useContext, useEffect } from "react";
67
import ReactPlayer from "react-player";
@@ -19,6 +20,13 @@ import { QuizHistoryDialog } from "@/components/quiz/quiz-history-dialog";
1920
import { QuizInfoCard } from "@/components/quiz/quiz-info-card";
2021
import { AspectRatio } from "@/components/ui/aspect-ratio";
2122
import { Card, CardContent } from "@/components/ui/card";
23+
import {
24+
Empty,
25+
EmptyDescription,
26+
EmptyHeader,
27+
EmptyMedia,
28+
EmptyTitle,
29+
} from "@/components/ui/empty";
2230
import { cn } from "@/lib/utils";
2331

2432
interface QuizPageClientProps {
@@ -47,8 +55,8 @@ function QuizPageContent({ quizId }: { quizId: string }): React.JSX.Element {
4755
masteredCount,
4856
totalQuestions,
4957
timerStore,
50-
answers,
5158
} = stats;
59+
const answers = quiz.current_session?.answers ?? [];
5260
const { isHost: isContinuityHost, peerConnections } = continuity;
5361
const {
5462
nextAction,
@@ -57,7 +65,7 @@ function QuizPageContent({ quizId }: { quizId: string }): React.JSX.Element {
5765
setSelectedAnswers,
5866
toggleHistory,
5967
toggleBrainrot,
60-
goToPreviousQuestion,
68+
togglePreviousQuestion,
6169
} = actions;
6270

6371
const {
@@ -124,29 +132,47 @@ function QuizPageContent({ quizId }: { quizId: string }): React.JSX.Element {
124132
>
125133
<div className="min-w-0 lg:col-span-2">
126134
<ViewTransition name={`quiz-open-${quiz.id}`} update="h-full">
127-
<QuestionCard
128-
quizId={quiz.id}
129-
question={currentQuestion}
130-
selectedAnswers={selectedAnswers}
131-
setSelectedAnswers={(newSelected) => {
132-
// If question is not multiple, unselect everything except the new
133-
if (currentQuestion !== null && !currentQuestion.multiple) {
134-
setSelectedAnswers(
135-
newSelected.length > 0 ? [newSelected[0]] : [],
136-
);
137-
} else {
138-
setSelectedAnswers(newSelected);
139-
}
140-
}}
141-
answers={answers}
142-
questionChecked={questionChecked}
143-
nextAction={nextAction}
144-
isQuizFinished={isQuizFinished}
145-
restartQuiz={resetProgress}
146-
goToPreviousQuestion={goToPreviousQuestion}
147-
isHistoryQuestion={isHistoryQuestion}
148-
canGoBack={canGoBack}
149-
/>
135+
{quiz.questions.length === 0 ? (
136+
<Card>
137+
<CardContent>
138+
<Empty>
139+
<EmptyHeader>
140+
<EmptyMedia variant="icon">
141+
<FileQuestionMarkIcon />
142+
</EmptyMedia>
143+
<EmptyTitle>Brak pytań</EmptyTitle>
144+
<EmptyDescription>
145+
W tym quizie nie ma jeszcze żadnych pytań.
146+
</EmptyDescription>
147+
</EmptyHeader>
148+
</Empty>
149+
</CardContent>
150+
</Card>
151+
) : (
152+
<QuestionCard
153+
quizId={quiz.id}
154+
question={currentQuestion}
155+
selectedAnswers={selectedAnswers}
156+
setSelectedAnswers={(newSelected) => {
157+
// If question is not multiple, unselect everything except the new
158+
if (currentQuestion !== null && !currentQuestion.multiple) {
159+
setSelectedAnswers(
160+
newSelected.length > 0 ? [newSelected[0]] : [],
161+
);
162+
} else {
163+
setSelectedAnswers(newSelected);
164+
}
165+
}}
166+
answers={answers}
167+
questionChecked={questionChecked}
168+
nextAction={nextAction}
169+
isQuizFinished={isQuizFinished}
170+
restartQuiz={resetProgress}
171+
togglePreviousQuestion={togglePreviousQuestion}
172+
isHistoryQuestion={isHistoryQuestion}
173+
canGoBack={canGoBack}
174+
/>
175+
)}
150176
</ViewTransition>
151177
</div>
152178
<ViewTransition name="quiz-info" update="h-full">

src/app/quiz/[quizId]/page.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { cookies } from "next/headers";
44
import { Suspense } from "react";
55

66
import { Loader } from "@/components/loader";
7+
import { quizDetailQueryKey } from "@/components/quiz/helpers/utils";
78
import { Card, CardContent } from "@/components/ui/card";
89
import { API_URL } from "@/lib/api";
910
import { AUTH_COOKIES } from "@/lib/auth/constants";
@@ -27,14 +28,10 @@ export default async function QuizPage({
2728

2829
const services = new ServiceRegistry(API_URL, {}, accessToken);
2930

30-
const include = ["user_settings", "current_session"];
31-
3231
await queryClient.prefetchQuery({
33-
queryKey: ["quiz", quizId, "details", { include }],
32+
queryKey: quizDetailQueryKey(quizId),
3433
queryFn: async () => {
35-
return await services.quiz.getQuiz(quizId, {
36-
include,
37-
});
34+
return await services.quiz.getQuizWithProgress(quizId);
3835
},
3936
});
4037

src/components/quiz/editor/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ export type { ImageButtonProps, ImagePreviewProps } from "./image";
33

44
export { ExplanationDialog, ExplanationButton } from "./explanation-dialog";
55

6-
export { QuestionForm } from "./question-form";
6+
export { QuestionFormContainer } from "./question-form-container";
7+
export { QuestionFormHeader } from "./question-form-header";
8+
export { QuestionFormContent } from "./question-form-content";
79
export { AnswerForm } from "./answer-form";

0 commit comments

Comments
 (0)