diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js
index 80b7c30..bdf12bb 100755
--- a/backend/services/vocabService.js
+++ b/backend/services/vocabService.js
@@ -2031,6 +2031,21 @@ export default class VocabService {
this._isTrainableSrsPair(item)
&& (!validKeys.size || validKeys.has(String(item.itemKey || '').trim()))
);
+ const scheduledRows = await VocabSrsItem.findAll({
+ where: { userId: user.id, courseId: Number(course.id) },
+ order: [['nextDueAt', 'ASC']]
+ });
+ const upcomingByDate = new Map();
+ scheduledRows
+ .filter((item) => (
+ this._isTrainableSrsPair(item)
+ && (!validKeys.size || validKeys.has(String(item.itemKey || '').trim()))
+ && new Date(item.nextDueAt).getTime() > now.getTime()
+ ))
+ .forEach((item) => {
+ const date = new Date(item.nextDueAt).toISOString().slice(0, 10);
+ upcomingByDate.set(date, (upcomingByDate.get(date) || 0) + 1);
+ });
const rows = validDueRows.slice(0, limit);
const totalDueCount = validDueRows.length;
@@ -2046,6 +2061,7 @@ export default class VocabService {
totalDueCount,
dailyLimit: DAILY_SRS_LIMIT,
limit,
+ upcoming: Array.from(upcomingByDate, ([date, count]) => ({ date, count })).slice(0, 6),
items: rows.map((item) => ({
itemKey: item.itemKey,
courseId: item.courseId,
diff --git a/frontend/src/i18n/locales/de/socialnetwork.json b/frontend/src/i18n/locales/de/socialnetwork.json
index d75bce6..d6384ea 100755
--- a/frontend/src/i18n/locales/de/socialnetwork.json
+++ b/frontend/src/i18n/locales/de/socialnetwork.json
@@ -772,14 +772,13 @@
"courseFlowBlockDescription": "Hier liegt der nächste reguläre Fortschritt im Kurs.",
"courseFlowBlockEmpty": "Der aktuelle Block ist bereits abgeschlossen oder es gibt gerade keine offene Blocklektion.",
"courseFlowIntensiveTitle": "Fällige Intensivphase",
- "courseFlowIntensiveDescription": "Verdichtete Wiederholung, sobald der Block davor weitgehend sitzt.",
- "courseFlowIntensiveEmpty": "Aktuell ist keine neue Intensivphase freigeschaltet.",
- "courseFlowIntensiveStatusAction": "Freischaltung prüfen",
- "courseFlowIntensiveStatusTitle": "Status der Intensivphase",
- "courseFlowIntensiveStatusAllDone": "Alle Intensivphasen dieses Kurses sind bereits abgeschlossen.",
- "courseFlowIntensiveStatusReady": "„{lesson}“ ist bereit und kann jetzt geöffnet werden.",
- "courseFlowIntensiveStatusProgress": "Für „{lesson}“ sind {done} von {total} vorausgehenden Lektionen im selben Block abgeschlossen.",
- "courseFlowIntensiveStatusNoDate": "Die Intensivphase wird nicht nach einer Wartezeit freigeschaltet, sondern sofort nach Abschluss dieser Lektionen.",
+ "courseFlowIntensiveDescription": "Zusätzliche Wiederholung für Begriffe, die du in der Tageswiederholung falsch beantwortet hast.",
+ "courseFlowIntensiveEmpty": "Aktuell sind keine Begriffe als schwer markiert.",
+ "courseFlowIntensiveStatusAction": "Nächste Wiederholungen prüfen",
+ "courseFlowIntensiveStatusTitle": "Nächste Vokabelwiederholungen",
+ "courseFlowIntensiveStatusAllDone": "Für abgeschlossene Lektionen sind derzeit keine weiteren Vokabelwiederholungen geplant.",
+ "courseFlowIntensiveStatusProgress": "{count} Begriffe",
+ "courseFlowIntensiveStatusNoDate": "Die Termine richten sich nach deinen richtigen Antworten: 1, 3, 7, 14, 30, 60 und 120 Tage. Eine falsche Antwort wird als schwer markiert und kommt zeitnah wieder.",
"courseFlowPracticeTitle": "Freie Vertiefung",
"courseFlowPracticeDescription": "Abgeschlossene Lektionen für lockeres Nachtrainieren außerhalb des Pflichtpfads.",
"courseFlowPracticeEmpty": "Sobald du erste Lektionen abgeschlossen hast, erscheinen sie hier für freies Nachtrainieren.",
diff --git a/frontend/src/i18n/locales/en/socialnetwork.json b/frontend/src/i18n/locales/en/socialnetwork.json
index 04c0c0e..bb0ac50 100755
--- a/frontend/src/i18n/locales/en/socialnetwork.json
+++ b/frontend/src/i18n/locales/en/socialnetwork.json
@@ -772,14 +772,13 @@
"courseFlowBlockDescription": "This is where the next regular progress step in the course lives.",
"courseFlowBlockEmpty": "The current block is already done or there is no open block lesson right now.",
"courseFlowIntensiveTitle": "Due intensive review",
- "courseFlowIntensiveDescription": "Condensed review once the block before it is mostly stable.",
- "courseFlowIntensiveEmpty": "No new intensive review is unlocked right now.",
- "courseFlowIntensiveStatusAction": "Check availability",
- "courseFlowIntensiveStatusTitle": "Intensive review status",
- "courseFlowIntensiveStatusAllDone": "All intensive review phases in this course are already complete.",
- "courseFlowIntensiveStatusReady": "“{lesson}” is ready and can be opened now.",
- "courseFlowIntensiveStatusProgress": "For “{lesson}”, {done} of {total} preceding lessons in the same block are complete.",
- "courseFlowIntensiveStatusNoDate": "The intensive review unlocks immediately after these lessons are complete; it does not have a waiting period.",
+ "courseFlowIntensiveDescription": "Extra review for terms answered incorrectly in the daily review.",
+ "courseFlowIntensiveEmpty": "No terms are currently marked as hard.",
+ "courseFlowIntensiveStatusAction": "Check upcoming reviews",
+ "courseFlowIntensiveStatusTitle": "Upcoming vocabulary reviews",
+ "courseFlowIntensiveStatusAllDone": "No further vocabulary reviews are currently scheduled for completed lessons.",
+ "courseFlowIntensiveStatusProgress": "{count} terms",
+ "courseFlowIntensiveStatusNoDate": "Dates are based on correct answers: 1, 3, 7, 14, 30, 60 and 120 days. An incorrect answer is marked hard and returns soon.",
"courseFlowPracticeTitle": "Free practice",
"courseFlowPracticeDescription": "Completed lessons for relaxed extra practice outside the required path.",
"courseFlowPracticeEmpty": "As soon as you complete your first lessons, they will appear here for free practice.",
diff --git a/frontend/src/views/social/VocabCourseView.vue b/frontend/src/views/social/VocabCourseView.vue
index caa73d6..5afd5ea 100755
--- a/frontend/src/views/social/VocabCourseView.vue
+++ b/frontend/src/views/social/VocabCourseView.vue
@@ -196,22 +196,20 @@