@schoolio/player 1.4.4 → 1.4.6

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 CHANGED
@@ -21,13 +21,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AttemptViewer: () => AttemptViewer,
24
+ ERROR_DEFINITIONS: () => ERROR_DEFINITIONS,
25
+ ErrorLogsPanel: () => ErrorLogsPanel,
26
+ ErrorTypesPanel: () => ErrorTypesPanel,
27
+ MaintenanceScreen: () => MaintenanceScreen,
24
28
  QuizApiClient: () => QuizApiClient,
25
29
  QuizPlayer: () => QuizPlayer,
26
30
  TextToSpeech: () => TextToSpeech,
27
31
  calculateScore: () => calculateScore,
28
32
  checkAnswer: () => checkAnswer,
29
33
  createAnswerDetail: () => createAnswerDetail,
30
- formatTime: () => formatTime
34
+ formatTime: () => formatTime,
35
+ getErrorFromHttpStatus: () => getErrorFromHttpStatus,
36
+ getErrorFromMessage: () => getErrorFromMessage
31
37
  });
32
38
  module.exports = __toCommonJS(index_exports);
33
39
 
@@ -136,6 +142,13 @@ var QuizApiClient = class {
136
142
  }
137
143
  return response.blob();
138
144
  }
145
+ async logError(params) {
146
+ try {
147
+ await this.request("POST", "/api/external/log-error", params);
148
+ } catch (e) {
149
+ console.warn("[QuizEngine] Failed to log error:", e);
150
+ }
151
+ }
139
152
  };
140
153
 
141
154
  // src/utils.ts
@@ -1056,8 +1069,191 @@ function QuestionChatPanel({
1056
1069
  ] });
1057
1070
  }
1058
1071
 
1059
- // src/QuizPlayer.tsx
1072
+ // src/errors.ts
1073
+ var ERROR_DEFINITIONS = {
1074
+ QUIZ_NOT_FOUND: {
1075
+ code: "QUIZ_NOT_FOUND",
1076
+ userMessage: "We couldn't find this quiz",
1077
+ subMessage: "The quiz may have been removed or the link is incorrect.",
1078
+ cause: "The quiz ID does not exist in the database, or the quiz has been deleted.",
1079
+ isBlocking: true
1080
+ },
1081
+ ATTEMPT_NOT_FOUND: {
1082
+ code: "ATTEMPT_NOT_FOUND",
1083
+ userMessage: "We couldn't find this quiz attempt",
1084
+ subMessage: "The attempt may have expired or the link is incorrect.",
1085
+ cause: "The attempt ID does not exist, or the attempt has been deleted/archived.",
1086
+ isBlocking: true
1087
+ },
1088
+ QUIZ_EXPIRED: {
1089
+ code: "QUIZ_EXPIRED",
1090
+ userMessage: "This quiz has expired",
1091
+ subMessage: "The deadline for this quiz has passed.",
1092
+ cause: "The quiz end date/time has passed and submissions are no longer accepted.",
1093
+ isBlocking: true
1094
+ },
1095
+ QUIZ_NOT_STARTED: {
1096
+ code: "QUIZ_NOT_STARTED",
1097
+ userMessage: "This quiz is not available yet",
1098
+ subMessage: "Please check back when the quiz opens.",
1099
+ cause: "The quiz start date/time has not yet been reached.",
1100
+ isBlocking: true
1101
+ },
1102
+ NETWORK_ERROR: {
1103
+ code: "NETWORK_ERROR",
1104
+ userMessage: "Connection problem",
1105
+ subMessage: "Please check your internet connection and try again.",
1106
+ cause: "Unable to reach the server due to network connectivity issues.",
1107
+ isBlocking: true
1108
+ },
1109
+ SERVER_ERROR: {
1110
+ code: "SERVER_ERROR",
1111
+ userMessage: "Something went wrong on our end",
1112
+ subMessage: "Our team has been notified. Please try again later.",
1113
+ cause: "The server encountered an internal error (HTTP 500+).",
1114
+ isBlocking: true
1115
+ },
1116
+ UNAUTHORIZED: {
1117
+ code: "UNAUTHORIZED",
1118
+ userMessage: "Please sign in to continue",
1119
+ subMessage: "You need to be logged in to access this quiz.",
1120
+ cause: "The user is not authenticated (HTTP 401).",
1121
+ isBlocking: true
1122
+ },
1123
+ FORBIDDEN: {
1124
+ code: "FORBIDDEN",
1125
+ userMessage: "You don't have access to this quiz",
1126
+ subMessage: "Contact your instructor if you believe this is a mistake.",
1127
+ cause: "The user does not have permission to access this resource (HTTP 403).",
1128
+ isBlocking: true
1129
+ },
1130
+ TTS_FAILED: {
1131
+ code: "TTS_FAILED",
1132
+ userMessage: "Text-to-speech unavailable",
1133
+ subMessage: "Audio features are temporarily unavailable.",
1134
+ cause: "The text-to-speech service failed or is unreachable.",
1135
+ isBlocking: false
1136
+ },
1137
+ CHAT_FAILED: {
1138
+ code: "CHAT_FAILED",
1139
+ userMessage: "Chat assistance unavailable",
1140
+ subMessage: "The AI helper is temporarily unavailable.",
1141
+ cause: "The chat/AI service failed to initialize or respond.",
1142
+ isBlocking: false
1143
+ },
1144
+ SUBMISSION_FAILED: {
1145
+ code: "SUBMISSION_FAILED",
1146
+ userMessage: "Failed to submit your answer",
1147
+ subMessage: "Please try again. Your progress has been saved.",
1148
+ cause: "The answer submission request failed due to network or server issues.",
1149
+ isBlocking: false
1150
+ },
1151
+ UNKNOWN_ERROR: {
1152
+ code: "UNKNOWN_ERROR",
1153
+ userMessage: "Something unexpected happened",
1154
+ subMessage: "Please try refreshing the page.",
1155
+ cause: "An unclassified error occurred.",
1156
+ isBlocking: true
1157
+ }
1158
+ };
1159
+ function getErrorFromHttpStatus(status, context) {
1160
+ switch (status) {
1161
+ case 401:
1162
+ return "UNAUTHORIZED";
1163
+ case 403:
1164
+ return "FORBIDDEN";
1165
+ case 404:
1166
+ return context === "attempt" ? "ATTEMPT_NOT_FOUND" : "QUIZ_NOT_FOUND";
1167
+ case 410:
1168
+ return "QUIZ_EXPIRED";
1169
+ case 500:
1170
+ case 502:
1171
+ case 503:
1172
+ case 504:
1173
+ return "SERVER_ERROR";
1174
+ default:
1175
+ if (status >= 400 && status < 500) {
1176
+ return context === "attempt" ? "ATTEMPT_NOT_FOUND" : "QUIZ_NOT_FOUND";
1177
+ }
1178
+ return "UNKNOWN_ERROR";
1179
+ }
1180
+ }
1181
+ function getErrorFromMessage(message, context) {
1182
+ const lowerMessage = message.toLowerCase();
1183
+ if (lowerMessage.includes("network") || lowerMessage.includes("fetch") || lowerMessage.includes("connection")) {
1184
+ return "NETWORK_ERROR";
1185
+ }
1186
+ if (lowerMessage.includes("not found") || lowerMessage.includes("404")) {
1187
+ return context === "attempt" ? "ATTEMPT_NOT_FOUND" : "QUIZ_NOT_FOUND";
1188
+ }
1189
+ if (lowerMessage.includes("unauthorized") || lowerMessage.includes("401")) {
1190
+ return "UNAUTHORIZED";
1191
+ }
1192
+ if (lowerMessage.includes("forbidden") || lowerMessage.includes("403")) {
1193
+ return "FORBIDDEN";
1194
+ }
1195
+ if (lowerMessage.includes("expired")) {
1196
+ return "QUIZ_EXPIRED";
1197
+ }
1198
+ if (lowerMessage.includes("tts") || lowerMessage.includes("speech")) {
1199
+ return "TTS_FAILED";
1200
+ }
1201
+ if (lowerMessage.includes("chat")) {
1202
+ return "CHAT_FAILED";
1203
+ }
1204
+ return "UNKNOWN_ERROR";
1205
+ }
1206
+
1207
+ // src/MaintenanceScreen.tsx
1060
1208
  var import_jsx_runtime3 = require("react/jsx-runtime");
1209
+ function MaintenanceScreen({ errorCode }) {
1210
+ const errorDef = errorCode ? ERROR_DEFINITIONS[errorCode] : null;
1211
+ const message = errorDef?.userMessage || "Your quiz is on its way...";
1212
+ const subMessage = errorDef?.subMessage || "Please check back soon!";
1213
+ const containerStyle = {
1214
+ display: "flex",
1215
+ flexDirection: "column",
1216
+ alignItems: "center",
1217
+ justifyContent: "center",
1218
+ minHeight: "300px",
1219
+ padding: "40px",
1220
+ background: "linear-gradient(135deg, #f8f7ff 0%, #e8e4f8 50%, #f0ebff 100%)",
1221
+ borderRadius: "16px"
1222
+ };
1223
+ const iconStyle = {
1224
+ fontSize: "48px",
1225
+ marginBottom: "24px",
1226
+ color: "#8b5cf6"
1227
+ };
1228
+ const messageStyle = {
1229
+ fontSize: "20px",
1230
+ fontWeight: "600",
1231
+ color: "#4c1d95",
1232
+ textAlign: "center",
1233
+ marginBottom: "12px"
1234
+ };
1235
+ const submessageStyle = {
1236
+ fontSize: "14px",
1237
+ color: "#7c3aed",
1238
+ textAlign: "center",
1239
+ opacity: 0.8
1240
+ };
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: containerStyle, "data-testid": "maintenance-screen", "data-error-code": errorCode || "none", children: [
1242
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: iconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1244
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 8v4" }),
1245
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 16h.01" })
1246
+ ] }) }),
1247
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: messageStyle, "data-testid": "text-error-message", children: message }),
1248
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: submessageStyle, "data-testid": "text-error-submessage", children: subMessage })
1249
+ ] });
1250
+ }
1251
+
1252
+ // src/assets/astronautData.ts
1253
+ var astronautImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAQ4CAMAAADfDTFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFYGBgsVEZcHBwq6urhYSEkZGRiomJuJsBMxoHJCAhUFBQQEBAXZu4ATtbnp6ev7+/dDURJnqMdnR1enl5ABoqAm2rVSYMamhpLCkqKCUlz8/PMS0uWksA39/fbmxtAViJEBAQAAAAzunzMDAwPDo6qKioj46OgICAoqKiOC8AOTU2oKCgaq3LNDExibbNQD4+mpqaV1RVRUJCZmRlpqampKSkSEVGlpaWUE5OTElKnJycIm5+mJiYXlxdf35+lJSUXFlaU1FSZGFiWFZWAV+UBGaebtLoWlhZqMjWTMjiS0hJc3FyAUlyidvtbGpraGZmb25ujYyMYF5ed3Z2F0lUFw4CAVB+////AUJnLCgpecXVKXyqfHp75eXlT0xN1dXVNzQ1hai8ksXZPzw9qNLlTn6UsOfywMDAICAgASxFwNzsEz1GgH5/R0RFJ1ZwOjc4JiIjNjM0KicoRmt4tra2HhscMi8vXVtbACU5CwsLLisreJ+xKUhWBHS0gYCBOzg5fnx9YmBghIOD/NQBITlHgH9/PMPgWVdYJyQlMCwtESYyIx8gTUtLgoGBPV5qSUdH8m4jg4KCVVNTAA8XfHt7DwcCAAcLAHW4FRQV7+/vr6+vBAwOOLfSDzE4LZKoHmJwRkNEQj9APjs8CyUqCBgcMZ62i4qLj4+P42chfXx8aWdoDw4OUk9QZWNjNavExVkcAGahGlViKYaal0UWjo2NbWtsiYiI1GAfh4aH7McBfmoBl5eXlZWVk5KSn5+fdHNzpaWlnZ2dfn19cW9viD4UkI+Qjo2OeHd33boBnoUBATNQzawBjncBbl0AnuHw7/b63+/3EBcbFH256urqEkpq+vr6mZmZElJ1GhgYU1xeo6OjGG6fm5ubEh4jRVdejIuM9fX1lpWWnp2elJOTICcrnJuboaGhornEE3WtQU5Wv9HaJzg8h5icQZSmz9jeeo+XY2xucHd7EjtTkJ2iBwYGfYqNGV+HMTtAQoWr8/v9v8bIw8vNIi0yZHyHFygs////mvWEFwAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAMcVSURBVHja7L3viyRnuf9f9CRCuhgLtAeTlj5TRcdTwSUkRo+bBDXG2SDoMIkubI/g8Sz4wBow5AdnzczAJsfAYGRXgo7MTPWjGA5pNAr7QEXQVNSQE9hnIsoiHvacj99z/oJ9dJ747brv+v2ju7q7qqa79/V6oMlmd3709vSrr+u+rvet/B0AAABqR+EhAAAAQMAAAAAIGAAAABAwAAAAAgYAAAAEDAAAgIABAAAAAQMAACBgAAAAQMAAAAAIGAAAAAEDAAAAAgaA6dE0zTkQKOqQhvzn4a92eGwAEDAAlE1bOzhQVd0YSVdVDhxMDICAAaCMktc5UC1jItTmQR8NAyBgAJjWvQOla0yLrjawMAACBoDJsPsNNb/CFTTNIfIfcytkqzlo82ACIGAAKFb5NjIKX0tVzIGmdXo5aFrf9XFGKdwcUAkDIGAAGE3HaaYKXsXU2r3CaI6ZKomtRp+HFgABA0CefQeJ0lc1+xOoN6bh5Pmxrjg2jzAAAgaAMfa1lMGU7g2wNTPekm46PMwACBgAIthON3Zs63R6JaGZsY+saDzYAAgYACR9JRqnYbZ75WL3lUiEh3XATBYAAgaAv9sHVrRJ3OlVQrsR/SyMZAEgYIDbHE2J2tfuVUjUwdYBE1kACBjg9sUJh6S6g06vcrSwF60rdKIBEDDAbYntWKEN272aiDi/yUAWAAIGuP30exAUo12nVyedRvCZVRQMgIABblf91lf8RsrgLgoGQMAAtyGBfnXT7p0KWhMFAyBggNuM4OzXck5Jv6ITHcxfNxnHAkDAAMuPFuq3d7qEClZYSgJAwADLTUedF/3GFKwf8FcDgIABlhf7YJ70G1OwxVEwAAIGWFb61imPXmUqWOUoGAABAywzgekac6RfMRHtLSXpA/6S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";
1254
+
1255
+ // src/QuizPlayer.tsx
1256
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1061
1257
  var defaultStyles = {
1062
1258
  container: {
1063
1259
  fontFamily: "system-ui, -apple-system, sans-serif",
@@ -1126,7 +1322,9 @@ var defaultStyles = {
1126
1322
  option: {
1127
1323
  width: "100%",
1128
1324
  padding: "12px 16px",
1129
- border: "2px solid #e5e7eb",
1325
+ borderWidth: "2px",
1326
+ borderStyle: "solid",
1327
+ borderColor: "#e5e7eb",
1130
1328
  borderRadius: "8px",
1131
1329
  cursor: "pointer",
1132
1330
  transition: "all 0.2s ease",
@@ -1420,7 +1618,7 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
1420
1618
  setDraggedIndex(null);
1421
1619
  setDragOverIndex(null);
1422
1620
  };
1423
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.options, children: currentOrder.map((itemIndex, position) => {
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentOrder.map((itemIndex, position) => {
1424
1622
  const isCorrectPosition = correctOrder?.[position] === itemIndex;
1425
1623
  const isDragging = draggedIndex === position;
1426
1624
  const isDragOver = dragOverIndex === position;
@@ -1443,7 +1641,7 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
1443
1641
  } else if (isDragOver) {
1444
1642
  itemStyle = { ...itemStyle, borderColor: "#6366f1", backgroundColor: "#eef2ff" };
1445
1643
  }
1446
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1644
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1447
1645
  "div",
1448
1646
  {
1449
1647
  style: itemStyle,
@@ -1455,34 +1653,34 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
1455
1653
  onDrop: (e) => handleDrop(e, position),
1456
1654
  onDragEnd: handleDragEnd,
1457
1655
  children: [
1458
- !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
1656
+ !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1459
1657
  cursor: "grab",
1460
1658
  padding: "4px",
1461
1659
  display: "flex",
1462
1660
  alignItems: "center",
1463
1661
  color: "#9ca3af"
1464
- }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1465
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
1466
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
1467
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
1468
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
1469
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
1470
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "19", r: "1" })
1662
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1663
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
1665
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
1667
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "19", r: "1" })
1471
1669
  ] }) }),
