From 4e5c2a1517c1723271f3833c225aad8f0b161019 Mon Sep 17 00:00:00 2001 From: feruzm Date: Sun, 6 Sep 2026 14:05:09 +0000 Subject: [PATCH] Drop reputation and account age from curation desk rows The author in a row is wrapped in ProfilePopover, whose hover card already carries the reputation next to the username and the joined date, so "rep 73" and "6 y" in the byline were repeating it a second time on every row. Account age was not purely informational though: it turned amber under 30 days. That part is a review signal the hover card does not reproduce, so it stays as a compact New account chip that appears only inside that window. AuthorAgeChip becomes NewAccountChip and the three age strings collapse to one. The quick view keeps its rep, where there is no hover card to fall back on. --- .../curation-desk/curation-queue-row.tsx | 24 +++++++++---------- apps/web/src/features/i18n/locales/en-US.json | 4 +--- .../curation-window-badge.spec.tsx | 17 ++++++++----- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/apps/web/src/features/curation-desk/curation-queue-row.tsx b/apps/web/src/features/curation-desk/curation-queue-row.tsx index 474642a0d9..0bdc5d85d5 100644 --- a/apps/web/src/features/curation-desk/curation-queue-row.tsx +++ b/apps/web/src/features/curation-desk/curation-queue-row.tsx @@ -60,27 +60,26 @@ interface Props extends RowActions { scalePct: number; } +const NEW_ACCOUNT_DAYS = 30; + function accountAgeDays(authorCreated: string | null | undefined, now: number): number | null { const ms = parseChainDate(authorCreated); if (ms == null) return null; return Math.floor((now - ms) / 86_400_000); } -function formatAge(days: number): string { - if (days >= 365) return i18next.t("curation-desk.row.age-years", { count: Math.floor(days / 365) }); - if (days >= 30) return i18next.t("curation-desk.row.age-months", { count: Math.floor(days / 30) }); - return i18next.t("curation-desk.row.age-days", { count: days }); -} - /** - * Account age of the author, amber under 30 days. Its own memo child on the - * shared clock, so the day counter never re-renders the row around it. + * Warns only while the author's account is under 30 days old. The plain age of + * an established account is not shown here: the author hover card already + * carries reputation and the joined date, so the byline would just repeat it. + * Its own memo child on the shared clock, so the day counter never re-renders + * the row around it. */ -export const AuthorAgeChip = memo(function AuthorAgeChip({ authorCreated }: { authorCreated: string | null | undefined }) { +export const NewAccountChip = memo(function NewAccountChip({ authorCreated }: { authorCreated: string | null | undefined }) { const now = useCurationTicker(); const days = accountAgeDays(authorCreated, now); - if (days == null) return null; - return {formatAge(days)}; + if (days == null || days >= NEW_ACCOUNT_DAYS) return null; + return {i18next.t("curation-desk.row.new-account")}; }); function appLabel(app: string | null): string { @@ -242,8 +241,7 @@ export const CurationQueueRow = memo(function CurationQueueRow(props: Props) { - {row.rep != null && {i18next.t("curation-desk.row.rep", { rep: row.rep })}} - + {row.is_new_author && ( {i18next.t("curation-desk.row.new-author", { n: row.author_post_count ?? 1 })} )} diff --git a/apps/web/src/features/i18n/locales/en-US.json b/apps/web/src/features/i18n/locales/en-US.json index 71341e9a0b..ba8453b8f5 100644 --- a/apps/web/src/features/i18n/locales/en-US.json +++ b/apps/web/src/features/i18n/locales/en-US.json @@ -4482,9 +4482,7 @@ "untitled": "@{{author}}'s post", "describe": "By @{{author}}, {{words}} words, curation window {{window}}", "rep": "rep {{rep}}", - "age-days": "{{count}} d", - "age-months": "{{count}} mo", - "age-years": "{{count}} y", + "new-account": "New account", "new-author": "New ยท post #{{n}}", "app-unknown": "unknown app", "no-community": "no community", diff --git a/apps/web/src/specs/features/curation-desk/curation-window-badge.spec.tsx b/apps/web/src/specs/features/curation-desk/curation-window-badge.spec.tsx index 1b964527b8..c61c8840eb 100644 --- a/apps/web/src/specs/features/curation-desk/curation-window-badge.spec.tsx +++ b/apps/web/src/specs/features/curation-desk/curation-window-badge.spec.tsx @@ -109,17 +109,22 @@ describe("author account age", () => { it("warns in amber for an account younger than 30 days", () => { renderRow(makeRow({ post_id: 5, author_created: new Date(Date.now() - 9 * 24 * HOUR).toISOString() })); - const chip = screen.getByText("curation-desk.row.age-days"); - expect(chip.className).toContain("text-warning-ink"); + expect(screen.getByText("curation-desk.row.new-account").className).toContain("text-warning-ink"); }); - it("stays neutral for an older account and renders nothing without author_created", () => { + it("says nothing for an established account or a missing creation date", () => { const { unmount } = renderRow(makeRow({ post_id: 6, author_created: new Date(Date.now() - 800 * 24 * HOUR).toISOString() })); - expect(screen.getByText("curation-desk.row.age-years").className).not.toContain("text-warning-ink"); + expect(screen.queryByText("curation-desk.row.new-account")).toBeNull(); unmount(); renderRow(makeRow({ post_id: 7, author_created: null })); - expect(screen.queryByText("curation-desk.row.age-days")).toBeNull(); - expect(screen.queryByText("curation-desk.row.age-years")).toBeNull(); + expect(screen.queryByText("curation-desk.row.new-account")).toBeNull(); + }); + + // The hover card on the author carries reputation and the joined date, so the + // byline no longer repeats them. + it("keeps reputation and plain account age out of the byline", () => { + renderRow(makeRow({ post_id: 8, rep: 73, author_created: new Date(Date.now() - 800 * 24 * HOUR).toISOString() })); + expect(screen.queryByText("curation-desk.row.rep")).toBeNull(); }); });