@thanh01.pmt/interactive-quiz-kit 1.0.47 → 1.0.49
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/authoring.cjs +53 -25
- package/dist/authoring.mjs +53 -25
- package/dist/index.cjs +53 -25
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +53 -25
- package/dist/react-ui.cjs +77 -31
- package/dist/react-ui.d.cts +6 -3
- package/dist/react-ui.d.ts +6 -3
- package/dist/react-ui.mjs +77 -31
- package/package.json +1 -1
package/dist/authoring.cjs
CHANGED
|
@@ -3998,20 +3998,30 @@ var PracticeHistoryService = class {
|
|
|
3998
3998
|
static saveHistory(history2) {
|
|
3999
3999
|
if (typeof window !== "undefined") {
|
|
4000
4000
|
try {
|
|
4001
|
-
localStorage.setItem(
|
|
4001
|
+
localStorage.setItem(
|
|
4002
|
+
LOCAL_STORAGE_KEY,
|
|
4003
|
+
JSON.stringify(history2)
|
|
4004
|
+
);
|
|
4002
4005
|
} catch (e2) {
|
|
4003
|
-
console.error(
|
|
4006
|
+
console.error(
|
|
4007
|
+
"Error saving practice history to localStorage:",
|
|
4008
|
+
e2
|
|
4009
|
+
);
|
|
4004
4010
|
}
|
|
4005
4011
|
}
|
|
4006
4012
|
}
|
|
4007
4013
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
4008
4014
|
const history2 = this.getPracticeHistory();
|
|
4009
4015
|
const topicsCovered = Array.from(
|
|
4010
|
-
new Set(
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4016
|
+
new Set(
|
|
4017
|
+
quizConfig.questions.map(
|
|
4018
|
+
(q) => JSON.stringify({
|
|
4019
|
+
subject: q.subject || "Uncategorized",
|
|
4020
|
+
category: q.category || "General",
|
|
4021
|
+
topic: q.topic || "General Topic"
|
|
4022
|
+
})
|
|
4023
|
+
)
|
|
4024
|
+
)
|
|
4015
4025
|
).map((s2) => JSON.parse(s2));
|
|
4016
4026
|
const newSession = {
|
|
4017
4027
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -4029,7 +4039,9 @@ var PracticeHistoryService = class {
|
|
|
4029
4039
|
history2.unshift(newSession);
|
|
4030
4040
|
this.saveHistory(history2);
|
|
4031
4041
|
if (this.syncProvider) {
|
|
4032
|
-
console.log(
|
|
4042
|
+
console.log(
|
|
4043
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
4044
|
+
);
|
|
4033
4045
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
4034
4046
|
console.error("Sync provider failed to push session:", err);
|
|
4035
4047
|
});
|
|
@@ -4043,7 +4055,9 @@ var PracticeHistoryService = class {
|
|
|
4043
4055
|
history2[sessionIndex].quizReview = review;
|
|
4044
4056
|
this.saveHistory(history2);
|
|
4045
4057
|
} else {
|
|
4046
|
-
console.warn(
|
|
4058
|
+
console.warn(
|
|
4059
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
4060
|
+
);
|
|
4047
4061
|
}
|
|
4048
4062
|
}
|
|
4049
4063
|
static getPracticeSessionById(sessionId) {
|
|
@@ -4063,6 +4077,14 @@ var PracticeHistoryService = class {
|
|
|
4063
4077
|
}
|
|
4064
4078
|
static getPracticeStats() {
|
|
4065
4079
|
const history2 = this.getPracticeHistory();
|
|
4080
|
+
return this.calculateStatsFromHistory(history2);
|
|
4081
|
+
}
|
|
4082
|
+
static clearHistory() {
|
|
4083
|
+
if (typeof window !== "undefined") {
|
|
4084
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
static calculateStatsFromHistory(history2) {
|
|
4066
4088
|
if (history2.length === 0) {
|
|
4067
4089
|
return {
|
|
4068
4090
|
totalSessions: 0,
|
|
@@ -4101,7 +4123,9 @@ var PracticeHistoryService = class {
|
|
|
4101
4123
|
const currentDay = new Date(sortedDays[i]);
|
|
4102
4124
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
4103
4125
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
4104
|
-
const diffDays = Math.round(
|
|
4126
|
+
const diffDays = Math.round(
|
|
4127
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
4128
|
+
);
|
|
4105
4129
|
if (diffDays === 1) {
|
|
4106
4130
|
currentStreak++;
|
|
4107
4131
|
} else {
|
|
@@ -4133,22 +4157,31 @@ var PracticeHistoryService = class {
|
|
|
4133
4157
|
const subjectPerf = {};
|
|
4134
4158
|
const topicPerf = {};
|
|
4135
4159
|
history2.forEach((session) => {
|
|
4136
|
-
session.summary.topics.forEach(
|
|
4137
|
-
|
|
4138
|
-
if (
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4160
|
+
session.summary.topics.forEach(
|
|
4161
|
+
(topicInfo) => {
|
|
4162
|
+
if (session.summary.percentage !== null) {
|
|
4163
|
+
if (!subjectPerf[topicInfo.subject])
|
|
4164
|
+
subjectPerf[topicInfo.subject] = {
|
|
4165
|
+
total: 0,
|
|
4166
|
+
count: 0
|
|
4167
|
+
};
|
|
4168
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
4169
|
+
subjectPerf[topicInfo.subject].count++;
|
|
4170
|
+
if (!topicPerf[topicInfo.topic])
|
|
4171
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
4172
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
4173
|
+
topicPerf[topicInfo.topic].count++;
|
|
4174
|
+
}
|
|
4144
4175
|
}
|
|
4145
|
-
|
|
4176
|
+
);
|
|
4146
4177
|
});
|
|
4147
4178
|
const formatPerf = (perfData) => {
|
|
4148
4179
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
4149
4180
|
name: name3,
|
|
4150
4181
|
totalSessions: data.count,
|
|
4151
|
-
averageScore: parseFloat(
|
|
4182
|
+
averageScore: parseFloat(
|
|
4183
|
+
(data.total / data.count).toFixed(2)
|
|
4184
|
+
)
|
|
4152
4185
|
})).sort((a2, b) => b.totalSessions - a2.totalSessions);
|
|
4153
4186
|
};
|
|
4154
4187
|
return {
|
|
@@ -4160,11 +4193,6 @@ var PracticeHistoryService = class {
|
|
|
4160
4193
|
performanceByTopic: formatPerf(topicPerf)
|
|
4161
4194
|
};
|
|
4162
4195
|
}
|
|
4163
|
-
static clearHistory() {
|
|
4164
|
-
if (typeof window !== "undefined") {
|
|
4165
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
4166
|
-
}
|
|
4167
|
-
}
|
|
4168
4196
|
};
|
|
4169
4197
|
// NEW: A static property to hold the injected sync provider
|
|
4170
4198
|
PracticeHistoryService.syncProvider = null;
|
package/dist/authoring.mjs
CHANGED
|
@@ -3972,20 +3972,30 @@ var PracticeHistoryService = class {
|
|
|
3972
3972
|
static saveHistory(history2) {
|
|
3973
3973
|
if (typeof window !== "undefined") {
|
|
3974
3974
|
try {
|
|
3975
|
-
localStorage.setItem(
|
|
3975
|
+
localStorage.setItem(
|
|
3976
|
+
LOCAL_STORAGE_KEY,
|
|
3977
|
+
JSON.stringify(history2)
|
|
3978
|
+
);
|
|
3976
3979
|
} catch (e2) {
|
|
3977
|
-
console.error(
|
|
3980
|
+
console.error(
|
|
3981
|
+
"Error saving practice history to localStorage:",
|
|
3982
|
+
e2
|
|
3983
|
+
);
|
|
3978
3984
|
}
|
|
3979
3985
|
}
|
|
3980
3986
|
}
|
|
3981
3987
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
3982
3988
|
const history2 = this.getPracticeHistory();
|
|
3983
3989
|
const topicsCovered = Array.from(
|
|
3984
|
-
new Set(
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3990
|
+
new Set(
|
|
3991
|
+
quizConfig.questions.map(
|
|
3992
|
+
(q) => JSON.stringify({
|
|
3993
|
+
subject: q.subject || "Uncategorized",
|
|
3994
|
+
category: q.category || "General",
|
|
3995
|
+
topic: q.topic || "General Topic"
|
|
3996
|
+
})
|
|
3997
|
+
)
|
|
3998
|
+
)
|
|
3989
3999
|
).map((s2) => JSON.parse(s2));
|
|
3990
4000
|
const newSession = {
|
|
3991
4001
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -4003,7 +4013,9 @@ var PracticeHistoryService = class {
|
|
|
4003
4013
|
history2.unshift(newSession);
|
|
4004
4014
|
this.saveHistory(history2);
|
|
4005
4015
|
if (this.syncProvider) {
|
|
4006
|
-
console.log(
|
|
4016
|
+
console.log(
|
|
4017
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
4018
|
+
);
|
|
4007
4019
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
4008
4020
|
console.error("Sync provider failed to push session:", err);
|
|
4009
4021
|
});
|
|
@@ -4017,7 +4029,9 @@ var PracticeHistoryService = class {
|
|
|
4017
4029
|
history2[sessionIndex].quizReview = review;
|
|
4018
4030
|
this.saveHistory(history2);
|
|
4019
4031
|
} else {
|
|
4020
|
-
console.warn(
|
|
4032
|
+
console.warn(
|
|
4033
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
4034
|
+
);
|
|
4021
4035
|
}
|
|
4022
4036
|
}
|
|
4023
4037
|
static getPracticeSessionById(sessionId) {
|
|
@@ -4037,6 +4051,14 @@ var PracticeHistoryService = class {
|
|
|
4037
4051
|
}
|
|
4038
4052
|
static getPracticeStats() {
|
|
4039
4053
|
const history2 = this.getPracticeHistory();
|
|
4054
|
+
return this.calculateStatsFromHistory(history2);
|
|
4055
|
+
}
|
|
4056
|
+
static clearHistory() {
|
|
4057
|
+
if (typeof window !== "undefined") {
|
|
4058
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
static calculateStatsFromHistory(history2) {
|
|
4040
4062
|
if (history2.length === 0) {
|
|
4041
4063
|
return {
|
|
4042
4064
|
totalSessions: 0,
|
|
@@ -4075,7 +4097,9 @@ var PracticeHistoryService = class {
|
|
|
4075
4097
|
const currentDay = new Date(sortedDays[i]);
|
|
4076
4098
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
4077
4099
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
4078
|
-
const diffDays = Math.round(
|
|
4100
|
+
const diffDays = Math.round(
|
|
4101
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
4102
|
+
);
|
|
4079
4103
|
if (diffDays === 1) {
|
|
4080
4104
|
currentStreak++;
|
|
4081
4105
|
} else {
|
|
@@ -4107,22 +4131,31 @@ var PracticeHistoryService = class {
|
|
|
4107
4131
|
const subjectPerf = {};
|
|
4108
4132
|
const topicPerf = {};
|
|
4109
4133
|
history2.forEach((session) => {
|
|
4110
|
-
session.summary.topics.forEach(
|
|
4111
|
-
|
|
4112
|
-
if (
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4134
|
+
session.summary.topics.forEach(
|
|
4135
|
+
(topicInfo) => {
|
|
4136
|
+
if (session.summary.percentage !== null) {
|
|
4137
|
+
if (!subjectPerf[topicInfo.subject])
|
|
4138
|
+
subjectPerf[topicInfo.subject] = {
|
|
4139
|
+
total: 0,
|
|
4140
|
+
count: 0
|
|
4141
|
+
};
|
|
4142
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
4143
|
+
subjectPerf[topicInfo.subject].count++;
|
|
4144
|
+
if (!topicPerf[topicInfo.topic])
|
|
4145
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
4146
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
4147
|
+
topicPerf[topicInfo.topic].count++;
|
|
4148
|
+
}
|
|
4118
4149
|
}
|
|
4119
|
-
|
|
4150
|
+
);
|
|
4120
4151
|
});
|
|
4121
4152
|
const formatPerf = (perfData) => {
|
|
4122
4153
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
4123
4154
|
name: name3,
|
|
4124
4155
|
totalSessions: data.count,
|
|
4125
|
-
averageScore: parseFloat(
|
|
4156
|
+
averageScore: parseFloat(
|
|
4157
|
+
(data.total / data.count).toFixed(2)
|
|
4158
|
+
)
|
|
4126
4159
|
})).sort((a2, b) => b.totalSessions - a2.totalSessions);
|
|
4127
4160
|
};
|
|
4128
4161
|
return {
|
|
@@ -4134,11 +4167,6 @@ var PracticeHistoryService = class {
|
|
|
4134
4167
|
performanceByTopic: formatPerf(topicPerf)
|
|
4135
4168
|
};
|
|
4136
4169
|
}
|
|
4137
|
-
static clearHistory() {
|
|
4138
|
-
if (typeof window !== "undefined") {
|
|
4139
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
4140
|
-
}
|
|
4141
|
-
}
|
|
4142
4170
|
};
|
|
4143
4171
|
// NEW: A static property to hold the injected sync provider
|
|
4144
4172
|
PracticeHistoryService.syncProvider = null;
|
package/dist/index.cjs
CHANGED
|
@@ -1964,20 +1964,30 @@ var PracticeHistoryService = class {
|
|
|
1964
1964
|
static saveHistory(history) {
|
|
1965
1965
|
if (typeof window !== "undefined") {
|
|
1966
1966
|
try {
|
|
1967
|
-
localStorage.setItem(
|
|
1967
|
+
localStorage.setItem(
|
|
1968
|
+
LOCAL_STORAGE_KEY,
|
|
1969
|
+
JSON.stringify(history)
|
|
1970
|
+
);
|
|
1968
1971
|
} catch (e) {
|
|
1969
|
-
console.error(
|
|
1972
|
+
console.error(
|
|
1973
|
+
"Error saving practice history to localStorage:",
|
|
1974
|
+
e
|
|
1975
|
+
);
|
|
1970
1976
|
}
|
|
1971
1977
|
}
|
|
1972
1978
|
}
|
|
1973
1979
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
1974
1980
|
const history = this.getPracticeHistory();
|
|
1975
1981
|
const topicsCovered = Array.from(
|
|
1976
|
-
new Set(
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1982
|
+
new Set(
|
|
1983
|
+
quizConfig.questions.map(
|
|
1984
|
+
(q) => JSON.stringify({
|
|
1985
|
+
subject: q.subject || "Uncategorized",
|
|
1986
|
+
category: q.category || "General",
|
|
1987
|
+
topic: q.topic || "General Topic"
|
|
1988
|
+
})
|
|
1989
|
+
)
|
|
1990
|
+
)
|
|
1981
1991
|
).map((s) => JSON.parse(s));
|
|
1982
1992
|
const newSession = {
|
|
1983
1993
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -1995,7 +2005,9 @@ var PracticeHistoryService = class {
|
|
|
1995
2005
|
history.unshift(newSession);
|
|
1996
2006
|
this.saveHistory(history);
|
|
1997
2007
|
if (this.syncProvider) {
|
|
1998
|
-
console.log(
|
|
2008
|
+
console.log(
|
|
2009
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
2010
|
+
);
|
|
1999
2011
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
2000
2012
|
console.error("Sync provider failed to push session:", err);
|
|
2001
2013
|
});
|
|
@@ -2009,7 +2021,9 @@ var PracticeHistoryService = class {
|
|
|
2009
2021
|
history[sessionIndex].quizReview = review;
|
|
2010
2022
|
this.saveHistory(history);
|
|
2011
2023
|
} else {
|
|
2012
|
-
console.warn(
|
|
2024
|
+
console.warn(
|
|
2025
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
2026
|
+
);
|
|
2013
2027
|
}
|
|
2014
2028
|
}
|
|
2015
2029
|
static getPracticeSessionById(sessionId) {
|
|
@@ -2029,6 +2043,14 @@ var PracticeHistoryService = class {
|
|
|
2029
2043
|
}
|
|
2030
2044
|
static getPracticeStats() {
|
|
2031
2045
|
const history = this.getPracticeHistory();
|
|
2046
|
+
return this.calculateStatsFromHistory(history);
|
|
2047
|
+
}
|
|
2048
|
+
static clearHistory() {
|
|
2049
|
+
if (typeof window !== "undefined") {
|
|
2050
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
static calculateStatsFromHistory(history) {
|
|
2032
2054
|
if (history.length === 0) {
|
|
2033
2055
|
return {
|
|
2034
2056
|
totalSessions: 0,
|
|
@@ -2067,7 +2089,9 @@ var PracticeHistoryService = class {
|
|
|
2067
2089
|
const currentDay = new Date(sortedDays[i]);
|
|
2068
2090
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
2069
2091
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
2070
|
-
const diffDays = Math.round(
|
|
2092
|
+
const diffDays = Math.round(
|
|
2093
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
2094
|
+
);
|
|
2071
2095
|
if (diffDays === 1) {
|
|
2072
2096
|
currentStreak++;
|
|
2073
2097
|
} else {
|
|
@@ -2099,22 +2123,31 @@ var PracticeHistoryService = class {
|
|
|
2099
2123
|
const subjectPerf = {};
|
|
2100
2124
|
const topicPerf = {};
|
|
2101
2125
|
history.forEach((session) => {
|
|
2102
|
-
session.summary.topics.forEach(
|
|
2103
|
-
|
|
2104
|
-
if (
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2126
|
+
session.summary.topics.forEach(
|
|
2127
|
+
(topicInfo) => {
|
|
2128
|
+
if (session.summary.percentage !== null) {
|
|
2129
|
+
if (!subjectPerf[topicInfo.subject])
|
|
2130
|
+
subjectPerf[topicInfo.subject] = {
|
|
2131
|
+
total: 0,
|
|
2132
|
+
count: 0
|
|
2133
|
+
};
|
|
2134
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
2135
|
+
subjectPerf[topicInfo.subject].count++;
|
|
2136
|
+
if (!topicPerf[topicInfo.topic])
|
|
2137
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
2138
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
2139
|
+
topicPerf[topicInfo.topic].count++;
|
|
2140
|
+
}
|
|
2110
2141
|
}
|
|
2111
|
-
|
|
2142
|
+
);
|
|
2112
2143
|
});
|
|
2113
2144
|
const formatPerf = (perfData) => {
|
|
2114
2145
|
return Object.entries(perfData).map(([name, data]) => ({
|
|
2115
2146
|
name,
|
|
2116
2147
|
totalSessions: data.count,
|
|
2117
|
-
averageScore: parseFloat(
|
|
2148
|
+
averageScore: parseFloat(
|
|
2149
|
+
(data.total / data.count).toFixed(2)
|
|
2150
|
+
)
|
|
2118
2151
|
})).sort((a, b) => b.totalSessions - a.totalSessions);
|
|
2119
2152
|
};
|
|
2120
2153
|
return {
|
|
@@ -2126,11 +2159,6 @@ var PracticeHistoryService = class {
|
|
|
2126
2159
|
performanceByTopic: formatPerf(topicPerf)
|
|
2127
2160
|
};
|
|
2128
2161
|
}
|
|
2129
|
-
static clearHistory() {
|
|
2130
|
-
if (typeof window !== "undefined") {
|
|
2131
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
2162
|
};
|
|
2135
2163
|
// NEW: A static property to hold the injected sync provider
|
|
2136
2164
|
PracticeHistoryService.syncProvider = null;
|
package/dist/index.d.cts
CHANGED
|
@@ -246,6 +246,7 @@ declare class PracticeHistoryService {
|
|
|
246
246
|
static getPracticeHistorySummary(): PracticeSessionSummary[];
|
|
247
247
|
static getPracticeStats(): PracticeStats;
|
|
248
248
|
static clearHistory(): void;
|
|
249
|
+
static calculateStatsFromHistory(history: PracticeSession[]): PracticeStats;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
declare class AchievementService {
|
package/dist/index.d.ts
CHANGED
|
@@ -246,6 +246,7 @@ declare class PracticeHistoryService {
|
|
|
246
246
|
static getPracticeHistorySummary(): PracticeSessionSummary[];
|
|
247
247
|
static getPracticeStats(): PracticeStats;
|
|
248
248
|
static clearHistory(): void;
|
|
249
|
+
static calculateStatsFromHistory(history: PracticeSession[]): PracticeStats;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
declare class AchievementService {
|
package/dist/index.mjs
CHANGED
|
@@ -1958,20 +1958,30 @@ var PracticeHistoryService = class {
|
|
|
1958
1958
|
static saveHistory(history) {
|
|
1959
1959
|
if (typeof window !== "undefined") {
|
|
1960
1960
|
try {
|
|
1961
|
-
localStorage.setItem(
|
|
1961
|
+
localStorage.setItem(
|
|
1962
|
+
LOCAL_STORAGE_KEY,
|
|
1963
|
+
JSON.stringify(history)
|
|
1964
|
+
);
|
|
1962
1965
|
} catch (e) {
|
|
1963
|
-
console.error(
|
|
1966
|
+
console.error(
|
|
1967
|
+
"Error saving practice history to localStorage:",
|
|
1968
|
+
e
|
|
1969
|
+
);
|
|
1964
1970
|
}
|
|
1965
1971
|
}
|
|
1966
1972
|
}
|
|
1967
1973
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
1968
1974
|
const history = this.getPracticeHistory();
|
|
1969
1975
|
const topicsCovered = Array.from(
|
|
1970
|
-
new Set(
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1976
|
+
new Set(
|
|
1977
|
+
quizConfig.questions.map(
|
|
1978
|
+
(q) => JSON.stringify({
|
|
1979
|
+
subject: q.subject || "Uncategorized",
|
|
1980
|
+
category: q.category || "General",
|
|
1981
|
+
topic: q.topic || "General Topic"
|
|
1982
|
+
})
|
|
1983
|
+
)
|
|
1984
|
+
)
|
|
1975
1985
|
).map((s) => JSON.parse(s));
|
|
1976
1986
|
const newSession = {
|
|
1977
1987
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -1989,7 +1999,9 @@ var PracticeHistoryService = class {
|
|
|
1989
1999
|
history.unshift(newSession);
|
|
1990
2000
|
this.saveHistory(history);
|
|
1991
2001
|
if (this.syncProvider) {
|
|
1992
|
-
console.log(
|
|
2002
|
+
console.log(
|
|
2003
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
2004
|
+
);
|
|
1993
2005
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
1994
2006
|
console.error("Sync provider failed to push session:", err);
|
|
1995
2007
|
});
|
|
@@ -2003,7 +2015,9 @@ var PracticeHistoryService = class {
|
|
|
2003
2015
|
history[sessionIndex].quizReview = review;
|
|
2004
2016
|
this.saveHistory(history);
|
|
2005
2017
|
} else {
|
|
2006
|
-
console.warn(
|
|
2018
|
+
console.warn(
|
|
2019
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
2020
|
+
);
|
|
2007
2021
|
}
|
|
2008
2022
|
}
|
|
2009
2023
|
static getPracticeSessionById(sessionId) {
|
|
@@ -2023,6 +2037,14 @@ var PracticeHistoryService = class {
|
|
|
2023
2037
|
}
|
|
2024
2038
|
static getPracticeStats() {
|
|
2025
2039
|
const history = this.getPracticeHistory();
|
|
2040
|
+
return this.calculateStatsFromHistory(history);
|
|
2041
|
+
}
|
|
2042
|
+
static clearHistory() {
|
|
2043
|
+
if (typeof window !== "undefined") {
|
|
2044
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
static calculateStatsFromHistory(history) {
|
|
2026
2048
|
if (history.length === 0) {
|
|
2027
2049
|
return {
|
|
2028
2050
|
totalSessions: 0,
|
|
@@ -2061,7 +2083,9 @@ var PracticeHistoryService = class {
|
|
|
2061
2083
|
const currentDay = new Date(sortedDays[i]);
|
|
2062
2084
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
2063
2085
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
2064
|
-
const diffDays = Math.round(
|
|
2086
|
+
const diffDays = Math.round(
|
|
2087
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
2088
|
+
);
|
|
2065
2089
|
if (diffDays === 1) {
|
|
2066
2090
|
currentStreak++;
|
|
2067
2091
|
} else {
|
|
@@ -2093,22 +2117,31 @@ var PracticeHistoryService = class {
|
|
|
2093
2117
|
const subjectPerf = {};
|
|
2094
2118
|
const topicPerf = {};
|
|
2095
2119
|
history.forEach((session) => {
|
|
2096
|
-
session.summary.topics.forEach(
|
|
2097
|
-
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2120
|
+
session.summary.topics.forEach(
|
|
2121
|
+
(topicInfo) => {
|
|
2122
|
+
if (session.summary.percentage !== null) {
|
|
2123
|
+
if (!subjectPerf[topicInfo.subject])
|
|
2124
|
+
subjectPerf[topicInfo.subject] = {
|
|
2125
|
+
total: 0,
|
|
2126
|
+
count: 0
|
|
2127
|
+
};
|
|
2128
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
2129
|
+
subjectPerf[topicInfo.subject].count++;
|
|
2130
|
+
if (!topicPerf[topicInfo.topic])
|
|
2131
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
2132
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
2133
|
+
topicPerf[topicInfo.topic].count++;
|
|
2134
|
+
}
|
|
2104
2135
|
}
|
|
2105
|
-
|
|
2136
|
+
);
|
|
2106
2137
|
});
|
|
2107
2138
|
const formatPerf = (perfData) => {
|
|
2108
2139
|
return Object.entries(perfData).map(([name, data]) => ({
|
|
2109
2140
|
name,
|
|
2110
2141
|
totalSessions: data.count,
|
|
2111
|
-
averageScore: parseFloat(
|
|
2142
|
+
averageScore: parseFloat(
|
|
2143
|
+
(data.total / data.count).toFixed(2)
|
|
2144
|
+
)
|
|
2112
2145
|
})).sort((a, b) => b.totalSessions - a.totalSessions);
|
|
2113
2146
|
};
|
|
2114
2147
|
return {
|
|
@@ -2120,11 +2153,6 @@ var PracticeHistoryService = class {
|
|
|
2120
2153
|
performanceByTopic: formatPerf(topicPerf)
|
|
2121
2154
|
};
|
|
2122
2155
|
}
|
|
2123
|
-
static clearHistory() {
|
|
2124
|
-
if (typeof window !== "undefined") {
|
|
2125
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
2156
|
};
|
|
2129
2157
|
// NEW: A static property to hold the injected sync provider
|
|
2130
2158
|
PracticeHistoryService.syncProvider = null;
|
package/dist/react-ui.cjs
CHANGED
|
@@ -139588,20 +139588,30 @@ var PracticeHistoryService = class {
|
|
|
139588
139588
|
static saveHistory(history2) {
|
|
139589
139589
|
if (typeof window !== "undefined") {
|
|
139590
139590
|
try {
|
|
139591
|
-
localStorage.setItem(
|
|
139591
|
+
localStorage.setItem(
|
|
139592
|
+
LOCAL_STORAGE_KEY,
|
|
139593
|
+
JSON.stringify(history2)
|
|
139594
|
+
);
|
|
139592
139595
|
} catch (e3) {
|
|
139593
|
-
console.error(
|
|
139596
|
+
console.error(
|
|
139597
|
+
"Error saving practice history to localStorage:",
|
|
139598
|
+
e3
|
|
139599
|
+
);
|
|
139594
139600
|
}
|
|
139595
139601
|
}
|
|
139596
139602
|
}
|
|
139597
139603
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
139598
139604
|
const history2 = this.getPracticeHistory();
|
|
139599
139605
|
const topicsCovered = Array.from(
|
|
139600
|
-
new Set(
|
|
139601
|
-
|
|
139602
|
-
|
|
139603
|
-
|
|
139604
|
-
|
|
139606
|
+
new Set(
|
|
139607
|
+
quizConfig.questions.map(
|
|
139608
|
+
(q2) => JSON.stringify({
|
|
139609
|
+
subject: q2.subject || "Uncategorized",
|
|
139610
|
+
category: q2.category || "General",
|
|
139611
|
+
topic: q2.topic || "General Topic"
|
|
139612
|
+
})
|
|
139613
|
+
)
|
|
139614
|
+
)
|
|
139605
139615
|
).map((s4) => JSON.parse(s4));
|
|
139606
139616
|
const newSession = {
|
|
139607
139617
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -139619,7 +139629,9 @@ var PracticeHistoryService = class {
|
|
|
139619
139629
|
history2.unshift(newSession);
|
|
139620
139630
|
this.saveHistory(history2);
|
|
139621
139631
|
if (this.syncProvider) {
|
|
139622
|
-
console.log(
|
|
139632
|
+
console.log(
|
|
139633
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
139634
|
+
);
|
|
139623
139635
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
139624
139636
|
console.error("Sync provider failed to push session:", err);
|
|
139625
139637
|
});
|
|
@@ -139633,7 +139645,9 @@ var PracticeHistoryService = class {
|
|
|
139633
139645
|
history2[sessionIndex].quizReview = review;
|
|
139634
139646
|
this.saveHistory(history2);
|
|
139635
139647
|
} else {
|
|
139636
|
-
console.warn(
|
|
139648
|
+
console.warn(
|
|
139649
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
139650
|
+
);
|
|
139637
139651
|
}
|
|
139638
139652
|
}
|
|
139639
139653
|
static getPracticeSessionById(sessionId) {
|
|
@@ -139653,6 +139667,14 @@ var PracticeHistoryService = class {
|
|
|
139653
139667
|
}
|
|
139654
139668
|
static getPracticeStats() {
|
|
139655
139669
|
const history2 = this.getPracticeHistory();
|
|
139670
|
+
return this.calculateStatsFromHistory(history2);
|
|
139671
|
+
}
|
|
139672
|
+
static clearHistory() {
|
|
139673
|
+
if (typeof window !== "undefined") {
|
|
139674
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
139675
|
+
}
|
|
139676
|
+
}
|
|
139677
|
+
static calculateStatsFromHistory(history2) {
|
|
139656
139678
|
if (history2.length === 0) {
|
|
139657
139679
|
return {
|
|
139658
139680
|
totalSessions: 0,
|
|
@@ -139691,7 +139713,9 @@ var PracticeHistoryService = class {
|
|
|
139691
139713
|
const currentDay = new Date(sortedDays[i2]);
|
|
139692
139714
|
const nextDay = new Date(sortedDays[i2 + 1]);
|
|
139693
139715
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
139694
|
-
const diffDays = Math.round(
|
|
139716
|
+
const diffDays = Math.round(
|
|
139717
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
139718
|
+
);
|
|
139695
139719
|
if (diffDays === 1) {
|
|
139696
139720
|
currentStreak++;
|
|
139697
139721
|
} else {
|
|
@@ -139723,22 +139747,31 @@ var PracticeHistoryService = class {
|
|
|
139723
139747
|
const subjectPerf = {};
|
|
139724
139748
|
const topicPerf = {};
|
|
139725
139749
|
history2.forEach((session) => {
|
|
139726
|
-
session.summary.topics.forEach(
|
|
139727
|
-
|
|
139728
|
-
if (
|
|
139729
|
-
|
|
139730
|
-
|
|
139731
|
-
|
|
139732
|
-
|
|
139733
|
-
|
|
139750
|
+
session.summary.topics.forEach(
|
|
139751
|
+
(topicInfo) => {
|
|
139752
|
+
if (session.summary.percentage !== null) {
|
|
139753
|
+
if (!subjectPerf[topicInfo.subject])
|
|
139754
|
+
subjectPerf[topicInfo.subject] = {
|
|
139755
|
+
total: 0,
|
|
139756
|
+
count: 0
|
|
139757
|
+
};
|
|
139758
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
139759
|
+
subjectPerf[topicInfo.subject].count++;
|
|
139760
|
+
if (!topicPerf[topicInfo.topic])
|
|
139761
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
139762
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
139763
|
+
topicPerf[topicInfo.topic].count++;
|
|
139764
|
+
}
|
|
139734
139765
|
}
|
|
139735
|
-
|
|
139766
|
+
);
|
|
139736
139767
|
});
|
|
139737
139768
|
const formatPerf = (perfData) => {
|
|
139738
139769
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
139739
139770
|
name: name3,
|
|
139740
139771
|
totalSessions: data.count,
|
|
139741
|
-
averageScore: parseFloat(
|
|
139772
|
+
averageScore: parseFloat(
|
|
139773
|
+
(data.total / data.count).toFixed(2)
|
|
139774
|
+
)
|
|
139742
139775
|
})).sort((a4, b2) => b2.totalSessions - a4.totalSessions);
|
|
139743
139776
|
};
|
|
139744
139777
|
return {
|
|
@@ -139750,11 +139783,6 @@ var PracticeHistoryService = class {
|
|
|
139750
139783
|
performanceByTopic: formatPerf(topicPerf)
|
|
139751
139784
|
};
|
|
139752
139785
|
}
|
|
139753
|
-
static clearHistory() {
|
|
139754
|
-
if (typeof window !== "undefined") {
|
|
139755
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
139756
|
-
}
|
|
139757
|
-
}
|
|
139758
139786
|
};
|
|
139759
139787
|
// NEW: A static property to hold the injected sync provider
|
|
139760
139788
|
PracticeHistoryService.syncProvider = null;
|
|
@@ -167238,15 +167266,19 @@ var ClientTranslation = ({ tKey, options, fallback: fallback2 }) => {
|
|
|
167238
167266
|
};
|
|
167239
167267
|
|
|
167240
167268
|
// src/react-ui/components/app/PersonalPracticeDashboard.tsx
|
|
167241
|
-
var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
167269
|
+
var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, isControlled = false }) => {
|
|
167242
167270
|
const router = navigation.useRouter();
|
|
167243
167271
|
const { toast: toast2 } = useToast();
|
|
167244
167272
|
const { t: t4, i18n } = useTranslation();
|
|
167245
167273
|
const [isMounted, setIsMounted] = React163.useState(false);
|
|
167246
167274
|
React163.useEffect(() => setIsMounted(true), []);
|
|
167247
167275
|
const [isLoading, setIsLoading] = React163.useState(true);
|
|
167248
|
-
const [stats, setStats] = React163.useState(
|
|
167249
|
-
|
|
167276
|
+
const [stats, setStats] = React163.useState(
|
|
167277
|
+
initialStats || null
|
|
167278
|
+
);
|
|
167279
|
+
const [history2, setHistory] = React163.useState(
|
|
167280
|
+
initialHistory || []
|
|
167281
|
+
);
|
|
167250
167282
|
const [userName, setUserName] = React163.useState(null);
|
|
167251
167283
|
const [allAchievements, setAllAchievements] = React163.useState([]);
|
|
167252
167284
|
const [motivationalQuote, setMotivationalQuote] = React163.useState(null);
|
|
@@ -167260,6 +167292,10 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167260
167292
|
);
|
|
167261
167293
|
const [isSettingsModalOpen, setIsSettingsModalOpen] = React163.useState(false);
|
|
167262
167294
|
const loadDashboardData = React163.useCallback(() => {
|
|
167295
|
+
if (isControlled) {
|
|
167296
|
+
setIsLoading(false);
|
|
167297
|
+
return;
|
|
167298
|
+
}
|
|
167263
167299
|
setIsLoading(true);
|
|
167264
167300
|
setDashboardLayout(DashboardLayoutService.getLayout());
|
|
167265
167301
|
const practiceHistory = PracticeHistoryService.getPracticeHistory();
|
|
@@ -167288,10 +167324,20 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167288
167324
|
if (KnowledgeCardService.getPendingConcepts().length > 0) {
|
|
167289
167325
|
CardGenerationProcessor.processQueue();
|
|
167290
167326
|
}
|
|
167291
|
-
}, [toast2, t4]);
|
|
167327
|
+
}, [isControlled, toast2, t4]);
|
|
167292
167328
|
React163.useEffect(() => {
|
|
167293
|
-
|
|
167294
|
-
|
|
167329
|
+
if (isControlled) {
|
|
167330
|
+
setHistory(initialHistory || []);
|
|
167331
|
+
setStats(initialStats || null);
|
|
167332
|
+
const name3 = UserConfigService.getFullName();
|
|
167333
|
+
setUserName(name3);
|
|
167334
|
+
const achievementsWithStatus = AchievementService.getAllAchievementsWithStatus();
|
|
167335
|
+
setAllAchievements(achievementsWithStatus);
|
|
167336
|
+
setIsLoading(false);
|
|
167337
|
+
} else {
|
|
167338
|
+
loadDashboardData();
|
|
167339
|
+
}
|
|
167340
|
+
}, [isControlled, initialHistory, initialStats, loadDashboardData]);
|
|
167295
167341
|
React163.useEffect(() => {
|
|
167296
167342
|
setMotivationalQuote(QuoteService.getRandomQuote());
|
|
167297
167343
|
const fetchAIQuote = async () => {
|
package/dist/react-ui.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { s as QuizConfig, g as QuizQuestion } from './quiz-config-o4j2dfsu.cjs';
|
|
2
2
|
export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion, D as DragAndDropQuestion, l as DraggableItem, m as DropZone, F as FillInTheBlanksQuestion, n as HotspotArea, H as HotspotQuestion, M as MarkdownString, k as MatchOptionItem, j as MatchPromptItem, d as MatchingQuestion, a as MultipleChoiceQuestion, b as MultipleResponseQuestion, N as NumericQuestion, h as QuestionOption, Q as QuestionTypeStrings, r as QuizSettings, R as RichContentString, q as SCORMSettings, f as ScratchProgrammingQuestion, i as SequenceItem, c as SequenceQuestion, S as ShortAnswerQuestion, p as SupportedCodingLanguage, o as TestCase, T as TrueFalseQuestion } from './quiz-config-o4j2dfsu.cjs';
|
|
3
3
|
export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, LearningObjectiveMetadata, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.cjs';
|
|
4
|
-
import { Q as QuizResultType, U as UserAnswerType, m as PracticeSuggestion, l as PracticeSuggestionTopic, i as Achievement,
|
|
5
|
-
export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty,
|
|
4
|
+
import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, i as Achievement, p as PracticeSessionSummary, h as QuizReviewContent } from './ai-ecosystem-DqFRlFU3.cjs';
|
|
5
|
+
export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DqFRlFU3.cjs';
|
|
6
6
|
import * as React$1 from 'react';
|
|
7
7
|
import React__default, { ReactNode } from 'react';
|
|
8
8
|
export { a as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, b as APIKeyManagerModal, c as ApiKeySettings, j as ApproachManager, B as BloomLevelManager, C as CategoryManager, i as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, M as MetadataTabs, e as QuestionFilters, f as QuestionFormDialog, d as QuestionList, h as QuestionTypeManager, Q as QuizAuthoringTool, S as SCORMExportModal, g as SubjectManager, k as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-DfLqsPwa.cjs';
|
|
@@ -72,6 +72,9 @@ declare const QuestionRenderer: React__default.ForwardRefExoticComponent<Questio
|
|
|
72
72
|
|
|
73
73
|
interface PersonalPracticeDashboardProps {
|
|
74
74
|
settingsPath?: string;
|
|
75
|
+
initialHistory?: PracticeSession[];
|
|
76
|
+
initialStats?: PracticeStats | null;
|
|
77
|
+
isControlled?: boolean;
|
|
75
78
|
}
|
|
76
79
|
declare const PersonalPracticeDashboard: React__default.FC<PersonalPracticeDashboardProps>;
|
|
77
80
|
|
|
@@ -215,4 +218,4 @@ declare const TabsList: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.Tab
|
|
|
215
218
|
declare const TabsTrigger: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
216
219
|
declare const TabsContent: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
217
220
|
|
|
218
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Achievement, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cheatsheet, Checkbox, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FreestyleQuizzesCard, GeneratedQuizzesCard, Input, Label, LanguageProvider, ManageTopics, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, PracticeSessionSummary, PracticeStats, PracticeSuggestion, PracticeSuggestionTopic, Progress, QuestionRenderer, QuizConfig, QuizDataManagement, QuizPlayer, QuizQuestion, QuizResult, QuizResultType, QuizReview, QuizReviewContent, RadioGroup, RadioGroupItem, ScrollArea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SettingsModal, Skeleton, SuggestionDialog, Tabs, TabsContent, TabsList, TabsTrigger, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadResourceModal, UserAnswerType };
|
|
221
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Achievement, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cheatsheet, Checkbox, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FreestyleQuizzesCard, GeneratedQuizzesCard, Input, Label, LanguageProvider, ManageTopics, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, PracticeSession, PracticeSessionSummary, PracticeStats, PracticeSuggestion, PracticeSuggestionTopic, Progress, QuestionRenderer, QuizConfig, QuizDataManagement, QuizPlayer, QuizQuestion, QuizResult, QuizResultType, QuizReview, QuizReviewContent, RadioGroup, RadioGroupItem, ScrollArea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SettingsModal, Skeleton, SuggestionDialog, Tabs, TabsContent, TabsList, TabsTrigger, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadResourceModal, UserAnswerType };
|
package/dist/react-ui.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { s as QuizConfig, g as QuizQuestion } from './quiz-config-o4j2dfsu.js';
|
|
2
2
|
export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion, D as DragAndDropQuestion, l as DraggableItem, m as DropZone, F as FillInTheBlanksQuestion, n as HotspotArea, H as HotspotQuestion, M as MarkdownString, k as MatchOptionItem, j as MatchPromptItem, d as MatchingQuestion, a as MultipleChoiceQuestion, b as MultipleResponseQuestion, N as NumericQuestion, h as QuestionOption, Q as QuestionTypeStrings, r as QuizSettings, R as RichContentString, q as SCORMSettings, f as ScratchProgrammingQuestion, i as SequenceItem, c as SequenceQuestion, S as ShortAnswerQuestion, p as SupportedCodingLanguage, o as TestCase, T as TrueFalseQuestion } from './quiz-config-o4j2dfsu.js';
|
|
3
3
|
export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, LearningObjectiveMetadata, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.js';
|
|
4
|
-
import { Q as QuizResultType, U as UserAnswerType, m as PracticeSuggestion, l as PracticeSuggestionTopic, i as Achievement,
|
|
5
|
-
export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty,
|
|
4
|
+
import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, i as Achievement, p as PracticeSessionSummary, h as QuizReviewContent } from './ai-ecosystem-DqVlSO3r.js';
|
|
5
|
+
export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DqVlSO3r.js';
|
|
6
6
|
import * as React$1 from 'react';
|
|
7
7
|
import React__default, { ReactNode } from 'react';
|
|
8
8
|
export { a as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, b as APIKeyManagerModal, c as ApiKeySettings, j as ApproachManager, B as BloomLevelManager, C as CategoryManager, i as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, M as MetadataTabs, e as QuestionFilters, f as QuestionFormDialog, d as QuestionList, h as QuestionTypeManager, Q as QuizAuthoringTool, S as SCORMExportModal, g as SubjectManager, k as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-Z0Qz6kch.js';
|
|
@@ -72,6 +72,9 @@ declare const QuestionRenderer: React__default.ForwardRefExoticComponent<Questio
|
|
|
72
72
|
|
|
73
73
|
interface PersonalPracticeDashboardProps {
|
|
74
74
|
settingsPath?: string;
|
|
75
|
+
initialHistory?: PracticeSession[];
|
|
76
|
+
initialStats?: PracticeStats | null;
|
|
77
|
+
isControlled?: boolean;
|
|
75
78
|
}
|
|
76
79
|
declare const PersonalPracticeDashboard: React__default.FC<PersonalPracticeDashboardProps>;
|
|
77
80
|
|
|
@@ -215,4 +218,4 @@ declare const TabsList: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.Tab
|
|
|
215
218
|
declare const TabsTrigger: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
216
219
|
declare const TabsContent: React$1.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
217
220
|
|
|
218
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Achievement, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cheatsheet, Checkbox, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FreestyleQuizzesCard, GeneratedQuizzesCard, Input, Label, LanguageProvider, ManageTopics, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, PracticeSessionSummary, PracticeStats, PracticeSuggestion, PracticeSuggestionTopic, Progress, QuestionRenderer, QuizConfig, QuizDataManagement, QuizPlayer, QuizQuestion, QuizResult, QuizResultType, QuizReview, QuizReviewContent, RadioGroup, RadioGroupItem, ScrollArea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SettingsModal, Skeleton, SuggestionDialog, Tabs, TabsContent, TabsList, TabsTrigger, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadResourceModal, UserAnswerType };
|
|
221
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Achievement, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cheatsheet, Checkbox, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FreestyleQuizzesCard, GeneratedQuizzesCard, Input, Label, LanguageProvider, ManageTopics, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, PracticeSession, PracticeSessionSummary, PracticeStats, PracticeSuggestion, PracticeSuggestionTopic, Progress, QuestionRenderer, QuizConfig, QuizDataManagement, QuizPlayer, QuizQuestion, QuizResult, QuizResultType, QuizReview, QuizReviewContent, RadioGroup, RadioGroupItem, ScrollArea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SettingsModal, Skeleton, SuggestionDialog, Tabs, TabsContent, TabsList, TabsTrigger, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadResourceModal, UserAnswerType };
|
package/dist/react-ui.mjs
CHANGED
|
@@ -139561,20 +139561,30 @@ var PracticeHistoryService = class {
|
|
|
139561
139561
|
static saveHistory(history2) {
|
|
139562
139562
|
if (typeof window !== "undefined") {
|
|
139563
139563
|
try {
|
|
139564
|
-
localStorage.setItem(
|
|
139564
|
+
localStorage.setItem(
|
|
139565
|
+
LOCAL_STORAGE_KEY,
|
|
139566
|
+
JSON.stringify(history2)
|
|
139567
|
+
);
|
|
139565
139568
|
} catch (e3) {
|
|
139566
|
-
console.error(
|
|
139569
|
+
console.error(
|
|
139570
|
+
"Error saving practice history to localStorage:",
|
|
139571
|
+
e3
|
|
139572
|
+
);
|
|
139567
139573
|
}
|
|
139568
139574
|
}
|
|
139569
139575
|
}
|
|
139570
139576
|
static saveCompletedPracticeSession(quizConfig, result, review = null) {
|
|
139571
139577
|
const history2 = this.getPracticeHistory();
|
|
139572
139578
|
const topicsCovered = Array.from(
|
|
139573
|
-
new Set(
|
|
139574
|
-
|
|
139575
|
-
|
|
139576
|
-
|
|
139577
|
-
|
|
139579
|
+
new Set(
|
|
139580
|
+
quizConfig.questions.map(
|
|
139581
|
+
(q2) => JSON.stringify({
|
|
139582
|
+
subject: q2.subject || "Uncategorized",
|
|
139583
|
+
category: q2.category || "General",
|
|
139584
|
+
topic: q2.topic || "General Topic"
|
|
139585
|
+
})
|
|
139586
|
+
)
|
|
139587
|
+
)
|
|
139578
139588
|
).map((s4) => JSON.parse(s4));
|
|
139579
139589
|
const newSession = {
|
|
139580
139590
|
id: `session_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
|
@@ -139592,7 +139602,9 @@ var PracticeHistoryService = class {
|
|
|
139592
139602
|
history2.unshift(newSession);
|
|
139593
139603
|
this.saveHistory(history2);
|
|
139594
139604
|
if (this.syncProvider) {
|
|
139595
|
-
console.log(
|
|
139605
|
+
console.log(
|
|
139606
|
+
`Sync provider found. Pushing session ${newSession.id} to backend.`
|
|
139607
|
+
);
|
|
139596
139608
|
this.syncProvider.pushSession(newSession).catch((err) => {
|
|
139597
139609
|
console.error("Sync provider failed to push session:", err);
|
|
139598
139610
|
});
|
|
@@ -139606,7 +139618,9 @@ var PracticeHistoryService = class {
|
|
|
139606
139618
|
history2[sessionIndex].quizReview = review;
|
|
139607
139619
|
this.saveHistory(history2);
|
|
139608
139620
|
} else {
|
|
139609
|
-
console.warn(
|
|
139621
|
+
console.warn(
|
|
139622
|
+
`Could not find session with ID "${sessionId}" to update review.`
|
|
139623
|
+
);
|
|
139610
139624
|
}
|
|
139611
139625
|
}
|
|
139612
139626
|
static getPracticeSessionById(sessionId) {
|
|
@@ -139626,6 +139640,14 @@ var PracticeHistoryService = class {
|
|
|
139626
139640
|
}
|
|
139627
139641
|
static getPracticeStats() {
|
|
139628
139642
|
const history2 = this.getPracticeHistory();
|
|
139643
|
+
return this.calculateStatsFromHistory(history2);
|
|
139644
|
+
}
|
|
139645
|
+
static clearHistory() {
|
|
139646
|
+
if (typeof window !== "undefined") {
|
|
139647
|
+
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
139648
|
+
}
|
|
139649
|
+
}
|
|
139650
|
+
static calculateStatsFromHistory(history2) {
|
|
139629
139651
|
if (history2.length === 0) {
|
|
139630
139652
|
return {
|
|
139631
139653
|
totalSessions: 0,
|
|
@@ -139664,7 +139686,9 @@ var PracticeHistoryService = class {
|
|
|
139664
139686
|
const currentDay = new Date(sortedDays[i2]);
|
|
139665
139687
|
const nextDay = new Date(sortedDays[i2 + 1]);
|
|
139666
139688
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
139667
|
-
const diffDays = Math.round(
|
|
139689
|
+
const diffDays = Math.round(
|
|
139690
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
139691
|
+
);
|
|
139668
139692
|
if (diffDays === 1) {
|
|
139669
139693
|
currentStreak++;
|
|
139670
139694
|
} else {
|
|
@@ -139696,22 +139720,31 @@ var PracticeHistoryService = class {
|
|
|
139696
139720
|
const subjectPerf = {};
|
|
139697
139721
|
const topicPerf = {};
|
|
139698
139722
|
history2.forEach((session) => {
|
|
139699
|
-
session.summary.topics.forEach(
|
|
139700
|
-
|
|
139701
|
-
if (
|
|
139702
|
-
|
|
139703
|
-
|
|
139704
|
-
|
|
139705
|
-
|
|
139706
|
-
|
|
139723
|
+
session.summary.topics.forEach(
|
|
139724
|
+
(topicInfo) => {
|
|
139725
|
+
if (session.summary.percentage !== null) {
|
|
139726
|
+
if (!subjectPerf[topicInfo.subject])
|
|
139727
|
+
subjectPerf[topicInfo.subject] = {
|
|
139728
|
+
total: 0,
|
|
139729
|
+
count: 0
|
|
139730
|
+
};
|
|
139731
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
139732
|
+
subjectPerf[topicInfo.subject].count++;
|
|
139733
|
+
if (!topicPerf[topicInfo.topic])
|
|
139734
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
139735
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
139736
|
+
topicPerf[topicInfo.topic].count++;
|
|
139737
|
+
}
|
|
139707
139738
|
}
|
|
139708
|
-
|
|
139739
|
+
);
|
|
139709
139740
|
});
|
|
139710
139741
|
const formatPerf = (perfData) => {
|
|
139711
139742
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
139712
139743
|
name: name3,
|
|
139713
139744
|
totalSessions: data.count,
|
|
139714
|
-
averageScore: parseFloat(
|
|
139745
|
+
averageScore: parseFloat(
|
|
139746
|
+
(data.total / data.count).toFixed(2)
|
|
139747
|
+
)
|
|
139715
139748
|
})).sort((a4, b2) => b2.totalSessions - a4.totalSessions);
|
|
139716
139749
|
};
|
|
139717
139750
|
return {
|
|
@@ -139723,11 +139756,6 @@ var PracticeHistoryService = class {
|
|
|
139723
139756
|
performanceByTopic: formatPerf(topicPerf)
|
|
139724
139757
|
};
|
|
139725
139758
|
}
|
|
139726
|
-
static clearHistory() {
|
|
139727
|
-
if (typeof window !== "undefined") {
|
|
139728
|
-
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
139729
|
-
}
|
|
139730
|
-
}
|
|
139731
139759
|
};
|
|
139732
139760
|
// NEW: A static property to hold the injected sync provider
|
|
139733
139761
|
PracticeHistoryService.syncProvider = null;
|
|
@@ -167211,15 +167239,19 @@ var ClientTranslation = ({ tKey, options, fallback: fallback2 }) => {
|
|
|
167211
167239
|
};
|
|
167212
167240
|
|
|
167213
167241
|
// src/react-ui/components/app/PersonalPracticeDashboard.tsx
|
|
167214
|
-
var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
167242
|
+
var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, isControlled = false }) => {
|
|
167215
167243
|
const router = useRouter();
|
|
167216
167244
|
const { toast: toast2 } = useToast();
|
|
167217
167245
|
const { t: t4, i18n } = useTranslation();
|
|
167218
167246
|
const [isMounted, setIsMounted] = useState(false);
|
|
167219
167247
|
useEffect(() => setIsMounted(true), []);
|
|
167220
167248
|
const [isLoading, setIsLoading] = useState(true);
|
|
167221
|
-
const [stats, setStats] = useState(
|
|
167222
|
-
|
|
167249
|
+
const [stats, setStats] = useState(
|
|
167250
|
+
initialStats || null
|
|
167251
|
+
);
|
|
167252
|
+
const [history2, setHistory] = useState(
|
|
167253
|
+
initialHistory || []
|
|
167254
|
+
);
|
|
167223
167255
|
const [userName, setUserName] = useState(null);
|
|
167224
167256
|
const [allAchievements, setAllAchievements] = useState([]);
|
|
167225
167257
|
const [motivationalQuote, setMotivationalQuote] = useState(null);
|
|
@@ -167233,6 +167265,10 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167233
167265
|
);
|
|
167234
167266
|
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
|
167235
167267
|
const loadDashboardData = useCallback(() => {
|
|
167268
|
+
if (isControlled) {
|
|
167269
|
+
setIsLoading(false);
|
|
167270
|
+
return;
|
|
167271
|
+
}
|
|
167236
167272
|
setIsLoading(true);
|
|
167237
167273
|
setDashboardLayout(DashboardLayoutService.getLayout());
|
|
167238
167274
|
const practiceHistory = PracticeHistoryService.getPracticeHistory();
|
|
@@ -167261,10 +167297,20 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167261
167297
|
if (KnowledgeCardService.getPendingConcepts().length > 0) {
|
|
167262
167298
|
CardGenerationProcessor.processQueue();
|
|
167263
167299
|
}
|
|
167264
|
-
}, [toast2, t4]);
|
|
167300
|
+
}, [isControlled, toast2, t4]);
|
|
167265
167301
|
useEffect(() => {
|
|
167266
|
-
|
|
167267
|
-
|
|
167302
|
+
if (isControlled) {
|
|
167303
|
+
setHistory(initialHistory || []);
|
|
167304
|
+
setStats(initialStats || null);
|
|
167305
|
+
const name3 = UserConfigService.getFullName();
|
|
167306
|
+
setUserName(name3);
|
|
167307
|
+
const achievementsWithStatus = AchievementService.getAllAchievementsWithStatus();
|
|
167308
|
+
setAllAchievements(achievementsWithStatus);
|
|
167309
|
+
setIsLoading(false);
|
|
167310
|
+
} else {
|
|
167311
|
+
loadDashboardData();
|
|
167312
|
+
}
|
|
167313
|
+
}, [isControlled, initialHistory, initialStats, loadDashboardData]);
|
|
167268
167314
|
useEffect(() => {
|
|
167269
167315
|
setMotivationalQuote(QuoteService.getRandomQuote());
|
|
167270
167316
|
const fetchAIQuote = async () => {
|
package/package.json
CHANGED