Smart review: name the source deck on every card, break the counts down

"It contains mistakes I either did more than once or from decks that I've
removed - there's no way there's 34 to repeat with 2 decks." The counts were
honest (dueItems/mistakeItems only resolve live deck+activity pairs; a seeded
repro with 37 SRS rows and 30 live shows "30 due"), but nothing in the UI said
where an item came from: a deck created twice from the same notes shows every
question twice, and a deck that survived a delete or a sync looks like a ghost.
Both read as a broken list.

- SessionFeed gains showDeck (review + mistakes): a deck chip above every
  card, so two identical questions are visibly two decks.
- The Smart review card breaks its numbers down under the buttons:
  "Due by deck: Sky deck - 17 - Sky deck (2) - 17", capped at three decks
  plus "+n more" (groupByDeck in lib/learning).
- New i18n keys (en + cs, plural forms for "+n more").

review-test pins it: a twin-deck seed renders the breakdown and both deck
chips in the feed. Version 0.6.8, SW v90.
This commit is contained in:
Martin Dvořák 2026-10-15 19:27:04 +00:00
commit 1e8606a95b
9 changed files with 129 additions and 8 deletions

View file

@ -845,6 +845,11 @@ const en: Record<string, string> = {
"review.due.one": "{n} due",
"review.due.few": "{n} due",
"review.due.many": "{n} due",
"review.dueByDeck": "Due by deck: {list}",
"review.mistakesByDeck": "Mistakes by deck: {list}",
"review.moreDecks.one": "+{n} more deck",
"review.moreDecks.few": "+{n} more decks",
"review.moreDecks.many": "+{n} more decks",
"review.mistakes.one": "{n} mistake",
"review.mistakes.few": "{n} mistakes",
"review.mistakes.many": "{n} mistakes",
@ -1846,6 +1851,11 @@ const cs: Record<string, string> = {
"review.due.one": "{n} k opakování",
"review.due.few": "{n} k opakování",
"review.due.many": "{n} k opakování",
"review.dueByDeck": "K opakování podle sady: {list}",
"review.mistakesByDeck": "Chyby podle sady: {list}",
"review.moreDecks.one": "+{n} další sada",
"review.moreDecks.few": "+{n} další sady",
"review.moreDecks.many": "+{n} dalších sad",
"review.mistakes.one": "{n} chyba",
"review.mistakes.few": "{n} chyby",
"review.mistakes.many": "{n} chyb",

View file

@ -71,6 +71,23 @@ export function mistakeCount(answers: AnswerRecord[], deckId?: string): number {
return mistakeItems(answers, deckId).length;
}
/**
* Where a review list comes from: one entry per deck, most items first. The
* Smart review card shows this under its buttons so a count that mixes decks
* ("34 due" with two decks on screen) is self-explanatory instead of looking
* like the same mistake twice or an item from a deck that was deleted.
*/
export function groupByDeck(items: ReviewItem[]): { label: string; count: number }[] {
const groups = new Map<string, { label: string; count: number }>();
for (const item of items) {
const key = item.deck.id;
const group = groups.get(key) ?? { label: item.deck.title, count: 0 };
group.count += 1;
groups.set(key, group);
}
return [...groups.values()].sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));
}
/* ------------------------------------------------------------------ */
/* Stats */
/* ------------------------------------------------------------------ */