@schoolio/player 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,595 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/QuizPlayer.tsx
5
+
6
+ // src/api.ts
7
+ var QuizApiClient = class {
8
+ constructor(config) {
9
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
10
+ this.authToken = config.authToken;
11
+ }
12
+ async request(method, endpoint, body) {
13
+ const headers = {
14
+ "Content-Type": "application/json"
15
+ };
16
+ if (this.authToken) {
17
+ headers["Authorization"] = `Bearer ${this.authToken}`;
18
+ }
19
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
20
+ method,
21
+ headers,
22
+ body: body ? JSON.stringify(body) : void 0
23
+ });
24
+ if (!response.ok) {
25
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
26
+ throw new Error(error.error || `HTTP ${response.status}`);
27
+ }
28
+ return response.json();
29
+ }
30
+ async getQuiz(quizId) {
31
+ return this.request("GET", `/api/external/quizzes/${quizId}`);
32
+ }
33
+ async createAttempt(params) {
34
+ return this.request("POST", "/api/external/quiz-attempts", params);
35
+ }
36
+ async updateAttempt(attemptId, data) {
37
+ return this.request(
38
+ "PATCH",
39
+ `/api/external/quiz-attempts/${attemptId}`,
40
+ data
41
+ );
42
+ }
43
+ async getAttempt(attemptId) {
44
+ return this.request("GET", `/api/external/quiz-attempts/${attemptId}`);
45
+ }
46
+ async getAttempts(params) {
47
+ const queryParams = new URLSearchParams();
48
+ if (params.assignLessonId) queryParams.set("assignLessonId", params.assignLessonId);
49
+ if (params.childId) queryParams.set("childId", params.childId);
50
+ if (params.quizId) queryParams.set("quizId", params.quizId);
51
+ return this.request(
52
+ "GET",
53
+ `/api/external/quiz-attempts?${queryParams.toString()}`
54
+ );
55
+ }
56
+ };
57
+
58
+ // src/utils.ts
59
+ function checkAnswer(question, selectedAnswer) {
60
+ const { type, correctAnswer, points } = question;
61
+ switch (type) {
62
+ case "single":
63
+ case "true-false": {
64
+ const isCorrect = selectedAnswer === correctAnswer;
65
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
66
+ }
67
+ case "multiple": {
68
+ if (!Array.isArray(selectedAnswer) || !Array.isArray(correctAnswer)) {
69
+ return { isCorrect: false, pointsEarned: 0 };
70
+ }
71
+ const sortedSelected = [...selectedAnswer].sort();
72
+ const sortedCorrect = [...correctAnswer].sort();
73
+ const isCorrect = sortedSelected.length === sortedCorrect.length && sortedSelected.every((val, idx) => val === sortedCorrect[idx]);
74
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
75
+ }
76
+ case "fill": {
77
+ if (!Array.isArray(selectedAnswer) || !question.blanks) {
78
+ return { isCorrect: false, pointsEarned: 0 };
79
+ }
80
+ const isCorrect = question.blanks.every(
81
+ (blank, idx) => selectedAnswer[idx]?.toLowerCase().trim() === blank.toLowerCase().trim()
82
+ );
83
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
84
+ }
85
+ case "sorting": {
86
+ if (!Array.isArray(selectedAnswer) || !question.correctOrder) {
87
+ return { isCorrect: false, pointsEarned: 0 };
88
+ }
89
+ const isCorrect = selectedAnswer.length === question.correctOrder.length && selectedAnswer.every((val, idx) => val === question.correctOrder[idx]);
90
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
91
+ }
92
+ case "matrix": {
93
+ if (typeof selectedAnswer !== "object" || !question.correctMatches) {
94
+ return { isCorrect: false, pointsEarned: 0 };
95
+ }
96
+ const selected = selectedAnswer;
97
+ const correct = question.correctMatches;
98
+ const isCorrect = Object.keys(correct).every(
99
+ (key) => selected[key] === correct[key]
100
+ );
101
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
102
+ }
103
+ case "free": {
104
+ if (typeof selectedAnswer !== "string" || typeof correctAnswer !== "string") {
105
+ return { isCorrect: false, pointsEarned: 0 };
106
+ }
107
+ const isCorrect = selectedAnswer.toLowerCase().trim() === correctAnswer.toLowerCase().trim();
108
+ return { isCorrect, pointsEarned: isCorrect ? points : 0 };
109
+ }
110
+ case "essay":
111
+ case "assessment":
112
+ return { isCorrect: false, pointsEarned: 0 };
113
+ default:
114
+ return { isCorrect: false, pointsEarned: 0 };
115
+ }
116
+ }
117
+ function createAnswerDetail(question, selectedAnswer) {
118
+ const { isCorrect, pointsEarned } = checkAnswer(question, selectedAnswer);
119
+ return {
120
+ questionId: question.id,
121
+ questionText: question.question,
122
+ questionType: question.type,
123
+ points: question.points,
124
+ pointsEarned,
125
+ selectedAnswer,
126
+ correctAnswer: question.correctAnswer,
127
+ isCorrect,
128
+ explanation: question.explanation,
129
+ hint: question.hint
130
+ };
131
+ }
132
+ function calculateScore(answers) {
133
+ const totalPoints = answers.reduce((sum, a) => sum + a.points, 0);
134
+ const earnedPoints = answers.reduce((sum, a) => sum + a.pointsEarned, 0);
135
+ const correctAnswers = answers.filter((a) => a.isCorrect).length;
136
+ const score = totalPoints > 0 ? Math.round(earnedPoints / totalPoints * 100) : 0;
137
+ return { score, correctAnswers, totalPoints, earnedPoints };
138
+ }
139
+ function formatTime(seconds) {
140
+ const mins = Math.floor(seconds / 60);
141
+ const secs = seconds % 60;
142
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
143
+ }
144
+ var defaultStyles = {
145
+ container: {
146
+ fontFamily: "system-ui, -apple-system, sans-serif",
147
+ maxWidth: "800px",
148
+ margin: "0 auto",
149
+ padding: "20px"
150
+ },
151
+ header: {
152
+ marginBottom: "20px",
153
+ borderBottom: "1px solid #e5e7eb",
154
+ paddingBottom: "16px"
155
+ },
156
+ title: {
157
+ fontSize: "24px",
158
+ fontWeight: "600",
159
+ marginBottom: "8px"
160
+ },
161
+ progress: {
162
+ fontSize: "14px",
163
+ color: "#6b7280"
164
+ },
165
+ progressBar: {
166
+ width: "100%",
167
+ height: "8px",
168
+ backgroundColor: "#e5e7eb",
169
+ borderRadius: "4px",
170
+ overflow: "hidden",
171
+ marginTop: "8px"
172
+ },
173
+ progressFill: {
174
+ height: "100%",
175
+ backgroundColor: "#3b82f6",
176
+ transition: "width 0.3s ease"
177
+ },
178
+ question: {
179
+ marginBottom: "24px"
180
+ },
181
+ questionText: {
182
+ fontSize: "18px",
183
+ fontWeight: "500",
184
+ marginBottom: "16px"
185
+ },
186
+ options: {
187
+ display: "flex",
188
+ flexDirection: "column",
189
+ gap: "8px"
190
+ },
191
+ option: {
192
+ padding: "12px 16px",
193
+ border: "2px solid #e5e7eb",
194
+ borderRadius: "8px",
195
+ cursor: "pointer",
196
+ transition: "all 0.2s ease"
197
+ },
198
+ optionSelected: {
199
+ borderColor: "#3b82f6",
200
+ backgroundColor: "#eff6ff"
201
+ },
202
+ input: {
203
+ width: "100%",
204
+ padding: "12px 16px",
205
+ border: "2px solid #e5e7eb",
206
+ borderRadius: "8px",
207
+ fontSize: "16px"
208
+ },
209
+ buttons: {
210
+ display: "flex",
211
+ justifyContent: "space-between",
212
+ marginTop: "24px"
213
+ },
214
+ button: {
215
+ padding: "12px 24px",
216
+ borderRadius: "8px",
217
+ fontSize: "16px",
218
+ fontWeight: "500",
219
+ cursor: "pointer",
220
+ border: "none",
221
+ transition: "all 0.2s ease"
222
+ },
223
+ buttonPrimary: {
224
+ backgroundColor: "#3b82f6",
225
+ color: "#ffffff"
226
+ },
227
+ buttonSecondary: {
228
+ backgroundColor: "#f3f4f6",
229
+ color: "#374151"
230
+ },
231
+ buttonDisabled: {
232
+ backgroundColor: "#e5e7eb",
233
+ color: "#9ca3af",
234
+ cursor: "not-allowed"
235
+ },
236
+ timer: {
237
+ fontSize: "14px",
238
+ color: "#6b7280",
239
+ marginLeft: "16px"
240
+ },
241
+ results: {
242
+ textAlign: "center",
243
+ padding: "40px 20px"
244
+ },
245
+ resultScore: {
246
+ fontSize: "48px",
247
+ fontWeight: "700",
248
+ color: "#3b82f6",
249
+ marginBottom: "8px"
250
+ },
251
+ resultLabel: {
252
+ fontSize: "18px",
253
+ color: "#6b7280"
254
+ },
255
+ loading: {
256
+ textAlign: "center",
257
+ padding: "40px",
258
+ color: "#6b7280"
259
+ },
260
+ error: {
261
+ textAlign: "center",
262
+ padding: "40px",
263
+ color: "#ef4444"
264
+ }
265
+ };
266
+ function QuizPlayer({
267
+ quizId,
268
+ lessonId,
269
+ assignLessonId,
270
+ courseId,
271
+ childId,
272
+ parentId,
273
+ apiBaseUrl,
274
+ authToken,
275
+ onComplete,
276
+ onError,
277
+ onProgress,
278
+ className
279
+ }) {
280
+ const [quiz, setQuiz] = useState(null);
281
+ const [attempt, setAttempt] = useState(null);
282
+ const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
283
+ const [answers, setAnswers] = useState(/* @__PURE__ */ new Map());
284
+ const [answersDetail, setAnswersDetail] = useState([]);
285
+ const [isSubmitting, setIsSubmitting] = useState(false);
286
+ const [isCompleted, setIsCompleted] = useState(false);
287
+ const [result, setResult] = useState(null);
288
+ const [error, setError] = useState(null);
289
+ const [isLoading, setIsLoading] = useState(true);
290
+ const [elapsedSeconds, setElapsedSeconds] = useState(0);
291
+ const apiClient = useRef(null);
292
+ const timerRef = useRef(null);
293
+ const startTimeRef = useRef(Date.now());
294
+ useEffect(() => {
295
+ apiClient.current = new QuizApiClient({ baseUrl: apiBaseUrl, authToken });
296
+ }, [apiBaseUrl, authToken]);
297
+ useEffect(() => {
298
+ async function initialize() {
299
+ if (!apiClient.current) return;
300
+ try {
301
+ setIsLoading(true);
302
+ setError(null);
303
+ const quizData = await apiClient.current.getQuiz(quizId);
304
+ setQuiz(quizData);
305
+ const attemptData = await apiClient.current.createAttempt({
306
+ quizId,
307
+ lessonId,
308
+ assignLessonId,
309
+ courseId,
310
+ childId,
311
+ parentId
312
+ });
313
+ setAttempt(attemptData);
314
+ if (attemptData.answers && attemptData.answers.length > 0) {
315
+ setAnswersDetail(attemptData.answers);
316
+ const answersMap = /* @__PURE__ */ new Map();
317
+ attemptData.answers.forEach((a) => {
318
+ answersMap.set(a.questionId, a.selectedAnswer);
319
+ });
320
+ setAnswers(answersMap);
321
+ }
322
+ if (attemptData.status === "completed") {
323
+ setIsCompleted(true);
324
+ const scoreData = calculateScore(attemptData.answers);
325
+ setResult({
326
+ attemptId: attemptData.id,
327
+ score: attemptData.score || scoreData.score,
328
+ correctAnswers: attemptData.correctAnswers || scoreData.correctAnswers,
329
+ totalQuestions: attemptData.totalQuestions,
330
+ answers: attemptData.answers,
331
+ timeSpentSeconds: attemptData.timeSpentSeconds || 0
332
+ });
333
+ }
334
+ setIsLoading(false);
335
+ } catch (err) {
336
+ const message = err instanceof Error ? err.message : "Failed to load quiz";
337
+ setError(message);
338
+ setIsLoading(false);
339
+ onError?.(err instanceof Error ? err : new Error(message));
340
+ }
341
+ }
342
+ initialize();
343
+ }, [quizId, lessonId, assignLessonId, courseId, childId, parentId, onError]);
344
+ useEffect(() => {
345
+ if (!isLoading && !isCompleted && !error) {
346
+ startTimeRef.current = Date.now();
347
+ timerRef.current = setInterval(() => {
348
+ setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
349
+ }, 1e3);
350
+ }
351
+ return () => {
352
+ if (timerRef.current) {
353
+ clearInterval(timerRef.current);
354
+ }
355
+ };
356
+ }, [isLoading, isCompleted, error]);
357
+ useEffect(() => {
358
+ if (quiz && onProgress) {
359
+ onProgress({
360
+ currentQuestion: currentQuestionIndex + 1,
361
+ totalQuestions: quiz.questions.length,
362
+ answeredQuestions: answers.size
363
+ });
364
+ }
365
+ }, [currentQuestionIndex, answers.size, quiz, onProgress]);
366
+ const currentQuestion = quiz?.questions[currentQuestionIndex];
367
+ const handleAnswerChange = useCallback((value) => {
368
+ if (!currentQuestion) return;
369
+ setAnswers((prev) => new Map(prev).set(currentQuestion.id, value));
370
+ }, [currentQuestion]);
371
+ const handleNext = useCallback(async () => {
372
+ if (!quiz || !attempt || !currentQuestion || !apiClient.current) return;
373
+ const selectedAnswer2 = answers.get(currentQuestion.id);
374
+ if (selectedAnswer2 === void 0) return;
375
+ const answerDetail = createAnswerDetail(currentQuestion, selectedAnswer2);
376
+ const newAnswersDetail = [...answersDetail];
377
+ const existingIdx = newAnswersDetail.findIndex((a) => a.questionId === currentQuestion.id);
378
+ if (existingIdx >= 0) {
379
+ newAnswersDetail[existingIdx] = answerDetail;
380
+ } else {
381
+ newAnswersDetail.push(answerDetail);
382
+ }
383
+ setAnswersDetail(newAnswersDetail);
384
+ try {
385
+ await apiClient.current.updateAttempt(attempt.id, {
386
+ answers: newAnswersDetail
387
+ });
388
+ } catch (err) {
389
+ console.error("Failed to save progress:", err);
390
+ }
391
+ if (currentQuestionIndex < quiz.questions.length - 1) {
392
+ setCurrentQuestionIndex((prev) => prev + 1);
393
+ }
394
+ }, [quiz, attempt, currentQuestion, answers, answersDetail, currentQuestionIndex]);
395
+ const handlePrevious = useCallback(() => {
396
+ if (currentQuestionIndex > 0) {
397
+ setCurrentQuestionIndex((prev) => prev - 1);
398
+ }
399
+ }, [currentQuestionIndex]);
400
+ const handleSubmit = useCallback(async () => {
401
+ if (!quiz || !attempt || !apiClient.current) return;
402
+ setIsSubmitting(true);
403
+ try {
404
+ const currentAnswer = currentQuestion ? answers.get(currentQuestion.id) : void 0;
405
+ let finalAnswersDetail = [...answersDetail];
406
+ if (currentQuestion && currentAnswer !== void 0) {
407
+ const answerDetail = createAnswerDetail(currentQuestion, currentAnswer);
408
+ const existingIdx = finalAnswersDetail.findIndex((a) => a.questionId === currentQuestion.id);
409
+ if (existingIdx >= 0) {
410
+ finalAnswersDetail[existingIdx] = answerDetail;
411
+ } else {
412
+ finalAnswersDetail.push(answerDetail);
413
+ }
414
+ }
415
+ const scoreData = calculateScore(finalAnswersDetail);
416
+ const timeSpent = Math.floor((Date.now() - startTimeRef.current) / 1e3);
417
+ const updatedAttempt = await apiClient.current.updateAttempt(attempt.id, {
418
+ answers: finalAnswersDetail,
419
+ status: "completed",
420
+ score: scoreData.score,
421
+ correctAnswers: scoreData.correctAnswers,
422
+ timeSpentSeconds: timeSpent
423
+ });
424
+ setIsCompleted(true);
425
+ const quizResult = {
426
+ attemptId: updatedAttempt.id,
427
+ score: scoreData.score,
428
+ correctAnswers: scoreData.correctAnswers,
429
+ totalQuestions: quiz.questions.length,
430
+ answers: finalAnswersDetail,
431
+ timeSpentSeconds: timeSpent
432
+ };
433
+ setResult(quizResult);
434
+ if (timerRef.current) {
435
+ clearInterval(timerRef.current);
436
+ }
437
+ onComplete?.(quizResult);
438
+ } catch (err) {
439
+ const message = err instanceof Error ? err.message : "Failed to submit quiz";
440
+ setError(message);
441
+ onError?.(err instanceof Error ? err : new Error(message));
442
+ } finally {
443
+ setIsSubmitting(false);
444
+ }
445
+ }, [quiz, attempt, currentQuestion, answers, answersDetail, onComplete, onError]);
446
+ if (isLoading) {
447
+ return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsx("div", { style: defaultStyles.loading, children: "Loading quiz..." }) });
448
+ }
449
+ if (error) {
450
+ return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsx("div", { style: defaultStyles.error, children: /* @__PURE__ */ jsxs("p", { children: [
451
+ "Error: ",
452
+ error
453
+ ] }) }) });
454
+ }
455
+ if (isCompleted && result) {
456
+ return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsxs("div", { style: defaultStyles.results, children: [
457
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.resultScore, children: [
458
+ result.score,
459
+ "%"
460
+ ] }),
461
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.resultLabel, children: [
462
+ result.correctAnswers,
463
+ " of ",
464
+ result.totalQuestions,
465
+ " correct"
466
+ ] }),
467
+ /* @__PURE__ */ jsxs("div", { style: { ...defaultStyles.resultLabel, marginTop: "8px" }, children: [
468
+ "Time: ",
469
+ formatTime(result.timeSpentSeconds)
470
+ ] })
471
+ ] }) });
472
+ }
473
+ if (!quiz || !currentQuestion) {
474
+ return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsx("div", { style: defaultStyles.error, children: "No quiz data available" }) });
475
+ }
476
+ const selectedAnswer = answers.get(currentQuestion.id);
477
+ const isLastQuestion = currentQuestionIndex === quiz.questions.length - 1;
478
+ const progressPercent = (currentQuestionIndex + 1) / quiz.questions.length * 100;
479
+ return /* @__PURE__ */ jsxs("div", { className, style: defaultStyles.container, children: [
480
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.header, children: [
481
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
482
+ /* @__PURE__ */ jsx("div", { style: defaultStyles.title, children: quiz.title }),
483
+ /* @__PURE__ */ jsx("div", { style: defaultStyles.timer, children: formatTime(elapsedSeconds) })
484
+ ] }),
485
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.progress, children: [
486
+ "Question ",
487
+ currentQuestionIndex + 1,
488
+ " of ",
489
+ quiz.questions.length
490
+ ] }),
491
+ /* @__PURE__ */ jsx("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ jsx("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
492
+ ] }),
493
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.question, children: [
494
+ /* @__PURE__ */ jsx("div", { style: defaultStyles.questionText, children: currentQuestion.question }),
495
+ (currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => /* @__PURE__ */ jsx(
496
+ "div",
497
+ {
498
+ style: {
499
+ ...defaultStyles.option,
500
+ ...selectedAnswer === option ? defaultStyles.optionSelected : {}
501
+ },
502
+ onClick: () => handleAnswerChange(option),
503
+ children: option
504
+ },
505
+ idx
506
+ )) }),
507
+ currentQuestion.type === "multiple" && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
508
+ const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
509
+ return /* @__PURE__ */ jsx(
510
+ "div",
511
+ {
512
+ style: {
513
+ ...defaultStyles.option,
514
+ ...selected ? defaultStyles.optionSelected : {}
515
+ },
516
+ onClick: () => {
517
+ const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];
518
+ if (selected) {
519
+ handleAnswerChange(current.filter((o) => o !== option));
520
+ } else {
521
+ handleAnswerChange([...current, option]);
522
+ }
523
+ },
524
+ children: option
525
+ },
526
+ idx
527
+ );
528
+ }) }),
529
+ (currentQuestion.type === "free" || currentQuestion.type === "essay") && /* @__PURE__ */ jsx(
530
+ "textarea",
531
+ {
532
+ style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
533
+ value: selectedAnswer || "",
534
+ onChange: (e) => handleAnswerChange(e.target.value),
535
+ placeholder: "Type your answer here..."
536
+ }
537
+ ),
538
+ currentQuestion.type === "fill" && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ jsx(
539
+ "input",
540
+ {
541
+ style: defaultStyles.input,
542
+ value: (Array.isArray(selectedAnswer) ? selectedAnswer[idx] : "") || "",
543
+ onChange: (e) => {
544
+ const current = Array.isArray(selectedAnswer) ? [...selectedAnswer] : [];
545
+ current[idx] = e.target.value;
546
+ handleAnswerChange(current);
547
+ },
548
+ placeholder: `Blank ${idx + 1}`
549
+ },
550
+ idx
551
+ )) })
552
+ ] }),
553
+ /* @__PURE__ */ jsxs("div", { style: defaultStyles.buttons, children: [
554
+ /* @__PURE__ */ jsx(
555
+ "button",
556
+ {
557
+ style: {
558
+ ...defaultStyles.button,
559
+ ...currentQuestionIndex > 0 ? defaultStyles.buttonSecondary : defaultStyles.buttonDisabled
560
+ },
561
+ onClick: handlePrevious,
562
+ disabled: currentQuestionIndex === 0,
563
+ children: "Previous"
564
+ }
565
+ ),
566
+ isLastQuestion ? /* @__PURE__ */ jsx(
567
+ "button",
568
+ {
569
+ style: {
570
+ ...defaultStyles.button,
571
+ ...isSubmitting ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
572
+ },
573
+ onClick: handleSubmit,
574
+ disabled: isSubmitting || selectedAnswer === void 0,
575
+ children: isSubmitting ? "Submitting..." : "Submit Quiz"
576
+ }
577
+ ) : /* @__PURE__ */ jsx(
578
+ "button",
579
+ {
580
+ style: {
581
+ ...defaultStyles.button,
582
+ ...selectedAnswer !== void 0 ? defaultStyles.buttonPrimary : defaultStyles.buttonDisabled
583
+ },
584
+ onClick: handleNext,
585
+ disabled: selectedAnswer === void 0,
586
+ children: "Next"
587
+ }
588
+ )
589
+ ] })
590
+ ] });
591
+ }
592
+
593
+ export { QuizApiClient, QuizPlayer, calculateScore, checkAnswer, createAnswerDetail, formatTime };
594
+ //# sourceMappingURL=index.mjs.map
595
+ //# sourceMappingURL=index.mjs.map