From 64f1a2e145fa7ab3002a65004dc15018c0e462b3 Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Sat, 22 Aug 2026 15:30:17 -0300 Subject: [PATCH] fix(webmail): a barra lateral mostra so o que esta por ler Mostrava tambem o tamanho de cada pasta. Sao numeros que nao mudam e que ninguem esta a espera: enchiam a barra sem dizer nada de util. Agora aparece um numero apenas onde ha correio por ler, e nada nas restantes. Consequencia a saber: Rascunhos nunca tem mensagens por ler - nada marca um rascunho como lido - portanto passa a nao ter numero nenhum. Quem quiser saber quantos rascunhos tem, ve-o no cabecalho da pasta. O tamanho continua no tooltip do link, e o cabecalho da lista continua a dize-lo por extenso, portanto a informacao nao se perdeu - deixou apenas de estar sempre no campo de visao. Co-Authored-By: Claude Opus 5 --- .../webmail/src/app/(user)/user/layout.tsx | 22 ++----- .../webmail/src/mail-state-integrity.test.ts | 21 ++++--- services/webmail/src/mailCounts.test.ts | 61 +++++++++++-------- services/webmail/src/sidebarBadge.test.ts | 52 ++++++++++++++++ 4 files changed, 101 insertions(+), 55 deletions(-) create mode 100644 services/webmail/src/sidebarBadge.test.ts diff --git a/services/webmail/src/app/(user)/user/layout.tsx b/services/webmail/src/app/(user)/user/layout.tsx index 14016fd..8a08a74 100644 --- a/services/webmail/src/app/(user)/user/layout.tsx +++ b/services/webmail/src/app/(user)/user/layout.tsx @@ -133,21 +133,10 @@ export default function UserWebmailLayout({ children }: { children: React.ReactN {item.label} - {/* The folder's size, shown quietly beside the badge: the - sidebar reported unread only, so there was nowhere in the - interface that said how much mail a folder holds. */} - {/* The folder size, always in the same quiet style, so it - can never be mistaken for an unread count. */} - {badge.total > 0 && ( - - {badge.total} - - )} - {/* The unread count, only when there is unread mail, and - visibly distinct from the size beside it. */} + {/* Only what is waiting to be read. The size of every folder + beside its name filled the rail with numbers that never + change and that nobody is waiting on; the folder heading + still says how much mail a folder holds. */} {badge.showsUnread && ( {folder.name} - {badge.total > 0 && ( - {badge.total} - )} {badge.showsUnread && ( {badge.unread} diff --git a/services/webmail/src/mail-state-integrity.test.ts b/services/webmail/src/mail-state-integrity.test.ts index 0beaa59..6097f86 100644 --- a/services/webmail/src/mail-state-integrity.test.ts +++ b/services/webmail/src/mail-state-integrity.test.ts @@ -36,17 +36,18 @@ describe("the counters the sidebar shows", () => { expect(code(USER_LAYOUT)).not.toMatch(/unread_count\s*\?\?/); }); - // The total was rendered twice for Drafts, where the badge and the size are - // the same number: "Rascunhos 1 1". - // - // Two occurrences now, not one: the standard folders and the folders the - // user created are rendered by separate templates. What must not happen is - // one template printing it twice, which is what the defect was. - it("renders the folder size once per folder template", () => { + // The sidebar shows what is waiting to be read and nothing else. It used to + // print the size of every folder beside its name - numbers that never change + // and that nobody is waiting on - and, worse, it printed the size in the + // unread badge's own place whenever nothing was unread, so an inbox of read + // mail showed "14" and reading another message never moved it. + it("renders only the unread count, never the folder size", () => { const layout = code(USER_LAYOUT); - expect(layout.match(/\{badge\.total\}/g) ?? []).toHaveLength(2); - // And each template guards the unread badge, so the two numbers can never - // be the same value shown twice. + // The size survives in the tooltip, which is not the rail. + const rendered = layout.match(/\{badge\.total\}/g) ?? []; + expect(rendered).toHaveLength(0); + // Both folder templates - the standard ones and the user's own - guard + // their badge on there actually being unread mail. expect(layout.match(/badge\.showsUnread/g) ?? []).toHaveLength(2); }); diff --git a/services/webmail/src/mailCounts.test.ts b/services/webmail/src/mailCounts.test.ts index 1a7b4f2..9203dfc 100644 --- a/services/webmail/src/mailCounts.test.ts +++ b/services/webmail/src/mailCounts.test.ts @@ -175,39 +175,46 @@ describe("the badge a sidebar folder renders", () => { { special_use: "archive", name: "Archive", unread_count: 0, total_count: 0 }, ]; - // The inbox showed "14" with nothing unread. Reading every message left it - // at 14, because 14 was the total wearing the unread badge's clothes. - it("does not show a total where an unread count belongs", () => { - const badge = folderBadge(folders, "inbox"); - expect(badge.unread).toBe(0); - expect(badge.showsUnread).toBe(false); - }); - - it("still reports the folder size, separately from the unread count", () => { - expect(folderBadge(folders, "inbox").total).toBe(14); - }); - - // Drafts counted total as its badge, so total and badge were the same - // number and the sidebar printed it twice: "Rascunhos 1 1". - it("never renders the same number twice for drafts", () => { - const badge = folderBadge(folders, "drafts"); - const rendered = [badge.showsUnread ? badge.unread : null, badge.total].filter( - (v) => v !== null, - ); - expect(rendered).toEqual([1]); - }); - - it("shows the unread count when there really is unread mail", () => { + // The sidebar shows what needs attention and nothing else. Printing the size + // of every folder beside its name filled the rail with numbers that never + // change and that nobody is waiting on. + it("shows the unread count when there is unread mail", () => { const badge = folderBadge(folders, "junk"); expect(badge.showsUnread).toBe(true); expect(badge.unread).toBe(3); - expect(badge.total).toBe(9); }); - it("shows nothing at all for an empty folder", () => { - const badge = folderBadge(folders, "archive"); + // An inbox whose mail has all been read shows nothing. This is also what the + // original defect looked like from the other side: it showed "14" - the + // total - and reading a message never moved it. + it("shows nothing when everything has been read", () => { + expect(folderBadge(folders, "inbox").showsUnread).toBe(false); + }); + + it("shows nothing for a folder nothing is delivered to", () => { + expect(folderBadge(folders, "sent").showsUnread).toBe(false); + }); + + it("shows nothing for an empty folder", () => { + expect(folderBadge(folders, "archive").showsUnread).toBe(false); + }); + + // Nothing marks a draft read, so its unread count is permanently zero. With + // only unread counts on show, Drafts carries no number at all. + it("shows nothing for drafts, which are never unread", () => { + expect(folderBadge(folders, "drafts").showsUnread).toBe(false); + }); + + // The total is still available to anything that wants it - the folder + // heading uses it - it is simply not what the rail displays. + it("still reports the folder size for callers that need it", () => { + expect(folderBadge(folders, "inbox").total).toBe(14); + }); + + it("copes with a folder that is not there", () => { + const badge = folderBadge(folders, "nao-existe"); expect(badge.showsUnread).toBe(false); - expect(badge.total).toBe(0); + expect(badge.unread).toBe(0); }); }); diff --git a/services/webmail/src/sidebarBadge.test.ts b/services/webmail/src/sidebarBadge.test.ts new file mode 100644 index 0000000..1d8d4d3 --- /dev/null +++ b/services/webmail/src/sidebarBadge.test.ts @@ -0,0 +1,52 @@ +import { describe, it, expect } from "vitest"; +import { folderBadge, type FolderSummary } from "./lib/mailCounts"; + +/** + * What the rail actually puts on screen, folder by folder. + * + * The component renders the unread count only when showsUnread is true, so + * this is the rendered result: a number, or nothing at all. Written as a table + * because the point of the change is what the rail looks like as a whole, not + * what one folder returns. + */ +function rendered(folders: FolderSummary[], route: string): string { + const badge = folderBadge(folders, route); + return badge.showsUnread ? String(badge.unread) : ""; +} + +describe("what each folder shows in the rail", () => { + const folders: FolderSummary[] = [ + { special_use: "inbox", name: "INBOX", unread_count: 3, total_count: 17 }, + { special_use: "sent", name: "Sent", unread_count: 0, total_count: 2 }, + { special_use: "drafts", name: "Drafts", unread_count: 0, total_count: 1 }, + { special_use: "junk", name: "Junk", unread_count: 0, total_count: 0 }, + { special_use: "", name: "Faturas", unread_count: 5, total_count: 9 }, + ]; + + it("shows only the unread count, never the size", () => { + expect(rendered(folders, "inbox")).toBe("3"); + expect(rendered(folders, "inbox")).not.toContain("17"); + }); + + it("shows nothing for folders with nothing unread", () => { + expect(rendered(folders, "sent")).toBe(""); + expect(rendered(folders, "drafts")).toBe(""); + expect(rendered(folders, "junk")).toBe(""); + }); + + it("shows the unread count on a folder the user created", () => { + expect(rendered(folders, "Faturas")).toBe("5"); + }); + + // The whole rail, as a reader sees it: a number only where mail is waiting. + it("leaves the rail carrying one number per folder with unread mail", () => { + const all = ["inbox", "sent", "drafts", "junk", "Faturas"].map((r) => rendered(folders, r)); + expect(all.filter((v) => v !== "")).toEqual(["3", "5"]); + }); + + it("is completely bare when everything has been read", () => { + const read = folders.map((f) => ({ ...f, unread_count: 0 })); + const all = ["inbox", "sent", "drafts", "junk", "Faturas"].map((r) => rendered(read, r)); + expect(all.every((v) => v === "")).toBe(true); + }); +});