1472
- showFeedback && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
1670
+ showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1473
1671
  display: "flex",
1474
1672
  alignItems: "center",
1475
1673
  color: isCorrectPosition ? "#22c55e" : "#ef4444"
1476
- }, children: isCorrectPosition ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1477
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
1478
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
1479
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1480
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1481
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1482
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1674
+ }, children: isCorrectPosition ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1675
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
1677
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1678
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1679
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1680
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1483
1681
  ] }) }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: items[itemIndex] }),
1485
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TextToSpeech, { text: items[itemIndex], size: "sm" }) })
1682
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: items[itemIndex] }),
1683
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: items[itemIndex], size: "sm" }) })
1486
1684
  ]
1487
1685
  },
1488
1686
  itemIndex
@@ -1536,9 +1734,9 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1536
1734
  delete newMatches[leftItem];
1537
1735
  onMatchChange(newMatches);
1538
1736
  };
1539
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "24px", flexWrap: "wrap" }, children: [
1540
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
1541
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Match these items:" }),
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "24px", flexWrap: "wrap" }, children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
1739
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Match these items:" }),
1542
1740
  leftItems.map((leftItem, idx) => {
1543
1741
  const matchedRight = currentMatches[leftItem];
1544
1742
  const correctMatch = correctMatches?.[leftItem];
@@ -1549,7 +1747,9 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1549
1747
  alignItems: "center",
1550
1748
  gap: "12px",
1551
1749
  padding: "12px 16px",
1552
- border: "2px dashed #e5e7eb",
1750
+ borderWidth: "2px",
1751
+ borderStyle: "dashed",
1752
+ borderColor: "#e5e7eb",
1553
1753
  borderRadius: "8px",
1554
1754
  backgroundColor: "#ffffff",
1555
1755
  minHeight: "56px",
@@ -1567,7 +1767,7 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1567
1767
  } else if (matchedRight) {
1568
1768
  rowStyle = { ...rowStyle, borderStyle: "solid", borderColor: "#22c55e" };
1569
1769
  }
1570
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1770
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1571
1771
  "div",
1572
1772
  {
1573
1773
  style: rowStyle,
@@ -1576,9 +1776,9 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1576
1776
  onDragLeave: handleDragLeave,
1577
1777
  onDrop: (e) => handleDrop(e, leftItem),
1578
1778
  children: [
1579
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1, fontWeight: "500" }, children: leftItem }),
1580
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#6b7280" }, children: "\u2192" }),
1581
- matchedRight ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
1779
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1, fontWeight: "500" }, children: leftItem }),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#6b7280" }, children: "\u2192" }),
1781
+ matchedRight ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
1582
1782
  display: "flex",
1583
1783
  alignItems: "center",
1584
1784
  gap: "8px",
@@ -1587,8 +1787,8 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1587
1787
  borderRadius: "6px",
1588
1788
  fontSize: "14px"
1589
1789
  }, children: [
1590
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: matchedRight }),
1591
- !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1790
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: matchedRight }),
1791
+ !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1592
1792
  "button",
1593
1793
  {
1594
1794
  onClick: () => handleClearMatch(leftItem),
@@ -1601,18 +1801,18 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1601
1801
  color: "#6b7280"
1602
1802
  },
1603
1803
  "aria-label": "Remove match",
1604
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1605
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1606
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1804
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1805
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1806
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1607
1807
  ] })
1608
1808
  }
1609
1809
  ),
1610
- showFeedback && (isCorrect ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#22c55e", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1611
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1612
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1810
+ showFeedback && (isCorrect ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#22c55e", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1811
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1812
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1613
1813
  ] }))
1614
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#9ca3af", fontSize: "14px", fontStyle: "italic" }, children: "Drop here" }),
1615
- showFeedback && !isCorrect && correctMatch && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { color: "#166534", fontSize: "13px", marginLeft: "8px" }, children: [
1814
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#9ca3af", fontSize: "14px", fontStyle: "italic" }, children: "Drop here" }),
1815
+ showFeedback && !isCorrect && correctMatch && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: "#166534", fontSize: "13px", marginLeft: "8px" }, children: [
1616
1816
  "(Correct: ",
1617
1817
  correctMatch,
1618
1818
  ")"
@@ -1623,16 +1823,18 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1623
1823
  );
1624
1824
  })
1625
1825
  ] }),
1626
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
1627
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Drag to match:" }),
1826
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
1827
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Drag to match:" }),
1628
1828
  unmatchedRightItems.length > 0 ? unmatchedRightItems.map((rightItem, idx) => {
1629
1829
  const isDragging = draggedItem === rightItem;
1630
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1830
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1631
1831
  "div",
1632
1832
  {
1633
1833
  style: {
1634
1834
  padding: "12px 16px",
1635
- border: "2px solid #e5e7eb",
1835
+ borderWidth: "2px",
1836
+ borderStyle: "solid",
1837
+ borderColor: "#e5e7eb",
1636
1838
  borderRadius: "8px",
1637
1839
  backgroundColor: "#ffffff",
1638
1840
  cursor: showFeedback ? "default" : "grab",
@@ -1647,20 +1849,20 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1647
1849
  onDragEnd: handleDragEnd,
1648
1850
  "data-testid": `draggable-right-${idx}`,
1649
1851
  children: [
1650
- !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { color: "#9ca3af", display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1651
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
1652
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
1653
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
1655
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "15", cy: "19", r: "1" })
1852
+ !showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#9ca3af", display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1853
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
1854
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
1855
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
1856
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "19", r: "1" })
1657
1859
  ] }) }),
1658
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: rightItem })
1860
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: rightItem })
1659
1861
  ]
1660
1862
  },
1661
1863
  idx
1662
1864
  );
1663
- }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
1865
+ }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
1664
1866
  padding: "16px",
1665
1867
  textAlign: "center",
1666
1868
  color: "#22c55e",
@@ -1670,7 +1872,7 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
1670
1872
  ] });
1671
1873
  }
1672
1874
  function Spinner({ size = 16, color = "#ffffff" }) {
1673
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1875
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1674
1876
  "span",
1675
1877
  {
1676
1878
  style: {
@@ -1682,7 +1884,7 @@ function Spinner({ size = 16, color = "#ffffff" }) {
1682
1884
  borderRadius: "50%",
1683
1885
  animation: "spin 0.8s linear infinite"
1684
1886
  },
1685
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1887
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1686
1888
  }
1687
1889
  );
1688
1890
  }
@@ -1700,7 +1902,8 @@ function QuizPlayer({
1700
1902
  onProgress,
1701
1903
  onGenerateMoreQuestions,
1702
1904
  className,
1703
- forceNewAttempt = true
1905
+ forceNewAttempt = true,
1906
+ hideScore = false
1704
1907
  }) {
1705
1908
  const [quiz, setQuiz] = (0, import_react3.useState)(null);
1706
1909
  const [attempt, setAttempt] = (0, import_react3.useState)(null);
@@ -1711,10 +1914,14 @@ function QuizPlayer({
1711
1914
  const [isNavigating, setIsNavigating] = (0, import_react3.useState)(false);
1712
1915
  const [isCompleted, setIsCompleted] = (0, import_react3.useState)(false);
1713
1916
  const [result, setResult] = (0, import_react3.useState)(null);
1714
- const [error, setError] = (0, import_react3.useState)(null);
1917
+ const [errorCode, setErrorCode] = (0, import_react3.useState)(null);
1715
1918
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
1716
1919
  const [elapsedSeconds, setElapsedSeconds] = (0, import_react3.useState)(0);
1717
1920
  const [showIntro, setShowIntro] = (0, import_react3.useState)(true);
1921
+ const [showResumeChoice, setShowResumeChoice] = (0, import_react3.useState)(false);
1922
+ const [hasExistingProgress, setHasExistingProgress] = (0, import_react3.useState)(false);
1923
+ const [existingProgressCount, setExistingProgressCount] = (0, import_react3.useState)(0);
1924
+ const [isStartingFresh, setIsStartingFresh] = (0, import_react3.useState)(false);
1718
1925
  const [timerStarted, setTimerStarted] = (0, import_react3.useState)(false);
1719
1926
  const [showFeedback, setShowFeedback] = (0, import_react3.useState)(false);
1720
1927
  const [currentAnswerDetail, setCurrentAnswerDetail] = (0, import_react3.useState)(null);
@@ -1728,6 +1935,7 @@ function QuizPlayer({
1728
1935
  const [showReportModal, setShowReportModal] = (0, import_react3.useState)(false);
1729
1936
  const [isReporting, setIsReporting] = (0, import_react3.useState)(false);
1730
1937
  const [reportComment, setReportComment] = (0, import_react3.useState)("");
1938
+ const [retryKey, setRetryKey] = (0, import_react3.useState)(0);
1731
1939
  const apiClient = (0, import_react3.useRef)(null);
1732
1940
  const timerRef = (0, import_react3.useRef)(null);
1733
1941
  const startTimeRef = (0, import_react3.useRef)(0);
@@ -1749,7 +1957,7 @@ function QuizPlayer({
1749
1957
  if (!apiClient.current) return;
1750
1958
  try {
1751
1959
  setIsLoading(true);
1752
- setError(null);
1960
+ setErrorCode(null);
1753
1961
  const quizData = await apiClient.current.getQuiz(quizId);
1754
1962
  setQuiz(quizData);
1755
1963
  const attemptData = await apiClient.current.createAttempt({
@@ -1762,7 +1970,10 @@ function QuizPlayer({
1762
1970
  forceNew: forceNewAttempt
1763
1971
  });
1764
1972
  setAttempt(attemptData);
1765
- if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0) {
1973
+ if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0 && attemptData.status === "in_progress") {
1974
+ setHasExistingProgress(true);
1975
+ setExistingProgressCount(attemptData.answers.length);
1976
+ setShowResumeChoice(true);
1766
1977
  setAnswersDetail(attemptData.answers);
1767
1978
  const answersMap = /* @__PURE__ */ new Map();
1768
1979
  attemptData.answers.forEach((a) => {
@@ -1785,15 +1996,23 @@ function QuizPlayer({
1785
1996
  setIsLoading(false);
1786
1997
  } catch (err) {
1787
1998
  const message = err instanceof Error ? err.message : "Failed to load quiz";
1788
- setError(message);
1999
+ const code = getErrorFromMessage(message, "quiz");
2000
+ setErrorCode(code);
2001
+ apiClient.current?.logError({
2002
+ errorCode: code,
2003
+ context: "quiz",
2004
+ resourceId: quizId,
2005
+ component: "QuizPlayer",
2006
+ message
2007
+ });
1789
2008
  setIsLoading(false);
1790
2009
  onErrorRef.current?.(err instanceof Error ? err : new Error(message));
1791
2010
  }
1792
2011
  }
1793
2012
  initialize();
1794
- }, [quizId, lessonId, assignLessonId, courseId, childId, parentId, forceNewAttempt]);
2013
+ }, [quizId, lessonId, assignLessonId, courseId, childId, parentId, forceNewAttempt, retryKey]);
1795
2014
  (0, import_react3.useEffect)(() => {
1796
- if (timerStarted && !isCompleted && !error) {
2015
+ if (timerStarted && !isCompleted && !errorCode) {
1797
2016
  startTimeRef.current = Date.now();
1798
2017
  timerRef.current = setInterval(() => {
1799
2018
  setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
@@ -1804,11 +2023,62 @@ function QuizPlayer({
1804
2023
  clearInterval(timerRef.current);
1805
2024
  }
1806
2025
  };
1807
- }, [timerStarted, isCompleted, error]);
2026
+ }, [timerStarted, isCompleted, errorCode]);
1808
2027
  const handleStart = (0, import_react3.useCallback)(() => {
1809
2028
  setShowIntro(false);
2029
+ setShowResumeChoice(false);
1810
2030
  setTimerStarted(true);
1811
2031
  }, []);
2032
+ const handleResumePrevious = (0, import_react3.useCallback)(() => {
2033
+ if (quiz && answers.size > 0) {
2034
+ const answeredIds = new Set(answers.keys());
2035
+ const allQs = [...quiz.questions, ...extraQuestions].filter((q) => !skippedQuestionIds.has(q.id));
2036
+ let resumeIndex = 0;
2037
+ for (let i = 0; i < allQs.length; i++) {
2038
+ if (!answeredIds.has(allQs[i].id)) {
2039
+ resumeIndex = i;
2040
+ break;
2041
+ }
2042
+ resumeIndex = allQs.length - 1;
2043
+ }
2044
+ setCurrentQuestionIndex(resumeIndex);
2045
+ }
2046
+ setShowIntro(false);
2047
+ setShowResumeChoice(false);
2048
+ setTimerStarted(true);
2049
+ }, [quiz, answers, extraQuestions, skippedQuestionIds]);
2050
+ const handleStartFresh = (0, import_react3.useCallback)(async () => {
2051
+ if (!apiClient.current || !attempt) return;
2052
+ setIsStartingFresh(true);
2053
+ try {
2054
+ await apiClient.current.updateAttempt(attempt.id, {
2055
+ status: "abandoned"
2056
+ });
2057
+ const newAttemptData = await apiClient.current.createAttempt({
2058
+ quizId,
2059
+ lessonId,
2060
+ assignLessonId,
2061
+ courseId,
2062
+ childId,
2063
+ parentId,
2064
+ forceNew: true
2065
+ });
2066
+ setAttempt(newAttemptData);
2067
+ setAnswers(/* @__PURE__ */ new Map());
2068
+ setAnswersDetail([]);
2069
+ setCurrentQuestionIndex(0);
2070
+ setHasExistingProgress(false);
2071
+ setExistingProgressCount(0);
2072
+ setShowResumeChoice(false);
2073
+ setShowIntro(false);
2074
+ setTimerStarted(true);
2075
+ } catch (err) {
2076
+ const message = err instanceof Error ? err.message : "Failed to start fresh";
2077
+ onErrorRef.current?.(new Error(message));
2078
+ } finally {
2079
+ setIsStartingFresh(false);
2080
+ }
2081
+ }, [attempt, quizId, lessonId, assignLessonId, courseId, childId, parentId]);
1812
2082
  (0, import_react3.useEffect)(() => {
1813
2083
  setShowFeedback(false);
1814
2084
  setCurrentAnswerDetail(null);
@@ -1928,7 +2198,15 @@ function QuizPlayer({
1928
2198
  onCompleteRef.current?.(quizResult);
1929
2199
  } catch (err) {
1930
2200
  const message = err instanceof Error ? err.message : "Failed to submit quiz";
1931
- setError(message);
2201
+ const code = getErrorFromMessage(message, "quiz");
2202
+ setErrorCode(code);
2203
+ apiClient.current?.logError({
2204
+ errorCode: code,
2205
+ context: "quiz",
2206
+ resourceId: quizId,
2207
+ component: "QuizPlayer",
2208
+ message
2209
+ });
1932
2210
  onErrorRef.current?.(err instanceof Error ? err : new Error(message));
1933
2211
  } finally {
1934
2212
  setIsSubmitting(false);
@@ -2006,14 +2284,43 @@ function QuizPlayer({
2006
2284
  setIsReporting(false);
2007
2285
  }
2008
2286
  }, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId]);
2287
+ const handleRetryQuiz = (0, import_react3.useCallback)(() => {
2288
+ setCurrentQuestionIndex(0);
2289
+ setAnswers(/* @__PURE__ */ new Map());
2290
+ setAnswersDetail([]);
2291
+ setIsCompleted(false);
2292
+ setResult(null);
2293
+ setErrorCode(null);
2294
+ setShowIntro(true);
2295
+ setShowFeedback(false);
2296
+ setCurrentAnswerDetail(null);
2297
+ setTimerStarted(false);
2298
+ setElapsedSeconds(0);
2299
+ startTimeRef.current = 0;
2300
+ setExtraQuestions([]);
2301
+ setSkippedQuestionIds(/* @__PURE__ */ new Set());
2302
+ setAttempt(null);
2303
+ setShowResumeChoice(false);
2304
+ setHasExistingProgress(false);
2305
+ setExistingProgressCount(0);
2306
+ setIsSubmitting(false);
2307
+ setIsNavigating(false);
2308
+ setIsGeneratingExtra(false);
2309
+ setIsStartingFresh(false);
2310
+ setShowSkipModal(false);
2311
+ setIsSkipping(false);
2312
+ setSkipComment("");
2313
+ setSelectedSkipReason(null);
2314
+ setShowReportModal(false);
2315
+ setIsReporting(false);
2316
+ setReportComment("");
2317
+ setRetryKey((prev) => prev + 1);
2318
+ }, []);
2009
2319
  if (isLoading) {
2010
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.loading, children: "Loading quiz..." }) });
2320
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.loading, children: "Loading quiz..." }) });
2011
2321
  }
2012
- if (error) {
2013
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.error, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
2014
- "Error: ",
2015
- error
2016
- ] }) }) });
2322
+ if (errorCode) {
2323
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MaintenanceScreen, { errorCode }) });
2017
2324
  }
