feat(vocab): implement daily hard vocab limit handling in practice dialog

This commit is contained in:
Torsten Schulz (local)
2026-08-21 09:03:40 +02:00
parent ad02dd006f
commit 2f4657c0fb
2 changed files with 24 additions and 1 deletions

View File

@@ -140,6 +140,7 @@ const PRACTICE_MIN_EXPOSURES = 3;
const SRS_SESSION_STORAGE_VERSION = 2;
const HARD_REQUIRED_CONSECUTIVE_CORRECT = 5;
const MAX_DAILY_DUE = 50;
const MAX_DAILY_HARD_VOCABS = 7;
export default {
name: 'VocabPracticeDialog',
@@ -148,6 +149,7 @@ export default {
return {
openParams: null, // { languageId, chapterId, lessonId, courseId }
onClose: null,
onDailyHardLimitReached: null,
loading: false,
allVocabs: false,
srsMode: false,
@@ -389,6 +391,19 @@ export default {
}
this.saveHardVocabMap();
},
maybeStartDailyHardPractice() {
if (!this.srsMode || this.hardCount < MAX_DAILY_HARD_VOCABS) return false;
const callback = this.onDailyHardLimitReached;
this.close();
this.$nextTick(() => {
try {
callback?.();
} catch (_) {
// A missing parent callback must not interrupt the dialog close.
}
});
return true;
},
unmarkCurrentAsHard() {
if (!this.current) return;
const matchingKey = this.findMatchingHardKey(this.current);
@@ -531,7 +546,7 @@ export default {
}
this.saveSrsSession();
},
open({ languageId, chapterId, lessonId, courseId, initialPool = null, initialHardPool = null, srsMode = false, closeOnHardCompletion = false, onClose = null }) {
open({ languageId, chapterId, lessonId, courseId, initialPool = null, initialHardPool = null, srsMode = false, closeOnHardCompletion = false, onDailyHardLimitReached = null, onClose = null }) {
if (this.autoAdvanceTimer) {
clearTimeout(this.autoAdvanceTimer);
this.autoAdvanceTimer = null;
@@ -542,6 +557,7 @@ export default {
console.debug('[VocabPracticeDialog] open called with', { languageId, chapterId, lessonId, courseId, srsMode, hasInitialPool: Array.isArray(initialPool) });
} catch (_) {}
this.onClose = typeof onClose === 'function' ? onClose : null;
this.onDailyHardLimitReached = typeof onDailyHardLimitReached === 'function' ? onDailyHardLimitReached : null;
this.srsMode = Boolean(srsMode);
this.initialPool = Array.isArray(initialPool) ? initialPool : null;
this.closeOnHardCompletion = Boolean(closeOnHardCompletion);
@@ -574,6 +590,7 @@ export default {
this.hardVocabMap[key] = { learning: item.learning, reference: item.reference, itemKey: item.itemKey || item.id || null };
});
}
if (this.maybeStartDailyHardPractice()) return;
this.reloadPool();
},
close() {
@@ -1240,6 +1257,7 @@ export default {
: [];
this.saveSrsSession();
}
if (!isCorrect && this.maybeStartDailyHardPractice()) return;
this.autoAdvanceTimer = setTimeout(() => {
this.autoAdvanceTimer = null;
this.next();

View File

@@ -946,7 +946,12 @@ export default {
this.$refs.practiceDialog?.open?.({
courseId: this.courseId,
initialPool: this.srsDueItems,
initialHardPool: this.hardVocabList,
srsMode: true,
onDailyHardLimitReached: async () => {
await this.refreshHardVocabList();
this.openHardPractice();
},
onClose: () => this.loadSrsDueItems()
});
},