Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 68 additions & 55 deletions src/routes/quiz/[collection]/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,29 @@
import { ArrowForwardIcon, AudioIcon, TextAppearanceIcon } from '$lib/icons';
import { compareVersions } from '$lib/scripts/stringUtils';
import { onDestroy } from 'svelte';
/** @type {import('./$types').PageData} */
export let data;
$: ({ locked, quiz, quizId, quizName, passScore } = data);
$: book = config.bookCollections
.find((x) => x.id === $refs.collection)
.books.find((x) => x.id === quizId);
$: displayLabel = quizName || 'Quiz';
$: if (quiz) {
resetQuizState();
score = 0;
questionNum = 0;
shuffledAnswers = [];
quizQuestions = book.quizFeatures['shuffle-questions']
? shuffleArray([...quiz.questions])
: [...quiz.questions];
handleQuestionChange();
playQuizQuestionAudio();
quizSaved = false;
} else {
stopAudioPlayback();
score = 0;
questionNum = 0;
shuffledAnswers = [];
quizQuestions = [];
quizSaved = false;
}
let textHighlightIndex = -1;
let quizSaved = false;
let shuffledAnswers = [];
let quizQuestions = [];
let score = 0;
let questionNum = 0;
let currentQuizQuestion;
let clicked = false;
let displayCorrect = false;
import { run } from 'svelte/legacy';
/**
* @typedef {Object} Props
* @property {import('./$types').PageData} data
*/
/** @type {Props} */
let { data } = $props();
let textHighlightIndex = $state(-1);
let quizSaved = $state(false);
let shuffledAnswers = $state([]);
let quizQuestions = $state([]);
let score = $state(0);
let questionNum = $state(0);
let currentQuizQuestion = $state();
let clicked = $state(false);
let displayCorrect = $state(false);
let currentQuestionAudio = null;
let currentAnswerAudio = null;
let currentExplanationAudio = null;
let explanation = '';
let explanation = $state('');
let commentaryMessage = '';
const quizAssetFolder = compareVersions(config.programVersion, '12.0') < 0 ? 'assets' : 'quiz';
Expand Down Expand Up @@ -297,6 +273,43 @@
onDestroy(() => {
stopAudioPlayback();
});
let { locked, quiz, quizId, quizName, passScore } = $derived(data);
let book = $derived(
config.bookCollections
.find((x) => x.id === $refs.collection)
.books.find((x) => x.id === quizId)
);
let displayLabel = $derived(quizName || 'Quiz');
effect(() => {
const { locked, quiz, quizId, quizName, passScore } = data;
setBook(
config.bookCollections
.find((x) => x.id === $refs.collection)
.books.find((x) => x.id === quizId)
);
setDisplayLabel(quizName || 'Quiz');
if (quiz) {
resetQuizState();
setScore(0);
setQuestionNum(0);
setShuffledAnswers([]);
const q = book.quizFeatures['shuffle-questions']
? shuffleArray([...quiz.questions])
: [...quiz.questions];
setQuizQuestions(q);
handleQuestionChange(q, 0);
playQuizQuestionAudio();
setQuizSaved(false);
} else {
stopAudioPlayback();
setScore(0);
setQuestionNum(0);
setShuffledAnswers([]);
setQuizQuestions([]);
setQuizSaved(false);
}
});
Comment on lines +276 to +312
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical issues in reactive state management

The effect implementation has several problems:

  1. Duplicate destructuring of data (already handled by $derived)
  2. Calling non-existent setter functions - Svelte 5 uses direct assignment to state variables
  3. handleQuestionChange called with wrong parameters

Apply this fix:

 let { locked, quiz, quizId, quizName, passScore } = $derived(data);
 let book = $derived(
     config.bookCollections
         .find((x) => x.id === $refs.collection)
         .books.find((x) => x.id === quizId)
 );
 let displayLabel = $derived(quizName || 'Quiz');
 effect(() => {
-    const { locked, quiz, quizId, quizName, passScore } = data;
-    setBook(
-        config.bookCollections
-            .find((x) => x.id === $refs.collection)
-            .books.find((x) => x.id === quizId)
-    );
-    setDisplayLabel(quizName || 'Quiz');
-
     if (quiz) {
         resetQuizState();
-        setScore(0);
-        setQuestionNum(0);
-        setShuffledAnswers([]);
+        score = 0;
+        questionNum = 0;
+        shuffledAnswers = [];
         const q = book.quizFeatures['shuffle-questions']
             ? shuffleArray([...quiz.questions])
             : [...quiz.questions];
-        setQuizQuestions(q);
-        handleQuestionChange(q, 0);
+        quizQuestions = q;
+        handleQuestionChange();
         playQuizQuestionAudio();
-        setQuizSaved(false);
+        quizSaved = false;
     } else {
         stopAudioPlayback();
-        setScore(0);
-        setQuestionNum(0);
-        setShuffledAnswers([]);
-        setQuizQuestions([]);
-        setQuizSaved(false);
+        score = 0;
+        questionNum = 0;
+        shuffledAnswers = [];
+        quizQuestions = [];
+        quizSaved = false;
     }
 });
🤖 Prompt for AI Agents
In src/routes/quiz/[collection]/[id]/+page.svelte lines 276 to 312, remove the
duplicate destructuring of data inside the effect since $derived already
provides reactive values. Replace all calls to non-existent setter functions
like setBook, setDisplayLabel, setScore, setQuestionNum, setShuffledAnswers,
setQuizQuestions, setQuizSaved with direct assignments to their corresponding
state variables. Correct the call to handleQuestionChange by passing the current
question index and the question object instead of the entire question array and
index. This will align the reactive state management with Svelte 5 conventions
and fix the parameter usage.

</script>

<div class="grid grid-rows-[auto,1fr] h-screen" style:font-size="{$bodyFontSize}px">
Expand All @@ -310,7 +323,7 @@
<div class="flex">
<button
class="dy-btn dy-btn-ghost dy-btn-circle"
on:click={() => {
onclick={() => {
$quizAudioActive = !$quizAudioActive;
}}
>
Expand All @@ -321,12 +334,12 @@
{/if}
</button>
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-label-has-associated-control -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_label_has_associated_control -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<label
class="dy-btn dy-btn-ghost p-0.5 dy-no-animation"
on:click={() => modal.open(MODAL_TEXT_APPEARANCE)}
onclick={() => modal.open(MODAL_TEXT_APPEARANCE)}
>
<TextAppearanceIcon color="white" />
</label>
Expand Down Expand Up @@ -378,7 +391,7 @@
<div class="quiz-question" style:line-height="{$bodyLineHeight}%">
{currentQuizQuestion.text}
{#if currentQuizQuestion.image}
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y_missing_attribute -->
<img
class="quiz-question-image h-40"
src={getImageSource(currentQuizQuestion.image)}
Expand All @@ -393,7 +406,7 @@
{#each shuffledAnswers as answer, currentIndex}
<button
class="w-5/6 md:w-64 lg:w-[20rem] mt-2"
on:click={() => {
onclick={() => {
onQuestionAnswered(answer);
}}
>
Expand Down Expand Up @@ -442,13 +455,13 @@
class:textHighlight={textHighlightIndex ===
currentIndex}
>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<img
class="cursor-pointer"
src={getImageSource(answer.image)}
alt={answer.text}
on:click={() => {
onclick={() => {
onQuestionAnswered(answer);
}}
/>
Expand All @@ -471,7 +484,7 @@
>
<button
class="dy-btn dy-btn-active p-2 px-8 mt-4"
on:click={() => {
onclick={() => {
onNextQuestion();
}}
>
Expand Down