2018
2325
  if (isCompleted && result) {
2019
2326
  const percentage = result.totalQuestions > 0 ? Math.round(result.correctAnswers / result.totalQuestions * 100) : 0;
@@ -2071,7 +2378,7 @@ function QuizPlayer({
2071
2378
  rotation: Math.random() * 360,
2072
2379
  size: 6 + Math.random() * 8
2073
2380
  }));
2074
- const StarIcon = ({ filled, delay }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2381
+ const StarIcon = ({ filled, delay }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2075
2382
  "svg",
2076
2383
  {
2077
2384
  width: "36",
@@ -2082,7 +2389,7 @@ function QuizPlayer({
2082
2389
  animationDelay: `${delay}s`,
2083
2390
  opacity: 0
2084
2391
  },
2085
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2392
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2086
2393
  "path",
2087
2394
  {
2088
2395
  d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z",
@@ -2093,62 +2400,23 @@ function QuizPlayer({
2093
2400
  )
2094
2401
  }
2095
2402
  );
2096
- const MascotOwl = ({ mood }) => {
2097
- const getEyeExpression = () => {
2098
- switch (mood) {
2099
- case "celebrating":
2100
- return { leftEye: ">", rightEye: "<", pupilY: 42 };
2101
- // Squinting happy
2102
- case "happy":
2103
- return { leftEye: null, rightEye: null, pupilY: 42 };
2104
- // Normal happy
2105
- case "encouraging":
2106
- return { leftEye: null, rightEye: null, pupilY: 44 };
2107
- // Looking down warmly
2108
- default:
2109
- return { leftEye: null, rightEye: null, pupilY: 42 };
2110
- }
2111
- };
2112
- const eyeExpr = getEyeExpression();
2113
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2114
- "svg",
2403
+ const Mascot = ({ mood }) => {
2404
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2405
+ "img",
2115
2406
  {
2116
- width: "120",
2117
- height: "120",
2118
- viewBox: "0 0 100 100",
2407
+ src: astronautImage,
2408
+ alt: "Astronaut mascot",
2409
+ width: "180",
2410
+ height: "180",
2119
2411
  style: {
2120
- animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite"
2121
- },
2122
- children: [
2123
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "50", cy: "60", rx: "35", ry: "30", fill: "#8b5cf6" }),
2124
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "50", cy: "65", rx: "25", ry: "20", fill: "#c4b5fd" }),
2125
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "50", cy: "35", r: "28", fill: "#a78bfa" }),
2126
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polygon", { points: "28,15 35,30 22,28", fill: "#7c3aed" }),
2127
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polygon", { points: "72,15 65,30 78,28", fill: "#7c3aed" }),
2128
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "38", cy: "38", rx: "10", ry: "12", fill: "white" }),
2129
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "62", cy: "38", rx: "10", ry: "12", fill: "white" }),
2130
- eyeExpr.leftEye ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { x: "38", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.leftEye }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "38", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
2131
- eyeExpr.rightEye ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { x: "62", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.rightEye }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "62", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
2132
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polygon", { points: "50,45 45,52 55,52", fill: "#fbbf24" }),
2133
- (mood === "celebrating" || mood === "happy") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2134
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "28", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" }),
2135
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "72", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" })
2136
- ] }),
2137
- mood === "celebrating" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2138
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "18", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(-30 18 55)" }),
2139
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "82", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(30 82 55)" })
2140
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2141
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "20", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" }),
2142
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "80", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" })
2143
- ] }),
2144
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "40", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" }),
2145
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ellipse", { cx: "60", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" })
2146
- ]
2412
+ animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite",
2413
+ objectFit: "contain"
2414
+ }
2147
2415
  }
2148
2416
  );
2149
2417
  };
2150
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, style: defaultStyles.container, children: [
2151
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
2418
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: defaultStyles.container, children: [
2419
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
2152
2420
  @keyframes confettiFall {
2153
2421
  0% {
2154
2422
  transform: translateY(-10px) rotate(0deg);
@@ -2211,9 +2479,19 @@ function QuizPlayer({
2211
2479
  opacity: 1;
2212
2480
  }
2213
2481
  }
2482
+ @keyframes buttonFadeIn {
2483
+ 0% {
2484
+ opacity: 0;
2485
+ transform: translateY(10px);
2486
+ }
2487
+ 100% {
2488
+ opacity: 1;
2489
+ transform: translateY(0);
2490
+ }
2491
+ }
2214
2492
  ` }),
2215
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.results, children: [
2216
- percentage >= 60 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.confettiContainer, children: confettiPieces.map((piece) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2493
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.results, children: [
2494
+ percentage >= 60 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.confettiContainer, children: confettiPieces.map((piece) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2217
2495
  "div",
2218
2496
  {
2219
2497
  style: {
@@ -2230,15 +2508,70 @@ function QuizPlayer({
2230
2508
  },
2231
2509
  piece.id
2232
2510
  )) }),
2233
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { ...defaultStyles.resultsBackground, background: theme.bgGradient } }),
2234
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.resultsContent, children: [
2235
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.resultStars, children: [
2236
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StarIcon, { filled: theme.stars >= 1, delay: 0.3 }),
2237
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StarIcon, { filled: theme.stars >= 2, delay: 0.5 }),
2238
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StarIcon, { filled: theme.stars >= 3, delay: 0.7 })
2511
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.resultsBackground, background: theme.bgGradient } }),
2512
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.resultsContent, children: hideScore ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2513
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginBottom: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Mascot, { mood: "happy" }) }),
2514
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2515
+ "div",
2516
+ {
2517
+ style: {
2518
+ background: "linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%)",
2519
+ padding: "12px 28px",
2520
+ borderRadius: "50px",
2521
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
2522
+ marginBottom: "20px",
2523
+ animation: "badgePop 0.6s ease-out 0.2s forwards",
2524
+ opacity: 0,
2525
+ border: "3px solid #22c55e"
2526
+ },
2527
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2528
+ "span",
2529
+ {
2530
+ style: {
2531
+ fontSize: "22px",
2532
+ fontWeight: "700",
2533
+ color: "#1f2937",
2534
+ textShadow: "0 1px 2px rgba(255,255,255,0.5)"
2535
+ },
2536
+ children: "All Done!"
2537
+ }
2538
+ )
2539
+ }
2540
+ ),
2541
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2542
+ "div",
2543
+ {
2544
+ style: {
2545
+ animation: "scoreSlideIn 0.5s ease-out 0.4s forwards",
2546
+ opacity: 0
2547
+ },
2548
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2549
+ "div",
2550
+ {
2551
+ style: {
2552
+ fontSize: "24px",
2553
+ fontWeight: "600",
2554
+ color: "#22c55e",
2555
+ lineHeight: "1.4",
2556
+ marginBottom: "12px"
2557
+ },
2558
+ children: "The quiz was submitted successfully!"
2559
+ }
2560
+ )
2561
+ }
2562
+ ),
2563
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
2564
+ "Time: ",
2565
+ formatTime(result.timeSpentSeconds)
2566
+ ] })
2567
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2568
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.resultStars, children: [
2569
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 1, delay: 0.3 }),
2570
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 2, delay: 0.5 }),
2571
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 3, delay: 0.7 })
2239
2572
  ] }),
2240
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MascotOwl, { mood: theme.mascotMood }) }),
2241
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2573
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Mascot, { mood: theme.mascotMood }) }),
2574
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2242
2575
  "div",
2243
2576
  {
2244
2577
  style: {
@@ -2251,7 +2584,7 @@ function QuizPlayer({
2251
2584
  opacity: 0,
2252
2585
  border: `3px solid ${theme.badgeColor}`
2253
2586
  },
2254
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2587
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2255
2588
  "span",
2256
2589
  {
2257
2590
  style: {
@@ -2265,7 +2598,7 @@ function QuizPlayer({
2265
2598
  )
2266
2599
  }
2267
2600
  ),
2268
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2601
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2269
2602
  "div",
2270
2603
  {
2271
2604
  style: {
@@ -2273,7 +2606,7 @@ function QuizPlayer({
2273
2606
  opacity: 0
2274
2607
  },
2275
2608
  children: [
2276
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2609
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2277
2610
  "div",
2278
2611
  {
2279
2612
  style: {
@@ -2290,7 +2623,7 @@ function QuizPlayer({
2290
2623
  ]
2291
2624
  }
2292
2625
  ),
2293
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2626
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2294
2627
  "div",
2295
2628
  {
2296
2629
  style: {
@@ -2305,25 +2638,116 @@ function QuizPlayer({
2305
2638
  ]
2306
2639
  }
2307
2640
  ),
2308
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
2641
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
2309
2642
  "Time: ",
2310
2643
  formatTime(result.timeSpentSeconds)
2311
- ] })
2312
- ] })
2644
+ ] }),
2645
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2646
+ "button",
2647
+ {
2648
+ style: {
2649
+ marginTop: "24px",
2650
+ padding: "14px 32px",
2651
+ fontSize: "16px",
2652
+ fontWeight: "600",
2653
+ color: "#7c3aed",
2654
+ background: "white",
2655
+ border: "2px solid #7c3aed",
2656
+ borderRadius: "12px",
2657
+ cursor: "pointer",
2658
+ transition: "all 0.2s ease",
2659
+ animation: "buttonFadeIn 0.5s ease-out 0.8s forwards",
2660
+ opacity: 0
2661
+ },
2662
+ onClick: handleRetryQuiz,
2663
+ onMouseOver: (e) => {
2664
+ e.currentTarget.style.background = "#7c3aed";
2665
+ e.currentTarget.style.color = "white";
2666
+ e.currentTarget.style.transform = "translateY(-2px)";
2667
+ },
2668
+ onMouseOut: (e) => {
2669
+ e.currentTarget.style.background = "white";
2670
+ e.currentTarget.style.color = "#7c3aed";
2671
+ e.currentTarget.style.transform = "translateY(0)";
2672
+ },
2673
+ "data-testid": "button-retry-quiz",
2674
+ children: "Try Again"
2675
+ }
2676
+ )
2677
+ ] }) })
2313
2678
  ] })
2314
2679
  ] });
2315
2680
  }
2681
+ if (quiz && showIntro && showResumeChoice && hasExistingProgress) {
2682
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.intro, children: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introTitle, children: "Welcome Back!" }),
2684
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introSubtitle, children: "You have an unfinished quiz. Would you like to continue or start over?" }),
2685
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
2686
+ existingProgressCount,
2687
+ " of ",
2688
+ quiz.questions.length,
2689
+ " question",
2690
+ quiz.questions.length !== 1 ? "s" : "",
2691
+ " answered"
2692
+ ] }),
2693
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginTop: "8px" }, children: [
2694
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2695
+ "button",
2696
+ {
2697
+ style: defaultStyles.startButton,
2698
+ onClick: handleResumePrevious,
2699
+ onMouseOver: (e) => {
2700
+ e.currentTarget.style.transform = "translateY(-2px)";
2701
+ e.currentTarget.style.boxShadow = "0 6px 20px rgba(124, 58, 237, 0.5)";
2702
+ },
2703
+ onMouseOut: (e) => {
2704
+ e.currentTarget.style.transform = "translateY(0)";
2705
+ e.currentTarget.style.boxShadow = "0 4px 14px rgba(124, 58, 237, 0.4)";
2706
+ },
2707
+ "data-testid": "button-continue-quiz",
2708
+ children: "Continue Where I Left Off"
2709
+ }
2710
+ ),
2711
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2712
+ "button",
2713
+ {
2714
+ style: {
2715
+ ...defaultStyles.startButton,
2716
+ background: "transparent",
2717
+ color: "#7c3aed",
2718
+ border: "2px solid #7c3aed",
2719
+ boxShadow: "none"
2720
+ },
2721
+ onClick: handleStartFresh,
2722
+ disabled: isStartingFresh,
2723
+ onMouseOver: (e) => {
2724
+ if (!isStartingFresh) {
2725
+ e.currentTarget.style.transform = "translateY(-2px)";
2726
+ e.currentTarget.style.background = "rgba(124, 58, 237, 0.1)";
2727
+ }
2728
+ },
2729
+ onMouseOut: (e) => {
2730
+ e.currentTarget.style.transform = "translateY(0)";
2731
+ e.currentTarget.style.background = "transparent";
2732
+ },
2733
+ "data-testid": "button-start-fresh",
2734
+ children: isStartingFresh ? "Starting..." : "Start Fresh"
2735
+ }
2736
+ )
2737
+ ] })
2738
+ ] }) });
2739
+ }
2316
2740
  if (quiz && showIntro) {
2317
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.intro, children: [
2318
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.introTitle, children: quiz.title }),
2319
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.introSubtitle, children: "Ready to test your knowledge?" }),
2320
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
2741
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.intro, children: [
2742
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introTitle, children: quiz.title }),
2743
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introSubtitle, children: "Ready to test your knowledge?" }),
2744
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
2321
2745
  quiz.questions.length,
2322
2746
  " question",
2323
2747
  quiz.questions.length !== 1 ? "s" : "",
2324
2748
  " to answer"
2325
2749
  ] }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2750
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2327
2751
  "button",
2328
2752
  {
2329
2753
  style: defaultStyles.startButton,
@@ -2343,7 +2767,7 @@ function QuizPlayer({
2343
2767
  ] }) });
2344
2768
  }
2345
2769
  if (!quiz || !currentQuestion) {
2346
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.error, children: "No quiz data available" }) });
2770
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.error, children: "No quiz data available" }) });
2347
2771
  }
2348
2772
  const selectedAnswer = answers.get(currentQuestion.id);
2349
2773
  const isLastQuestion = currentQuestionIndex === totalQuestions - 1;
@@ -2351,294 +2775,166 @@ function QuizPlayer({
2351
2775
  const remainingSlots = maxQuestions - totalQuestions;
2352
2776
  const questionsToAdd = Math.min(5, remainingSlots);
2353
2777
  const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;
2354
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.mainLayout, children: [
2355
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.quizContent, children: [
2356
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.header, children: [
2357
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.title, children: quiz.title }),
2358
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.progress, children: [
2359
- "Question ",
2360
- currentQuestionIndex + 1,
2361
- " of ",
2362
- totalQuestions
2363
- ] }),
2364
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
2365
- ] }),
2366
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...defaultStyles.question, position: "relative", paddingBottom: "40px" }, children: [
2367
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.questionText, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TextToSpeech, { text: currentQuestion.question, inline: true, size: "md" }) }),
2368
- isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2369
- "button",
2370
- {
2371
- onClick: () => setShowSkipModal(true),
2372
- title: "Skip question",
2373
- style: {
2374
- position: "absolute",
2375
- bottom: "8px",
2376
- left: "0",
2377
- background: "transparent",
2378
- border: "none",
2379
- cursor: "pointer",
2380
- padding: "6px 10px",
2381
- borderRadius: "6px",
2382
- color: "#9ca3af",
2383
- display: "flex",
2384
- alignItems: "center",
2385
- justifyContent: "center",
2386
- gap: "4px",
2387
- fontSize: "12px",
2388
- opacity: 0.6,
2389
- transition: "opacity 0.2s, color 0.2s"
2390
- },
2391
- onMouseEnter: (e) => {
2392
- e.currentTarget.style.opacity = "1";
2393
- e.currentTarget.style.color = "#6b7280";
2394
- },
2395
- onMouseLeave: (e) => {
2396
- e.currentTarget.style.opacity = "0.6";
2397
- e.currentTarget.style.color = "#9ca3af";
2398
- },
2399
- "data-testid": "button-skip-question",
2400
- children: [
2401
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2402
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polygon", { points: "5 4 15 12 5 20 5 4" }),
2403
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "19", y1: "5", x2: "19", y2: "19" })
2404
- ] }),
2405
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Skip" })
2406
- ]
2407
- }
2408
- ),
2409
- !isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2410
- "button",
2411
- {
2412
- onClick: () => setShowReportModal(true),
2413
- title: "Report an issue with this question",
2414
- style: {
2415
- position: "absolute",
2416
- bottom: "8px",
2417
- left: "0",
2418
- background: "transparent",
2419
- border: "none",
2420
- cursor: "pointer",
2421
- padding: "6px 10px",
2422
- borderRadius: "6px",
2423
- color: "#9ca3af",
2424
- display: "flex",
2425
- alignItems: "center",
2426
- justifyContent: "center",
2427
- gap: "4px",
2428
- fontSize: "12px",
2429
- opacity: 0.6,
2430
- transition: "opacity 0.2s, color 0.2s"
2431
- },
2432
- onMouseEnter: (e) => {
2433
- e.currentTarget.style.opacity = "1";
2434
- e.currentTarget.style.color = "#ef4444";
2435
- },
2436
- onMouseLeave: (e) => {
2437
- e.currentTarget.style.opacity = "0.6";
2438
- e.currentTarget.style.color = "#9ca3af";
2439
- },
2440
- "data-testid": "button-report-question",
2441
- children: [
2442
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2443
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" }),
2444
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", y1: "22", x2: "4", y2: "15" })
2445
- ] }),
2446
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Report" })
2447
- ]
2778
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: defaultStyles.container, children: [
2779
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
2780
+ .quiz-option:focus,
2781
+ .quiz-option:active,
2782
+ .quiz-option:focus-visible,
2783
+ .quiz-option:focus-within {
2784
+ outline: none !important;
2785
+ box-shadow: none !important;
2448
2786
  }
2449
- ),
2450
- (currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
2451
- const isSelected = selectedAnswer === option;
2452
- const isCorrectOption = currentQuestion.correctAnswer === option;
2453
- let optionStyle = { ...defaultStyles.option };
2454
- if (showFeedback) {
2455
- if (isCorrectOption) {
2456
- optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
2457
- } else if (isSelected && !isCorrectOption) {
2458
- optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
2459
- }
2460
- } else if (isSelected) {
2461
- optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
2787
+ .quiz-option {
2788
+ -webkit-tap-highlight-color: transparent;
2462
2789
  }
2463
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2464
- "div",
2790
+ ` }),
2791
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.mainLayout, children: [
2792
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.quizContent, children: [
2793
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.header, children: [
2794
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.title, children: quiz.title }),
2795
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.progress, children: [
2796
+ "Question ",
2797
+ currentQuestionIndex + 1,
2798
+ " of ",
2799
+ totalQuestions
2800
+ ] }),
2801
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
2802
+ ] }),
2803
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.question, position: "relative", paddingBottom: "40px" }, children: [
2804
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.questionText, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: currentQuestion.question, inline: true, size: "md" }) }),
2805
+ isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2806
+ "button",
2465
2807
  {
2808
+ onClick: () => setShowSkipModal(true),
2809
+ title: "Skip question",
2466
2810
  style: {
2467
- ...optionStyle,
2468
- cursor: showFeedback ? "default" : "pointer",
2811
+ position: "absolute",
2812
+ bottom: "8px",
2813
+ left: "0",
2814
+ background: "transparent",
2815
+ border: "none",
2816
+ cursor: "pointer",
2817
+ padding: "6px 10px",
2818
+ borderRadius: "6px",
2819
+ color: "#9ca3af",
2469
2820
  display: "flex",
2470
2821
  alignItems: "center",
2471
- gap: "8px"
2822
+ justifyContent: "center",
2823
+ gap: "4px",
2824
+ fontSize: "12px",
2825
+ opacity: 0.6,
2826
+ transition: "opacity 0.2s, color 0.2s"
2827
+ },
2828
+ onMouseEnter: (e) => {
2829
+ e.currentTarget.style.opacity = "1";
2830
+ e.currentTarget.style.color = "#6b7280";
2472
2831
  },
2473
- onClick: () => !showFeedback && handleAnswerChange(option),
2832
+ onMouseLeave: (e) => {
2833
+ e.currentTarget.style.opacity = "0.6";
2834
+ e.currentTarget.style.color = "#9ca3af";
2835
+ },
2836
+ "data-testid": "button-skip-question",
2474
2837
  children: [
2475
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
2476
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: option })
2838
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2839
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polygon", { points: "5 4 15 12 5 20 5 4" }),
2840
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "19", y1: "5", x2: "19", y2: "19" })
2841
+ ] }),
2842
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Skip" })
2477
2843
  ]
