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