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 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Opus 5 committed 2026-08-22 15:30:17 -03:00
1 parent e4491479ef
commit 64f1a2e145
4 files changed
+101 -55

No files matched your search

@@ -133,21 +133,10 @@ export default function UserWebmailLayout({ children }: { children: React.ReactN
<Icon className={`h-[17px] w-[17px] flex-none ${isActive ? "text-indigo-500" : "text-slate-400"}`} />
<span className="min-w-0 flex-1 text-[13.5px] leading-snug">{item.label}</span>
<span className="flex flex-none items-center gap-1.5">
{/* 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 && (
<span
className="text-[11.5px] tabular-nums text-slate-500"
title={t("mail.messagesInFolder", { count: badge.total })}
>
{badge.total}
</span>
)}
{/* 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 && (
<span
className={`rounded-full px-1.5 py-px text-[11px] font-medium tabular-nums ${
@@ -186,9 +175,6 @@ export default function UserWebmailLayout({ children }: { children: React.ReactN
/>
<span className="min-w-0 flex-1 truncate text-[13.5px] leading-snug">{folder.name}</span>
<span className="flex flex-none items-center gap-1.5 pr-5">
{badge.total > 0 && (
<span className="text-[11.5px] tabular-nums text-slate-500">{badge.total}</span>
)}
{badge.showsUnread && (
<span className="rounded-full bg-indigo-500/20 px-1.5 py-px text-[11px] font-medium tabular-nums text-indigo-300">
{badge.unread}
@@ -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);
});
+34 -27
View File
@@ -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);
});
});
+52
View File
@@ -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);
});
});