2478
- },
2479
- idx
2480
- );
2481
- }) }),
2482
- currentQuestion.type === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
2483
- const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
2484
- const correctAnswers = Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer : currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : [];
2485
- const isCorrectOption = correctAnswers.includes(option);
2486
- let optionStyle = { ...defaultStyles.option };
2487
- if (showFeedback) {
2488
- if (isCorrectOption) {
2489
- optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
2490
- } else if (selected && !isCorrectOption) {
2491
- optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
2492
2844
  }
2493
- } else if (selected) {
2494
- optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
2495
- }
2496
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2497
- "div",
2845
+ ),
2846
+ !isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2847
+ "button",
2498
2848
  {
2849
+ onClick: () => setShowReportModal(true),
2850
+ title: "Report an issue with this question",
2499
2851
  style: {
2500
- ...optionStyle,
2501
- cursor: showFeedback ? "default" : "pointer",
2852
+ position: "absolute",
2853
+ bottom: "8px",
2854
+ left: "0",
2855
+ background: "transparent",
2856
+ border: "none",
2857
+ cursor: "pointer",
2858
+ padding: "6px 10px",
2859
+ borderRadius: "6px",
2860
+ color: "#9ca3af",
2502
2861
  display: "flex",
2503
2862
  alignItems: "center",
2504
- gap: "8px"
2863
+ justifyContent: "center",
2864
+ gap: "4px",
2865
+ fontSize: "12px",
2866
+ opacity: 0.6,
2867
+ transition: "opacity 0.2s, color 0.2s"
2505
2868
  },
2506
- onClick: () => {
2507
- if (showFeedback) return;
2508
- const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];
2509
- if (selected) {
2510
- handleAnswerChange(current.filter((o) => o !== option));
2511
- } else {
2512
- handleAnswerChange([...current, option]);
2513
- }
2869
+ onMouseEnter: (e) => {
2870
+ e.currentTarget.style.opacity = "1";
2871
+ e.currentTarget.style.color = "#ef4444";
2872
+ },
2873
+ onMouseLeave: (e) => {
2874
+ e.currentTarget.style.opacity = "0.6";
2875
+ e.currentTarget.style.color = "#9ca3af";
2514
2876
  },
2877
+ "data-testid": "button-report-question",
2515
2878
  children: [
2516
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
2517
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: option })
2879
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2880
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" }),
2881
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "4", y1: "22", x2: "4", y2: "15" })
2882
+ ] }),
2883
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Report" })
2518
2884
  ]
2519
- },
2520
- idx
2521
- );
2522
- }) }),
2523
- (currentQuestion.type === "free" || currentQuestion.type === "essay") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2524
- "textarea",
2525
- {
2526
- style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
2527
- value: selectedAnswer || "",
2528
- onChange: (e) => handleAnswerChange(e.target.value),
2529
- placeholder: "Type your answer here...",
2530
- disabled: showFeedback
2531
- }
2532
- ),
2533
- currentQuestion.type === "fill" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2534
- "input",
2535
- {
2536
- style: defaultStyles.input,
2537
- value: (Array.isArray(selectedAnswer) ? selectedAnswer[idx] : "") || "",
2538
- onChange: (e) => {
2539
- const current = Array.isArray(selectedAnswer) ? [...selectedAnswer] : [];
2540
- current[idx] = e.target.value;
2541
- handleAnswerChange(current);
2542
- },
2543
- placeholder: `Blank ${idx + 1}`,
2544
- disabled: showFeedback
2545
- },
2546
- idx
2547
- )) }),
2548
- currentQuestion.type === "sorting" && currentQuestion.items && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2549
- SortingDragDrop,
2550
- {
2551
- items: currentQuestion.items,
2552
- currentOrder: Array.isArray(selectedAnswer) ? selectedAnswer : currentQuestion.items.map((_, i) => i),
2553
- correctOrder: currentQuestion.correctOrder,
2554
- showFeedback,
2555
- onOrderChange: handleAnswerChange
2556
- }
2557
- ),
2558
- currentQuestion.type === "matrix" && currentQuestion.leftItems && currentQuestion.rightItems && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2559
- MatchingDragDrop,
2560
- {
2561
- leftItems: currentQuestion.leftItems,
2562
- rightItems: currentQuestion.rightItems,
2563
- currentMatches: typeof selectedAnswer === "object" && selectedAnswer !== null && !Array.isArray(selectedAnswer) ? selectedAnswer : {},
2564
- correctMatches: currentQuestion.correctMatches,
2565
- showFeedback,
2566
- onMatchChange: handleAnswerChange
2567
- }
2568
- ),
2569
- currentQuestion.type === "assessment" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.options, children: (() => {
2570
- const scaleType = currentQuestion.scaleType || "likert";
2571
- if (scaleType === "yes-no") {
2572
- const options = ["Yes", "No"];
2573
- return options.map((option, idx) => {
2574
- const isSelected = selectedAnswer === option;
2575
- let optionStyle = { ...defaultStyles.option };
2576
- if (isSelected) {
2577
- optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
2885
+ }
2886
+ ),
2887
+ (currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
2888
+ const isSelected = selectedAnswer === option;
2889
+ const isCorrectOption = currentQuestion.correctAnswer === option;
2890
+ let optionStyle = { ...defaultStyles.option };
2891
+ if (showFeedback) {
2892
+ if (isCorrectOption) {
2893
+ optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
2894
+ } else if (isSelected && !isCorrectOption) {
2895
+ optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
2578
2896
  }
2579
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2580
- "div",
2581
- {
2582
- style: {
2583
- ...optionStyle,
2584
- cursor: showFeedback ? "default" : "pointer",
2585
- display: "flex",
2586
- alignItems: "center",
2587
- gap: "8px"
2588
- },
2589
- onClick: () => !showFeedback && handleAnswerChange(option),
2590
- "data-testid": `assessment-option-${option.toLowerCase()}`,
2591
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: option })
2592
- },
2593
- idx
2594
- );
2595
- });
2596
- }
2597
- if (scaleType === "rating") {
2598
- const min = currentQuestion.scaleMin || 1;
2599
- const max = currentQuestion.scaleMax || 5;
2600
- const ratings = Array.from({ length: max - min + 1 }, (_, i) => min + i);
2601
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap", justifyContent: "center" }, children: ratings.map((rating) => {
2602
- const isSelected = selectedAnswer === rating;
2603
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2604
- "button",
2605
- {
2606
- onClick: () => !showFeedback && handleAnswerChange(rating),
2607
- disabled: showFeedback,
2608
- style: {
2609
- width: "48px",
2610
- height: "48px",
2611
- borderRadius: "50%",
2612
- border: isSelected ? "2px solid #6721b0" : "2px solid #e5e7eb",
2613
- backgroundColor: isSelected ? "#f3e8ff" : "#ffffff",
2614
- cursor: showFeedback ? "not-allowed" : "pointer",
2615
- fontSize: "18px",
2616
- fontWeight: "600",
2617
- color: isSelected ? "#6721b0" : "#374151"
2618
- },
2619
- "data-testid": `assessment-rating-${rating}`,
2620
- children: rating
2897
+ } else if (isSelected) {
2898
+ optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
2899
+ }
2900
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2901
+ "div",
2902
+ {
2903
+ className: "quiz-option",
2904
+ style: {
2905
+ ...optionStyle,
2906
+ cursor: showFeedback ? "default" : "pointer",
2907
+ display: "flex",
2908
+ alignItems: "center",
2909
+ gap: "8px"
2621
2910
  },
2622
- rating
2623
- );
2624
- }) });
2625
- }
2626
- const likertOptions = [
2627
- "Strongly Disagree",
2628
- "Disagree",
2629
- "Neutral",
2630
- "Agree",
2631
- "Strongly Agree"
2632
- ];
2633
- return likertOptions.map((option, idx) => {
2634
- const isSelected = selectedAnswer === option;
2911
+ onClick: () => !showFeedback && handleAnswerChange(option),
2912
+ children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
2914
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
2915
+ ]
2916
+ },
2917
+ idx
2918
+ );
2919
+ }) }),
2920
+ currentQuestion.type === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
2921
+ const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
2922
+ const correctAnswers = Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer : currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : [];
2923
+ const isCorrectOption = correctAnswers.includes(option);
2635
2924
  let optionStyle = { ...defaultStyles.option };
2636
- if (isSelected) {
2925
+ if (showFeedback) {
2926
+ if (isCorrectOption) {
2927
+ optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
2928
+ } else if (selected && !isCorrectOption) {
2929
+ optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
2930
+ }
2931
+ } else if (selected) {
2637
2932
  optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
2638
2933
  }
2639
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2934
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2640
2935
  "div",
2641
2936
  {
2937
+ className: "quiz-option",
2642
2938
  style: {
2643
2939
  ...optionStyle,
2644
2940
  cursor: showFeedback ? "default" : "pointer",
@@ -2646,356 +2942,504 @@ function QuizPlayer({
2646
2942
  alignItems: "center",
2647
2943
  gap: "8px"
2648
2944
  },
2649
- onClick: () => !showFeedback && handleAnswerChange(option),
2650
- "data-testid": `assessment-likert-${idx}`,
2651
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: option })
2945
+ onClick: () => {
2946
+ if (showFeedback) return;
2947
+ const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];
2948
+ if (selected) {
2949
+ handleAnswerChange(current.filter((o) => o !== option));
2950
+ } else {
2951
+ handleAnswerChange([...current, option]);
2952
+ }
2953
+ },
2954
+ children: [
2955
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
2956
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
2957
+ ]
2652
2958
  },
2653
2959
  idx
2654
2960
  );
