@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.
@@ -3998,20 +3998,30 @@ var PracticeHistoryService = class {
3998
3998
  static saveHistory(history2) {
3999
3999
  if (typeof window !== "undefined") {
4000
4000
  try {
4001
- localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(history2));
4001
+ localStorage.setItem(
4002
+ LOCAL_STORAGE_KEY,
4003
+ JSON.stringify(history2)
4004
+ );
4002
4005
  } catch (e2) {
4003
- console.error("Error saving practice history to localStorage:", e2);
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(quizConfig.questions.map((q) => JSON.stringify({
4011
- subject: q.subject || "Uncategorized",
4012
- category: q.category || "General",
4013
- topic: q.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
4137
- if (session.summary.percentage !== null) {
4138
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
4139
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
4140
- subjectPerf[topicInfo.subject].count++;
4141
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
4142
- topicPerf[topicInfo.topic].total += session.summary.percentage;
4143
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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 {
@@ -3972,20 +3972,30 @@ var PracticeHistoryService = class {
3972
3972
  static saveHistory(history2) {
3973
3973
  if (typeof window !== "undefined") {
3974
3974
  try {
3975
- localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(history2));
3975
+ localStorage.setItem(
3976
+ LOCAL_STORAGE_KEY,
3977
+ JSON.stringify(history2)
3978
+ );
3976
3979
  } catch (e2) {
3977
- console.error("Error saving practice history to localStorage:", e2);
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(quizConfig.questions.map((q) => JSON.stringify({
3985
- subject: q.subject || "Uncategorized",
3986
- category: q.category || "General",
3987
- topic: q.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
4111
- if (session.summary.percentage !== null) {
4112
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
4113
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
4114
- subjectPerf[topicInfo.subject].count++;
4115
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
4116
- topicPerf[topicInfo.topic].total += session.summary.percentage;
4117
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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(LOCAL_STORAGE_KEY, JSON.stringify(history));
1967
+ localStorage.setItem(
1968
+ LOCAL_STORAGE_KEY,
1969
+ JSON.stringify(history)
1970
+ );
1968
1971
  } catch (e) {
1969
- console.error("Error saving practice history to localStorage:", e);
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(quizConfig.questions.map((q) => JSON.stringify({
1977
- subject: q.subject || "Uncategorized",
1978
- category: q.category || "General",
1979
- topic: q.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
2103
- if (session.summary.percentage !== null) {
2104
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
2105
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
2106
- subjectPerf[topicInfo.subject].count++;
2107
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
2108
- topicPerf[topicInfo.topic].total += session.summary.percentage;
2109
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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(LOCAL_STORAGE_KEY, JSON.stringify(history));
1961
+ localStorage.setItem(
1962
+ LOCAL_STORAGE_KEY,
1963
+ JSON.stringify(history)
1964
+ );
1962
1965
  } catch (e) {
1963
- console.error("Error saving practice history to localStorage:", e);
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(quizConfig.questions.map((q) => JSON.stringify({
1971
- subject: q.subject || "Uncategorized",
1972
- category: q.category || "General",
1973
- topic: q.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
2097
- if (session.summary.percentage !== null) {
2098
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
2099
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
2100
- subjectPerf[topicInfo.subject].count++;
2101
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
2102
- topicPerf[topicInfo.topic].total += session.summary.percentage;
2103
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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(LOCAL_STORAGE_KEY, JSON.stringify(history2));
139591
+ localStorage.setItem(
139592
+ LOCAL_STORAGE_KEY,
139593
+ JSON.stringify(history2)
139594
+ );
139592
139595
  } catch (e3) {
139593
- console.error("Error saving practice history to localStorage:", e3);
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(quizConfig.questions.map((q2) => JSON.stringify({
139601
- subject: q2.subject || "Uncategorized",
139602
- category: q2.category || "General",
139603
- topic: q2.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
139727
- if (session.summary.percentage !== null) {
139728
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
139729
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
139730
- subjectPerf[topicInfo.subject].count++;
139731
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
139732
- topicPerf[topicInfo.topic].total += session.summary.percentage;
139733
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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(null);
167249
- const [history2, setHistory] = React163.useState([]);
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
- loadDashboardData();
167294
- }, [loadDashboardData]);
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 () => {
@@ -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, o as PracticeStats, 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, n as PracticeSession, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DqFRlFU3.cjs';
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 };
@@ -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, o as PracticeStats, 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, n as PracticeSession, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DqVlSO3r.js';
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(LOCAL_STORAGE_KEY, JSON.stringify(history2));
139564
+ localStorage.setItem(
139565
+ LOCAL_STORAGE_KEY,
139566
+ JSON.stringify(history2)
139567
+ );
139565
139568
  } catch (e3) {
139566
- console.error("Error saving practice history to localStorage:", e3);
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(quizConfig.questions.map((q2) => JSON.stringify({
139574
- subject: q2.subject || "Uncategorized",
139575
- category: q2.category || "General",
139576
- topic: q2.topic || "General Topic"
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(`Sync provider found. Pushing session ${newSession.id} to backend.`);
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(`Could not find session with ID "${sessionId}" to update review.`);
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(diffTime / (1e3 * 60 * 60 * 24));
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((topicInfo) => {
139700
- if (session.summary.percentage !== null) {
139701
- if (!subjectPerf[topicInfo.subject]) subjectPerf[topicInfo.subject] = { total: 0, count: 0 };
139702
- subjectPerf[topicInfo.subject].total += session.summary.percentage;
139703
- subjectPerf[topicInfo.subject].count++;
139704
- if (!topicPerf[topicInfo.topic]) topicPerf[topicInfo.topic] = { total: 0, count: 0 };
139705
- topicPerf[topicInfo.topic].total += session.summary.percentage;
139706
- topicPerf[topicInfo.topic].count++;
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((data.total / data.count).toFixed(2))
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(null);
167222
- const [history2, setHistory] = useState([]);
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
- loadDashboardData();
167267
- }, [loadDashboardData]);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thanh01.pmt/interactive-quiz-kit",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "A comprehensive library for creating, managing, and playing interactive quizzes, with AI generation and SCORM support.",
5
5
  "keywords": [
6
6
  "react",