From af58a39a681e845f9b6897b8ab47f3974d2bd99f Mon Sep 17 00:00:00 2001 From: bartoszfabianowski <281041@student.pwr.edu.pl> Date: Sun, 14 Dec 2025 15:59:27 +0100 Subject: [PATCH 1/4] feat: dodanie trybu zaawansowanego per-pytanie --- src/components/quiz/question-form.tsx | 72 +++++++++++++++++------- src/components/quiz/quiz-editor.tsx | 80 ++++++++++++++++----------- 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/src/components/quiz/question-form.tsx b/src/components/quiz/question-form.tsx index 8aa7a99..1b686b3 100644 --- a/src/components/quiz/question-form.tsx +++ b/src/components/quiz/question-form.tsx @@ -1,3 +1,4 @@ +// src/components/quiz/question-form.tsx import { Trash2, TrashIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -5,22 +6,23 @@ import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; import type { Answer, Question } from "@/types/quiz.ts"; interface questionFormProps { - question: Question; - onUpdate: (updatedQuestion: Question) => void; + question: Question & { advanced?: boolean }; + onUpdate: (updatedQuestion: Question & { advanced?: boolean }) => void; onRemove: (id: number) => void; - advancedMode?: boolean; } export function QuestionForm({ question, onUpdate, onRemove, - advancedMode = false, }: questionFormProps) { + const isAdvanced = Boolean(question.advanced); + const handleTextChange = (text: string) => { onUpdate({ ...question, question: text }); }; @@ -53,7 +55,7 @@ export function QuestionForm({ }; const addAnswer = () => { - const newAnswer = { answer: "", correct: false, image: "" }; + const newAnswer = { answer: "", correct: false, image: "" } as Answer; onUpdate({ ...question, answers: [...question.answers, newAnswer] }); }; @@ -95,16 +97,30 @@ export function QuestionForm({ > Pytanie {question.id} - +
(() => { if (initialQuiz?.questions != null && initialQuiz.questions.length > 0) { - return initialQuiz.questions; + return initialQuiz.questions.map((q) => ({ + ...q, + // preserve per-question advanced if present, otherwise infer from content or global default + advanced: + Boolean((q as unknown as Q).advanced) || + Boolean(q.image) || + Boolean(q.explanation) || + q.answers.some((a) => Boolean(a.image)) || + initialAdvancedDefault, + })); } return [ { @@ -78,18 +103,16 @@ export function QuizEditor({ { answer: "", correct: false }, { answer: "", correct: false }, ], + image: "", + explanation: "", + advanced: initialAdvancedDefault, }, ]; }); + const [error, setError] = useState(null); - const [advancedMode, setAdvancedMode] = useState( - initialQuiz?.questions?.some( - (q) => - Boolean(q.image) || - Boolean(q.explanation) || - q.answers.some((a) => Boolean(a.image)), - ) ?? false, - ); + const [advancedMode, setAdvancedMode] = useState(initialAdvancedDefault); + const [previousQuestionId, setPreviousQuestionId] = useState (() => questions.reduce((max, q) => Math.max(q.id, max), 0), ); @@ -128,6 +151,7 @@ export function QuizEditor({ ], image: "", explanation: "", + advanced: advancedMode, // use global as default for new question }, ]); setPreviousQuestionId(newId); @@ -158,7 +182,7 @@ export function QuizEditor({ }); }; - const updateQuestion = (updated: Question) => { + const updateQuestion = (updated: Q) => { setQuestions((previous) => previous.map((q) => (q.id === updated.id ? updated : q)), ); @@ -171,7 +195,7 @@ export function QuizEditor({ const draft = { title, description, - questions: sanitizeQuestions(questions, advancedMode), + questions: sanitizeQuestions(questions), }; draft.title = draft.title.trimEnd(); @@ -223,7 +247,7 @@ export function QuizEditor({ From 0cf189c0cdede7719d5200b9d41dfe72676275a4 Mon Sep 17 00:00:00 2001 From: bartoszfabianowski <281041@student.pwr.edu.pl> Date: Sun, 14 Dec 2025 17:17:21 +0100 Subject: [PATCH 2/4] feat: added advanced mode per question fix --- src/components/quiz/question-form.tsx | 5 ----- src/components/quiz/quiz-editor.tsx | 8 ++------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/components/quiz/question-form.tsx b/src/components/quiz/question-form.tsx index 1b686b3..f16e5e4 100644 --- a/src/components/quiz/question-form.tsx +++ b/src/components/quiz/question-form.tsx @@ -1,4 +1,3 @@ -// src/components/quiz/question-form.tsx import { Trash2, TrashIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -36,8 +35,6 @@ export function QuestionForm({ }; const handleMultipleChange = (multiple: boolean) => { - // If switching from multiple choice to single choice and there are multiple correct answers, - // keep only the first correct answer if ( !multiple && question.multiple && @@ -60,8 +57,6 @@ export function QuestionForm({ }; const updateAnswer = (index: number, updatedAnswer: Answer) => { - // If this is a single-choice question and we're marking an answer as correct, - // unmark all other answers as correct if (!question.multiple && updatedAnswer.correct) { const updatedAnswers = question.answers.map((a, index_) => ({ ...a, diff --git a/src/components/quiz/quiz-editor.tsx b/src/components/quiz/quiz-editor.tsx index c5ce591..2c73e36 100644 --- a/src/components/quiz/quiz-editor.tsx +++ b/src/components/quiz/quiz-editor.tsx @@ -1,4 +1,3 @@ -// src/components/quiz/quiz-editor.tsx import { ArrowDownToLineIcon, PlusIcon } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; @@ -35,7 +34,6 @@ interface QuizEditorProps { saving?: boolean; } -// Utility to strip advanced fields when advancedMode is disabled per question const sanitizeQuestions = (questions: (Question & { advanced?: boolean })[]) => questions.map((q) => { const isAdvanced = Boolean(q.advanced); @@ -65,7 +63,6 @@ export function QuizEditor({ onSaveAndClose, saving = false, }: QuizEditorProps) { - // default advanced for existing quiz: if any question had advanced fields const initialAdvancedDefault = initialQuiz?.questions?.some( (q) => @@ -85,7 +82,7 @@ export function QuizEditor({ if (initialQuiz?.questions != null && initialQuiz.questions.length > 0) { return initialQuiz.questions.map((q) => ({ ...q, - // preserve per-question advanced if present, otherwise infer from content or global default + advanced: Boolean((q as unknown as Q).advanced) || Boolean(q.image) || @@ -117,7 +114,6 @@ export function QuizEditor({ questions.reduce((max, q) => Math.max(q.id, max), 0), ); - // all questions multiple toggle state (true / false / mixed null) const allQuestionsMultiple: boolean | null = useMemo(() => { if (questions.length === 0) { return null; @@ -151,7 +147,7 @@ export function QuizEditor({ ], image: "", explanation: "", - advanced: advancedMode, // use global as default for new question + advanced: advancedMode, }, ]); setPreviousQuestionId(newId); From 3801202b8d8253a0249b37384c7663c799cd61f4 Mon Sep 17 00:00:00 2001 From: Antoni Czaplicki{ - setAllQuestionsMultiple(Boolean(checked)); + setAllQuestionsMultiple(checked as boolean); }} /> Date: Sun, 4 Jan 2026 20:47:21 +0100 Subject: [PATCH 3/4] fix: correct some mistakes --- src/components/quiz/question-form.tsx | 6 +++- src/components/quiz/quiz-editor.tsx | 43 +++++++++++++-------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/components/quiz/question-form.tsx b/src/components/quiz/question-form.tsx index f16e5e4..ea9c844 100644 --- a/src/components/quiz/question-form.tsx +++ b/src/components/quiz/question-form.tsx @@ -35,6 +35,8 @@ export function QuestionForm({ }; const handleMultipleChange = (multiple: boolean) => { + // If switching from multiple choice to single choice and there are multiple correct answers, + // keep only the first correct answer if ( !multiple && question.multiple && @@ -52,11 +54,13 @@ export function QuestionForm({ }; const addAnswer = () => { - const newAnswer = { answer: "", correct: false, image: "" } as Answer; + const newAnswer: Answer = { answer: "", correct: false, image: "" }; onUpdate({ ...question, answers: [...question.answers, newAnswer] }); }; const updateAnswer = (index: number, updatedAnswer: Answer) => { + // If this is a single-choice question and we're marking an answer as correct, + // unmark all other answers as correct if (!question.multiple && updatedAnswer.correct) { const updatedAnswers = question.answers.map((a, index_) => ({ ...a, diff --git a/src/components/quiz/quiz-editor.tsx b/src/components/quiz/quiz-editor.tsx index 41b4607..b7f22bc 100644 --- a/src/components/quiz/quiz-editor.tsx +++ b/src/components/quiz/quiz-editor.tsx @@ -37,8 +37,9 @@ interface QuizEditorProps { const sanitizeQuestions = (questions: (Question & { advanced?: boolean })[]) => questions.map((q) => { const isAdvanced = Boolean(q.advanced); + const { advanced, ...rest } = q; return { - ...q, + ...rest, image: isAdvanced ? q.image : undefined, explanation: isAdvanced ? q.explanation : undefined, answers: q.answers.map((a) => ({ @@ -76,19 +77,17 @@ export function QuizEditor({ initialQuiz?.description ?? "", ); - type Q = Question & { advanced?: boolean }; + type QuestionWithAdvanced = Question & { advanced?: boolean }; - const [questions, setQuestions] = useState (() => { + const [questions, setQuestions] = useState(() => { if (initialQuiz?.questions != null && initialQuiz.questions.length > 0) { return initialQuiz.questions.map((q) => ({ ...q, - advanced: - Boolean((q as unknown as Q).advanced) || + Boolean((q as unknown as QuestionWithAdvanced).advanced) || Boolean(q.image) || Boolean(q.explanation) || - q.answers.some((a) => Boolean(a.image)) || - initialAdvancedDefault, + q.answers.some((a) => Boolean(a.image)), })); } return [ @@ -178,7 +177,7 @@ export function QuizEditor({ }); }; - const updateQuestion = (updated: Q) => { + const updateQuestion = (updated: QuestionWithAdvanced) => { setQuestions((previous) => previous.map((q) => (q.id === updated.id ? updated : q)), ); @@ -285,22 +284,20 @@ export function QuizEditor({ }} /> - {advancedMode ? ( - -- ) : ( --+{ - setAllQuestionsMultiple(checked as boolean); - }} - /> - - ++- ) : null} +{ + setAllQuestionsMultiple(Boolean(checked)); + }} + /> + -Pytania
From 6462efeccf5dc6e8121da61ab6bb921431c10352 Mon Sep 17 00:00:00 2001 From: Antoni CzaplickiDate: Sun, 4 Jan 2026 20:57:27 +0100 Subject: [PATCH 4/4] fix: correct some mistakes --- src/components/quiz/question-form.tsx | 57 ++++++++++----------------- src/components/quiz/quiz-editor.tsx | 7 ++-- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/components/quiz/question-form.tsx b/src/components/quiz/question-form.tsx index ea9c844..c9e2523 100644 --- a/src/components/quiz/question-form.tsx +++ b/src/components/quiz/question-form.tsx @@ -9,7 +9,7 @@ import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; import type { Answer, Question } from "@/types/quiz.ts"; -interface questionFormProps { +interface QuestionFormProps { question: Question & { advanced?: boolean }; onUpdate: (updatedQuestion: Question & { advanced?: boolean }) => void; onRemove: (id: number) => void; @@ -19,7 +19,7 @@ export function QuestionForm({ question, onUpdate, onRemove, -}: questionFormProps) { +}: QuestionFormProps) { const isAdvanced = Boolean(question.advanced); const handleTextChange = (text: string) => { @@ -54,7 +54,7 @@ export function QuestionForm({ }; const addAnswer = () => { - const newAnswer: Answer = { answer: "", correct: false, image: "" }; + const newAnswer = { answer: "", correct: false, image: "" }; onUpdate({ ...question, answers: [...question.answers, newAnswer] }); }; @@ -160,42 +160,25 @@ export function QuestionForm({ }} /> -{ - handleMultipleChange(Boolean(checked)); - }} - /> - - -- )} + ) : null} + +--{ - handleMultipleChange(Boolean(checked)); - }} - /> - - +{ + handleMultipleChange(Boolean(checked)); + }} + /> + + Odpowiedzi diff --git a/src/components/quiz/quiz-editor.tsx b/src/components/quiz/quiz-editor.tsx index b7f22bc..b027a38 100644 --- a/src/components/quiz/quiz-editor.tsx +++ b/src/components/quiz/quiz-editor.tsx @@ -34,7 +34,9 @@ interface QuizEditorProps { saving?: boolean; } -const sanitizeQuestions = (questions: (Question & { advanced?: boolean })[]) => +type QuestionWithAdvanced = Question & { advanced?: boolean }; + +const sanitizeQuestions = (questions: QuestionWithAdvanced[]) => questions.map((q) => { const isAdvanced = Boolean(q.advanced); const { advanced, ...rest } = q; @@ -77,14 +79,11 @@ export function QuizEditor({ initialQuiz?.description ?? "", ); - type QuestionWithAdvanced = Question & { advanced?: boolean }; - const [questions, setQuestions] = useState
(() => { if (initialQuiz?.questions != null && initialQuiz.questions.length > 0) { return initialQuiz.questions.map((q) => ({ ...q, advanced: - Boolean((q as unknown as QuestionWithAdvanced).advanced) || Boolean(q.image) || Boolean(q.explanation) || q.answers.some((a) => Boolean(a.image)),