2655
- });
2656
- })() }),
2657
- showFeedback && currentAnswerDetail && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
2658
- ...defaultStyles.feedback,
2659
- ...currentQuestion.type === "assessment" ? defaultStyles.feedbackNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect
2660
- }, children: [
2661
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
2662
- ...defaultStyles.feedbackTitle,
2663
- ...currentQuestion.type === "assessment" ? defaultStyles.feedbackTitleNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect
2664
- }, children: currentQuestion.type === "assessment" ? "\u2713 Response recorded" : currentAnswerDetail.isCorrect ? "\u2713 Correct!" : "\u2717 Incorrect" }),
2665
- currentQuestion.explanation && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.feedbackExplanation, children: currentQuestion.explanation })
2666
- ] })
2667
- ] }),
2668
- showSkipModal && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
2669
- position: "fixed",
2670
- top: 0,
2671
- left: 0,
2672
- right: 0,
2673
- bottom: 0,
2674
- backgroundColor: "rgba(0, 0, 0, 0.5)",
2675
- display: "flex",
2676
- alignItems: "center",
2677
- justifyContent: "center",
2678
- zIndex: 1e3
2679
- }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
2680
- backgroundColor: "#ffffff",
2681
- borderRadius: "12px",
2682
- padding: "24px",
2683
- maxWidth: "400px",
2684
- width: "90%",
2685
- boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
2686
- }, children: [
2687
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Skip Question" }),
2688
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { margin: "0 0 16px 0", fontSize: "14px", color: "#6b7280" }, children: "Help us improve by telling us why you're skipping this question." }),
2689
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px", marginBottom: "16px" }, children: [
2690
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2691
- "button",
2961
+ }) }),
2962
+ (currentQuestion.type === "free" || currentQuestion.type === "essay") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2963
+ "textarea",
2692
2964
  {
2693
- onClick: () => setSelectedSkipReason("question_issue"),
2694
- disabled: isSkipping,
2695
- style: {
2696
- padding: "12px 16px",
2697
- borderRadius: "8px",
2698
- border: selectedSkipReason === "question_issue" ? "2px solid #8b5cf6" : "1px solid #e5e7eb",
2699
- backgroundColor: selectedSkipReason === "question_issue" ? "#f5f3ff" : "#f9fafb",
2700
- cursor: isSkipping ? "not-allowed" : "pointer",
2701
- fontSize: "14px",
2702
- fontWeight: "500",
2703
- color: "#374151",
2704
- textAlign: "left",
2705
- opacity: isSkipping ? 0.6 : 1
2706
- },
2707
- "data-testid": "button-skip-reason-issue",
2708
- children: "Question has an issue"
2965
+ style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
2966
+ value: selectedAnswer || "",
2967
+ onChange: (e) => handleAnswerChange(e.target.value),
2968
+ placeholder: "Type your answer here...",
2969
+ disabled: showFeedback
2709
2970
  }
2710
2971
  ),
2711
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2712
- "button",
2972
+ currentQuestion.type === "fill" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2973
+ "input",
2713
2974
  {
2714
- onClick: () => setSelectedSkipReason("dont_know"),
2715
- disabled: isSkipping,
2716
- style: {
2717
- padding: "12px 16px",
2718
- borderRadius: "8px",
2719
- border: selectedSkipReason === "dont_know" ? "2px solid #8b5cf6" : "1px solid #e5e7eb",
2720
- backgroundColor: selectedSkipReason === "dont_know" ? "#f5f3ff" : "#f9fafb",
2721
- cursor: isSkipping ? "not-allowed" : "pointer",
2722
- fontSize: "14px",
2723
- fontWeight: "500",
2724
- color: "#374151",
2725
- textAlign: "left",
2726
- opacity: isSkipping ? 0.6 : 1
2975
+ style: defaultStyles.input,
2976
+ value: (Array.isArray(selectedAnswer) ? selectedAnswer[idx] : "") || "",
2977
+ onChange: (e) => {
2978
+ const current = Array.isArray(selectedAnswer) ? [...selectedAnswer] : [];
2979
+ current[idx] = e.target.value;
2980
+ handleAnswerChange(current);
2727
2981
  },
2728
- "data-testid": "button-skip-reason-dont-know",
2729
- children: "I don't know the answer"
2730
- }
2731
- )
2732
- ] }),
2733
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginBottom: "16px" }, children: [
2734
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: { display: "block", fontSize: "13px", fontWeight: "500", color: "#374151", marginBottom: "6px" }, children: "Additional details (optional)" }),
2735
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2736
- "textarea",
2982
+ placeholder: `Blank ${idx + 1}`,
2983
+ disabled: showFeedback
2984
+ },
2985
+ idx
2986
+ )) }),
2987
+ currentQuestion.type === "sorting" && currentQuestion.items && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2988
+ SortingDragDrop,
2737
2989
  {
2738
- value: skipComment,
2739
- onChange: (e) => setSkipComment(e.target.value.slice(0, 200)),
2740
- placeholder: "Tell us more about the issue...",
2741
- disabled: isSkipping,
2742
- style: {
2743
- width: "100%",
2744
- minHeight: "80px",
2745
- padding: "10px 12px",
2746
- borderRadius: "8px",
2747
- border: "1px solid #e5e7eb",
2748
- fontSize: "14px",
2749
- resize: "vertical",
2750
- fontFamily: "inherit",
2751
- boxSizing: "border-box"
2752
- },
2753
- "data-testid": "input-skip-comment"
2990
+ items: currentQuestion.items,
2991
+ currentOrder: Array.isArray(selectedAnswer) ? selectedAnswer : currentQuestion.items.map((_, i) => i),
2992
+ correctOrder: currentQuestion.correctOrder,
2993
+ showFeedback,
2994
+ onOrderChange: handleAnswerChange
2754
2995
  }
2755
2996
  ),
2756
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
2757
- skipComment.length,
2758
- "/200"
2759
- ] })
2760
- ] }),
2761
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
2762
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2763
- "button",
2997
+ currentQuestion.type === "matrix" && currentQuestion.leftItems && currentQuestion.rightItems && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2998
+ MatchingDragDrop,
2764
2999
  {
2765
- onClick: () => {
2766
- setShowSkipModal(false);
2767
- setSkipComment("");
2768
- setSelectedSkipReason(null);
2769
- },
2770
- style: {
2771
- flex: 1,
2772
- padding: "10px 16px",
2773
- borderRadius: "8px",
2774
- border: "1px solid #e5e7eb",
2775
- backgroundColor: "#ffffff",
2776
- cursor: "pointer",
2777
- fontSize: "14px",
2778
- fontWeight: "500",
2779
- color: "#6b7280"
2780
- },
2781
- "data-testid": "button-skip-cancel",
2782
- children: "Cancel"
3000
+ leftItems: currentQuestion.leftItems,
3001
+ rightItems: currentQuestion.rightItems,
3002
+ currentMatches: typeof selectedAnswer === "object" && selectedAnswer !== null && !Array.isArray(selectedAnswer) ? selectedAnswer : {},
3003
+ correctMatches: currentQuestion.correctMatches,
3004
+ showFeedback,
3005
+ onMatchChange: handleAnswerChange
2783
3006
  }
2784
3007
  ),
2785
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2786
- "button",
2787
- {
2788
- onClick: () => selectedSkipReason && handleSkipQuestion(selectedSkipReason, skipComment),
2789
- disabled: isSkipping || !selectedSkipReason,
2790
- style: {
2791
- flex: 1,
2792
- padding: "10px 16px",
2793
- borderRadius: "8px",
2794
- border: "none",
2795
- backgroundColor: selectedSkipReason ? "#8b5cf6" : "#d1d5db",
2796
- cursor: isSkipping || !selectedSkipReason ? "not-allowed" : "pointer",
2797
- fontSize: "14px",
2798
- fontWeight: "500",
2799
- color: "#ffffff",
2800
- opacity: isSkipping ? 0.6 : 1
2801
- },
2802
- "data-testid": "button-skip-submit",
2803
- children: isSkipping ? "Skipping..." : "Skip Question"
3008
+ currentQuestion.type === "assessment" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: (() => {
3009
+ const scaleType = currentQuestion.scaleType || "likert";
3010
+ if (scaleType === "yes-no") {
3011
+ const options = ["Yes", "No"];
3012
+ return options.map((option, idx) => {
3013
+ const isSelected = selectedAnswer === option;
3014
+ let optionStyle = { ...defaultStyles.option };
3015
+ if (isSelected) {
3016
+ optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
3017
+ }
3018
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3019
+ "div",
3020
+ {
3021
+ className: "quiz-option",
3022
+ style: {
3023
+ ...optionStyle,
3024
+ cursor: showFeedback ? "default" : "pointer",
3025
+ display: "flex",
3026
+ alignItems: "center",
3027
+ gap: "8px"
3028
+ },
3029
+ onClick: () => !showFeedback && handleAnswerChange(option),
3030
+ "data-testid": `assessment-option-${option.toLowerCase()}`,
3031
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
3032
+ },
3033
+ idx
3034
+ );
3035
+ });
2804
3036
  }
2805
- )
2806
- ] })
2807
- ] }) }),
2808
- showReportModal && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
2809
- position: "fixed",
2810
- top: 0,
2811
- left: 0,
2812
- right: 0,
2813
- bottom: 0,
2814
- backgroundColor: "rgba(0, 0, 0, 0.5)",
2815
- display: "flex",
2816
- alignItems: "center",
2817
- justifyContent: "center",
2818
- zIndex: 1e3
2819
- }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: {
2820
- backgroundColor: "#ffffff",
2821
- borderRadius: "12px",
2822
- padding: "24px",
2823
- maxWidth: "400px",
2824
- width: "90%",
2825
- boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
2826
- }, children: [
2827
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Report Question" }),
2828
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { margin: "0 0 16px 0", fontSize: "14px", color: "#6b7280" }, children: "What's wrong with this question?" }),
2829
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { marginBottom: "16px" }, children: [
2830
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2831
- "textarea",
2832
- {
2833
- value: reportComment,
2834
- onChange: (e) => setReportComment(e.target.value.slice(0, 300)),
2835
- placeholder: "Describe the issue with this question...",
2836
- disabled: isReporting,
2837
- style: {
2838
- width: "100%",
2839
- minHeight: "120px",
2840
- padding: "10px 12px",
2841
- borderRadius: "8px",
2842
- border: "1px solid #e5e7eb",
2843
- fontSize: "14px",
2844
- resize: "vertical",
2845
- fontFamily: "inherit",
2846
- boxSizing: "border-box"
2847
- },
2848
- "data-testid": "input-report-comment"
3037
+ if (scaleType === "rating") {
3038
+ const min = currentQuestion.scaleMin || 1;
3039
+ const max = currentQuestion.scaleMax || 5;
3040
+ const ratings = Array.from({ length: max - min + 1 }, (_, i) => min + i);
3041
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap", justifyContent: "center" }, children: ratings.map((rating) => {
3042
+ const isSelected = selectedAnswer === rating;
3043
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3044
+ "button",
3045
+ {
3046
+ className: "quiz-option",
3047
+ onClick: () => !showFeedback && handleAnswerChange(rating),
3048
+ disabled: showFeedback,
3049
+ style: {
3050
+ width: "48px",
3051
+ height: "48px",
3052
+ borderRadius: "50%",
3053
+ border: isSelected ? "2px solid #6721b0" : "2px solid #e5e7eb",
3054
+ backgroundColor: isSelected ? "#f3e8ff" : "#ffffff",
3055
+ cursor: showFeedback ? "not-allowed" : "pointer",
3056
+ fontSize: "18px",
3057
+ fontWeight: "600",
3058
+ color: isSelected ? "#6721b0" : "#374151",
3059
+ outline: "none"
3060
+ },
3061
+ "data-testid": `assessment-rating-${rating}`,
3062
+ children: rating
3063
+ },
3064
+ rating
3065
+ );
3066
+ }) });
2849
3067
  }
2850
- ),
2851
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
2852
- reportComment.length,
2853
- "/300"
3068
+ const likertOptions = [
3069
+ "Strongly Disagree",
3070
+ "Disagree",
3071
+ "Neutral",
3072
+ "Agree",
3073
+ "Strongly Agree"
3074
+ ];
3075
+ return likertOptions.map((option, idx) => {
3076
+ const isSelected = selectedAnswer === option;
3077
+ let optionStyle = { ...defaultStyles.option };
3078
+ if (isSelected) {
3079
+ optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
3080
+ }
3081
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3082
+ "div",
3083
+ {
3084
+ className: "quiz-option",
3085
+ style: {
3086
+ ...optionStyle,
3087
+ cursor: showFeedback ? "default" : "pointer",
3088
+ display: "flex",
3089
+ alignItems: "center",
3090
+ gap: "8px"
3091
+ },
3092
+ onClick: () => !showFeedback && handleAnswerChange(option),
3093
+ "data-testid": `assessment-likert-${idx}`,
3094
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
3095
+ },
3096
+ idx
3097
+ );
3098
+ });
3099
+ })() }),
3100
+ showFeedback && currentAnswerDetail && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
3101
+ ...defaultStyles.feedback,
3102
+ ...currentQuestion.type === "assessment" ? defaultStyles.feedbackNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect
3103
+ }, children: [
3104
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
3105
+ ...defaultStyles.feedbackTitle,
3106
+ ...currentQuestion.type === "assessment" ? defaultStyles.feedbackTitleNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect
3107
+ }, children: currentQuestion.type === "assessment" ? "\u2713 Response recorded" : currentAnswerDetail.isCorrect ? "\u2713 Correct!" : "\u2717 Incorrect" }),
3108
+ currentQuestion.explanation && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.feedbackExplanation, children: currentQuestion.explanation })
2854
3109
  ] })
2855
3110
  ] }),
