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:
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"}`} />
|
<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="min-w-0 flex-1 text-[13.5px] leading-snug">{item.label}</span>
|
||||||
<span className="flex flex-none items-center gap-1.5">
|
<span className="flex flex-none items-center gap-1.5">
|
||||||
{/* The folder's size, shown quietly beside the badge: the
|
{/* Only what is waiting to be read. The size of every folder
|
||||||
sidebar reported unread only, so there was nowhere in the
|
beside its name filled the rail with numbers that never
|
||||||
interface that said how much mail a folder holds. */}
|
change and that nobody is waiting on; the folder heading
|
||||||
{/* The folder size, always in the same quiet style, so it
|
still says how much mail a folder holds. */}
|
||||||
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. */}
|
|
||||||
{badge.showsUnread && (
|
{badge.showsUnread && (
|
||||||
<span
|
<span
|
||||||
className={`rounded-full px-1.5 py-px text-[11px] font-medium tabular-nums ${
|
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="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">
|
<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 && (
|
{badge.showsUnread && (
|
||||||
<span className="rounded-full bg-indigo-500/20 px-1.5 py-px text-[11px] font-medium tabular-nums text-indigo-300">
|
<span className="rounded-full bg-indigo-500/20 px-1.5 py-px text-[11px] font-medium tabular-nums text-indigo-300">
|
||||||
{badge.unread}
|
{badge.unread}
|
||||||
|
|||||||
@@ -36,17 +36,18 @@ describe("the counters the sidebar shows", () => {
|
|||||||
expect(code(USER_LAYOUT)).not.toMatch(/unread_count\s*\?\?/);
|
expect(code(USER_LAYOUT)).not.toMatch(/unread_count\s*\?\?/);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The total was rendered twice for Drafts, where the badge and the size are
|
// The sidebar shows what is waiting to be read and nothing else. It used to
|
||||||
// the same number: "Rascunhos 1 1".
|
// 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
|
||||||
// Two occurrences now, not one: the standard folders and the folders the
|
// unread badge's own place whenever nothing was unread, so an inbox of read
|
||||||
// user created are rendered by separate templates. What must not happen is
|
// mail showed "14" and reading another message never moved it.
|
||||||
// one template printing it twice, which is what the defect was.
|
it("renders only the unread count, never the folder size", () => {
|
||||||
it("renders the folder size once per folder template", () => {
|
|
||||||
const layout = code(USER_LAYOUT);
|
const layout = code(USER_LAYOUT);
|
||||||
expect(layout.match(/\{badge\.total\}/g) ?? []).toHaveLength(2);
|
// The size survives in the tooltip, which is not the rail.
|
||||||
// And each template guards the unread badge, so the two numbers can never
|
const rendered = layout.match(/\{badge\.total\}/g) ?? [];
|
||||||
// be the same value shown twice.
|
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);
|
expect(layout.match(/badge\.showsUnread/g) ?? []).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -175,39 +175,46 @@ describe("the badge a sidebar folder renders", () => {
|
|||||||
{ special_use: "archive", name: "Archive", unread_count: 0, total_count: 0 },
|
{ special_use: "archive", name: "Archive", unread_count: 0, total_count: 0 },
|
||||||
];
|
];
|
||||||
|
|
||||||
// The inbox showed "14" with nothing unread. Reading every message left it
|
// The sidebar shows what needs attention and nothing else. Printing the size
|
||||||
// at 14, because 14 was the total wearing the unread badge's clothes.
|
// of every folder beside its name filled the rail with numbers that never
|
||||||
it("does not show a total where an unread count belongs", () => {
|
// change and that nobody is waiting on.
|
||||||
const badge = folderBadge(folders, "inbox");
|
it("shows the unread count when there is unread mail", () => {
|
||||||
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", () => {
|
|
||||||
const badge = folderBadge(folders, "junk");
|
const badge = folderBadge(folders, "junk");
|
||||||
expect(badge.showsUnread).toBe(true);
|
expect(badge.showsUnread).toBe(true);
|
||||||
expect(badge.unread).toBe(3);
|
expect(badge.unread).toBe(3);
|
||||||
expect(badge.total).toBe(9);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows nothing at all for an empty folder", () => {
|
// An inbox whose mail has all been read shows nothing. This is also what the
|
||||||
const badge = folderBadge(folders, "archive");
|
// 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.showsUnread).toBe(false);
|
||||||
expect(badge.total).toBe(0);
|
expect(badge.unread).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user