@thanh01.pmt/interactive-quiz-kit 1.0.47 → 1.0.48
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 +45 -20
- package/dist/authoring.mjs +45 -20
- package/dist/index.cjs +45 -20
- package/dist/index.mjs +45 -20
- package/dist/react-ui.cjs +69 -26
- package/dist/react-ui.d.cts +6 -3
- package/dist/react-ui.d.ts +6 -3
- package/dist/react-ui.mjs +69 -26
- 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) {
|
|
@@ -4101,7 +4115,9 @@ var PracticeHistoryService = class {
|
|
|
4101
4115
|
const currentDay = new Date(sortedDays[i]);
|
|
4102
4116
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
4103
4117
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
4104
|
-
const diffDays = Math.round(
|
|
4118
|
+
const diffDays = Math.round(
|
|
4119
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
4120
|
+
);
|
|
4105
4121
|
if (diffDays === 1) {
|
|
4106
4122
|
currentStreak++;
|
|
4107
4123
|
} else {
|
|
@@ -4133,22 +4149,31 @@ var PracticeHistoryService = class {
|
|
|
4133
4149
|
const subjectPerf = {};
|
|
4134
4150
|
const topicPerf = {};
|
|
4135
4151
|
history2.forEach((session) => {
|
|
4136
|
-
session.summary.topics.forEach(
|
|
4137
|
-
|
|
4138
|
-
if (
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4152
|
+
session.summary.topics.forEach(
|
|
4153
|
+
(topicInfo) => {
|
|
4154
|
+
if (session.summary.percentage !== null) {
|
|
4155
|
+
if (!subjectPerf[topicInfo.subject])
|
|
4156
|
+
subjectPerf[topicInfo.subject] = {
|
|
4157
|
+
total: 0,
|
|
4158
|
+
count: 0
|
|
4159
|
+
};
|
|
4160
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
4161
|
+
subjectPerf[topicInfo.subject].count++;
|
|
4162
|
+
if (!topicPerf[topicInfo.topic])
|
|
4163
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
4164
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
4165
|
+
topicPerf[topicInfo.topic].count++;
|
|
4166
|
+
}
|
|
4144
4167
|
}
|
|
4145
|
-
|
|
4168
|
+
);
|
|
4146
4169
|
});
|
|
4147
4170
|
const formatPerf = (perfData) => {
|
|
4148
4171
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
4149
4172
|
name: name3,
|
|
4150
4173
|
totalSessions: data.count,
|
|
4151
|
-
averageScore: parseFloat(
|
|
4174
|
+
averageScore: parseFloat(
|
|
4175
|
+
(data.total / data.count).toFixed(2)
|
|
4176
|
+
)
|
|
4152
4177
|
})).sort((a2, b) => b.totalSessions - a2.totalSessions);
|
|
4153
4178
|
};
|
|
4154
4179
|
return {
|
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) {
|
|
@@ -4075,7 +4089,9 @@ var PracticeHistoryService = class {
|
|
|
4075
4089
|
const currentDay = new Date(sortedDays[i]);
|
|
4076
4090
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
4077
4091
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
4078
|
-
const diffDays = Math.round(
|
|
4092
|
+
const diffDays = Math.round(
|
|
4093
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
4094
|
+
);
|
|
4079
4095
|
if (diffDays === 1) {
|
|
4080
4096
|
currentStreak++;
|
|
4081
4097
|
} else {
|
|
@@ -4107,22 +4123,31 @@ var PracticeHistoryService = class {
|
|
|
4107
4123
|
const subjectPerf = {};
|
|
4108
4124
|
const topicPerf = {};
|
|
4109
4125
|
history2.forEach((session) => {
|
|
4110
|
-
session.summary.topics.forEach(
|
|
4111
|
-
|
|
4112
|
-
if (
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4126
|
+
session.summary.topics.forEach(
|
|
4127
|
+
(topicInfo) => {
|
|
4128
|
+
if (session.summary.percentage !== null) {
|
|
4129
|
+
if (!subjectPerf[topicInfo.subject])
|
|
4130
|
+
subjectPerf[topicInfo.subject] = {
|
|
4131
|
+
total: 0,
|
|
4132
|
+
count: 0
|
|
4133
|
+
};
|
|
4134
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
4135
|
+
subjectPerf[topicInfo.subject].count++;
|
|
4136
|
+
if (!topicPerf[topicInfo.topic])
|
|
4137
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
4138
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
4139
|
+
topicPerf[topicInfo.topic].count++;
|
|
4140
|
+
}
|
|
4118
4141
|
}
|
|
4119
|
-
|
|
4142
|
+
);
|
|
4120
4143
|
});
|
|
4121
4144
|
const formatPerf = (perfData) => {
|
|
4122
4145
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
4123
4146
|
name: name3,
|
|
4124
4147
|
totalSessions: data.count,
|
|
4125
|
-
averageScore: parseFloat(
|
|
4148
|
+
averageScore: parseFloat(
|
|
4149
|
+
(data.total / data.count).toFixed(2)
|
|
4150
|
+
)
|
|
4126
4151
|
})).sort((a2, b) => b.totalSessions - a2.totalSessions);
|
|
4127
4152
|
};
|
|
4128
4153
|
return {
|
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) {
|
|
@@ -2067,7 +2081,9 @@ var PracticeHistoryService = class {
|
|
|
2067
2081
|
const currentDay = new Date(sortedDays[i]);
|
|
2068
2082
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
2069
2083
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
2070
|
-
const diffDays = Math.round(
|
|
2084
|
+
const diffDays = Math.round(
|
|
2085
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
2086
|
+
);
|
|
2071
2087
|
if (diffDays === 1) {
|
|
2072
2088
|
currentStreak++;
|
|
2073
2089
|
} else {
|
|
@@ -2099,22 +2115,31 @@ var PracticeHistoryService = class {
|
|
|
2099
2115
|
const subjectPerf = {};
|
|
2100
2116
|
const topicPerf = {};
|
|
2101
2117
|
history.forEach((session) => {
|
|
2102
|
-
session.summary.topics.forEach(
|
|
2103
|
-
|
|
2104
|
-
if (
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2118
|
+
session.summary.topics.forEach(
|
|
2119
|
+
(topicInfo) => {
|
|
2120
|
+
if (session.summary.percentage !== null) {
|
|
2121
|
+
if (!subjectPerf[topicInfo.subject])
|
|
2122
|
+
subjectPerf[topicInfo.subject] = {
|
|
2123
|
+
total: 0,
|
|
2124
|
+
count: 0
|
|
2125
|
+
};
|
|
2126
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
2127
|
+
subjectPerf[topicInfo.subject].count++;
|
|
2128
|
+
if (!topicPerf[topicInfo.topic])
|
|
2129
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
2130
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
2131
|
+
topicPerf[topicInfo.topic].count++;
|
|
2132
|
+
}
|
|
2110
2133
|
}
|
|
2111
|
-
|
|
2134
|
+
);
|
|
2112
2135
|
});
|
|
2113
2136
|
const formatPerf = (perfData) => {
|
|
2114
2137
|
return Object.entries(perfData).map(([name, data]) => ({
|
|
2115
2138
|
name,
|
|
2116
2139
|
totalSessions: data.count,
|
|
2117
|
-
averageScore: parseFloat(
|
|
2140
|
+
averageScore: parseFloat(
|
|
2141
|
+
(data.total / data.count).toFixed(2)
|
|
2142
|
+
)
|
|
2118
2143
|
})).sort((a, b) => b.totalSessions - a.totalSessions);
|
|
2119
2144
|
};
|
|
2120
2145
|
return {
|
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) {
|
|
@@ -2061,7 +2075,9 @@ var PracticeHistoryService = class {
|
|
|
2061
2075
|
const currentDay = new Date(sortedDays[i]);
|
|
2062
2076
|
const nextDay = new Date(sortedDays[i + 1]);
|
|
2063
2077
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
2064
|
-
const diffDays = Math.round(
|
|
2078
|
+
const diffDays = Math.round(
|
|
2079
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
2080
|
+
);
|
|
2065
2081
|
if (diffDays === 1) {
|
|
2066
2082
|
currentStreak++;
|
|
2067
2083
|
} else {
|
|
@@ -2093,22 +2109,31 @@ var PracticeHistoryService = class {
|
|
|
2093
2109
|
const subjectPerf = {};
|
|
2094
2110
|
const topicPerf = {};
|
|
2095
2111
|
history.forEach((session) => {
|
|
2096
|
-
session.summary.topics.forEach(
|
|
2097
|
-
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2112
|
+
session.summary.topics.forEach(
|
|
2113
|
+
(topicInfo) => {
|
|
2114
|
+
if (session.summary.percentage !== null) {
|
|
2115
|
+
if (!subjectPerf[topicInfo.subject])
|
|
2116
|
+
subjectPerf[topicInfo.subject] = {
|
|
2117
|
+
total: 0,
|
|
2118
|
+
count: 0
|
|
2119
|
+
};
|
|
2120
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
2121
|
+
subjectPerf[topicInfo.subject].count++;
|
|
2122
|
+
if (!topicPerf[topicInfo.topic])
|
|
2123
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
2124
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
2125
|
+
topicPerf[topicInfo.topic].count++;
|
|
2126
|
+
}
|
|
2104
2127
|
}
|
|
2105
|
-
|
|
2128
|
+
);
|
|
2106
2129
|
});
|
|
2107
2130
|
const formatPerf = (perfData) => {
|
|
2108
2131
|
return Object.entries(perfData).map(([name, data]) => ({
|
|
2109
2132
|
name,
|
|
2110
2133
|
totalSessions: data.count,
|
|
2111
|
-
averageScore: parseFloat(
|
|
2134
|
+
averageScore: parseFloat(
|
|
2135
|
+
(data.total / data.count).toFixed(2)
|
|
2136
|
+
)
|
|
2112
2137
|
})).sort((a, b) => b.totalSessions - a.totalSessions);
|
|
2113
2138
|
};
|
|
2114
2139
|
return {
|
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) {
|
|
@@ -139691,7 +139705,9 @@ var PracticeHistoryService = class {
|
|
|
139691
139705
|
const currentDay = new Date(sortedDays[i2]);
|
|
139692
139706
|
const nextDay = new Date(sortedDays[i2 + 1]);
|
|
139693
139707
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
139694
|
-
const diffDays = Math.round(
|
|
139708
|
+
const diffDays = Math.round(
|
|
139709
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
139710
|
+
);
|
|
139695
139711
|
if (diffDays === 1) {
|
|
139696
139712
|
currentStreak++;
|
|
139697
139713
|
} else {
|
|
@@ -139723,22 +139739,31 @@ var PracticeHistoryService = class {
|
|
|
139723
139739
|
const subjectPerf = {};
|
|
139724
139740
|
const topicPerf = {};
|
|
139725
139741
|
history2.forEach((session) => {
|
|
139726
|
-
session.summary.topics.forEach(
|
|
139727
|
-
|
|
139728
|
-
if (
|
|
139729
|
-
|
|
139730
|
-
|
|
139731
|
-
|
|
139732
|
-
|
|
139733
|
-
|
|
139742
|
+
session.summary.topics.forEach(
|
|
139743
|
+
(topicInfo) => {
|
|
139744
|
+
if (session.summary.percentage !== null) {
|
|
139745
|
+
if (!subjectPerf[topicInfo.subject])
|
|
139746
|
+
subjectPerf[topicInfo.subject] = {
|
|
139747
|
+
total: 0,
|
|
139748
|
+
count: 0
|
|
139749
|
+
};
|
|
139750
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
139751
|
+
subjectPerf[topicInfo.subject].count++;
|
|
139752
|
+
if (!topicPerf[topicInfo.topic])
|
|
139753
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
139754
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
139755
|
+
topicPerf[topicInfo.topic].count++;
|
|
139756
|
+
}
|
|
139734
139757
|
}
|
|
139735
|
-
|
|
139758
|
+
);
|
|
139736
139759
|
});
|
|
139737
139760
|
const formatPerf = (perfData) => {
|
|
139738
139761
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
139739
139762
|
name: name3,
|
|
139740
139763
|
totalSessions: data.count,
|
|
139741
|
-
averageScore: parseFloat(
|
|
139764
|
+
averageScore: parseFloat(
|
|
139765
|
+
(data.total / data.count).toFixed(2)
|
|
139766
|
+
)
|
|
139742
139767
|
})).sort((a4, b2) => b2.totalSessions - a4.totalSessions);
|
|
139743
139768
|
};
|
|
139744
139769
|
return {
|
|
@@ -167238,15 +167263,19 @@ var ClientTranslation = ({ tKey, options, fallback: fallback2 }) => {
|
|
|
167238
167263
|
};
|
|
167239
167264
|
|
|
167240
167265
|
// src/react-ui/components/app/PersonalPracticeDashboard.tsx
|
|
167241
|
-
var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
167266
|
+
var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, isControlled = false }) => {
|
|
167242
167267
|
const router = navigation.useRouter();
|
|
167243
167268
|
const { toast: toast2 } = useToast();
|
|
167244
167269
|
const { t: t4, i18n } = useTranslation();
|
|
167245
167270
|
const [isMounted, setIsMounted] = React163.useState(false);
|
|
167246
167271
|
React163.useEffect(() => setIsMounted(true), []);
|
|
167247
167272
|
const [isLoading, setIsLoading] = React163.useState(true);
|
|
167248
|
-
const [stats, setStats] = React163.useState(
|
|
167249
|
-
|
|
167273
|
+
const [stats, setStats] = React163.useState(
|
|
167274
|
+
initialStats || null
|
|
167275
|
+
);
|
|
167276
|
+
const [history2, setHistory] = React163.useState(
|
|
167277
|
+
initialHistory || []
|
|
167278
|
+
);
|
|
167250
167279
|
const [userName, setUserName] = React163.useState(null);
|
|
167251
167280
|
const [allAchievements, setAllAchievements] = React163.useState([]);
|
|
167252
167281
|
const [motivationalQuote, setMotivationalQuote] = React163.useState(null);
|
|
@@ -167260,6 +167289,10 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167260
167289
|
);
|
|
167261
167290
|
const [isSettingsModalOpen, setIsSettingsModalOpen] = React163.useState(false);
|
|
167262
167291
|
const loadDashboardData = React163.useCallback(() => {
|
|
167292
|
+
if (isControlled) {
|
|
167293
|
+
setIsLoading(false);
|
|
167294
|
+
return;
|
|
167295
|
+
}
|
|
167263
167296
|
setIsLoading(true);
|
|
167264
167297
|
setDashboardLayout(DashboardLayoutService.getLayout());
|
|
167265
167298
|
const practiceHistory = PracticeHistoryService.getPracticeHistory();
|
|
@@ -167288,10 +167321,20 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167288
167321
|
if (KnowledgeCardService.getPendingConcepts().length > 0) {
|
|
167289
167322
|
CardGenerationProcessor.processQueue();
|
|
167290
167323
|
}
|
|
167291
|
-
}, [toast2, t4]);
|
|
167324
|
+
}, [isControlled, toast2, t4]);
|
|
167292
167325
|
React163.useEffect(() => {
|
|
167293
|
-
|
|
167294
|
-
|
|
167326
|
+
if (isControlled) {
|
|
167327
|
+
setHistory(initialHistory || []);
|
|
167328
|
+
setStats(initialStats || null);
|
|
167329
|
+
const name3 = UserConfigService.getFullName();
|
|
167330
|
+
setUserName(name3);
|
|
167331
|
+
const achievementsWithStatus = AchievementService.getAllAchievementsWithStatus();
|
|
167332
|
+
setAllAchievements(achievementsWithStatus);
|
|
167333
|
+
setIsLoading(false);
|
|
167334
|
+
} else {
|
|
167335
|
+
loadDashboardData();
|
|
167336
|
+
}
|
|
167337
|
+
}, [isControlled, initialHistory, initialStats, loadDashboardData]);
|
|
167295
167338
|
React163.useEffect(() => {
|
|
167296
167339
|
setMotivationalQuote(QuoteService.getRandomQuote());
|
|
167297
167340
|
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) {
|
|
@@ -139664,7 +139678,9 @@ var PracticeHistoryService = class {
|
|
|
139664
139678
|
const currentDay = new Date(sortedDays[i2]);
|
|
139665
139679
|
const nextDay = new Date(sortedDays[i2 + 1]);
|
|
139666
139680
|
const diffTime = currentDay.getTime() - nextDay.getTime();
|
|
139667
|
-
const diffDays = Math.round(
|
|
139681
|
+
const diffDays = Math.round(
|
|
139682
|
+
diffTime / (1e3 * 60 * 60 * 24)
|
|
139683
|
+
);
|
|
139668
139684
|
if (diffDays === 1) {
|
|
139669
139685
|
currentStreak++;
|
|
139670
139686
|
} else {
|
|
@@ -139696,22 +139712,31 @@ var PracticeHistoryService = class {
|
|
|
139696
139712
|
const subjectPerf = {};
|
|
139697
139713
|
const topicPerf = {};
|
|
139698
139714
|
history2.forEach((session) => {
|
|
139699
|
-
session.summary.topics.forEach(
|
|
139700
|
-
|
|
139701
|
-
if (
|
|
139702
|
-
|
|
139703
|
-
|
|
139704
|
-
|
|
139705
|
-
|
|
139706
|
-
|
|
139715
|
+
session.summary.topics.forEach(
|
|
139716
|
+
(topicInfo) => {
|
|
139717
|
+
if (session.summary.percentage !== null) {
|
|
139718
|
+
if (!subjectPerf[topicInfo.subject])
|
|
139719
|
+
subjectPerf[topicInfo.subject] = {
|
|
139720
|
+
total: 0,
|
|
139721
|
+
count: 0
|
|
139722
|
+
};
|
|
139723
|
+
subjectPerf[topicInfo.subject].total += session.summary.percentage;
|
|
139724
|
+
subjectPerf[topicInfo.subject].count++;
|
|
139725
|
+
if (!topicPerf[topicInfo.topic])
|
|
139726
|
+
topicPerf[topicInfo.topic] = { total: 0, count: 0 };
|
|
139727
|
+
topicPerf[topicInfo.topic].total += session.summary.percentage;
|
|
139728
|
+
topicPerf[topicInfo.topic].count++;
|
|
139729
|
+
}
|
|
139707
139730
|
}
|
|
139708
|
-
|
|
139731
|
+
);
|
|
139709
139732
|
});
|
|
139710
139733
|
const formatPerf = (perfData) => {
|
|
139711
139734
|
return Object.entries(perfData).map(([name3, data]) => ({
|
|
139712
139735
|
name: name3,
|
|
139713
139736
|
totalSessions: data.count,
|
|
139714
|
-
averageScore: parseFloat(
|
|
139737
|
+
averageScore: parseFloat(
|
|
139738
|
+
(data.total / data.count).toFixed(2)
|
|
139739
|
+
)
|
|
139715
139740
|
})).sort((a4, b2) => b2.totalSessions - a4.totalSessions);
|
|
139716
139741
|
};
|
|
139717
139742
|
return {
|
|
@@ -167211,15 +167236,19 @@ var ClientTranslation = ({ tKey, options, fallback: fallback2 }) => {
|
|
|
167211
167236
|
};
|
|
167212
167237
|
|
|
167213
167238
|
// src/react-ui/components/app/PersonalPracticeDashboard.tsx
|
|
167214
|
-
var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
167239
|
+
var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, isControlled = false }) => {
|
|
167215
167240
|
const router = useRouter();
|
|
167216
167241
|
const { toast: toast2 } = useToast();
|
|
167217
167242
|
const { t: t4, i18n } = useTranslation();
|
|
167218
167243
|
const [isMounted, setIsMounted] = useState(false);
|
|
167219
167244
|
useEffect(() => setIsMounted(true), []);
|
|
167220
167245
|
const [isLoading, setIsLoading] = useState(true);
|
|
167221
|
-
const [stats, setStats] = useState(
|
|
167222
|
-
|
|
167246
|
+
const [stats, setStats] = useState(
|
|
167247
|
+
initialStats || null
|
|
167248
|
+
);
|
|
167249
|
+
const [history2, setHistory] = useState(
|
|
167250
|
+
initialHistory || []
|
|
167251
|
+
);
|
|
167223
167252
|
const [userName, setUserName] = useState(null);
|
|
167224
167253
|
const [allAchievements, setAllAchievements] = useState([]);
|
|
167225
167254
|
const [motivationalQuote, setMotivationalQuote] = useState(null);
|
|
@@ -167233,6 +167262,10 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167233
167262
|
);
|
|
167234
167263
|
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
|
167235
167264
|
const loadDashboardData = useCallback(() => {
|
|
167265
|
+
if (isControlled) {
|
|
167266
|
+
setIsLoading(false);
|
|
167267
|
+
return;
|
|
167268
|
+
}
|
|
167236
167269
|
setIsLoading(true);
|
|
167237
167270
|
setDashboardLayout(DashboardLayoutService.getLayout());
|
|
167238
167271
|
const practiceHistory = PracticeHistoryService.getPracticeHistory();
|
|
@@ -167261,10 +167294,20 @@ var PersonalPracticeDashboard = ({ settingsPath }) => {
|
|
|
167261
167294
|
if (KnowledgeCardService.getPendingConcepts().length > 0) {
|
|
167262
167295
|
CardGenerationProcessor.processQueue();
|
|
167263
167296
|
}
|
|
167264
|
-
}, [toast2, t4]);
|
|
167297
|
+
}, [isControlled, toast2, t4]);
|
|
167265
167298
|
useEffect(() => {
|
|
167266
|
-
|
|
167267
|
-
|
|
167299
|
+
if (isControlled) {
|
|
167300
|
+
setHistory(initialHistory || []);
|
|
167301
|
+
setStats(initialStats || null);
|
|
167302
|
+
const name3 = UserConfigService.getFullName();
|
|
167303
|
+
setUserName(name3);
|
|
167304
|
+
const achievementsWithStatus = AchievementService.getAllAchievementsWithStatus();
|
|
167305
|
+
setAllAchievements(achievementsWithStatus);
|
|
167306
|
+
setIsLoading(false);
|
|
167307
|
+
} else {
|
|
167308
|
+
loadDashboardData();
|
|
167309
|
+
}
|
|
167310
|
+
}, [isControlled, initialHistory, initialStats, loadDashboardData]);
|
|
167268
167311
|
useEffect(() => {
|
|
167269
167312
|
setMotivationalQuote(QuoteService.getRandomQuote());
|
|
167270
167313
|
const fetchAIQuote = async () => {
|
package/package.json
CHANGED