2856
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
2857
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3111
+ showSkipModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
3112
+ position: "fixed",
3113
+ top: 0,
3114
+ left: 0,
3115
+ right: 0,
3116
+ bottom: 0,
3117
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3118
+ display: "flex",
3119
+ alignItems: "center",
3120
+ justifyContent: "center",
3121
+ zIndex: 1e3
3122
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
3123
+ backgroundColor: "#ffffff",
3124
+ borderRadius: "12px",
3125
+ padding: "24px",
3126
+ maxWidth: "400px",
3127
+ width: "90%",
3128
+ boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
3129
+ }, children: [
3130
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Skip Question" }),
3131
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 16px 0", fontSize: "14px", color: "#6b7280" }, children: "Help us improve by telling us why you're skipping this question." }),
3132
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px", marginBottom: "16px" }, children: [
3133
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3134
+ "button",
3135
+ {
3136
+ onClick: () => setSelectedSkipReason("question_issue"),
3137
+ disabled: isSkipping,
3138
+ style: {
3139
+ padding: "12px 16px",
3140
+ borderRadius: "8px",
3141
+ border: selectedSkipReason === "question_issue" ? "2px solid #8b5cf6" : "1px solid #e5e7eb",
3142
+ backgroundColor: selectedSkipReason === "question_issue" ? "#f5f3ff" : "#f9fafb",
3143
+ cursor: isSkipping ? "not-allowed" : "pointer",
3144
+ fontSize: "14px",
3145
+ fontWeight: "500",
3146
+ color: "#374151",
3147
+ textAlign: "left",
3148
+ opacity: isSkipping ? 0.6 : 1
3149
+ },
3150
+ "data-testid": "button-skip-reason-issue",
3151
+ children: "Question has an issue"
3152
+ }
3153
+ ),
3154
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3155
+ "button",
3156
+ {
3157
+ onClick: () => setSelectedSkipReason("dont_know"),
3158
+ disabled: isSkipping,
3159
+ style: {
3160
+ padding: "12px 16px",
3161
+ borderRadius: "8px",
3162
+ border: selectedSkipReason === "dont_know" ? "2px solid #8b5cf6" : "1px solid #e5e7eb",
3163
+ backgroundColor: selectedSkipReason === "dont_know" ? "#f5f3ff" : "#f9fafb",
3164
+ cursor: isSkipping ? "not-allowed" : "pointer",
3165
+ fontSize: "14px",
3166
+ fontWeight: "500",
3167
+ color: "#374151",
3168
+ textAlign: "left",
3169
+ opacity: isSkipping ? 0.6 : 1
3170
+ },
3171
+ "data-testid": "button-skip-reason-dont-know",
3172
+ children: "I don't know the answer"
3173
+ }
3174
+ )
3175
+ ] }),
3176
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "16px" }, children: [
3177
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: { display: "block", fontSize: "13px", fontWeight: "500", color: "#374151", marginBottom: "6px" }, children: "Additional details (optional)" }),
3178
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3179
+ "textarea",
3180
+ {
3181
+ value: skipComment,
3182
+ onChange: (e) => setSkipComment(e.target.value.slice(0, 200)),
3183
+ placeholder: "Tell us more about the issue...",
3184
+ disabled: isSkipping,
3185
+ style: {
3186
+ width: "100%",
3187
+ minHeight: "80px",
3188
+ padding: "10px 12px",
3189
+ borderRadius: "8px",
3190
+ border: "1px solid #e5e7eb",
3191
+ fontSize: "14px",
3192
+ resize: "vertical",
3193
+ fontFamily: "inherit",
3194
+ boxSizing: "border-box"
3195
+ },
3196
+ "data-testid": "input-skip-comment"
3197
+ }
3198
+ ),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
3200
+ skipComment.length,
3201
+ "/200"
3202
+ ] })
3203
+ ] }),
3204
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
3205
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3206
+ "button",
3207
+ {
3208
+ onClick: () => {
3209
+ setShowSkipModal(false);
3210
+ setSkipComment("");
3211
+ setSelectedSkipReason(null);
3212
+ },
3213
+ style: {
3214
+ flex: 1,
3215
+ padding: "10px 16px",
3216
+ borderRadius: "8px",
3217
+ border: "1px solid #e5e7eb",
3218
+ backgroundColor: "#ffffff",
3219
+ cursor: "pointer",
3220
+ fontSize: "14px",
3221
+ fontWeight: "500",
3222
+ color: "#6b7280"
3223
+ },
3224
+ "data-testid": "button-skip-cancel",
3225
+ children: "Cancel"
3226
+ }
3227
+ ),
3228
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3229
+ "button",
3230
+ {
3231
+ onClick: () => selectedSkipReason && handleSkipQuestion(selectedSkipReason, skipComment),
3232
+ disabled: isSkipping || !selectedSkipReason,
3233
+ style: {
3234
+ flex: 1,
3235
+ padding: "10px 16px",
3236
+ borderRadius: "8px",
3237
+ border: "none",
3238
+ backgroundColor: selectedSkipReason ? "#8b5cf6" : "#d1d5db",
3239
+ cursor: isSkipping || !selectedSkipReason ? "not-allowed" : "pointer",
3240
+ fontSize: "14px",
3241
+ fontWeight: "500",
3242
+ color: "#ffffff",
3243
+ opacity: isSkipping ? 0.6 : 1
3244
+ },
3245
+ "data-testid": "button-skip-submit",
3246
+ children: isSkipping ? "Skipping..." : "Skip Question"
3247
+ }
3248
+ )
3249
+ ] })
3250
+ ] }) }),
3251
+ showReportModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
3252
+ position: "fixed",
3253
+ top: 0,
3254
+ left: 0,
3255
+ right: 0,
3256
+ bottom: 0,
3257
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3258
+ display: "flex",
3259
+ alignItems: "center",
3260
+ justifyContent: "center",
3261
+ zIndex: 1e3
3262
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
3263
+ backgroundColor: "#ffffff",
3264
+ borderRadius: "12px",
3265
+ padding: "24px",
3266
+ maxWidth: "400px",
3267
+ width: "90%",
3268
+ boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
3269
+ }, children: [
3270
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Report Question" }),
3271
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 16px 0", fontSize: "14px", color: "#6b7280" }, children: "What's wrong with this question?" }),
3272
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "16px" }, children: [
3273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3274
+ "textarea",
3275
+ {
3276
+ value: reportComment,
3277
+ onChange: (e) => setReportComment(e.target.value.slice(0, 300)),
3278
+ placeholder: "Describe the issue with this question...",
3279
+ disabled: isReporting,
3280
+ style: {
3281
+ width: "100%",
3282
+ minHeight: "120px",
3283
+ padding: "10px 12px",
3284
+ borderRadius: "8px",
3285
+ border: "1px solid #e5e7eb",
3286
+ fontSize: "14px",
3287
+ resize: "vertical",
3288
+ fontFamily: "inherit",
3289
+ boxSizing: "border-box"
3290
+ },
3291
+ "data-testid": "input-report-comment"
3292
+ }
3293
+ ),
3294
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
3295
+ reportComment.length,
3296
+ "/300"
3297
+ ] })
3298
+ ] }),
3299
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
3300
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3301
+ "button",
3302
+ {
3303
+ onClick: () => {
3304
+ setShowReportModal(false);
3305
+ setReportComment("");
3306
+ },
3307
+ style: {
3308
+ flex: 1,
3309
+ padding: "10px 16px",
3310
+ borderRadius: "8px",
3311
+ border: "1px solid #e5e7eb",
3312
+ backgroundColor: "#ffffff",
3313
+ cursor: "pointer",
3314
+ fontSize: "14px",
3315
+ fontWeight: "500",
3316
+ color: "#6b7280"
3317
+ },
3318
+ "data-testid": "button-report-cancel",
3319
+ children: "Cancel"
3320
+ }
3321
+ ),
3322
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3323
+ "button",
3324
+ {
3325
+ onClick: () => handleReportQuestion(reportComment),
3326
+ disabled: isReporting || !reportComment.trim(),
3327
+ style: {
3328
+ flex: 1,
3329
+ padding: "10px 16px",
3330
+ borderRadius: "8px",
3331
+ border: "none",
3332
+ backgroundColor: reportComment.trim() ? "#ef4444" : "#d1d5db",
3333
+ cursor: isReporting || !reportComment.trim() ? "not-allowed" : "pointer",
3334
+ fontSize: "14px",
3335
+ fontWeight: "500",
3336
+ color: "#ffffff",
3337
+ opacity: isReporting ? 0.6 : 1
3338
+ },
3339
+ "data-testid": "button-report-submit",
3340
+ children: isReporting ? "Reporting..." : "Report"
3341
+ }
3342
+ )
3343
+ ] })
3344
+ ] }) }),
3345
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.buttonsColumn, children: [
3346
+ showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2858
3347
  "button",
2859
3348
  {
2860
- onClick: () => {
2861
- setShowReportModal(false);
2862
- setReportComment("");
2863
- },
2864
3349
  style: {
2865
- flex: 1,
2866
- padding: "10px 16px",
2867
- borderRadius: "8px",
2868
- border: "1px solid #e5e7eb",
2869
- backgroundColor: "#ffffff",
2870
- cursor: "pointer",
2871
- fontSize: "14px",
2872
- fontWeight: "500",
2873
- color: "#6b7280"
3350
+ ...defaultStyles.buttonAddMore,
3351
+ ...isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}
2874
3352
  },
2875
- "data-testid": "button-report-cancel",
2876
- children: "Cancel"
3353
+ onClick: handleAddMoreQuestions,
3354
+ disabled: isGeneratingExtra,
3355
+ "data-testid": "button-add-more-questions",
3356
+ children: isGeneratingExtra ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3357
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }),
3358
+ "Generating Questions..."
3359
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3360
+ "+ Add ",
3361
+ questionsToAdd,
3362
+ " More Question",
3363
+ questionsToAdd !== 1 ? "s" : ""
3364
+ ] })
2877
3365
  }
2878
3366
  ),
2879
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2880
- "button",
2881
- {
2882
- onClick: () => handleReportQuestion(reportComment),
2883
- disabled: isReporting || !reportComment.trim(),
2884
- style: {
2885
- flex: 1,
2886
- padding: "10px 16px",
2887
- borderRadius: "8px",
2888
- border: "none",
2889
- backgroundColor: reportComment.trim() ? "#ef4444" : "#d1d5db",
2890
- cursor: isReporting || !reportComment.trim() ? "not-allowed" : "pointer",
2891
- fontSize: "14px",
2892
- fontWeight: "500",
2893
- color: "#ffffff",
2894
- opacity: isReporting ? 0.6 : 1
2895
- },
2896
- "data-testid": "button-report-submit",
2897
- children: isReporting ? "Reporting..." : "Report"
2898
- }
2899
- )
3367
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.buttons, justifyContent: "flex-end" }, children: showFeedback ? (
3368
+ // After viewing feedback
3369
+ isLastQuestion ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3370
+ "button",
3371
+ {
3372
+ style: {
3373
+ ...defaultStyles.button,
3374
+ ...isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
3375
+ },
3376
+ onClick: handleSubmit,
3377
+ disabled: isSubmitting || isGeneratingExtra,
3378
+ "data-testid": "button-submit-quiz",
3379
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
3380
+ }
3381
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3382
+ "button",
3383
+ {
3384
+ style: {
3385
+ ...defaultStyles.button,
3386
+ ...defaultStyles.buttonPrimary
3387
+ },
3388
+ onClick: handleContinue,
3389
+ "data-testid": "button-continue",
3390
+ children: "Continue"
3391
+ }
3392
+ )
3393
+ ) : (
3394
+ // Before checking answer
3395
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3396
+ "button",
3397
+ {
3398
+ style: {
3399
+ ...defaultStyles.button,
3400
+ ...isNavigating || selectedAnswer === void 0 ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
3401
+ },
3402
+ onClick: handleCheckAnswer,
3403
+ disabled: isNavigating || selectedAnswer === void 0,
3404
+ "data-testid": "button-check-answer",
3405
+ children: isNavigating ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Check Answer"
3406
+ }
3407
+ )
3408
+ ) })
2900
3409
  ] })
2901
- ] }) }),
2902
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.buttonsColumn, children: [
2903
- showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2904
- "button",
2905
- {
2906
- style: {
2907
- ...defaultStyles.buttonAddMore,
2908
- ...isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}
2909
- },
2910
- onClick: handleAddMoreQuestions,
2911
- disabled: isGeneratingExtra,
2912
- "data-testid": "button-add-more-questions",
2913
- children: isGeneratingExtra ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2914
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { size: 16, color: "#9ca3af" }),
2915
- "Generating Questions..."
2916
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2917
- "+ Add ",
2918
- questionsToAdd,
2919
- " More Question",
2920
- questionsToAdd !== 1 ? "s" : ""
2921
- ] })
2922
- }
2923
- ),
2924
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { ...defaultStyles.buttons, justifyContent: "flex-end" }, children: showFeedback ? (
2925
- // After viewing feedback
2926
- isLastQuestion ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2927
- "button",
2928
- {
2929
- style: {
2930
- ...defaultStyles.button,
2931
- ...isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
2932
- },
2933
- onClick: handleSubmit,
2934
- disabled: isSubmitting || isGeneratingExtra,
2935
- "data-testid": "button-submit-quiz",
2936
- children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
2937
- }
2938
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2939
- "button",
2940
- {
2941
- style: {
2942
- ...defaultStyles.button,
2943
- ...defaultStyles.buttonPrimary
2944
- },
2945
- onClick: handleContinue,
2946
- "data-testid": "button-continue",
2947
- children: "Continue"
2948
- }
2949
- )
2950
- ) : (
2951
- // Before checking answer
2952
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2953
- "button",
2954
- {
2955
- style: {
2956
- ...defaultStyles.button,
2957
- ...isNavigating || selectedAnswer === void 0 ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
2958
- },
2959
- onClick: handleCheckAnswer,
2960
- disabled: isNavigating || selectedAnswer === void 0,
2961
- "data-testid": "button-check-answer",
2962
- children: isNavigating ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Check Answer"
2963
- }
2964
- )
2965
- ) })
2966
- ] })
2967
- ] }),
2968
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: defaultStyles.chatPanel, children: apiClient.current && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2969
- QuestionChatPanel,
2970
- {
2971
- apiClient: apiClient.current,
2972
- question: {
2973
- id: currentQuestion.id,
2974
- question: currentQuestion.question,
2975
- type: currentQuestion.type,
2976
- options: currentQuestion.options,
2977
- correctAnswer: currentQuestion.correctAnswer,
2978
- explanation: currentQuestion.explanation
2979
- },
2980
- quizId: quiz.id,
2981
- childId,
2982
- parentId,
2983
- lessonId,
2984
- courseId,
2985
- answerResult: showFeedback && currentAnswerDetail ? {
2986
- wasIncorrect: currentQuestion.type !== "assessment" && !currentAnswerDetail.isCorrect,
2987
- selectedAnswer: typeof selectedAnswer === "string" ? selectedAnswer : Array.isArray(selectedAnswer) ? selectedAnswer.join(", ") : void 0,
2988
- correctAnswer: typeof currentQuestion.correctAnswer === "string" ? currentQuestion.correctAnswer : Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer.join(", ") : void 0,
2989
- explanation: currentQuestion.explanation
2990
- } : void 0
2991
- }
2992
- ) })
2993
- ] }) });
3410
+ ] }),
3411
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.chatPanel, children: apiClient.current && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3412
+ QuestionChatPanel,
3413
+ {
3414
+ apiClient: apiClient.current,
3415
+ question: {
3416
+ id: currentQuestion.id,
3417
+ question: currentQuestion.question,
3418
+ type: currentQuestion.type,
3419
+ options: currentQuestion.options,
3420
+ correctAnswer: currentQuestion.correctAnswer,
3421
+ explanation: currentQuestion.explanation
3422
+ },
3423
+ quizId: quiz.id,
3424
+ childId,
3425
+ parentId,
3426
+ lessonId,
3427
+ courseId,
3428
+ answerResult: showFeedback && currentAnswerDetail ? {
3429
+ wasIncorrect: currentQuestion.type !== "assessment" && !currentAnswerDetail.isCorrect,
3430
+ selectedAnswer: typeof selectedAnswer === "string" ? selectedAnswer : Array.isArray(selectedAnswer) ? selectedAnswer.join(", ") : void 0,
3431
+ correctAnswer: typeof currentQuestion.correctAnswer === "string" ? currentQuestion.correctAnswer : Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer.join(", ") : void 0,
3432
+ explanation: currentQuestion.explanation
3433
+ } : void 0
3434
+ }
3435
+ ) })
3436
+ ] })
3437
+ ] });
2994
3438
  }
2995
3439
 
2996
3440
  // src/AttemptViewer.tsx
2997
3441
  var import_react4 = require("react");
2998
- var import_jsx_runtime4 = require("react/jsx-runtime");
3442
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2999
3443
  var defaultStyles2 = {
3000
3444
  container: {
3001
3445
  fontFamily: "system-ui, -apple-system, sans-serif",
@@ -3138,7 +3582,12 @@ var defaultStyles2 = {
3138
3582
  marginTop: "12px",
3139
3583
  display: "flex",
3140
3584
  flexDirection: "column",
3141
- gap: "8px"
3585
+ gap: "8px",
3586
+ backgroundColor: "#ffffff",
3587
+ padding: "16px",
3588
+ borderRadius: "8px",
3589
+ border: "1px solid #e5e7eb",
3590
+ boxShadow: "0 1px 3px rgba(0, 0, 0, 0.05)"
3142
3591
  },
3143
3592
  chatMessage: {
3144
3593
  padding: "8px 12px",
@@ -3248,23 +3697,39 @@ function AttemptViewer({
3248
3697
  }) {
3249
3698
  const [attempt, setAttempt] = (0, import_react4.useState)(null);
3250
3699
  const [loading, setLoading] = (0, import_react4.useState)(true);
3251
- const [error, setError] = (0, import_react4.useState)(null);
3700
+ const [errorCode, setErrorCode] = (0, import_react4.useState)(null);
3252
3701
  const [chatHistories, setChatHistories] = (0, import_react4.useState)({});
3253
3702
  const [expandedChats, setExpandedChats] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
3703
+ const [fetchedAttemptId, setFetchedAttemptId] = (0, import_react4.useState)(null);
3704
+ const onErrorRef = (0, import_react4.useRef)(onError);
3705
+ onErrorRef.current = onError;
3254
3706
  (0, import_react4.useEffect)(() => {
3707
+ if (fetchedAttemptId === attemptId) return;
3255
3708
  const apiClient = new QuizApiClient({
3256
3709
  baseUrl: apiBaseUrl,
3257
3710
  authToken
3258
3711
  });
3259
3712
  async function fetchAttempt() {
3260
3713
  setLoading(true);
3261
- setError(null);
3714
+ setErrorCode(null);
3262
3715
  try {
3263
3716
  const response = await fetch(`${apiBaseUrl}/api/external/quiz-attempts/${attemptId}`, {
3264
3717
  headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
3265
3718
  });
3266
3719
  if (!response.ok) {
3267
- throw new Error(`Failed to fetch attempt: ${response.statusText}`);
3720
+ const code = getErrorFromHttpStatus(response.status, "attempt");
3721
+ setErrorCode(code);
3722
+ apiClient.logError({
3723
+ errorCode: code,
3724
+ context: "attempt",
3725
+ resourceId: attemptId,
3726
+ component: "AttemptViewer",
3727
+ message: `HTTP ${response.status}: ${response.statusText}`
3728
+ });
3729
+ onErrorRef.current?.(new Error(`Failed to fetch attempt: ${response.statusText}`));
3730
+ setLoading(false);
3731
+ setFetchedAttemptId(attemptId);
3732
+ return;
3268
3733
  }
3269
3734
  const data = await response.json();
3270
3735
  setAttempt(data);
@@ -3278,14 +3743,23 @@ function AttemptViewer({
3278
3743
  }
3279
3744
  } catch (err) {
3280
3745
  const errorMessage = err instanceof Error ? err.message : "Failed to load attempt";
3281
- setError(errorMessage);
3282
- onError?.(err instanceof Error ? err : new Error(errorMessage));
3746
+ const code = getErrorFromMessage(errorMessage, "attempt");
3747
+ setErrorCode(code);
3748
+ apiClient.logError({
3749
+ errorCode: code,
3750
+ context: "attempt",
3751
+ resourceId: attemptId,
3752
+ component: "AttemptViewer",
3753
+ message: errorMessage
3754
+ });
3755
+ onErrorRef.current?.(err instanceof Error ? err : new Error(errorMessage));
3283
3756
  } finally {
3284
3757
  setLoading(false);
3758
+ setFetchedAttemptId(attemptId);
3285
3759
  }
3286
3760
  }
3287
3761
  fetchAttempt();
3288
- }, [attemptId, apiBaseUrl, authToken, onError, showConversation]);
3762
+ }, [attemptId, apiBaseUrl, authToken, showConversation, fetchedAttemptId]);
3289
3763
  const toggleChatExpanded = (questionId) => {
3290
3764
  setExpandedChats((prev) => {
3291
3765
  const newSet = new Set(prev);
@@ -3299,53 +3773,49 @@ function AttemptViewer({
3299
3773
  };
3300
3774
  const handleRetry = () => {
3301
3775
  setLoading(true);
3302
- setError(null);
3776
+ setErrorCode(null);
3303
3777
  window.location.reload();
3304
3778
  };
3305
3779
  if (loading) {
3306
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.container, className, children: [
3307
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: spinnerKeyframes }),
3308
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.loading, children: [
3309
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.spinner }),
3310
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { marginTop: "16px", color: "#6b7280" }, children: "Loading attempt..." })
3780
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.container, className, children: [
3781
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: spinnerKeyframes }),
3782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.loading, children: [
3783
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.spinner }),
3784
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { marginTop: "16px", color: "#6b7280" }, children: "Loading attempt..." })
3311
3785
  ] })
