@schoolio/player 1.4.4 → 1.4.5
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.d.mts +51 -2
- package/dist/index.d.ts +51 -2
- package/dist/index.js +1238 -268
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1232 -268
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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/
|
|
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",
|
|
@@ -1420,7 +1616,7 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
|
|
|
1420
1616
|
setDraggedIndex(null);
|
|
1421
1617
|
setDragOverIndex(null);
|
|
1422
1618
|
};
|
|
1423
|
-
return /* @__PURE__ */ (0,
|
|
1619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentOrder.map((itemIndex, position) => {
|
|
1424
1620
|
const isCorrectPosition = correctOrder?.[position] === itemIndex;
|
|
1425
1621
|
const isDragging = draggedIndex === position;
|
|
1426
1622
|
const isDragOver = dragOverIndex === position;
|
|
@@ -1443,7 +1639,7 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
|
|
|
1443
1639
|
} else if (isDragOver) {
|
|
1444
1640
|
itemStyle = { ...itemStyle, borderColor: "#6366f1", backgroundColor: "#eef2ff" };
|
|
1445
1641
|
}
|
|
1446
|
-
return /* @__PURE__ */ (0,
|
|
1642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1447
1643
|
"div",
|
|
1448
1644
|
{
|
|
1449
1645
|
style: itemStyle,
|
|
@@ -1455,34 +1651,34 @@ function SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOr
|
|
|
1455
1651
|
onDrop: (e) => handleDrop(e, position),
|
|
1456
1652
|
onDragEnd: handleDragEnd,
|
|
1457
1653
|
children: [
|
|
1458
|
-
!showFeedback && /* @__PURE__ */ (0,
|
|
1654
|
+
!showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
1459
1655
|
cursor: "grab",
|
|
1460
1656
|
padding: "4px",
|
|
1461
1657
|
display: "flex",
|
|
1462
1658
|
alignItems: "center",
|
|
1463
1659
|
color: "#9ca3af"
|
|
1464
|
-
}, children: /* @__PURE__ */ (0,
|
|
1465
|
-
/* @__PURE__ */ (0,
|
|
1466
|
-
/* @__PURE__ */ (0,
|
|
1467
|
-
/* @__PURE__ */ (0,
|
|
1468
|
-
/* @__PURE__ */ (0,
|
|
1469
|
-
/* @__PURE__ */ (0,
|
|
1470
|
-
/* @__PURE__ */ (0,
|
|
1660
|
+
}, 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: [
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
|
|
1662
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
|
|
1663
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
|
|
1666
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "19", r: "1" })
|
|
1471
1667
|
] }) }),
|
|
1472
|
-
showFeedback && /* @__PURE__ */ (0,
|
|
1668
|
+
showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
1473
1669
|
display: "flex",
|
|
1474
1670
|
alignItems: "center",
|
|
1475
1671
|
color: isCorrectPosition ? "#22c55e" : "#ef4444"
|
|
1476
|
-
}, children: isCorrectPosition ? /* @__PURE__ */ (0,
|
|
1477
|
-
/* @__PURE__ */ (0,
|
|
1478
|
-
/* @__PURE__ */ (0,
|
|
1479
|
-
] }) : /* @__PURE__ */ (0,
|
|
1480
|
-
/* @__PURE__ */ (0,
|
|
1481
|
-
/* @__PURE__ */ (0,
|
|
1482
|
-
/* @__PURE__ */ (0,
|
|
1672
|
+
}, 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: [
|
|
1673
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
|
|
1675
|
+
] }) : /* @__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: [
|
|
1676
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1677
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
|
|
1678
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
1483
1679
|
] }) }),
|
|
1484
|
-
/* @__PURE__ */ (0,
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: items[itemIndex] }),
|
|
1681
|
+
/* @__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
1682
|
]
|
|
1487
1683
|
},
|
|
1488
1684
|
itemIndex
|
|
@@ -1536,9 +1732,9 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1536
1732
|
delete newMatches[leftItem];
|
|
1537
1733
|
onMatchChange(newMatches);
|
|
1538
1734
|
};
|
|
1539
|
-
return /* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
1541
|
-
/* @__PURE__ */ (0,
|
|
1735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "24px", flexWrap: "wrap" }, children: [
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Match these items:" }),
|
|
1542
1738
|
leftItems.map((leftItem, idx) => {
|
|
1543
1739
|
const matchedRight = currentMatches[leftItem];
|
|
1544
1740
|
const correctMatch = correctMatches?.[leftItem];
|
|
@@ -1567,7 +1763,7 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1567
1763
|
} else if (matchedRight) {
|
|
1568
1764
|
rowStyle = { ...rowStyle, borderStyle: "solid", borderColor: "#22c55e" };
|
|
1569
1765
|
}
|
|
1570
|
-
return /* @__PURE__ */ (0,
|
|
1766
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1571
1767
|
"div",
|
|
1572
1768
|
{
|
|
1573
1769
|
style: rowStyle,
|
|
@@ -1576,9 +1772,9 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1576
1772
|
onDragLeave: handleDragLeave,
|
|
1577
1773
|
onDrop: (e) => handleDrop(e, leftItem),
|
|
1578
1774
|
children: [
|
|
1579
|
-
/* @__PURE__ */ (0,
|
|
1580
|
-
/* @__PURE__ */ (0,
|
|
1581
|
-
matchedRight ? /* @__PURE__ */ (0,
|
|
1775
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1, fontWeight: "500" }, children: leftItem }),
|
|
1776
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#6b7280" }, children: "\u2192" }),
|
|
1777
|
+
matchedRight ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
|
|
1582
1778
|
display: "flex",
|
|
1583
1779
|
alignItems: "center",
|
|
1584
1780
|
gap: "8px",
|
|
@@ -1587,8 +1783,8 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1587
1783
|
borderRadius: "6px",
|
|
1588
1784
|
fontSize: "14px"
|
|
1589
1785
|
}, children: [
|
|
1590
|
-
/* @__PURE__ */ (0,
|
|
1591
|
-
!showFeedback && /* @__PURE__ */ (0,
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: matchedRight }),
|
|
1787
|
+
!showFeedback && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1592
1788
|
"button",
|
|
1593
1789
|
{
|
|
1594
1790
|
onClick: () => handleClearMatch(leftItem),
|
|
@@ -1601,18 +1797,18 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1601
1797
|
color: "#6b7280"
|
|
1602
1798
|
},
|
|
1603
1799
|
"aria-label": "Remove match",
|
|
1604
|
-
children: /* @__PURE__ */ (0,
|
|
1605
|
-
/* @__PURE__ */ (0,
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1800
|
+
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: [
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1802
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1607
1803
|
] })
|
|
1608
1804
|
}
|
|
1609
1805
|
),
|
|
1610
|
-
showFeedback && (isCorrect ? /* @__PURE__ */ (0,
|
|
1611
|
-
/* @__PURE__ */ (0,
|
|
1612
|
-
/* @__PURE__ */ (0,
|
|
1806
|
+
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: [
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1613
1809
|
] }))
|
|
1614
|
-
] }) : /* @__PURE__ */ (0,
|
|
1615
|
-
showFeedback && !isCorrect && correctMatch && /* @__PURE__ */ (0,
|
|
1810
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#9ca3af", fontSize: "14px", fontStyle: "italic" }, children: "Drop here" }),
|
|
1811
|
+
showFeedback && !isCorrect && correctMatch && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: "#166534", fontSize: "13px", marginLeft: "8px" }, children: [
|
|
1616
1812
|
"(Correct: ",
|
|
1617
1813
|
correctMatch,
|
|
1618
1814
|
")"
|
|
@@ -1623,11 +1819,11 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1623
1819
|
);
|
|
1624
1820
|
})
|
|
1625
1821
|
] }),
|
|
1626
|
-
/* @__PURE__ */ (0,
|
|
1627
|
-
/* @__PURE__ */ (0,
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { flex: 1, minWidth: "200px", display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", fontWeight: "600", color: "#6b7280", marginBottom: "4px" }, children: "Drag to match:" }),
|
|
1628
1824
|
unmatchedRightItems.length > 0 ? unmatchedRightItems.map((rightItem, idx) => {
|
|
1629
1825
|
const isDragging = draggedItem === rightItem;
|
|
1630
|
-
return /* @__PURE__ */ (0,
|
|
1826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1631
1827
|
"div",
|
|
1632
1828
|
{
|
|
1633
1829
|
style: {
|
|
@@ -1647,20 +1843,20 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1647
1843
|
onDragEnd: handleDragEnd,
|
|
1648
1844
|
"data-testid": `draggable-right-${idx}`,
|
|
1649
1845
|
children: [
|
|
1650
|
-
!showFeedback && /* @__PURE__ */ (0,
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1652
|
-
/* @__PURE__ */ (0,
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
1654
|
-
/* @__PURE__ */ (0,
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
1656
|
-
/* @__PURE__ */ (0,
|
|
1846
|
+
!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: [
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
|
|
1848
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
|
|
1849
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
|
|
1852
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "15", cy: "19", r: "1" })
|
|
1657
1853
|
] }) }),
|
|
1658
|
-
/* @__PURE__ */ (0,
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: rightItem })
|
|
1659
1855
|
]
|
|
1660
1856
|
},
|
|
1661
1857
|
idx
|
|
1662
1858
|
);
|
|
1663
|
-
}) : /* @__PURE__ */ (0,
|
|
1859
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
1664
1860
|
padding: "16px",
|
|
1665
1861
|
textAlign: "center",
|
|
1666
1862
|
color: "#22c55e",
|
|
@@ -1670,7 +1866,7 @@ function MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatche
|
|
|
1670
1866
|
] });
|
|
1671
1867
|
}
|
|
1672
1868
|
function Spinner({ size = 16, color = "#ffffff" }) {
|
|
1673
|
-
return /* @__PURE__ */ (0,
|
|
1869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1674
1870
|
"span",
|
|
1675
1871
|
{
|
|
1676
1872
|
style: {
|
|
@@ -1682,7 +1878,7 @@ function Spinner({ size = 16, color = "#ffffff" }) {
|
|
|
1682
1878
|
borderRadius: "50%",
|
|
1683
1879
|
animation: "spin 0.8s linear infinite"
|
|
1684
1880
|
},
|
|
1685
|
-
children: /* @__PURE__ */ (0,
|
|
1881
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
|
|
1686
1882
|
}
|
|
1687
1883
|
);
|
|
1688
1884
|
}
|
|
@@ -1700,7 +1896,8 @@ function QuizPlayer({
|
|
|
1700
1896
|
onProgress,
|
|
1701
1897
|
onGenerateMoreQuestions,
|
|
1702
1898
|
className,
|
|
1703
|
-
forceNewAttempt = true
|
|
1899
|
+
forceNewAttempt = true,
|
|
1900
|
+
hideScore = false
|
|
1704
1901
|
}) {
|
|
1705
1902
|
const [quiz, setQuiz] = (0, import_react3.useState)(null);
|
|
1706
1903
|
const [attempt, setAttempt] = (0, import_react3.useState)(null);
|
|
@@ -1711,10 +1908,14 @@ function QuizPlayer({
|
|
|
1711
1908
|
const [isNavigating, setIsNavigating] = (0, import_react3.useState)(false);
|
|
1712
1909
|
const [isCompleted, setIsCompleted] = (0, import_react3.useState)(false);
|
|
1713
1910
|
const [result, setResult] = (0, import_react3.useState)(null);
|
|
1714
|
-
const [
|
|
1911
|
+
const [errorCode, setErrorCode] = (0, import_react3.useState)(null);
|
|
1715
1912
|
const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
|
|
1716
1913
|
const [elapsedSeconds, setElapsedSeconds] = (0, import_react3.useState)(0);
|
|
1717
1914
|
const [showIntro, setShowIntro] = (0, import_react3.useState)(true);
|
|
1915
|
+
const [showResumeChoice, setShowResumeChoice] = (0, import_react3.useState)(false);
|
|
1916
|
+
const [hasExistingProgress, setHasExistingProgress] = (0, import_react3.useState)(false);
|
|
1917
|
+
const [existingProgressCount, setExistingProgressCount] = (0, import_react3.useState)(0);
|
|
1918
|
+
const [isStartingFresh, setIsStartingFresh] = (0, import_react3.useState)(false);
|
|
1718
1919
|
const [timerStarted, setTimerStarted] = (0, import_react3.useState)(false);
|
|
1719
1920
|
const [showFeedback, setShowFeedback] = (0, import_react3.useState)(false);
|
|
1720
1921
|
const [currentAnswerDetail, setCurrentAnswerDetail] = (0, import_react3.useState)(null);
|
|
@@ -1749,7 +1950,7 @@ function QuizPlayer({
|
|
|
1749
1950
|
if (!apiClient.current) return;
|
|
1750
1951
|
try {
|
|
1751
1952
|
setIsLoading(true);
|
|
1752
|
-
|
|
1953
|
+
setErrorCode(null);
|
|
1753
1954
|
const quizData = await apiClient.current.getQuiz(quizId);
|
|
1754
1955
|
setQuiz(quizData);
|
|
1755
1956
|
const attemptData = await apiClient.current.createAttempt({
|
|
@@ -1762,7 +1963,10 @@ function QuizPlayer({
|
|
|
1762
1963
|
forceNew: forceNewAttempt
|
|
1763
1964
|
});
|
|
1764
1965
|
setAttempt(attemptData);
|
|
1765
|
-
if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0) {
|
|
1966
|
+
if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0 && attemptData.status === "in_progress") {
|
|
1967
|
+
setHasExistingProgress(true);
|
|
1968
|
+
setExistingProgressCount(attemptData.answers.length);
|
|
1969
|
+
setShowResumeChoice(true);
|
|
1766
1970
|
setAnswersDetail(attemptData.answers);
|
|
1767
1971
|
const answersMap = /* @__PURE__ */ new Map();
|
|
1768
1972
|
attemptData.answers.forEach((a) => {
|
|
@@ -1785,7 +1989,15 @@ function QuizPlayer({
|
|
|
1785
1989
|
setIsLoading(false);
|
|
1786
1990
|
} catch (err) {
|
|
1787
1991
|
const message = err instanceof Error ? err.message : "Failed to load quiz";
|
|
1788
|
-
|
|
1992
|
+
const code = getErrorFromMessage(message, "quiz");
|
|
1993
|
+
setErrorCode(code);
|
|
1994
|
+
apiClient.current?.logError({
|
|
1995
|
+
errorCode: code,
|
|
1996
|
+
context: "quiz",
|
|
1997
|
+
resourceId: quizId,
|
|
1998
|
+
component: "QuizPlayer",
|
|
1999
|
+
message
|
|
2000
|
+
});
|
|
1789
2001
|
setIsLoading(false);
|
|
1790
2002
|
onErrorRef.current?.(err instanceof Error ? err : new Error(message));
|
|
1791
2003
|
}
|
|
@@ -1793,7 +2005,7 @@ function QuizPlayer({
|
|
|
1793
2005
|
initialize();
|
|
1794
2006
|
}, [quizId, lessonId, assignLessonId, courseId, childId, parentId, forceNewAttempt]);
|
|
1795
2007
|
(0, import_react3.useEffect)(() => {
|
|
1796
|
-
if (timerStarted && !isCompleted && !
|
|
2008
|
+
if (timerStarted && !isCompleted && !errorCode) {
|
|
1797
2009
|
startTimeRef.current = Date.now();
|
|
1798
2010
|
timerRef.current = setInterval(() => {
|
|
1799
2011
|
setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
|
|
@@ -1804,11 +2016,62 @@ function QuizPlayer({
|
|
|
1804
2016
|
clearInterval(timerRef.current);
|
|
1805
2017
|
}
|
|
1806
2018
|
};
|
|
1807
|
-
}, [timerStarted, isCompleted,
|
|
2019
|
+
}, [timerStarted, isCompleted, errorCode]);
|
|
1808
2020
|
const handleStart = (0, import_react3.useCallback)(() => {
|
|
1809
2021
|
setShowIntro(false);
|
|
2022
|
+
setShowResumeChoice(false);
|
|
1810
2023
|
setTimerStarted(true);
|
|
1811
2024
|
}, []);
|
|
2025
|
+
const handleResumePrevious = (0, import_react3.useCallback)(() => {
|
|
2026
|
+
if (quiz && answers.size > 0) {
|
|
2027
|
+
const answeredIds = new Set(answers.keys());
|
|
2028
|
+
const allQs = [...quiz.questions, ...extraQuestions].filter((q) => !skippedQuestionIds.has(q.id));
|
|
2029
|
+
let resumeIndex = 0;
|
|
2030
|
+
for (let i = 0; i < allQs.length; i++) {
|
|
2031
|
+
if (!answeredIds.has(allQs[i].id)) {
|
|
2032
|
+
resumeIndex = i;
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
resumeIndex = allQs.length - 1;
|
|
2036
|
+
}
|
|
2037
|
+
setCurrentQuestionIndex(resumeIndex);
|
|
2038
|
+
}
|
|
2039
|
+
setShowIntro(false);
|
|
2040
|
+
setShowResumeChoice(false);
|
|
2041
|
+
setTimerStarted(true);
|
|
2042
|
+
}, [quiz, answers, extraQuestions, skippedQuestionIds]);
|
|
2043
|
+
const handleStartFresh = (0, import_react3.useCallback)(async () => {
|
|
2044
|
+
if (!apiClient.current || !attempt) return;
|
|
2045
|
+
setIsStartingFresh(true);
|
|
2046
|
+
try {
|
|
2047
|
+
await apiClient.current.updateAttempt(attempt.id, {
|
|
2048
|
+
status: "abandoned"
|
|
2049
|
+
});
|
|
2050
|
+
const newAttemptData = await apiClient.current.createAttempt({
|
|
2051
|
+
quizId,
|
|
2052
|
+
lessonId,
|
|
2053
|
+
assignLessonId,
|
|
2054
|
+
courseId,
|
|
2055
|
+
childId,
|
|
2056
|
+
parentId,
|
|
2057
|
+
forceNew: true
|
|
2058
|
+
});
|
|
2059
|
+
setAttempt(newAttemptData);
|
|
2060
|
+
setAnswers(/* @__PURE__ */ new Map());
|
|
2061
|
+
setAnswersDetail([]);
|
|
2062
|
+
setCurrentQuestionIndex(0);
|
|
2063
|
+
setHasExistingProgress(false);
|
|
2064
|
+
setExistingProgressCount(0);
|
|
2065
|
+
setShowResumeChoice(false);
|
|
2066
|
+
setShowIntro(false);
|
|
2067
|
+
setTimerStarted(true);
|
|
2068
|
+
} catch (err) {
|
|
2069
|
+
const message = err instanceof Error ? err.message : "Failed to start fresh";
|
|
2070
|
+
onErrorRef.current?.(new Error(message));
|
|
2071
|
+
} finally {
|
|
2072
|
+
setIsStartingFresh(false);
|
|
2073
|
+
}
|
|
2074
|
+
}, [attempt, quizId, lessonId, assignLessonId, courseId, childId, parentId]);
|
|
1812
2075
|
(0, import_react3.useEffect)(() => {
|
|
1813
2076
|
setShowFeedback(false);
|
|
1814
2077
|
setCurrentAnswerDetail(null);
|
|
@@ -1928,7 +2191,15 @@ function QuizPlayer({
|
|
|
1928
2191
|
onCompleteRef.current?.(quizResult);
|
|
1929
2192
|
} catch (err) {
|
|
1930
2193
|
const message = err instanceof Error ? err.message : "Failed to submit quiz";
|
|
1931
|
-
|
|
2194
|
+
const code = getErrorFromMessage(message, "quiz");
|
|
2195
|
+
setErrorCode(code);
|
|
2196
|
+
apiClient.current?.logError({
|
|
2197
|
+
errorCode: code,
|
|
2198
|
+
context: "quiz",
|
|
2199
|
+
resourceId: quizId,
|
|
2200
|
+
component: "QuizPlayer",
|
|
2201
|
+
message
|
|
2202
|
+
});
|
|
1932
2203
|
onErrorRef.current?.(err instanceof Error ? err : new Error(message));
|
|
1933
2204
|
} finally {
|
|
1934
2205
|
setIsSubmitting(false);
|
|
@@ -2007,13 +2278,10 @@ function QuizPlayer({
|
|
|
2007
2278
|
}
|
|
2008
2279
|
}, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId]);
|
|
2009
2280
|
if (isLoading) {
|
|
2010
|
-
return /* @__PURE__ */ (0,
|
|
2281
|
+
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
2282
|
}
|
|
2012
|
-
if (
|
|
2013
|
-
return /* @__PURE__ */ (0,
|
|
2014
|
-
"Error: ",
|
|
2015
|
-
error
|
|
2016
|
-
] }) }) });
|
|
2283
|
+
if (errorCode) {
|
|
2284
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MaintenanceScreen, { errorCode }) });
|
|
2017
2285
|
}
|
|
2018
2286
|
if (isCompleted && result) {
|
|
2019
2287
|
const percentage = result.totalQuestions > 0 ? Math.round(result.correctAnswers / result.totalQuestions * 100) : 0;
|
|
@@ -2071,7 +2339,7 @@ function QuizPlayer({
|
|
|
2071
2339
|
rotation: Math.random() * 360,
|
|
2072
2340
|
size: 6 + Math.random() * 8
|
|
2073
2341
|
}));
|
|
2074
|
-
const StarIcon = ({ filled, delay }) => /* @__PURE__ */ (0,
|
|
2342
|
+
const StarIcon = ({ filled, delay }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2075
2343
|
"svg",
|
|
2076
2344
|
{
|
|
2077
2345
|
width: "36",
|
|
@@ -2082,7 +2350,7 @@ function QuizPlayer({
|
|
|
2082
2350
|
animationDelay: `${delay}s`,
|
|
2083
2351
|
opacity: 0
|
|
2084
2352
|
},
|
|
2085
|
-
children: /* @__PURE__ */ (0,
|
|
2353
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2086
2354
|
"path",
|
|
2087
2355
|
{
|
|
2088
2356
|
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 +2361,23 @@ function QuizPlayer({
|
|
|
2093
2361
|
)
|
|
2094
2362
|
}
|
|
2095
2363
|
);
|
|
2096
|
-
const
|
|
2097
|
-
|
|
2098
|
-
|
|
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",
|
|
2364
|
+
const Mascot = ({ mood }) => {
|
|
2365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2366
|
+
"img",
|
|
2115
2367
|
{
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2368
|
+
src: astronautImage,
|
|
2369
|
+
alt: "Astronaut mascot",
|
|
2370
|
+
width: "180",
|
|
2371
|
+
height: "180",
|
|
2119
2372
|
style: {
|
|
2120
|
-
animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite"
|
|
2121
|
-
|
|
2122
|
-
|
|
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
|
-
]
|
|
2373
|
+
animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite",
|
|
2374
|
+
objectFit: "contain"
|
|
2375
|
+
}
|
|
2147
2376
|
}
|
|
2148
2377
|
);
|
|
2149
2378
|
};
|
|
2150
|
-
return /* @__PURE__ */ (0,
|
|
2151
|
-
/* @__PURE__ */ (0,
|
|
2379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, style: defaultStyles.container, children: [
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
2152
2381
|
@keyframes confettiFall {
|
|
2153
2382
|
0% {
|
|
2154
2383
|
transform: translateY(-10px) rotate(0deg);
|
|
@@ -2212,8 +2441,8 @@ function QuizPlayer({
|
|
|
2212
2441
|
}
|
|
2213
2442
|
}
|
|
2214
2443
|
` }),
|
|
2215
|
-
/* @__PURE__ */ (0,
|
|
2216
|
-
percentage >= 60 && /* @__PURE__ */ (0,
|
|
2444
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.results, children: [
|
|
2445
|
+
percentage >= 60 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.confettiContainer, children: confettiPieces.map((piece) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2217
2446
|
"div",
|
|
2218
2447
|
{
|
|
2219
2448
|
style: {
|
|
@@ -2230,15 +2459,70 @@ function QuizPlayer({
|
|
|
2230
2459
|
},
|
|
2231
2460
|
piece.id
|
|
2232
2461
|
)) }),
|
|
2233
|
-
/* @__PURE__ */ (0,
|
|
2234
|
-
/* @__PURE__ */ (0,
|
|
2235
|
-
/* @__PURE__ */ (0,
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2462
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.resultsBackground, background: theme.bgGradient } }),
|
|
2463
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.resultsContent, children: hideScore ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginBottom: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Mascot, { mood: "happy" }) }),
|
|
2465
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2466
|
+
"div",
|
|
2467
|
+
{
|
|
2468
|
+
style: {
|
|
2469
|
+
background: "linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%)",
|
|
2470
|
+
padding: "12px 28px",
|
|
2471
|
+
borderRadius: "50px",
|
|
2472
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
2473
|
+
marginBottom: "20px",
|
|
2474
|
+
animation: "badgePop 0.6s ease-out 0.2s forwards",
|
|
2475
|
+
opacity: 0,
|
|
2476
|
+
border: "3px solid #22c55e"
|
|
2477
|
+
},
|
|
2478
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2479
|
+
"span",
|
|
2480
|
+
{
|
|
2481
|
+
style: {
|
|
2482
|
+
fontSize: "22px",
|
|
2483
|
+
fontWeight: "700",
|
|
2484
|
+
color: "#1f2937",
|
|
2485
|
+
textShadow: "0 1px 2px rgba(255,255,255,0.5)"
|
|
2486
|
+
},
|
|
2487
|
+
children: "All Done!"
|
|
2488
|
+
}
|
|
2489
|
+
)
|
|
2490
|
+
}
|
|
2491
|
+
),
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2493
|
+
"div",
|
|
2494
|
+
{
|
|
2495
|
+
style: {
|
|
2496
|
+
animation: "scoreSlideIn 0.5s ease-out 0.4s forwards",
|
|
2497
|
+
opacity: 0
|
|
2498
|
+
},
|
|
2499
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2500
|
+
"div",
|
|
2501
|
+
{
|
|
2502
|
+
style: {
|
|
2503
|
+
fontSize: "24px",
|
|
2504
|
+
fontWeight: "600",
|
|
2505
|
+
color: "#22c55e",
|
|
2506
|
+
lineHeight: "1.4",
|
|
2507
|
+
marginBottom: "12px"
|
|
2508
|
+
},
|
|
2509
|
+
children: "The quiz was submitted successfully!"
|
|
2510
|
+
}
|
|
2511
|
+
)
|
|
2512
|
+
}
|
|
2513
|
+
),
|
|
2514
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
|
|
2515
|
+
"Time: ",
|
|
2516
|
+
formatTime(result.timeSpentSeconds)
|
|
2517
|
+
] })
|
|
2518
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
2519
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.resultStars, children: [
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 1, delay: 0.3 }),
|
|
2521
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 2, delay: 0.5 }),
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StarIcon, { filled: theme.stars >= 3, delay: 0.7 })
|
|
2239
2523
|
] }),
|
|
2240
|
-
/* @__PURE__ */ (0,
|
|
2241
|
-
/* @__PURE__ */ (0,
|
|
2524
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Mascot, { mood: theme.mascotMood }) }),
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2242
2526
|
"div",
|
|
2243
2527
|
{
|
|
2244
2528
|
style: {
|
|
@@ -2251,7 +2535,7 @@ function QuizPlayer({
|
|
|
2251
2535
|
opacity: 0,
|
|
2252
2536
|
border: `3px solid ${theme.badgeColor}`
|
|
2253
2537
|
},
|
|
2254
|
-
children: /* @__PURE__ */ (0,
|
|
2538
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2255
2539
|
"span",
|
|
2256
2540
|
{
|
|
2257
2541
|
style: {
|
|
@@ -2265,7 +2549,7 @@ function QuizPlayer({
|
|
|
2265
2549
|
)
|
|
2266
2550
|
}
|
|
2267
2551
|
),
|
|
2268
|
-
/* @__PURE__ */ (0,
|
|
2552
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2269
2553
|
"div",
|
|
2270
2554
|
{
|
|
2271
2555
|
style: {
|
|
@@ -2273,7 +2557,7 @@ function QuizPlayer({
|
|
|
2273
2557
|
opacity: 0
|
|
2274
2558
|
},
|
|
2275
2559
|
children: [
|
|
2276
|
-
/* @__PURE__ */ (0,
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2277
2561
|
"div",
|
|
2278
2562
|
{
|
|
2279
2563
|
style: {
|
|
@@ -2290,7 +2574,7 @@ function QuizPlayer({
|
|
|
2290
2574
|
]
|
|
2291
2575
|
}
|
|
2292
2576
|
),
|
|
2293
|
-
/* @__PURE__ */ (0,
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2294
2578
|
"div",
|
|
2295
2579
|
{
|
|
2296
2580
|
style: {
|
|
@@ -2305,25 +2589,84 @@ function QuizPlayer({
|
|
|
2305
2589
|
]
|
|
2306
2590
|
}
|
|
2307
2591
|
),
|
|
2308
|
-
/* @__PURE__ */ (0,
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
|
|
2309
2593
|
"Time: ",
|
|
2310
2594
|
formatTime(result.timeSpentSeconds)
|
|
2311
2595
|
] })
|
|
2312
|
-
] })
|
|
2596
|
+
] }) })
|
|
2313
2597
|
] })
|
|
2314
2598
|
] });
|
|
2315
2599
|
}
|
|
2600
|
+
if (quiz && showIntro && showResumeChoice && hasExistingProgress) {
|
|
2601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.intro, children: [
|
|
2602
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introTitle, children: "Welcome Back!" }),
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introSubtitle, children: "You have an unfinished quiz. Would you like to continue or start over?" }),
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
|
|
2605
|
+
existingProgressCount,
|
|
2606
|
+
" of ",
|
|
2607
|
+
quiz.questions.length,
|
|
2608
|
+
" question",
|
|
2609
|
+
quiz.questions.length !== 1 ? "s" : "",
|
|
2610
|
+
" answered"
|
|
2611
|
+
] }),
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginTop: "8px" }, children: [
|
|
2613
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2614
|
+
"button",
|
|
2615
|
+
{
|
|
2616
|
+
style: defaultStyles.startButton,
|
|
2617
|
+
onClick: handleResumePrevious,
|
|
2618
|
+
onMouseOver: (e) => {
|
|
2619
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
2620
|
+
e.currentTarget.style.boxShadow = "0 6px 20px rgba(124, 58, 237, 0.5)";
|
|
2621
|
+
},
|
|
2622
|
+
onMouseOut: (e) => {
|
|
2623
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
2624
|
+
e.currentTarget.style.boxShadow = "0 4px 14px rgba(124, 58, 237, 0.4)";
|
|
2625
|
+
},
|
|
2626
|
+
"data-testid": "button-continue-quiz",
|
|
2627
|
+
children: "Continue Where I Left Off"
|
|
2628
|
+
}
|
|
2629
|
+
),
|
|
2630
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2631
|
+
"button",
|
|
2632
|
+
{
|
|
2633
|
+
style: {
|
|
2634
|
+
...defaultStyles.startButton,
|
|
2635
|
+
background: "transparent",
|
|
2636
|
+
color: "#7c3aed",
|
|
2637
|
+
border: "2px solid #7c3aed",
|
|
2638
|
+
boxShadow: "none"
|
|
2639
|
+
},
|
|
2640
|
+
onClick: handleStartFresh,
|
|
2641
|
+
disabled: isStartingFresh,
|
|
2642
|
+
onMouseOver: (e) => {
|
|
2643
|
+
if (!isStartingFresh) {
|
|
2644
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
2645
|
+
e.currentTarget.style.background = "rgba(124, 58, 237, 0.1)";
|
|
2646
|
+
}
|
|
2647
|
+
},
|
|
2648
|
+
onMouseOut: (e) => {
|
|
2649
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
2650
|
+
e.currentTarget.style.background = "transparent";
|
|
2651
|
+
},
|
|
2652
|
+
"data-testid": "button-start-fresh",
|
|
2653
|
+
children: isStartingFresh ? "Starting..." : "Start Fresh"
|
|
2654
|
+
}
|
|
2655
|
+
)
|
|
2656
|
+
] })
|
|
2657
|
+
] }) });
|
|
2658
|
+
}
|
|
2316
2659
|
if (quiz && showIntro) {
|
|
2317
|
-
return /* @__PURE__ */ (0,
|
|
2318
|
-
/* @__PURE__ */ (0,
|
|
2319
|
-
/* @__PURE__ */ (0,
|
|
2320
|
-
/* @__PURE__ */ (0,
|
|
2660
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.intro, children: [
|
|
2661
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introTitle, children: quiz.title }),
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.introSubtitle, children: "Ready to test your knowledge?" }),
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
|
|
2321
2664
|
quiz.questions.length,
|
|
2322
2665
|
" question",
|
|
2323
2666
|
quiz.questions.length !== 1 ? "s" : "",
|
|
2324
2667
|
" to answer"
|
|
2325
2668
|
] }),
|
|
2326
|
-
/* @__PURE__ */ (0,
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2327
2670
|
"button",
|
|
2328
2671
|
{
|
|
2329
2672
|
style: defaultStyles.startButton,
|
|
@@ -2343,7 +2686,7 @@ function QuizPlayer({
|
|
|
2343
2686
|
] }) });
|
|
2344
2687
|
}
|
|
2345
2688
|
if (!quiz || !currentQuestion) {
|
|
2346
|
-
return /* @__PURE__ */ (0,
|
|
2689
|
+
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
2690
|
}
|
|
2348
2691
|
const selectedAnswer = answers.get(currentQuestion.id);
|
|
2349
2692
|
const isLastQuestion = currentQuestionIndex === totalQuestions - 1;
|
|
@@ -2351,21 +2694,21 @@ function QuizPlayer({
|
|
|
2351
2694
|
const remainingSlots = maxQuestions - totalQuestions;
|
|
2352
2695
|
const questionsToAdd = Math.min(5, remainingSlots);
|
|
2353
2696
|
const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;
|
|
2354
|
-
return /* @__PURE__ */ (0,
|
|
2355
|
-
/* @__PURE__ */ (0,
|
|
2356
|
-
/* @__PURE__ */ (0,
|
|
2357
|
-
/* @__PURE__ */ (0,
|
|
2358
|
-
/* @__PURE__ */ (0,
|
|
2697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.mainLayout, children: [
|
|
2698
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.quizContent, children: [
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.header, children: [
|
|
2700
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.title, children: quiz.title }),
|
|
2701
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.progress, children: [
|
|
2359
2702
|
"Question ",
|
|
2360
2703
|
currentQuestionIndex + 1,
|
|
2361
2704
|
" of ",
|
|
2362
2705
|
totalQuestions
|
|
2363
2706
|
] }),
|
|
2364
|
-
/* @__PURE__ */ (0,
|
|
2707
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
|
|
2365
2708
|
] }),
|
|
2366
|
-
/* @__PURE__ */ (0,
|
|
2367
|
-
/* @__PURE__ */ (0,
|
|
2368
|
-
isExtraQuestion && /* @__PURE__ */ (0,
|
|
2709
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles.question, position: "relative", paddingBottom: "40px" }, children: [
|
|
2710
|
+
/* @__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" }) }),
|
|
2711
|
+
isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2369
2712
|
"button",
|
|
2370
2713
|
{
|
|
2371
2714
|
onClick: () => setShowSkipModal(true),
|
|
@@ -2398,15 +2741,15 @@ function QuizPlayer({
|
|
|
2398
2741
|
},
|
|
2399
2742
|
"data-testid": "button-skip-question",
|
|
2400
2743
|
children: [
|
|
2401
|
-
/* @__PURE__ */ (0,
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2403
|
-
/* @__PURE__ */ (0,
|
|
2744
|
+
/* @__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: [
|
|
2745
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polygon", { points: "5 4 15 12 5 20 5 4" }),
|
|
2746
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "19", y1: "5", x2: "19", y2: "19" })
|
|
2404
2747
|
] }),
|
|
2405
|
-
/* @__PURE__ */ (0,
|
|
2748
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Skip" })
|
|
2406
2749
|
]
|
|
2407
2750
|
}
|
|
2408
2751
|
),
|
|
2409
|
-
!isExtraQuestion && /* @__PURE__ */ (0,
|
|
2752
|
+
!isExtraQuestion && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2410
2753
|
"button",
|
|
2411
2754
|
{
|
|
2412
2755
|
onClick: () => setShowReportModal(true),
|
|
@@ -2439,15 +2782,15 @@ function QuizPlayer({
|
|
|
2439
2782
|
},
|
|
2440
2783
|
"data-testid": "button-report-question",
|
|
2441
2784
|
children: [
|
|
2442
|
-
/* @__PURE__ */ (0,
|
|
2443
|
-
/* @__PURE__ */ (0,
|
|
2444
|
-
/* @__PURE__ */ (0,
|
|
2785
|
+
/* @__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: [
|
|
2786
|
+
/* @__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" }),
|
|
2787
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "4", y1: "22", x2: "4", y2: "15" })
|
|
2445
2788
|
] }),
|
|
2446
|
-
/* @__PURE__ */ (0,
|
|
2789
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Report" })
|
|
2447
2790
|
]
|
|
2448
2791
|
}
|
|
2449
2792
|
),
|
|
2450
|
-
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0,
|
|
2793
|
+
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
2451
2794
|
const isSelected = selectedAnswer === option;
|
|
2452
2795
|
const isCorrectOption = currentQuestion.correctAnswer === option;
|
|
2453
2796
|
let optionStyle = { ...defaultStyles.option };
|
|
@@ -2460,7 +2803,7 @@ function QuizPlayer({
|
|
|
2460
2803
|
} else if (isSelected) {
|
|
2461
2804
|
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
2462
2805
|
}
|
|
2463
|
-
return /* @__PURE__ */ (0,
|
|
2806
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2464
2807
|
"div",
|
|
2465
2808
|
{
|
|
2466
2809
|
style: {
|
|
@@ -2472,14 +2815,14 @@ function QuizPlayer({
|
|
|
2472
2815
|
},
|
|
2473
2816
|
onClick: () => !showFeedback && handleAnswerChange(option),
|
|
2474
2817
|
children: [
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2476
|
-
/* @__PURE__ */ (0,
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
|
|
2819
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
|
|
2477
2820
|
]
|
|
2478
2821
|
},
|
|
2479
2822
|
idx
|
|
2480
2823
|
);
|
|
2481
2824
|
}) }),
|
|
2482
|
-
currentQuestion.type === "multiple" && /* @__PURE__ */ (0,
|
|
2825
|
+
currentQuestion.type === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
2483
2826
|
const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
|
|
2484
2827
|
const correctAnswers = Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer : currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : [];
|
|
2485
2828
|
const isCorrectOption = correctAnswers.includes(option);
|
|
@@ -2493,7 +2836,7 @@ function QuizPlayer({
|
|
|
2493
2836
|
} else if (selected) {
|
|
2494
2837
|
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
2495
2838
|
}
|
|
2496
|
-
return /* @__PURE__ */ (0,
|
|
2839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2497
2840
|
"div",
|
|
2498
2841
|
{
|
|
2499
2842
|
style: {
|
|
@@ -2513,14 +2856,14 @@ function QuizPlayer({
|
|
|
2513
2856
|
}
|
|
2514
2857
|
},
|
|
2515
2858
|
children: [
|
|
2516
|
-
/* @__PURE__ */ (0,
|
|
2517
|
-
/* @__PURE__ */ (0,
|
|
2859
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TextToSpeech, { text: option, size: "sm" }) }),
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
|
|
2518
2861
|
]
|
|
2519
2862
|
},
|
|
2520
2863
|
idx
|
|
2521
2864
|
);
|
|
2522
2865
|
}) }),
|
|
2523
|
-
(currentQuestion.type === "free" || currentQuestion.type === "essay") && /* @__PURE__ */ (0,
|
|
2866
|
+
(currentQuestion.type === "free" || currentQuestion.type === "essay") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2524
2867
|
"textarea",
|
|
2525
2868
|
{
|
|
2526
2869
|
style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
|
|
@@ -2530,7 +2873,7 @@ function QuizPlayer({
|
|
|
2530
2873
|
disabled: showFeedback
|
|
2531
2874
|
}
|
|
2532
2875
|
),
|
|
2533
|
-
currentQuestion.type === "fill" && /* @__PURE__ */ (0,
|
|
2876
|
+
currentQuestion.type === "fill" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2534
2877
|
"input",
|
|
2535
2878
|
{
|
|
2536
2879
|
style: defaultStyles.input,
|
|
@@ -2545,7 +2888,7 @@ function QuizPlayer({
|
|
|
2545
2888
|
},
|
|
2546
2889
|
idx
|
|
2547
2890
|
)) }),
|
|
2548
|
-
currentQuestion.type === "sorting" && currentQuestion.items && /* @__PURE__ */ (0,
|
|
2891
|
+
currentQuestion.type === "sorting" && currentQuestion.items && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2549
2892
|
SortingDragDrop,
|
|
2550
2893
|
{
|
|
2551
2894
|
items: currentQuestion.items,
|
|
@@ -2555,7 +2898,7 @@ function QuizPlayer({
|
|
|
2555
2898
|
onOrderChange: handleAnswerChange
|
|
2556
2899
|
}
|
|
2557
2900
|
),
|
|
2558
|
-
currentQuestion.type === "matrix" && currentQuestion.leftItems && currentQuestion.rightItems && /* @__PURE__ */ (0,
|
|
2901
|
+
currentQuestion.type === "matrix" && currentQuestion.leftItems && currentQuestion.rightItems && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2559
2902
|
MatchingDragDrop,
|
|
2560
2903
|
{
|
|
2561
2904
|
leftItems: currentQuestion.leftItems,
|
|
@@ -2566,7 +2909,7 @@ function QuizPlayer({
|
|
|
2566
2909
|
onMatchChange: handleAnswerChange
|
|
2567
2910
|
}
|
|
2568
2911
|
),
|
|
2569
|
-
currentQuestion.type === "assessment" && /* @__PURE__ */ (0,
|
|
2912
|
+
currentQuestion.type === "assessment" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.options, children: (() => {
|
|
2570
2913
|
const scaleType = currentQuestion.scaleType || "likert";
|
|
2571
2914
|
if (scaleType === "yes-no") {
|
|
2572
2915
|
const options = ["Yes", "No"];
|
|
@@ -2576,7 +2919,7 @@ function QuizPlayer({
|
|
|
2576
2919
|
if (isSelected) {
|
|
2577
2920
|
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
2578
2921
|
}
|
|
2579
|
-
return /* @__PURE__ */ (0,
|
|
2922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2580
2923
|
"div",
|
|
2581
2924
|
{
|
|
2582
2925
|
style: {
|
|
@@ -2588,7 +2931,7 @@ function QuizPlayer({
|
|
|
2588
2931
|
},
|
|
2589
2932
|
onClick: () => !showFeedback && handleAnswerChange(option),
|
|
2590
2933
|
"data-testid": `assessment-option-${option.toLowerCase()}`,
|
|
2591
|
-
children: /* @__PURE__ */ (0,
|
|
2934
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
|
|
2592
2935
|
},
|
|
2593
2936
|
idx
|
|
2594
2937
|
);
|
|
@@ -2598,9 +2941,9 @@ function QuizPlayer({
|
|
|
2598
2941
|
const min = currentQuestion.scaleMin || 1;
|
|
2599
2942
|
const max = currentQuestion.scaleMax || 5;
|
|
2600
2943
|
const ratings = Array.from({ length: max - min + 1 }, (_, i) => min + i);
|
|
2601
|
-
return /* @__PURE__ */ (0,
|
|
2944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap", justifyContent: "center" }, children: ratings.map((rating) => {
|
|
2602
2945
|
const isSelected = selectedAnswer === rating;
|
|
2603
|
-
return /* @__PURE__ */ (0,
|
|
2946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2604
2947
|
"button",
|
|
2605
2948
|
{
|
|
2606
2949
|
onClick: () => !showFeedback && handleAnswerChange(rating),
|
|
@@ -2636,7 +2979,7 @@ function QuizPlayer({
|
|
|
2636
2979
|
if (isSelected) {
|
|
2637
2980
|
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
2638
2981
|
}
|
|
2639
|
-
return /* @__PURE__ */ (0,
|
|
2982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2640
2983
|
"div",
|
|
2641
2984
|
{
|
|
2642
2985
|
style: {
|
|
@@ -2648,24 +2991,24 @@ function QuizPlayer({
|
|
|
2648
2991
|
},
|
|
2649
2992
|
onClick: () => !showFeedback && handleAnswerChange(option),
|
|
2650
2993
|
"data-testid": `assessment-likert-${idx}`,
|
|
2651
|
-
children: /* @__PURE__ */ (0,
|
|
2994
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flex: 1 }, children: option })
|
|
2652
2995
|
},
|
|
2653
2996
|
idx
|
|
2654
2997
|
);
|
|
2655
2998
|
});
|
|
2656
2999
|
})() }),
|
|
2657
|
-
showFeedback && currentAnswerDetail && /* @__PURE__ */ (0,
|
|
3000
|
+
showFeedback && currentAnswerDetail && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
|
|
2658
3001
|
...defaultStyles.feedback,
|
|
2659
3002
|
...currentQuestion.type === "assessment" ? defaultStyles.feedbackNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect
|
|
2660
3003
|
}, children: [
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
3004
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
2662
3005
|
...defaultStyles.feedbackTitle,
|
|
2663
3006
|
...currentQuestion.type === "assessment" ? defaultStyles.feedbackTitleNeutral : currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect
|
|
2664
3007
|
}, children: currentQuestion.type === "assessment" ? "\u2713 Response recorded" : currentAnswerDetail.isCorrect ? "\u2713 Correct!" : "\u2717 Incorrect" }),
|
|
2665
|
-
currentQuestion.explanation && /* @__PURE__ */ (0,
|
|
3008
|
+
currentQuestion.explanation && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.feedbackExplanation, children: currentQuestion.explanation })
|
|
2666
3009
|
] })
|
|
2667
3010
|
] }),
|
|
2668
|
-
showSkipModal && /* @__PURE__ */ (0,
|
|
3011
|
+
showSkipModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
2669
3012
|
position: "fixed",
|
|
2670
3013
|
top: 0,
|
|
2671
3014
|
left: 0,
|
|
@@ -2676,7 +3019,7 @@ function QuizPlayer({
|
|
|
2676
3019
|
alignItems: "center",
|
|
2677
3020
|
justifyContent: "center",
|
|
2678
3021
|
zIndex: 1e3
|
|
2679
|
-
}, children: /* @__PURE__ */ (0,
|
|
3022
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
|
|
2680
3023
|
backgroundColor: "#ffffff",
|
|
2681
3024
|
borderRadius: "12px",
|
|
2682
3025
|
padding: "24px",
|
|
@@ -2684,10 +3027,10 @@ function QuizPlayer({
|
|
|
2684
3027
|
width: "90%",
|
|
2685
3028
|
boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
|
|
2686
3029
|
}, children: [
|
|
2687
|
-
/* @__PURE__ */ (0,
|
|
2688
|
-
/* @__PURE__ */ (0,
|
|
2689
|
-
/* @__PURE__ */ (0,
|
|
2690
|
-
/* @__PURE__ */ (0,
|
|
3030
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Skip Question" }),
|
|
3031
|
+
/* @__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." }),
|
|
3032
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px", marginBottom: "16px" }, children: [
|
|
3033
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2691
3034
|
"button",
|
|
2692
3035
|
{
|
|
2693
3036
|
onClick: () => setSelectedSkipReason("question_issue"),
|
|
@@ -2708,7 +3051,7 @@ function QuizPlayer({
|
|
|
2708
3051
|
children: "Question has an issue"
|
|
2709
3052
|
}
|
|
2710
3053
|
),
|
|
2711
|
-
/* @__PURE__ */ (0,
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2712
3055
|
"button",
|
|
2713
3056
|
{
|
|
2714
3057
|
onClick: () => setSelectedSkipReason("dont_know"),
|
|
@@ -2730,9 +3073,9 @@ function QuizPlayer({
|
|
|
2730
3073
|
}
|
|
2731
3074
|
)
|
|
2732
3075
|
] }),
|
|
2733
|
-
/* @__PURE__ */ (0,
|
|
2734
|
-
/* @__PURE__ */ (0,
|
|
2735
|
-
/* @__PURE__ */ (0,
|
|
3076
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "16px" }, children: [
|
|
3077
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: { display: "block", fontSize: "13px", fontWeight: "500", color: "#374151", marginBottom: "6px" }, children: "Additional details (optional)" }),
|
|
3078
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2736
3079
|
"textarea",
|
|
2737
3080
|
{
|
|
2738
3081
|
value: skipComment,
|
|
@@ -2753,13 +3096,13 @@ function QuizPlayer({
|
|
|
2753
3096
|
"data-testid": "input-skip-comment"
|
|
2754
3097
|
}
|
|
2755
3098
|
),
|
|
2756
|
-
/* @__PURE__ */ (0,
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
|
|
2757
3100
|
skipComment.length,
|
|
2758
3101
|
"/200"
|
|
2759
3102
|
] })
|
|
2760
3103
|
] }),
|
|
2761
|
-
/* @__PURE__ */ (0,
|
|
2762
|
-
/* @__PURE__ */ (0,
|
|
3104
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
3105
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2763
3106
|
"button",
|
|
2764
3107
|
{
|
|
2765
3108
|
onClick: () => {
|
|
@@ -2782,7 +3125,7 @@ function QuizPlayer({
|
|
|
2782
3125
|
children: "Cancel"
|
|
2783
3126
|
}
|
|
2784
3127
|
),
|
|
2785
|
-
/* @__PURE__ */ (0,
|
|
3128
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2786
3129
|
"button",
|
|
2787
3130
|
{
|
|
2788
3131
|
onClick: () => selectedSkipReason && handleSkipQuestion(selectedSkipReason, skipComment),
|
|
@@ -2805,7 +3148,7 @@ function QuizPlayer({
|
|
|
2805
3148
|
)
|
|
2806
3149
|
] })
|
|
2807
3150
|
] }) }),
|
|
2808
|
-
showReportModal && /* @__PURE__ */ (0,
|
|
3151
|
+
showReportModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
2809
3152
|
position: "fixed",
|
|
2810
3153
|
top: 0,
|
|
2811
3154
|
left: 0,
|
|
@@ -2816,7 +3159,7 @@ function QuizPlayer({
|
|
|
2816
3159
|
alignItems: "center",
|
|
2817
3160
|
justifyContent: "center",
|
|
2818
3161
|
zIndex: 1e3
|
|
2819
|
-
}, children: /* @__PURE__ */ (0,
|
|
3162
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: {
|
|
2820
3163
|
backgroundColor: "#ffffff",
|
|
2821
3164
|
borderRadius: "12px",
|
|
2822
3165
|
padding: "24px",
|
|
@@ -2824,10 +3167,10 @@ function QuizPlayer({
|
|
|
2824
3167
|
width: "90%",
|
|
2825
3168
|
boxShadow: "0 20px 40px rgba(0, 0, 0, 0.2)"
|
|
2826
3169
|
}, children: [
|
|
2827
|
-
/* @__PURE__ */ (0,
|
|
2828
|
-
/* @__PURE__ */ (0,
|
|
2829
|
-
/* @__PURE__ */ (0,
|
|
2830
|
-
/* @__PURE__ */ (0,
|
|
3170
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { style: { margin: "0 0 8px 0", fontSize: "18px", fontWeight: "600", color: "#1f2937" }, children: "Report Question" }),
|
|
3171
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 16px 0", fontSize: "14px", color: "#6b7280" }, children: "What's wrong with this question?" }),
|
|
3172
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "16px" }, children: [
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2831
3174
|
"textarea",
|
|
2832
3175
|
{
|
|
2833
3176
|
value: reportComment,
|
|
@@ -2848,13 +3191,13 @@ function QuizPlayer({
|
|
|
2848
3191
|
"data-testid": "input-report-comment"
|
|
2849
3192
|
}
|
|
2850
3193
|
),
|
|
2851
|
-
/* @__PURE__ */ (0,
|
|
3194
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px", textAlign: "right" }, children: [
|
|
2852
3195
|
reportComment.length,
|
|
2853
3196
|
"/300"
|
|
2854
3197
|
] })
|
|
2855
3198
|
] }),
|
|
2856
|
-
/* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
3199
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
3200
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2858
3201
|
"button",
|
|
2859
3202
|
{
|
|
2860
3203
|
onClick: () => {
|
|
@@ -2876,7 +3219,7 @@ function QuizPlayer({
|
|
|
2876
3219
|
children: "Cancel"
|
|
2877
3220
|
}
|
|
2878
3221
|
),
|
|
2879
|
-
/* @__PURE__ */ (0,
|
|
3222
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2880
3223
|
"button",
|
|
2881
3224
|
{
|
|
2882
3225
|
onClick: () => handleReportQuestion(reportComment),
|
|
@@ -2899,8 +3242,8 @@ function QuizPlayer({
|
|
|
2899
3242
|
)
|
|
2900
3243
|
] })
|
|
2901
3244
|
] }) }),
|
|
2902
|
-
/* @__PURE__ */ (0,
|
|
2903
|
-
showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ (0,
|
|
3245
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: defaultStyles.buttonsColumn, children: [
|
|
3246
|
+
showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2904
3247
|
"button",
|
|
2905
3248
|
{
|
|
2906
3249
|
style: {
|
|
@@ -2910,10 +3253,10 @@ function QuizPlayer({
|
|
|
2910
3253
|
onClick: handleAddMoreQuestions,
|
|
2911
3254
|
disabled: isGeneratingExtra,
|
|
2912
3255
|
"data-testid": "button-add-more-questions",
|
|
2913
|
-
children: isGeneratingExtra ? /* @__PURE__ */ (0,
|
|
2914
|
-
/* @__PURE__ */ (0,
|
|
3256
|
+
children: isGeneratingExtra ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3257
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }),
|
|
2915
3258
|
"Generating Questions..."
|
|
2916
|
-
] }) : /* @__PURE__ */ (0,
|
|
3259
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
2917
3260
|
"+ Add ",
|
|
2918
3261
|
questionsToAdd,
|
|
2919
3262
|
" More Question",
|
|
@@ -2921,9 +3264,9 @@ function QuizPlayer({
|
|
|
2921
3264
|
] })
|
|
2922
3265
|
}
|
|
2923
3266
|
),
|
|
2924
|
-
/* @__PURE__ */ (0,
|
|
3267
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...defaultStyles.buttons, justifyContent: "flex-end" }, children: showFeedback ? (
|
|
2925
3268
|
// After viewing feedback
|
|
2926
|
-
isLastQuestion ? /* @__PURE__ */ (0,
|
|
3269
|
+
isLastQuestion ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2927
3270
|
"button",
|
|
2928
3271
|
{
|
|
2929
3272
|
style: {
|
|
@@ -2933,9 +3276,9 @@ function QuizPlayer({
|
|
|
2933
3276
|
onClick: handleSubmit,
|
|
2934
3277
|
disabled: isSubmitting || isGeneratingExtra,
|
|
2935
3278
|
"data-testid": "button-submit-quiz",
|
|
2936
|
-
children: isSubmitting ? /* @__PURE__ */ (0,
|
|
3279
|
+
children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
|
|
2937
3280
|
}
|
|
2938
|
-
) : /* @__PURE__ */ (0,
|
|
3281
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2939
3282
|
"button",
|
|
2940
3283
|
{
|
|
2941
3284
|
style: {
|
|
@@ -2949,7 +3292,7 @@ function QuizPlayer({
|
|
|
2949
3292
|
)
|
|
2950
3293
|
) : (
|
|
2951
3294
|
// Before checking answer
|
|
2952
|
-
/* @__PURE__ */ (0,
|
|
3295
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2953
3296
|
"button",
|
|
2954
3297
|
{
|
|
2955
3298
|
style: {
|
|
@@ -2959,13 +3302,13 @@ function QuizPlayer({
|
|
|
2959
3302
|
onClick: handleCheckAnswer,
|
|
2960
3303
|
disabled: isNavigating || selectedAnswer === void 0,
|
|
2961
3304
|
"data-testid": "button-check-answer",
|
|
2962
|
-
children: isNavigating ? /* @__PURE__ */ (0,
|
|
3305
|
+
children: isNavigating ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Check Answer"
|
|
2963
3306
|
}
|
|
2964
3307
|
)
|
|
2965
3308
|
) })
|
|
2966
3309
|
] })
|
|
2967
3310
|
] }),
|
|
2968
|
-
/* @__PURE__ */ (0,
|
|
3311
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles.chatPanel, children: apiClient.current && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2969
3312
|
QuestionChatPanel,
|
|
2970
3313
|
{
|
|
2971
3314
|
apiClient: apiClient.current,
|
|
@@ -2995,7 +3338,7 @@ function QuizPlayer({
|
|
|
2995
3338
|
|
|
2996
3339
|
// src/AttemptViewer.tsx
|
|
2997
3340
|
var import_react4 = require("react");
|
|
2998
|
-
var
|
|
3341
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2999
3342
|
var defaultStyles2 = {
|
|
3000
3343
|
container: {
|
|
3001
3344
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
@@ -3248,23 +3591,39 @@ function AttemptViewer({
|
|
|
3248
3591
|
}) {
|
|
3249
3592
|
const [attempt, setAttempt] = (0, import_react4.useState)(null);
|
|
3250
3593
|
const [loading, setLoading] = (0, import_react4.useState)(true);
|
|
3251
|
-
const [
|
|
3594
|
+
const [errorCode, setErrorCode] = (0, import_react4.useState)(null);
|
|
3252
3595
|
const [chatHistories, setChatHistories] = (0, import_react4.useState)({});
|
|
3253
3596
|
const [expandedChats, setExpandedChats] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
|
|
3597
|
+
const [fetchedAttemptId, setFetchedAttemptId] = (0, import_react4.useState)(null);
|
|
3598
|
+
const onErrorRef = (0, import_react4.useRef)(onError);
|
|
3599
|
+
onErrorRef.current = onError;
|
|
3254
3600
|
(0, import_react4.useEffect)(() => {
|
|
3601
|
+
if (fetchedAttemptId === attemptId) return;
|
|
3255
3602
|
const apiClient = new QuizApiClient({
|
|
3256
3603
|
baseUrl: apiBaseUrl,
|
|
3257
3604
|
authToken
|
|
3258
3605
|
});
|
|
3259
3606
|
async function fetchAttempt() {
|
|
3260
3607
|
setLoading(true);
|
|
3261
|
-
|
|
3608
|
+
setErrorCode(null);
|
|
3262
3609
|
try {
|
|
3263
3610
|
const response = await fetch(`${apiBaseUrl}/api/external/quiz-attempts/${attemptId}`, {
|
|
3264
3611
|
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
3265
3612
|
});
|
|
3266
3613
|
if (!response.ok) {
|
|
3267
|
-
|
|
3614
|
+
const code = getErrorFromHttpStatus(response.status, "attempt");
|
|
3615
|
+
setErrorCode(code);
|
|
3616
|
+
apiClient.logError({
|
|
3617
|
+
errorCode: code,
|
|
3618
|
+
context: "attempt",
|
|
3619
|
+
resourceId: attemptId,
|
|
3620
|
+
component: "AttemptViewer",
|
|
3621
|
+
message: `HTTP ${response.status}: ${response.statusText}`
|
|
3622
|
+
});
|
|
3623
|
+
onErrorRef.current?.(new Error(`Failed to fetch attempt: ${response.statusText}`));
|
|
3624
|
+
setLoading(false);
|
|
3625
|
+
setFetchedAttemptId(attemptId);
|
|
3626
|
+
return;
|
|
3268
3627
|
}
|
|
3269
3628
|
const data = await response.json();
|
|
3270
3629
|
setAttempt(data);
|
|
@@ -3278,14 +3637,23 @@ function AttemptViewer({
|
|
|
3278
3637
|
}
|
|
3279
3638
|
} catch (err) {
|
|
3280
3639
|
const errorMessage = err instanceof Error ? err.message : "Failed to load attempt";
|
|
3281
|
-
|
|
3282
|
-
|
|
3640
|
+
const code = getErrorFromMessage(errorMessage, "attempt");
|
|
3641
|
+
setErrorCode(code);
|
|
3642
|
+
apiClient.logError({
|
|
3643
|
+
errorCode: code,
|
|
3644
|
+
context: "attempt",
|
|
3645
|
+
resourceId: attemptId,
|
|
3646
|
+
component: "AttemptViewer",
|
|
3647
|
+
message: errorMessage
|
|
3648
|
+
});
|
|
3649
|
+
onErrorRef.current?.(err instanceof Error ? err : new Error(errorMessage));
|
|
3283
3650
|
} finally {
|
|
3284
3651
|
setLoading(false);
|
|
3652
|
+
setFetchedAttemptId(attemptId);
|
|
3285
3653
|
}
|
|
3286
3654
|
}
|
|
3287
3655
|
fetchAttempt();
|
|
3288
|
-
}, [attemptId, apiBaseUrl, authToken,
|
|
3656
|
+
}, [attemptId, apiBaseUrl, authToken, showConversation, fetchedAttemptId]);
|
|
3289
3657
|
const toggleChatExpanded = (questionId) => {
|
|
3290
3658
|
setExpandedChats((prev) => {
|
|
3291
3659
|
const newSet = new Set(prev);
|
|
@@ -3299,53 +3667,49 @@ function AttemptViewer({
|
|
|
3299
3667
|
};
|
|
3300
3668
|
const handleRetry = () => {
|
|
3301
3669
|
setLoading(true);
|
|
3302
|
-
|
|
3670
|
+
setErrorCode(null);
|
|
3303
3671
|
window.location.reload();
|
|
3304
3672
|
};
|
|
3305
3673
|
if (loading) {
|
|
3306
|
-
return /* @__PURE__ */ (0,
|
|
3307
|
-
/* @__PURE__ */ (0,
|
|
3308
|
-
/* @__PURE__ */ (0,
|
|
3309
|
-
/* @__PURE__ */ (0,
|
|
3310
|
-
/* @__PURE__ */ (0,
|
|
3674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.container, className, children: [
|
|
3675
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: spinnerKeyframes }),
|
|
3676
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.loading, children: [
|
|
3677
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.spinner }),
|
|
3678
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { marginTop: "16px", color: "#6b7280" }, children: "Loading attempt..." })
|
|
3311
3679
|
] })
|
|
3312
3680
|
] });
|
|
3313
3681
|
}
|
|
3314
|
-
if (
|
|
3315
|
-
return /* @__PURE__ */ (0,
|
|
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
|
-
] }) });
|
|
3682
|
+
if (errorCode || !attempt) {
|
|
3683
|
+
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
3684
|
}
|
|
3321
3685
|
const scorePercentage = attempt.score ?? 0;
|
|
3322
3686
|
const correctCount = attempt.correctAnswers ?? 0;
|
|
3323
3687
|
const totalQuestions = attempt.totalQuestions;
|
|
3324
3688
|
const timeSpent = attempt.timeSpentSeconds ?? 0;
|
|
3325
|
-
return /* @__PURE__ */ (0,
|
|
3326
|
-
/* @__PURE__ */ (0,
|
|
3327
|
-
/* @__PURE__ */ (0,
|
|
3328
|
-
/* @__PURE__ */ (0,
|
|
3329
|
-
/* @__PURE__ */ (0,
|
|
3689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.container, className, children: [
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: spinnerKeyframes }),
|
|
3691
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.header, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryGrid, children: [
|
|
3692
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
|
|
3693
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
|
|
3330
3694
|
scorePercentage,
|
|
3331
3695
|
"%"
|
|
3332
3696
|
] }),
|
|
3333
|
-
/* @__PURE__ */ (0,
|
|
3697
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Score" })
|
|
3334
3698
|
] }),
|
|
3335
|
-
/* @__PURE__ */ (0,
|
|
3336
|
-
/* @__PURE__ */ (0,
|
|
3699
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
|
|
3700
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryValue, children: [
|
|
3337
3701
|
correctCount,
|
|
3338
3702
|
"/",
|
|
3339
3703
|
totalQuestions
|
|
3340
3704
|
] }),
|
|
3341
|
-
/* @__PURE__ */ (0,
|
|
3705
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
|
|
3342
3706
|
] }),
|
|
3343
|
-
/* @__PURE__ */ (0,
|
|
3344
|
-
/* @__PURE__ */ (0,
|
|
3345
|
-
/* @__PURE__ */ (0,
|
|
3707
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.summaryCard, children: [
|
|
3708
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryValue, children: formatTime(timeSpent) }),
|
|
3709
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.summaryLabel, children: "Time" })
|
|
3346
3710
|
] })
|
|
3347
3711
|
] }) }),
|
|
3348
|
-
/* @__PURE__ */ (0,
|
|
3712
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.questionsList, children: attempt.answers.map((answer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3349
3713
|
"div",
|
|
3350
3714
|
{
|
|
3351
3715
|
style: {
|
|
@@ -3353,12 +3717,12 @@ function AttemptViewer({
|
|
|
3353
3717
|
...answer.isCorrect ? defaultStyles2.questionCardCorrect : defaultStyles2.questionCardIncorrect
|
|
3354
3718
|
},
|
|
3355
3719
|
children: [
|
|
3356
|
-
/* @__PURE__ */ (0,
|
|
3357
|
-
/* @__PURE__ */ (0,
|
|
3720
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.questionHeader, children: [
|
|
3721
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: defaultStyles2.questionNumber, children: [
|
|
3358
3722
|
"Question ",
|
|
3359
3723
|
index + 1
|
|
3360
3724
|
] }),
|
|
3361
|
-
/* @__PURE__ */ (0,
|
|
3725
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3362
3726
|
"span",
|
|
3363
3727
|
{
|
|
3364
3728
|
style: {
|
|
@@ -3369,35 +3733,35 @@ function AttemptViewer({
|
|
|
3369
3733
|
}
|
|
3370
3734
|
)
|
|
3371
3735
|
] }),
|
|
3372
|
-
/* @__PURE__ */ (0,
|
|
3373
|
-
/* @__PURE__ */ (0,
|
|
3374
|
-
/* @__PURE__ */ (0,
|
|
3375
|
-
/* @__PURE__ */ (0,
|
|
3736
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: defaultStyles2.questionText, children: answer.questionText }),
|
|
3737
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.answerSection, children: [
|
|
3738
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.answerLabel, children: "Your answer:" }),
|
|
3739
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.studentAnswer, children: formatAnswer(answer.selectedAnswer, answer.questionType, answer.items, answer.leftItems) })
|
|
3376
3740
|
] }),
|
|
3377
|
-
!answer.isCorrect && answer.correctAnswer && /* @__PURE__ */ (0,
|
|
3378
|
-
/* @__PURE__ */ (0,
|
|
3379
|
-
/* @__PURE__ */ (0,
|
|
3741
|
+
!answer.isCorrect && answer.correctAnswer && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.answerSection, children: [
|
|
3742
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: defaultStyles2.answerLabel, children: "Correct answer:" }),
|
|
3743
|
+
/* @__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
3744
|
] }),
|
|
3381
|
-
/* @__PURE__ */ (0,
|
|
3745
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.points, children: [
|
|
3382
3746
|
answer.pointsEarned,
|
|
3383
3747
|
" / ",
|
|
3384
3748
|
answer.points,
|
|
3385
3749
|
" points"
|
|
3386
3750
|
] }),
|
|
3387
|
-
showExplanations && answer.explanation && /* @__PURE__ */ (0,
|
|
3388
|
-
/* @__PURE__ */ (0,
|
|
3751
|
+
showExplanations && answer.explanation && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.explanation, children: [
|
|
3752
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Explanation:" }),
|
|
3389
3753
|
" ",
|
|
3390
3754
|
answer.explanation
|
|
3391
3755
|
] }),
|
|
3392
|
-
showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && /* @__PURE__ */ (0,
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3756
|
+
showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: defaultStyles2.chatHistorySection, children: [
|
|
3757
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3394
3758
|
"button",
|
|
3395
3759
|
{
|
|
3396
3760
|
style: defaultStyles2.chatToggleButton,
|
|
3397
3761
|
onClick: () => toggleChatExpanded(answer.questionId),
|
|
3398
3762
|
"data-testid": `button-toggle-chat-${answer.questionId}`,
|
|
3399
3763
|
children: [
|
|
3400
|
-
/* @__PURE__ */ (0,
|
|
3764
|
+
/* @__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
3765
|
expandedChats.has(answer.questionId) ? "Hide" : "View",
|
|
3402
3766
|
" Chat History (",
|
|
3403
3767
|
chatHistories[answer.questionId].messages.length,
|
|
@@ -3405,7 +3769,7 @@ function AttemptViewer({
|
|
|
3405
3769
|
]
|
|
3406
3770
|
}
|
|
3407
3771
|
),
|
|
3408
|
-
expandedChats.has(answer.questionId) && /* @__PURE__ */ (0,
|
|
3772
|
+
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
3773
|
"div",
|
|
3410
3774
|
{
|
|
3411
3775
|
style: {
|
|
@@ -3423,15 +3787,621 @@ function AttemptViewer({
|
|
|
3423
3787
|
)) })
|
|
3424
3788
|
] });
|
|
3425
3789
|
}
|
|
3790
|
+
|
|
3791
|
+
// src/ErrorTypesPanel.tsx
|
|
3792
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3793
|
+
var panelStyles2 = {
|
|
3794
|
+
container: {
|
|
3795
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
3796
|
+
padding: "24px",
|
|
3797
|
+
backgroundColor: "#ffffff",
|
|
3798
|
+
borderRadius: "12px",
|
|
3799
|
+
maxWidth: "800px"
|
|
3800
|
+
},
|
|
3801
|
+
header: {
|
|
3802
|
+
marginBottom: "24px"
|
|
3803
|
+
},
|
|
3804
|
+
title: {
|
|
3805
|
+
fontSize: "20px",
|
|
3806
|
+
fontWeight: "600",
|
|
3807
|
+
color: "#111827",
|
|
3808
|
+
marginBottom: "8px"
|
|
3809
|
+
},
|
|
3810
|
+
subtitle: {
|
|
3811
|
+
fontSize: "14px",
|
|
3812
|
+
color: "#6b7280"
|
|
3813
|
+
},
|
|
3814
|
+
section: {
|
|
3815
|
+
marginBottom: "24px"
|
|
3816
|
+
},
|
|
3817
|
+
sectionTitle: {
|
|
3818
|
+
fontSize: "14px",
|
|
3819
|
+
fontWeight: "600",
|
|
3820
|
+
color: "#374151",
|
|
3821
|
+
marginBottom: "12px",
|
|
3822
|
+
textTransform: "uppercase",
|
|
3823
|
+
letterSpacing: "0.05em"
|
|
3824
|
+
},
|
|
3825
|
+
errorList: {
|
|
3826
|
+
display: "flex",
|
|
3827
|
+
flexDirection: "column",
|
|
3828
|
+
gap: "12px"
|
|
3829
|
+
},
|
|
3830
|
+
errorCard: {
|
|
3831
|
+
padding: "16px",
|
|
3832
|
+
backgroundColor: "#f9fafb",
|
|
3833
|
+
borderRadius: "8px",
|
|
3834
|
+
border: "1px solid #e5e7eb"
|
|
3835
|
+
},
|
|
3836
|
+
errorCardBlocking: {
|
|
3837
|
+
borderLeft: "4px solid #ef4444"
|
|
3838
|
+
},
|
|
3839
|
+
errorCardNonBlocking: {
|
|
3840
|
+
borderLeft: "4px solid #f59e0b"
|
|
3841
|
+
},
|
|
3842
|
+
errorHeader: {
|
|
3843
|
+
display: "flex",
|
|
3844
|
+
justifyContent: "space-between",
|
|
3845
|
+
alignItems: "flex-start",
|
|
3846
|
+
marginBottom: "8px"
|
|
3847
|
+
},
|
|
3848
|
+
errorCode: {
|
|
3849
|
+
fontSize: "13px",
|
|
3850
|
+
fontWeight: "600",
|
|
3851
|
+
color: "#1f2937",
|
|
3852
|
+
fontFamily: "monospace",
|
|
3853
|
+
backgroundColor: "#e5e7eb",
|
|
3854
|
+
padding: "2px 8px",
|
|
3855
|
+
borderRadius: "4px"
|
|
3856
|
+
},
|
|
3857
|
+
errorBadge: {
|
|
3858
|
+
fontSize: "11px",
|
|
3859
|
+
fontWeight: "500",
|
|
3860
|
+
padding: "2px 8px",
|
|
3861
|
+
borderRadius: "12px"
|
|
3862
|
+
},
|
|
3863
|
+
blockingBadge: {
|
|
3864
|
+
backgroundColor: "#fee2e2",
|
|
3865
|
+
color: "#dc2626"
|
|
3866
|
+
},
|
|
3867
|
+
nonBlockingBadge: {
|
|
3868
|
+
backgroundColor: "#fef3c7",
|
|
3869
|
+
color: "#d97706"
|
|
3870
|
+
},
|
|
3871
|
+
userMessage: {
|
|
3872
|
+
fontSize: "15px",
|
|
3873
|
+
fontWeight: "500",
|
|
3874
|
+
color: "#111827",
|
|
3875
|
+
marginBottom: "4px"
|
|
3876
|
+
},
|
|
3877
|
+
subMessage: {
|
|
3878
|
+
fontSize: "13px",
|
|
3879
|
+
color: "#6b7280",
|
|
3880
|
+
marginBottom: "8px"
|
|
3881
|
+
},
|
|
3882
|
+
causeLabel: {
|
|
3883
|
+
fontSize: "11px",
|
|
3884
|
+
fontWeight: "600",
|
|
3885
|
+
color: "#9ca3af",
|
|
3886
|
+
textTransform: "uppercase",
|
|
3887
|
+
marginBottom: "4px"
|
|
3888
|
+
},
|
|
3889
|
+
causeText: {
|
|
3890
|
+
fontSize: "13px",
|
|
3891
|
+
color: "#4b5563",
|
|
3892
|
+
fontStyle: "italic"
|
|
3893
|
+
}
|
|
3894
|
+
};
|
|
3895
|
+
function ErrorTypesPanel({ className }) {
|
|
3896
|
+
const blockingErrors = Object.values(ERROR_DEFINITIONS).filter((e) => e.isBlocking);
|
|
3897
|
+
const nonBlockingErrors = Object.values(ERROR_DEFINITIONS).filter((e) => !e.isBlocking);
|
|
3898
|
+
const renderErrorCard = (error) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3899
|
+
"div",
|
|
3900
|
+
{
|
|
3901
|
+
style: {
|
|
3902
|
+
...panelStyles2.errorCard,
|
|
3903
|
+
...error.isBlocking ? panelStyles2.errorCardBlocking : panelStyles2.errorCardNonBlocking
|
|
3904
|
+
},
|
|
3905
|
+
"data-testid": `error-card-${error.code}`,
|
|
3906
|
+
children: [
|
|
3907
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.errorHeader, children: [
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { style: panelStyles2.errorCode, children: error.code }),
|
|
3909
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3910
|
+
"span",
|
|
3911
|
+
{
|
|
3912
|
+
style: {
|
|
3913
|
+
...panelStyles2.errorBadge,
|
|
3914
|
+
...error.isBlocking ? panelStyles2.blockingBadge : panelStyles2.nonBlockingBadge
|
|
3915
|
+
},
|
|
3916
|
+
children: error.isBlocking ? "Blocking" : "Non-Blocking"
|
|
3917
|
+
}
|
|
3918
|
+
)
|
|
3919
|
+
] }),
|
|
3920
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.userMessage, children: error.userMessage }),
|
|
3921
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.subMessage, children: error.subMessage }),
|
|
3922
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.causeLabel, children: "Why this happens:" }),
|
|
3923
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.causeText, children: error.cause })
|
|
3924
|
+
]
|
|
3925
|
+
},
|
|
3926
|
+
error.code
|
|
3927
|
+
);
|
|
3928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.container, className, "data-testid": "error-types-panel", children: [
|
|
3929
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.header, children: [
|
|
3930
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { style: panelStyles2.title, children: "Error Types Reference" }),
|
|
3931
|
+
/* @__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." })
|
|
3932
|
+
] }),
|
|
3933
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.section, children: [
|
|
3934
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: panelStyles2.sectionTitle, children: [
|
|
3935
|
+
"Blocking Errors (",
|
|
3936
|
+
blockingErrors.length,
|
|
3937
|
+
")"
|
|
3938
|
+
] }),
|
|
3939
|
+
/* @__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." }),
|
|
3940
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.errorList, children: blockingErrors.map(renderErrorCard) })
|
|
3941
|
+
] }),
|
|
3942
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: panelStyles2.section, children: [
|
|
3943
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: panelStyles2.sectionTitle, children: [
|
|
3944
|
+
"Non-Blocking Errors (",
|
|
3945
|
+
nonBlockingErrors.length,
|
|
3946
|
+
")"
|
|
3947
|
+
] }),
|
|
3948
|
+
/* @__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." }),
|
|
3949
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: panelStyles2.errorList, children: nonBlockingErrors.map(renderErrorCard) })
|
|
3950
|
+
] })
|
|
3951
|
+
] });
|
|
3952
|
+
}
|
|
3953
|
+
|
|
3954
|
+
// src/ErrorLogsPanel.tsx
|
|
3955
|
+
var import_react5 = require("react");
|
|
3956
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3957
|
+
var panelStyles3 = {
|
|
3958
|
+
container: {
|
|
3959
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
3960
|
+
padding: "24px",
|
|
3961
|
+
backgroundColor: "#ffffff",
|
|
3962
|
+
borderRadius: "12px",
|
|
3963
|
+
maxWidth: "1000px"
|
|
3964
|
+
},
|
|
3965
|
+
header: {
|
|
3966
|
+
marginBottom: "24px"
|
|
3967
|
+
},
|
|
3968
|
+
title: {
|
|
3969
|
+
fontSize: "20px",
|
|
3970
|
+
fontWeight: "600",
|
|
3971
|
+
color: "#111827",
|
|
3972
|
+
marginBottom: "8px"
|
|
3973
|
+
},
|
|
3974
|
+
subtitle: {
|
|
3975
|
+
fontSize: "14px",
|
|
3976
|
+
color: "#6b7280"
|
|
3977
|
+
},
|
|
3978
|
+
tabs: {
|
|
3979
|
+
display: "flex",
|
|
3980
|
+
gap: "8px",
|
|
3981
|
+
marginBottom: "16px",
|
|
3982
|
+
borderBottom: "1px solid #e5e7eb",
|
|
3983
|
+
paddingBottom: "12px"
|
|
3984
|
+
},
|
|
3985
|
+
tab: {
|
|
3986
|
+
padding: "8px 16px",
|
|
3987
|
+
fontSize: "14px",
|
|
3988
|
+
fontWeight: "500",
|
|
3989
|
+
borderRadius: "6px",
|
|
3990
|
+
cursor: "pointer",
|
|
3991
|
+
border: "none",
|
|
3992
|
+
backgroundColor: "transparent",
|
|
3993
|
+
color: "#6b7280"
|
|
3994
|
+
},
|
|
3995
|
+
tabActive: {
|
|
3996
|
+
backgroundColor: "#6721b0",
|
|
3997
|
+
color: "#ffffff"
|
|
3998
|
+
},
|
|
3999
|
+
stats: {
|
|
4000
|
+
display: "flex",
|
|
4001
|
+
gap: "16px",
|
|
4002
|
+
marginBottom: "20px"
|
|
4003
|
+
},
|
|
4004
|
+
statCard: {
|
|
4005
|
+
padding: "12px 16px",
|
|
4006
|
+
backgroundColor: "#f9fafb",
|
|
4007
|
+
borderRadius: "8px",
|
|
4008
|
+
flex: 1
|
|
4009
|
+
},
|
|
4010
|
+
statValue: {
|
|
4011
|
+
fontSize: "24px",
|
|
4012
|
+
fontWeight: "700",
|
|
4013
|
+
color: "#111827"
|
|
4014
|
+
},
|
|
4015
|
+
statLabel: {
|
|
4016
|
+
fontSize: "12px",
|
|
4017
|
+
color: "#6b7280",
|
|
4018
|
+
textTransform: "uppercase",
|
|
4019
|
+
letterSpacing: "0.05em"
|
|
4020
|
+
},
|
|
4021
|
+
errorList: {
|
|
4022
|
+
display: "flex",
|
|
4023
|
+
flexDirection: "column",
|
|
4024
|
+
gap: "12px"
|
|
4025
|
+
},
|
|
4026
|
+
errorCard: {
|
|
4027
|
+
padding: "16px",
|
|
4028
|
+
backgroundColor: "#f9fafb",
|
|
4029
|
+
borderRadius: "8px",
|
|
4030
|
+
border: "1px solid #e5e7eb"
|
|
4031
|
+
},
|
|
4032
|
+
errorCardRecent: {
|
|
4033
|
+
borderLeft: "4px solid #ef4444",
|
|
4034
|
+
backgroundColor: "#fef2f2"
|
|
4035
|
+
},
|
|
4036
|
+
errorCardOld: {
|
|
4037
|
+
borderLeft: "4px solid #9ca3af",
|
|
4038
|
+
opacity: 0.7
|
|
4039
|
+
},
|
|
4040
|
+
errorHeader: {
|
|
4041
|
+
display: "flex",
|
|
4042
|
+
justifyContent: "space-between",
|
|
4043
|
+
alignItems: "flex-start",
|
|
4044
|
+
marginBottom: "8px"
|
|
4045
|
+
},
|
|
4046
|
+
errorLeft: {
|
|
4047
|
+
flex: 1
|
|
4048
|
+
},
|
|
4049
|
+
errorCode: {
|
|
4050
|
+
fontSize: "13px",
|
|
4051
|
+
fontWeight: "600",
|
|
4052
|
+
color: "#1f2937",
|
|
4053
|
+
fontFamily: "monospace",
|
|
4054
|
+
backgroundColor: "#e5e7eb",
|
|
4055
|
+
padding: "2px 8px",
|
|
4056
|
+
borderRadius: "4px",
|
|
4057
|
+
display: "inline-block"
|
|
4058
|
+
},
|
|
4059
|
+
countBadge: {
|
|
4060
|
+
fontSize: "14px",
|
|
4061
|
+
fontWeight: "700",
|
|
4062
|
+
padding: "4px 12px",
|
|
4063
|
+
borderRadius: "16px",
|
|
4064
|
+
backgroundColor: "#ef4444",
|
|
4065
|
+
color: "#ffffff"
|
|
4066
|
+
},
|
|
4067
|
+
countBadgeLow: {
|
|
4068
|
+
backgroundColor: "#f59e0b"
|
|
4069
|
+
},
|
|
4070
|
+
contextBadge: {
|
|
4071
|
+
fontSize: "11px",
|
|
4072
|
+
fontWeight: "500",
|
|
4073
|
+
padding: "2px 8px",
|
|
4074
|
+
borderRadius: "4px",
|
|
4075
|
+
marginLeft: "8px",
|
|
4076
|
+
backgroundColor: "#dbeafe",
|
|
4077
|
+
color: "#1d4ed8"
|
|
4078
|
+
},
|
|
4079
|
+
userMessage: {
|
|
4080
|
+
fontSize: "15px",
|
|
4081
|
+
fontWeight: "500",
|
|
4082
|
+
color: "#111827",
|
|
4083
|
+
marginTop: "8px",
|
|
4084
|
+
marginBottom: "4px"
|
|
4085
|
+
},
|
|
4086
|
+
resourceId: {
|
|
4087
|
+
fontSize: "12px",
|
|
4088
|
+
color: "#6b7280",
|
|
4089
|
+
fontFamily: "monospace",
|
|
4090
|
+
marginTop: "4px"
|
|
4091
|
+
},
|
|
4092
|
+
resourceLink: {
|
|
4093
|
+
color: "#6721b0",
|
|
4094
|
+
textDecoration: "underline",
|
|
4095
|
+
cursor: "pointer"
|
|
4096
|
+
},
|
|
4097
|
+
timestamps: {
|
|
4098
|
+
display: "flex",
|
|
4099
|
+
gap: "16px",
|
|
4100
|
+
marginTop: "8px",
|
|
4101
|
+
fontSize: "12px",
|
|
4102
|
+
color: "#9ca3af"
|
|
4103
|
+
},
|
|
4104
|
+
dismissButton: {
|
|
4105
|
+
padding: "6px 12px",
|
|
4106
|
+
fontSize: "12px",
|
|
4107
|
+
fontWeight: "500",
|
|
4108
|
+
borderRadius: "4px",
|
|
4109
|
+
cursor: "pointer",
|
|
4110
|
+
border: "1px solid #e5e7eb",
|
|
4111
|
+
backgroundColor: "#ffffff",
|
|
4112
|
+
color: "#6b7280",
|
|
4113
|
+
marginTop: "8px"
|
|
4114
|
+
},
|
|
4115
|
+
dismissButtonHover: {
|
|
4116
|
+
backgroundColor: "#f3f4f6"
|
|
4117
|
+
},
|
|
4118
|
+
emptyState: {
|
|
4119
|
+
textAlign: "center",
|
|
4120
|
+
padding: "40px",
|
|
4121
|
+
color: "#9ca3af",
|
|
4122
|
+
fontSize: "14px"
|
|
4123
|
+
},
|
|
4124
|
+
loading: {
|
|
4125
|
+
textAlign: "center",
|
|
4126
|
+
padding: "40px",
|
|
4127
|
+
color: "#6b7280",
|
|
4128
|
+
fontSize: "14px"
|
|
4129
|
+
},
|
|
4130
|
+
pagination: {
|
|
4131
|
+
display: "flex",
|
|
4132
|
+
justifyContent: "center",
|
|
4133
|
+
gap: "8px",
|
|
4134
|
+
marginTop: "20px"
|
|
4135
|
+
},
|
|
4136
|
+
pageButton: {
|
|
4137
|
+
padding: "8px 12px",
|
|
4138
|
+
fontSize: "14px",
|
|
4139
|
+
borderRadius: "4px",
|
|
4140
|
+
cursor: "pointer",
|
|
4141
|
+
border: "1px solid #e5e7eb",
|
|
4142
|
+
backgroundColor: "#ffffff",
|
|
4143
|
+
color: "#374151"
|
|
4144
|
+
},
|
|
4145
|
+
pageButtonDisabled: {
|
|
4146
|
+
opacity: 0.5,
|
|
4147
|
+
cursor: "not-allowed"
|
|
4148
|
+
}
|
|
4149
|
+
};
|
|
4150
|
+
function formatRelativeTime(dateStr) {
|
|
4151
|
+
const date = new Date(dateStr);
|
|
4152
|
+
const now = /* @__PURE__ */ new Date();
|
|
4153
|
+
const diffMs = now.getTime() - date.getTime();
|
|
4154
|
+
const diffMins = Math.floor(diffMs / 6e4);
|
|
4155
|
+
const diffHours = Math.floor(diffMs / 36e5);
|
|
4156
|
+
const diffDays = Math.floor(diffMs / 864e5);
|
|
4157
|
+
if (diffMins < 1) return "Just now";
|
|
4158
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
4159
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
4160
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
4161
|
+
return date.toLocaleDateString();
|
|
4162
|
+
}
|
|
4163
|
+
function isRecent(dateStr) {
|
|
4164
|
+
const date = new Date(dateStr);
|
|
4165
|
+
const now = /* @__PURE__ */ new Date();
|
|
4166
|
+
const diffMs = now.getTime() - date.getTime();
|
|
4167
|
+
const diffHours = diffMs / 36e5;
|
|
4168
|
+
return diffHours < 24;
|
|
4169
|
+
}
|
|
4170
|
+
function ErrorLogsPanel({ apiBaseUrl, authToken, onResourceClick }) {
|
|
4171
|
+
const [logs, setLogs] = (0, import_react5.useState)([]);
|
|
4172
|
+
const [loading, setLoading] = (0, import_react5.useState)(true);
|
|
4173
|
+
const [showDismissed, setShowDismissed] = (0, import_react5.useState)(false);
|
|
4174
|
+
const [page, setPage] = (0, import_react5.useState)(1);
|
|
4175
|
+
const [totalPages, setTotalPages] = (0, import_react5.useState)(1);
|
|
4176
|
+
const [total, setTotal] = (0, import_react5.useState)(0);
|
|
4177
|
+
(0, import_react5.useEffect)(() => {
|
|
4178
|
+
fetchLogs();
|
|
4179
|
+
}, [showDismissed, page]);
|
|
4180
|
+
async function fetchLogs() {
|
|
4181
|
+
setLoading(true);
|
|
4182
|
+
try {
|
|
4183
|
+
const params = new URLSearchParams();
|
|
4184
|
+
params.set("dismissed", showDismissed ? "true" : "false");
|
|
4185
|
+
params.set("page", page.toString());
|
|
4186
|
+
params.set("limit", "20");
|
|
4187
|
+
const response = await fetch(`${apiBaseUrl}/api/admin/error-logs?${params}`, {
|
|
4188
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
4189
|
+
});
|
|
4190
|
+
if (response.ok) {
|
|
4191
|
+
const data = await response.json();
|
|
4192
|
+
setLogs(data.items || []);
|
|
4193
|
+
setTotalPages(data.totalPages || 1);
|
|
4194
|
+
setTotal(data.total || 0);
|
|
4195
|
+
}
|
|
4196
|
+
} catch (err) {
|
|
4197
|
+
console.error("Failed to fetch error logs:", err);
|
|
4198
|
+
} finally {
|
|
4199
|
+
setLoading(false);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
async function handleDismiss(id) {
|
|
4203
|
+
try {
|
|
4204
|
+
const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/dismiss`, {
|
|
4205
|
+
method: "PATCH",
|
|
4206
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
4207
|
+
});
|
|
4208
|
+
if (response.ok) {
|
|
4209
|
+
fetchLogs();
|
|
4210
|
+
}
|
|
4211
|
+
} catch (err) {
|
|
4212
|
+
console.error("Failed to dismiss error:", err);
|
|
4213
|
+
}
|
|
4214
|
+
}
|
|
4215
|
+
async function handleUndismiss(id) {
|
|
4216
|
+
try {
|
|
4217
|
+
const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/undismiss`, {
|
|
4218
|
+
method: "PATCH",
|
|
4219
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
4220
|
+
});
|
|
4221
|
+
if (response.ok) {
|
|
4222
|
+
fetchLogs();
|
|
4223
|
+
}
|
|
4224
|
+
} catch (err) {
|
|
4225
|
+
console.error("Failed to undismiss error:", err);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
function getErrorDefinition(code) {
|
|
4229
|
+
return ERROR_DEFINITIONS[code];
|
|
4230
|
+
}
|
|
4231
|
+
const totalErrors = logs.reduce((sum, log) => sum + log.count, 0);
|
|
4232
|
+
const recentCount = logs.filter((log) => isRecent(log.lastSeenAt)).length;
|
|
4233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.container, "data-testid": "error-logs-panel", children: [
|
|
4234
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.header, children: [
|
|
4235
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: panelStyles3.title, children: "Error Tracking" }),
|
|
4236
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: panelStyles3.subtitle, children: "Aggregated errors from QuizPlayer and AttemptViewer components, sorted by occurrence count" })
|
|
4237
|
+
] }),
|
|
4238
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.tabs, children: [
|
|
4239
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4240
|
+
"button",
|
|
4241
|
+
{
|
|
4242
|
+
style: {
|
|
4243
|
+
...panelStyles3.tab,
|
|
4244
|
+
...showDismissed ? {} : panelStyles3.tabActive
|
|
4245
|
+
},
|
|
4246
|
+
onClick: () => {
|
|
4247
|
+
setShowDismissed(false);
|
|
4248
|
+
setPage(1);
|
|
4249
|
+
},
|
|
4250
|
+
"data-testid": "tab-active-errors",
|
|
4251
|
+
children: "Active Errors"
|
|
4252
|
+
}
|
|
4253
|
+
),
|
|
4254
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4255
|
+
"button",
|
|
4256
|
+
{
|
|
4257
|
+
style: {
|
|
4258
|
+
...panelStyles3.tab,
|
|
4259
|
+
...showDismissed ? panelStyles3.tabActive : {}
|
|
4260
|
+
},
|
|
4261
|
+
onClick: () => {
|
|
4262
|
+
setShowDismissed(true);
|
|
4263
|
+
setPage(1);
|
|
4264
|
+
},
|
|
4265
|
+
"data-testid": "tab-dismissed-errors",
|
|
4266
|
+
children: "Dismissed"
|
|
4267
|
+
}
|
|
4268
|
+
)
|
|
4269
|
+
] }),
|
|
4270
|
+
!showDismissed && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.stats, children: [
|
|
4271
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
|
|
4272
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statValue, children: total }),
|
|
4273
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Unique Errors" })
|
|
4274
|
+
] }),
|
|
4275
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
|
|
4276
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statValue, children: totalErrors }),
|
|
4277
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Total Occurrences" })
|
|
4278
|
+
] }),
|
|
4279
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.statCard, children: [
|
|
4280
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...panelStyles3.statValue, color: recentCount > 0 ? "#ef4444" : "#22c55e" }, children: recentCount }),
|
|
4281
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.statLabel, children: "Last 24h" })
|
|
4282
|
+
] })
|
|
4283
|
+
] }),
|
|
4284
|
+
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) => {
|
|
4285
|
+
const def = getErrorDefinition(log.errorCode);
|
|
4286
|
+
const recent = isRecent(log.lastSeenAt);
|
|
4287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4288
|
+
"div",
|
|
4289
|
+
{
|
|
4290
|
+
style: {
|
|
4291
|
+
...panelStyles3.errorCard,
|
|
4292
|
+
...recent ? panelStyles3.errorCardRecent : panelStyles3.errorCardOld
|
|
4293
|
+
},
|
|
4294
|
+
"data-testid": `error-log-${log.id}`,
|
|
4295
|
+
children: [
|
|
4296
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.errorHeader, children: [
|
|
4297
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.errorLeft, children: [
|
|
4298
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: panelStyles3.errorCode, children: log.errorCode }),
|
|
4299
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: panelStyles3.contextBadge, children: log.context }),
|
|
4300
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...panelStyles3.contextBadge, backgroundColor: "#f3e8ff", color: "#7c3aed" }, children: log.component })
|
|
4301
|
+
] }),
|
|
4302
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4303
|
+
"span",
|
|
4304
|
+
{
|
|
4305
|
+
style: {
|
|
4306
|
+
...panelStyles3.countBadge,
|
|
4307
|
+
...log.count < 10 ? panelStyles3.countBadgeLow : {}
|
|
4308
|
+
},
|
|
4309
|
+
children: [
|
|
4310
|
+
log.count,
|
|
4311
|
+
"x"
|
|
4312
|
+
]
|
|
4313
|
+
}
|
|
4314
|
+
)
|
|
4315
|
+
] }),
|
|
4316
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: panelStyles3.userMessage, children: def?.userMessage || log.lastMessage || "Unknown error" }),
|
|
4317
|
+
log.resourceId && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.resourceId, children: [
|
|
4318
|
+
"Resource:",
|
|
4319
|
+
" ",
|
|
4320
|
+
onResourceClick ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4321
|
+
"span",
|
|
4322
|
+
{
|
|
4323
|
+
style: panelStyles3.resourceLink,
|
|
4324
|
+
onClick: () => onResourceClick(log.resourceId, log.context),
|
|
4325
|
+
"data-testid": `link-resource-${log.id}`,
|
|
4326
|
+
children: log.resourceId
|
|
4327
|
+
}
|
|
4328
|
+
) : log.resourceId
|
|
4329
|
+
] }),
|
|
4330
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.timestamps, children: [
|
|
4331
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
4332
|
+
"First: ",
|
|
4333
|
+
formatRelativeTime(log.firstSeenAt)
|
|
4334
|
+
] }),
|
|
4335
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
4336
|
+
"Last: ",
|
|
4337
|
+
formatRelativeTime(log.lastSeenAt)
|
|
4338
|
+
] })
|
|
4339
|
+
] }),
|
|
4340
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4341
|
+
"button",
|
|
4342
|
+
{
|
|
4343
|
+
style: panelStyles3.dismissButton,
|
|
4344
|
+
onClick: () => showDismissed ? handleUndismiss(log.id) : handleDismiss(log.id),
|
|
4345
|
+
"data-testid": `button-dismiss-${log.id}`,
|
|
4346
|
+
children: showDismissed ? "Restore" : "Dismiss"
|
|
4347
|
+
}
|
|
4348
|
+
)
|
|
4349
|
+
]
|
|
4350
|
+
},
|
|
4351
|
+
log.id
|
|
4352
|
+
);
|
|
4353
|
+
}) }),
|
|
4354
|
+
totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: panelStyles3.pagination, children: [
|
|
4355
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4356
|
+
"button",
|
|
4357
|
+
{
|
|
4358
|
+
style: {
|
|
4359
|
+
...panelStyles3.pageButton,
|
|
4360
|
+
...page <= 1 ? panelStyles3.pageButtonDisabled : {}
|
|
4361
|
+
},
|
|
4362
|
+
onClick: () => setPage((p) => Math.max(1, p - 1)),
|
|
4363
|
+
disabled: page <= 1,
|
|
4364
|
+
"data-testid": "button-prev-page",
|
|
4365
|
+
children: "Previous"
|
|
4366
|
+
}
|
|
4367
|
+
),
|
|
4368
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { padding: "8px 12px", color: "#6b7280" }, children: [
|
|
4369
|
+
"Page ",
|
|
4370
|
+
page,
|
|
4371
|
+
" of ",
|
|
4372
|
+
totalPages
|
|
4373
|
+
] }),
|
|
4374
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4375
|
+
"button",
|
|
4376
|
+
{
|
|
4377
|
+
style: {
|
|
4378
|
+
...panelStyles3.pageButton,
|
|
4379
|
+
...page >= totalPages ? panelStyles3.pageButtonDisabled : {}
|
|
4380
|
+
},
|
|
4381
|
+
onClick: () => setPage((p) => Math.min(totalPages, p + 1)),
|
|
4382
|
+
disabled: page >= totalPages,
|
|
4383
|
+
"data-testid": "button-next-page",
|
|
4384
|
+
children: "Next"
|
|
4385
|
+
}
|
|
4386
|
+
)
|
|
4387
|
+
] })
|
|
4388
|
+
] });
|
|
4389
|
+
}
|
|
3426
4390
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3427
4391
|
0 && (module.exports = {
|
|
3428
4392
|
AttemptViewer,
|
|
4393
|
+
ERROR_DEFINITIONS,
|
|
4394
|
+
ErrorLogsPanel,
|
|
4395
|
+
ErrorTypesPanel,
|
|
4396
|
+
MaintenanceScreen,
|
|
3429
4397
|
QuizApiClient,
|
|
3430
4398
|
QuizPlayer,
|
|
3431
4399
|
TextToSpeech,
|
|
3432
4400
|
calculateScore,
|
|
3433
4401
|
checkAnswer,
|
|
3434
4402
|
createAnswerDetail,
|
|
3435
|
-
formatTime
|
|
4403
|
+
formatTime,
|
|
4404
|
+
getErrorFromHttpStatus,
|
|
4405
|
+
getErrorFromMessage
|
|
3436
4406
|
});
|
|
3437
4407
|
//# sourceMappingURL=index.js.map
|