3312
3786
  ] });
3313
3787
  }
3314
- if (error || !attempt) {
3315
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.container, className, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.error, children: [
3316
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontSize: "18px", fontWeight: "500" }, children: "Failed to load attempt" }),
3317
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { marginTop: "8px", color: "#6b7280" }, children: error }),
3318
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { style: defaultStyles2.retryButton, onClick: handleRetry, children: "Try Again" })
3319
- ] }) });
3788
+ if (errorCode || !attempt) {
3789
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.container, className, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MaintenanceScreen, { errorCode: errorCode || "ATTEMPT_NOT_FOUND" }) });
3320
3790
  }
3321
3791
  const scorePercentage = attempt.score ?? 0;
3322
3792
  const correctCount = attempt.correctAnswers ?? 0;
3323
3793
  const totalQuestions = attempt.totalQuestions;
3324
3794
  const timeSpent = attempt.timeSpentSeconds ?? 0;
3325
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.container, className, children: [
3326
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: spinnerKeyframes }),
3327
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.header, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryGrid, children: [
3328
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3329
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
3795
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.container, className, children: [
3796
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: spinnerKeyframes }),
3797
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.header, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryGrid, children: [
3798
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3799
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
3330
3800
  scorePercentage,
3331
3801
  "%"
3332
3802
  ] }),
3333
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Score" })
3803
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Score" })
3334
3804
  ] }),
3335
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3336
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
3805
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3806
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
3337
3807
  correctCount,
3338
3808
  "/",
3339
3809
  totalQuestions
3340
3810
  ] }),
3341
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
3811
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
3342
3812
  ] }),
3343
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3344
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.summaryValue, children: formatTime(timeSpent) }),
3345
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Time" })
3813
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
3814
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryValue, children: formatTime(timeSpent) }),
3815
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Time" })
3346
3816
  ] })
3347
3817
  ] }) }),
3348
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.questionsList, children: attempt.answers.map((answer, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3818
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.questionsList, children: attempt.answers.map((answer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3349
3819
  "div",
3350
3820
  {
3351
3821
  style: {
@@ -3353,12 +3823,12 @@ function AttemptViewer({
3353
3823
  ...answer.isCorrect ? defaultStyles2.questionCardCorrect : defaultStyles2.questionCardIncorrect
3354
3824
  },
3355
3825
  children: [
3356
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.questionHeader, children: [
3357
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: defaultStyles2.questionNumber, children: [
3826
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.questionHeader, children: [
3827
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: defaultStyles2.questionNumber, children: [
3358
3828
  "Question ",
3359
3829
  index + 1
3360
3830
  ] }),
3361
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3831
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3362
3832
  "span",
3363
3833
  {
3364
3834
  style: {
@@ -3369,35 +3839,35 @@ function AttemptViewer({
3369
3839
  }
3370
3840
  )
3371
3841
  ] }),
3372
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.questionText, children: answer.questionText }),
3373
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.answerSection, children: [
3374
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: defaultStyles2.answerLabel, children: "Your answer:" }),
3375
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: defaultStyles2.studentAnswer, children: formatAnswer(answer.selectedAnswer, answer.questionType, answer.items, answer.leftItems) })
3842
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.questionText, children: answer.questionText }),
3843
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.answerSection, children: [
3844
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.answerLabel, children: "Your answer:" }),
3845
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.studentAnswer, children: formatAnswer(answer.selectedAnswer, answer.questionType, answer.items, answer.leftItems) })
3376
3846
  ] }),
3377
- !answer.isCorrect && answer.correctAnswer && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.answerSection, children: [
3378
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: defaultStyles2.answerLabel, children: "Correct answer:" }),
3379
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: defaultStyles2.correctAnswer, children: answer.questionType === "sorting" && answer.items && answer.correctOrder ? formatCorrectSortingAnswer(answer.items, answer.correctOrder) : answer.questionType === "matrix" && answer.correctAnswer && typeof answer.correctAnswer === "object" && !Array.isArray(answer.correctAnswer) ? formatCorrectMatrixAnswer(answer.correctAnswer, answer.leftItems) : formatAnswer(answer.correctAnswer, answer.questionType, answer.items, answer.leftItems) })
3847
+ !answer.isCorrect && answer.correctAnswer && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.answerSection, children: [
3848
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.answerLabel, children: "Correct answer:" }),
3849
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.correctAnswer, children: answer.questionType === "sorting" && answer.items && answer.correctOrder ? formatCorrectSortingAnswer(answer.items, answer.correctOrder) : answer.questionType === "matrix" && answer.correctAnswer && typeof answer.correctAnswer === "object" && !Array.isArray(answer.correctAnswer) ? formatCorrectMatrixAnswer(answer.correctAnswer, answer.leftItems) : formatAnswer(answer.correctAnswer, answer.questionType, answer.items, answer.leftItems) })
3380
3850
  ] }),
3381
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.points, children: [
3851
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.points, children: [
3382
3852
  answer.pointsEarned,
3383
3853
  " / ",
3384
3854
  answer.points,
3385
3855
  " points"
3386
3856
  ] }),
3387
- showExplanations && answer.explanation && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.explanation, children: [
3388
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Explanation:" }),
3857
+ showExplanations && answer.explanation && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.explanation, children: [
3858
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Explanation:" }),
3389
3859
  " ",
3390
3860
  answer.explanation
3391
3861
  ] }),
3392
- showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles2.chatHistorySection, children: [
3393
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3862
+ showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.chatHistorySection, children: [
3863
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3394
3864
  "button",
3395
3865
  {
3396
3866
  style: defaultStyles2.chatToggleButton,
3397
3867
  onClick: () => toggleChatExpanded(answer.questionId),
3398
3868
  "data-testid": `button-toggle-chat-${answer.questionId}`,
3399
3869
  children: [
3400
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) }),
3870
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) }),
3401
3871
  expandedChats.has(answer.questionId) ? "Hide" : "View",
3402
3872
  " Chat History (",
3403
3873
  chatHistories[answer.questionId].messages.length,
@@ -3405,7 +3875,7 @@ function AttemptViewer({
3405
3875
  ]
3406
3876
  }
3407
3877
  ),
3408
- expandedChats.has(answer.questionId) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.chatMessages, children: chatHistories[answer.questionId].messages.map((msg, msgIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3878
+ expandedChats.has(answer.questionId) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.chatMessages, children: chatHistories[answer.questionId].messages.map((msg, msgIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3409
3879
  "div",
3410
3880
  {
3411
3881
  style: {
@@ -3423,15 +3893,621 @@ function AttemptViewer({
3423
3893
  )) })
3424
3894
  ] });
3425
3895
  }
3896
+
3897
+ // src/ErrorTypesPanel.tsx
3898
+ var import_jsx_runtime6 = require("react/jsx-runtime");
3899
+ var panelStyles2 = {
3900
+ container: {
3901
+ fontFamily: "system-ui, -apple-system, sans-serif",
3902
+ padding: "24px",
3903
+ backgroundColor: "#ffffff",
3904
+ borderRadius: "12px",
3905
+ maxWidth: "800px"
3906
+ },
3907
+ header: {
3908
+ marginBottom: "24px"
3909
+ },
3910
+ title: {
3911
+ fontSize: "20px",
3912
+ fontWeight: "600",
3913
+ color: "#111827",
3914
+ marginBottom: "8px"
3915
+ },
3916
+ subtitle: {
3917
+ fontSize: "14px",
3918
+ color: "#6b7280"
3919
+ },
3920
+ section: {
3921
+ marginBottom: "24px"
3922
+ },
3923
+ sectionTitle: {
3924
+ fontSize: "14px",
3925
+ fontWeight: "600",
3926
+ color: "#374151",
3927
+ marginBottom: "12px",
3928
+ textTransform: "uppercase",
3929
+ letterSpacing: "0.05em"
3930
+ },
3931
+ errorList: {
3932
+ display: "flex",
3933
+ flexDirection: "column",
3934
+ gap: "12px"
3935
+ },
3936
+ errorCard: {
3937
+ padding: "16px",
3938
+ backgroundColor: "#f9fafb",
3939
+ borderRadius: "8px",
3940
+ border: "1px solid #e5e7eb"
3941
+ },
3942
+ errorCardBlocking: {
3943
+ borderLeft: "4px solid #ef4444"
3944
+ },
3945
+ errorCardNonBlocking: {
3946
+ borderLeft: "4px solid #f59e0b"
3947
+ },
3948
+ errorHeader: {
3949
+ display: "flex",
3950
+ justifyContent: "space-between",
3951
+ alignItems: "flex-start",
3952
+ marginBottom: "8px"
3953
+ },
3954
+ errorCode: {
3955
+ fontSize: "13px",
3956
+ fontWeight: "600",
3957
+ color: "#1f2937",
3958
+ fontFamily: "monospace",
3959
+ backgroundColor: "#e5e7eb",
3960
+ padding: "2px 8px",
3961
+ borderRadius: "4px"
3962
+ },
3963
+ errorBadge: {
3964
+ fontSize: "11px",
3965
+ fontWeight: "500",
3966
+ padding: "2px 8px",
3967
+ borderRadius: "12px"
3968
+ },
3969
+ blockingBadge: {
3970
+ backgroundColor: "#fee2e2",
3971
+ color: "#dc2626"
3972
+ },
3973
+ nonBlockingBadge: {
3974
+ backgroundColor: "#fef3c7",
3975
+ color: "#d97706"
3976
+ },
3977
+ userMessage: {
3978
+ fontSize: "15px",
3979
+ fontWeight: "500",
3980
+ color: "#111827",
3981
+ marginBottom: "4px"
3982
+ },
3983
+ subMessage: {
3984
+ fontSize: "13px",
3985
+ color: "#6b7280",
3986
+ marginBottom: "8px"
3987
+ },
3988
+ causeLabel: {
3989
+ fontSize: "11px",
3990
+ fontWeight: "600",
3991
+ color: "#9ca3af",
3992
+ textTransform: "uppercase",
3993
+ marginBottom: "4px"
3994
+ },
3995
+ causeText: {
3996
+ fontSize: "13px",
3997
+ color: "#4b5563",
3998
+ fontStyle: "italic"
3999
+ }
4000
+ };
4001
+ function ErrorTypesPanel({ className }) {
4002
+ const blockingErrors = Object.values(ERROR_DEFINITIONS).filter((e) => e.isBlocking);
4003
+ const nonBlockingErrors = Object.values(ERROR_DEFINITIONS).filter((e) => !e.isBlocking);
4004
+ const renderErrorCard = (error) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4005
+ "div",
4006
+ {
4007
+ style: {
4008
+ ...panelStyles2.errorCard,
4009
+ ...error.isBlocking ? panelStyles2.errorCardBlocking : panelStyles2.errorCardNonBlocking
4010
+ },
4011
+ "data-testid": `error-card-${error.code}`,
4012
+ children: [
4013
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.errorHeader, children: [
4014
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { style: panelStyles2.errorCode, children: error.code }),
4015
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4016
+ "span",
4017
+ {
4018
+ style: {
4019
+ ...panelStyles2.errorBadge,
4020
+ ...error.isBlocking ? panelStyles2.blockingBadge : panelStyles2.nonBlockingBadge
4021
+ },
4022
+ children: error.isBlocking ? "Blocking" : "Non-Blocking"
4023
+ }
4024
+ )
4025
+ ] }),
4026
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.userMessage, children: error.userMessage }),
4027
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.subMessage, children: error.subMessage }),
4028
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.causeLabel, children: "Why this happens:" }),
4029
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.causeText, children: error.cause })
4030
+ ]
4031
+ },
4032
+ error.code
4033
+ );
4034
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.container, className, "data-testid": "error-types-panel", children: [
4035
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.header, children: [
4036
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { style: panelStyles2.title, children: "Error Types Reference" }),
4037
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: panelStyles2.subtitle, children: "List of all error types that can occur in the quiz components, with user-facing messages and technical causes." })
4038
+ ] }),
4039
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.section, children: [
4040
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: panelStyles2.sectionTitle, children: [
4041
+ "Blocking Errors (",
4042
+ blockingErrors.length,
4043
+ ")"
4044
+ ] }),
4045
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { ...panelStyles2.subtitle, marginBottom: "12px" }, children: "These errors prevent the quiz from loading or continuing. Users see a full-screen error message." }),
4046
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.errorList, children: blockingErrors.map(renderErrorCard) })
4047
+ ] }),
4048
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.section, children: [
4049
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: panelStyles2.sectionTitle, children: [
4050
+ "Non-Blocking Errors (",
4051
+ nonBlockingErrors.length,
4052
+ ")"
4053
+ ] }),
4054
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { ...panelStyles2.subtitle, marginBottom: "12px" }, children: "These errors affect specific features but allow the quiz to continue. Users may see a toast notification." }),
4055
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.errorList, children: nonBlockingErrors.map(renderErrorCard) })
4056
+ ] })
4057
+ ] });
4058
+ }
4059
+
4060
+ // src/ErrorLogsPanel.tsx
4061
+ var import_react5 = require("react");
4062
+ var import_jsx_runtime7 = require("react/jsx-runtime");
4063
+ var panelStyles3 = {
4064
+ container: {
4065
+ fontFamily: "system-ui, -apple-system, sans-serif",
4066
+ padding: "24px",
4067
+ backgroundColor: "#ffffff",
4068
+ borderRadius: "12px",
4069
+ maxWidth: "1000px"
4070
+ },
4071
+ header: {
4072
+ marginBottom: "24px"
4073
+ },
4074
+ title: {
4075
+ fontSize: "20px",
4076
+ fontWeight: "600",
4077
+ color: "#111827",
4078
+ marginBottom: "8px"
4079
+ },
4080
+ subtitle: {
4081
+ fontSize: "14px",
4082
+ color: "#6b7280"
4083
+ },
4084
+ tabs: {
4085
+ display: "flex",
4086
+ gap: "8px",
4087
+ marginBottom: "16px",
4088
+ borderBottom: "1px solid #e5e7eb",
4089
+ paddingBottom: "12px"
4090
+ },
4091
+ tab: {
4092
+ padding: "8px 16px",
4093
+ fontSize: "14px",
4094
+ fontWeight: "500",
4095
+ borderRadius: "6px",
4096
+ cursor: "pointer",
4097
+ border: "none",
4098
+ backgroundColor: "transparent",
4099
+ color: "#6b7280"
4100
+ },
4101
+ tabActive: {
4102
+ backgroundColor: "#6721b0",
4103
+ color: "#ffffff"
4104
+ },
4105
+ stats: {
4106
+ display: "flex",
4107
+ gap: "16px",
4108
+ marginBottom: "20px"
4109
+ },
4110
+ statCard: {
4111
+ padding: "12px 16px",
4112
+ backgroundColor: "#f9fafb",
4113
+ borderRadius: "8px",
4114
+ flex: 1
4115
+ },
4116
+ statValue: {
4117
+ fontSize: "24px",
4118
+ fontWeight: "700",
4119
+ color: "#111827"
4120
+ },
4121
+ statLabel: {
4122
+ fontSize: "12px",
4123
+ color: "#6b7280",
4124
+ textTransform: "uppercase",
4125
+ letterSpacing: "0.05em"
4126
+ },
4127
+ errorList: {
4128
+ display: "flex",
4129
+ flexDirection: "column",
4130
+ gap: "12px"
4131
+ },
4132
+ errorCard: {
4133
+ padding: "16px",
4134
+ backgroundColor: "#f9fafb",
4135
+ borderRadius: "8px",
4136
+ border: "1px solid #e5e7eb"
4137
+ },
4138
+ errorCardRecent: {
4139
+ borderLeft: "4px solid #ef4444",
4140
+ backgroundColor: "#fef2f2"
4141
+ },
4142
+ errorCardOld: {
4143
+ borderLeft: "4px solid #9ca3af",
4144
+ opacity: 0.7
4145
+ },
4146
+ errorHeader: {
4147
+ display: "flex",
4148
+ justifyContent: "space-between",
4149
+ alignItems: "flex-start",
4150
+ marginBottom: "8px"
4151
+ },
4152
+ errorLeft: {
4153
+ flex: 1
4154
+ },
4155
+ errorCode: {
4156
+ fontSize: "13px",
4157
+ fontWeight: "600",
4158
+ color: "#1f2937",
4159
+ fontFamily: "monospace",
4160
+ backgroundColor: "#e5e7eb",
4161
+ padding: "2px 8px",
4162
+ borderRadius: "4px",
4163
+ display: "inline-block"
4164
+ },
4165
+ countBadge: {
4166
+ fontSize: "14px",
4167
+ fontWeight: "700",
4168
+ padding: "4px 12px",
4169
+ borderRadius: "16px",
4170
+ backgroundColor: "#ef4444",
4171
+ color: "#ffffff"
4172
+ },
4173
+ countBadgeLow: {
4174
+ backgroundColor: "#f59e0b"
4175
+ },
4176
+ contextBadge: {
4177
+ fontSize: "11px",
4178
+ fontWeight: "500",
4179
+ padding: "2px 8px",
4180
+ borderRadius: "4px",
4181
+ marginLeft: "8px",
4182
+ backgroundColor: "#dbeafe",
4183
+ color: "#1d4ed8"
4184
+ },
4185
+ userMessage: {
4186
+ fontSize: "15px",
4187
+ fontWeight: "500",
4188
+ color: "#111827",
4189
+ marginTop: "8px",
4190
+ marginBottom: "4px"
4191
+ },
4192
+ resourceId: {
4193
+ fontSize: "12px",
4194
+ color: "#6b7280",
4195
+ fontFamily: "monospace",
4196
+ marginTop: "4px"
4197
+ },
4198
+ resourceLink: {
4199
+ color: "#6721b0",
4200
+ textDecoration: "underline",
4201
+ cursor: "pointer"
4202
+ },
4203
+ timestamps: {
4204
+ display: "flex",
4205
+ gap: "16px",
4206
+ marginTop: "8px",
4207
+ fontSize: "12px",
4208
+ color: "#9ca3af"
4209
+ },
4210
+ dismissButton: {
4211
+ padding: "6px 12px",
4212
+ fontSize: "12px",
4213
+ fontWeight: "500",
4214
+ borderRadius: "4px",
4215
+ cursor: "pointer",
4216
+ border: "1px solid #e5e7eb",
4217
+ backgroundColor: "#ffffff",
4218
+ color: "#6b7280",
4219
+ marginTop: "8px"
4220
+ },
4221
+ dismissButtonHover: {
4222
+ backgroundColor: "#f3f4f6"
4223
+ },
4224
+ emptyState: {
4225
+ textAlign: "center",
4226
+ padding: "40px",
4227
+ color: "#9ca3af",
4228
+ fontSize: "14px"
4229
+ },
4230
+ loading: {
4231
+ textAlign: "center",
4232
+ padding: "40px",
4233
+ color: "#6b7280",
4234
+ fontSize: "14px"
4235
+ },
4236
+ pagination: {
4237
+ display: "flex",
4238
+ justifyContent: "center",
4239
+ gap: "8px",
4240
+ marginTop: "20px"
4241
+ },
4242
+ pageButton: {
4243
+ padding: "8px 12px",
4244
+ fontSize: "14px",
4245
+ borderRadius: "4px",
4246
+ cursor: "pointer",
4247
+ border: "1px solid #e5e7eb",
4248
+ backgroundColor: "#ffffff",
4249
+ color: "#374151"
4250
+ },
4251
+ pageButtonDisabled: {
4252
+ opacity: 0.5,
4253
+ cursor: "not-allowed"
4254
+ }
4255
+ };
4256
+ function formatRelativeTime(dateStr) {
4257
+ const date = new Date(dateStr);
4258
+ const now = /* @__PURE__ */ new Date();
4259
+ const diffMs = now.getTime() - date.getTime();
4260
+ const diffMins = Math.floor(diffMs / 6e4);
4261
+ const diffHours = Math.floor(diffMs / 36e5);
4262
+ const diffDays = Math.floor(diffMs / 864e5);
4263
+ if (diffMins < 1) return "Just now";
4264
+ if (diffMins < 60) return `${diffMins}m ago`;
4265
+ if (diffHours < 24) return `${diffHours}h ago`;
4266
+ if (diffDays < 7) return `${diffDays}d ago`;
4267
+ return date.toLocaleDateString();
4268
+ }
4269
+ function isRecent(dateStr) {
4270
+ const date = new Date(dateStr);
4271
+ const now = /* @__PURE__ */ new Date();
4272
+ const diffMs = now.getTime() - date.getTime();
4273
+ const diffHours = diffMs / 36e5;
4274
+ return diffHours < 24;
4275
+ }
4276
+ function ErrorLogsPanel({ apiBaseUrl, authToken, onResourceClick }) {
4277
+ const [logs, setLogs] = (0, import_react5.useState)([]);
4278
+ const [loading, setLoading] = (0, import_react5.useState)(true);
4279
+ const [showDismissed, setShowDismissed] = (0, import_react5.useState)(false);
4280
+ const [page, setPage] = (0, import_react5.useState)(1);
4281
+ const [totalPages, setTotalPages] = (0, import_react5.useState)(1);
4282
+ const [total, setTotal] = (0, import_react5.useState)(0);
4283
+ (0, import_react5.useEffect)(() => {
4284
+ fetchLogs();
4285
+ }, [showDismissed, page]);
4286
+ async function fetchLogs() {
4287
+ setLoading(true);
4288
+ try {
4289
+ const params = new URLSearchParams();
4290
+ params.set("dismissed", showDismissed ? "true" : "false");
4291
+ params.set("page", page.toString());
4292
+ params.set("limit", "20");
4293
+ const response = await fetch(`${apiBaseUrl}/api/admin/error-logs?${params}`, {
4294
+ headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
4295
+ });
4296
+ if (response.ok) {
4297
+ const data = await response.json();
4298
+ setLogs(data.items || []);
4299
+ setTotalPages(data.totalPages || 1);
4300
+ setTotal(data.total || 0);
4301
+ }
4302
+ } catch (err) {
4303
+ console.error("Failed to fetch error logs:", err);
4304
+ } finally {
4305
+ setLoading(false);
4306
+ }
4307
+ }
4308
+ async function handleDismiss(id) {
4309
+ try {
4310
+ const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/dismiss`, {
4311
+ method: "PATCH",
4312
+ headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
4313
+ });
4314
+ if (response.ok) {
4315
+ fetchLogs();
4316
+ }
4317
+ } catch (err) {
4318
+ console.error("Failed to dismiss error:", err);
4319
+ }
4320
+ }
4321
+ async function handleUndismiss(id) {
4322
+ try {
4323
+ const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/undismiss`, {
4324
+ method: "PATCH",
4325
+ headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
4326
+ });
4327
+ if (response.ok) {
4328
+ fetchLogs();
4329
+ }
4330
+ } catch (err) {
4331
+ console.error("Failed to undismiss error:", err);
4332
+ }
4333
+ }
4334
+ function getErrorDefinition(code) {
4335
+ return ERROR_DEFINITIONS[code];
4336
+ }
4337
+ const totalErrors = logs.reduce((sum, log) => sum + log.count, 0);
4338
+ const recentCount = logs.filter((log) => isRecent(log.lastSeenAt)).length;
4339
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.container, "data-testid": "error-logs-panel", children: [
4340
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.header, children: [
4341
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: panelStyles3.title, children: "Error Tracking" }),
4342
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: panelStyles3.subtitle, children: "Aggregated errors from QuizPlayer and AttemptViewer components, sorted by occurrence count" })
4343
+ ] }),
4344
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.tabs, children: [
4345
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4346
+ "button",
4347
+ {
4348
+ style: {
4349
+ ...panelStyles3.tab,
4350
+ ...showDismissed ? {} : panelStyles3.tabActive
4351
+ },
4352
+ onClick: () => {
4353
+ setShowDismissed(false);
4354
+ setPage(1);
4355
+ },
4356
+ "data-testid": "tab-active-errors",
4357
+ children: "Active Errors"
4358
+ }
4359
+ ),
4360
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4361
+ "button",
4362
+ {
4363
+ style: {
4364
+ ...panelStyles3.tab,
4365
+ ...showDismissed ? panelStyles3.tabActive : {}
4366
+ },
4367
+ onClick: () => {
4368
+ setShowDismissed(true);
4369
+ setPage(1);
4370
+ },
4371
+ "data-testid": "tab-dismissed-errors",
4372
+ children: "Dismissed"
4373
+ }
4374
+ )
4375
+ ] }),
4376
+ !showDismissed && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.stats, children: [
4377
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
4378
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statValue, children: total }),
4379
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Unique Errors" })
4380
+ ] }),
4381
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
4382
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statValue, children: totalErrors }),
4383
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Total Occurrences" })
4384
+ ] }),
4385
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
4386
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...panelStyles3.statValue, color: recentCount > 0 ? "#ef4444" : "#22c55e" }, children: recentCount }),
4387
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Last 24h" })
4388
+ ] })
4389
+ ] }),
4390
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.loading, children: "Loading..." }) : logs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.emptyState, children: showDismissed ? "No dismissed errors" : "No active errors" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.errorList, children: logs.map((log) => {
4391
+ const def = getErrorDefinition(log.errorCode);
4392
+ const recent = isRecent(log.lastSeenAt);
4393
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
4394
+ "div",
4395
+ {
4396
+ style: {
4397
+ ...panelStyles3.errorCard,
4398
+ ...recent ? panelStyles3.errorCardRecent : panelStyles3.errorCardOld
4399
+ },
4400
+ "data-testid": `error-log-${log.id}`,
4401
+ children: [
4402
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.errorHeader, children: [
4403
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.errorLeft, children: [
4404
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: panelStyles3.errorCode, children: log.errorCode }),
4405
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: panelStyles3.contextBadge, children: log.context }),
4406
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...panelStyles3.contextBadge, backgroundColor: "#f3e8ff", color: "#7c3aed" }, children: log.component })
4407
+ ] }),
4408
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
4409
+ "span",
4410
+ {
4411
+ style: {
4412
+ ...panelStyles3.countBadge,
4413
+ ...log.count < 10 ? panelStyles3.countBadgeLow : {}
4414
+ },
4415
+ children: [
4416
+ log.count,
4417
+ "x"
4418
+ ]
4419
+ }
4420
+ )
4421
+ ] }),
4422
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.userMessage, children: def?.userMessage || log.lastMessage || "Unknown error" }),
4423
+ log.resourceId && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.resourceId, children: [
4424
+ "Resource:",
4425
+ " ",
4426
+ onResourceClick ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4427
+ "span",
4428
+ {
4429
+ style: panelStyles3.resourceLink,
4430
+ onClick: () => onResourceClick(log.resourceId, log.context),
4431
+ "data-testid": `link-resource-${log.id}`,
4432
+ children: log.resourceId
4433
+ }
4434
+ ) : log.resourceId
4435
+ ] }),
4436
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.timestamps, children: [
4437
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
4438
+ "First: ",
4439
+ formatRelativeTime(log.firstSeenAt)
4440
+ ] }),
4441
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
4442
+ "Last: ",
4443
+ formatRelativeTime(log.lastSeenAt)
4444
+ ] })
4445
+ ] }),
4446
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4447
+ "button",
4448
+ {
4449
+ style: panelStyles3.dismissButton,
4450
+ onClick: () => showDismissed ? handleUndismiss(log.id) : handleDismiss(log.id),
4451
+ "data-testid": `button-dismiss-${log.id}`,
4452
+ children: showDismissed ? "Restore" : "Dismiss"
4453
+ }
4454
+ )
4455
+ ]
4456
+ },
4457
+ log.id
4458
+ );
4459
+ }) }),
4460
+ totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.pagination, children: [
4461
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4462
+ "button",
4463
+ {
4464
+ style: {
4465
+ ...panelStyles3.pageButton,
4466
+ ...page <= 1 ? panelStyles3.pageButtonDisabled : {}
4467
+ },
4468
+ onClick: () => setPage((p) => Math.max(1, p - 1)),
4469
+ disabled: page <= 1,
4470
+ "data-testid": "button-prev-page",
4471
+ children: "Previous"
4472
+ }
4473
+ ),
4474
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { padding: "8px 12px", color: "#6b7280" }, children: [
4475
+ "Page ",
4476
+ page,
4477
+ " of ",
4478
+ totalPages
4479
+ ] }),
4480
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4481
+ "button",
4482
+ {
4483
+ style: {
4484
+ ...panelStyles3.pageButton,
4485
+ ...page >= totalPages ? panelStyles3.pageButtonDisabled : {}
4486
+ },
4487
+ onClick: () => setPage((p) => Math.min(totalPages, p + 1)),
4488
+ disabled: page >= totalPages,
4489
+ "data-testid": "button-next-page",
4490
+ children: "Next"
4491
+ }
4492
+ )
4493
+ ] })
4494
+ ] });
4495
+ }
3426
4496
  // Annotate the CommonJS export names for ESM import in node:
3427
4497
  0 && (module.exports = {
3428
4498
  AttemptViewer,
4499
+ ERROR_DEFINITIONS,
4500
+ ErrorLogsPanel,
4501
+ ErrorTypesPanel,
4502
+ MaintenanceScreen,
3429
4503
  QuizApiClient,
3430
4504
  QuizPlayer,
3431
4505
  TextToSpeech,
3432
4506
  calculateScore,
3433
4507
  checkAnswer,
3434
4508
  createAnswerDetail,
3435
- formatTime
4509
+ formatTime,
4510
+ getErrorFromHttpStatus,
4511
+ getErrorFromMessage
3436
4512
  });
3437
4513
  //# sourceMappingURL=index.js.map