fix(notifications): a notice keeps what to say and says it in the reader's language when shown
This commit is contained in:
@@ -9,7 +9,7 @@ import { afterEach, describe, expect, it, onTestFinished, vi } from "vitest";
|
||||
import { act, cleanup, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { api, type AppNotification } from "../../lib/api";
|
||||
import type { Notification as ClientNotif } from "../../lib/notifications";
|
||||
import { raw, type Notification as ClientNotif } from "../../lib/notifications";
|
||||
|
||||
const h = vi.hoisted(() => ({
|
||||
server: [] as unknown[],
|
||||
@@ -116,7 +116,7 @@ const client = (id: number, extra: Partial<ClientNotif> = {}) =>
|
||||
({
|
||||
id,
|
||||
level: "success",
|
||||
message: `Activity ${id}`,
|
||||
message: raw(`Activity ${id}`),
|
||||
requiresInteraction: false,
|
||||
ts: Date.now(),
|
||||
read: true,
|
||||
|
||||
@@ -50,6 +50,7 @@ vi.mock("../../components/ui/PageShell", async (importOriginal) => ({
|
||||
|
||||
import NotificationsPanel from "./NotificationsPanel";
|
||||
import { focusNavItem, restoreNavPosition } from "../../lib/listNav";
|
||||
import { raw } from "../../lib/notifications";
|
||||
|
||||
// The server list goes through the real live query, so an optimistic patch of its cache is seen.
|
||||
beforeEach(() => {
|
||||
@@ -80,7 +81,7 @@ const client = (id: number, ageMs: number, extra: Partial<ClientNotif> = {}) =>
|
||||
({
|
||||
id,
|
||||
level: "success",
|
||||
message: `Activity ${id}.`,
|
||||
message: raw(`Activity ${id}.`),
|
||||
requiresInteraction: false,
|
||||
ts: Date.now() - ageMs,
|
||||
read: true,
|
||||
@@ -122,8 +123,8 @@ describe("NotificationsPanel · order", () => {
|
||||
h.client = [
|
||||
client(9, 5 * 60 * 1000, {
|
||||
level: "warning",
|
||||
title: "common.accessRequestsTitle",
|
||||
message: "1 pending",
|
||||
title: raw("common.accessRequestsTitle"),
|
||||
message: raw("1 pending"),
|
||||
meta: { kind: "access-requests" },
|
||||
}),
|
||||
client(8, 2 * D),
|
||||
@@ -366,8 +367,8 @@ describe("NotificationsPanel · order", () => {
|
||||
h.client = [
|
||||
client(9, 5 * 60 * 1000, {
|
||||
level: "warning",
|
||||
title: "common.accessRequestsTitle",
|
||||
message: "1 pending",
|
||||
title: raw("common.accessRequestsTitle"),
|
||||
message: raw("1 pending"),
|
||||
meta: { kind: "access-requests" },
|
||||
}),
|
||||
];
|
||||
@@ -465,7 +466,9 @@ describe("NotificationsPanel · order", () => {
|
||||
// A screen reader hears the name while the keyboard is on the row, and Back finds the row it
|
||||
// left by it: "Download ready" alone was every download's name.
|
||||
h.server = [server(1, 1 * H, true), server(2, 2 * H, true)];
|
||||
h.client = [client(3, 3 * H, { title: "Something broke", message: "Unexpected error." })];
|
||||
h.client = [
|
||||
client(3, 3 * H, { title: raw("Something broke"), message: raw("Unexpected error.") }),
|
||||
];
|
||||
mount();
|
||||
await loaded();
|
||||
expect(
|
||||
|
||||
@@ -29,16 +29,18 @@ import { useLiveQuery } from "../../lib/useLiveQuery";
|
||||
import { focusAccessRequestsTab } from "../../lib/adminUsersTab";
|
||||
import { focusSettingsTab } from "../../lib/settingsTab";
|
||||
import {
|
||||
type ChannelSubscribedMeta,
|
||||
clearAll as clearClient,
|
||||
dismiss as dismissClient,
|
||||
getNotifications,
|
||||
getUnreadCount,
|
||||
markAllRead as markAllClientRead,
|
||||
msg,
|
||||
type Notification as ClientNotif,
|
||||
remove as removeClient,
|
||||
resolveVideo,
|
||||
sayNotif,
|
||||
subscribe,
|
||||
type Notification as ClientNotif,
|
||||
type ChannelSubscribedMeta,
|
||||
type VideoHiddenMeta,
|
||||
type VideoWatchedMeta,
|
||||
} from "../../lib/notifications";
|
||||
@@ -250,7 +252,7 @@ export default function NotificationsPanel() {
|
||||
// Quietly resolve the now-stale notice (no confirmation toast — the change is visible).
|
||||
resolveVideo(meta.videoId);
|
||||
})
|
||||
.catch((e) => notifyActionError(e, t("inbox.revertFailed")));
|
||||
.catch((e) => notifyActionError(e, msg("inbox.revertFailed")));
|
||||
}
|
||||
|
||||
// --- The rows' ONE menu -------------------------------------------------------------
|
||||
@@ -707,10 +709,12 @@ function serverRowText(
|
||||
* Trimmed as Back saves it (`lib/listNav`), or a title ending in a space never matches its row. */
|
||||
const rowName = (title: string, body: string | null | undefined): string =>
|
||||
(body ? `${title}: ${body}` : title).trim();
|
||||
const clientRowName = (n: ClientNotif): string =>
|
||||
n.title ? rowName(n.title, n.message) : rowName(n.message, null);
|
||||
const clientRowName = (n: ClientNotif, t: TFunction): string =>
|
||||
n.title
|
||||
? rowName(sayNotif(n.title, t), sayNotif(n.message, t))
|
||||
: rowName(sayNotif(n.message, t), null);
|
||||
const entryName = (e: InboxEntry, t: TFunction, lang: string): string => {
|
||||
if (e.src === "client") return clientRowName(e.n);
|
||||
if (e.src === "client") return clientRowName(e.n, t);
|
||||
const { title, body } = serverRowText(e.n, t, lang);
|
||||
return rowName(title, body);
|
||||
};
|
||||
@@ -854,15 +858,15 @@ function ClientActivityRow({
|
||||
const access = n.meta?.kind === "access-requests" ? n.meta : null;
|
||||
return (
|
||||
<div
|
||||
{...navItemAttrs(navIndex, clientRowName(n))}
|
||||
{...navItemAttrs(navIndex, clientRowName(n, t))}
|
||||
{...rowProps}
|
||||
className={`${SURFACE.card} group p-3.5 flex items-start gap-3 ${needsAction ? "ring-1 ring-accent/30" : ""}`}
|
||||
>
|
||||
<Icon className={`w-4 h-4 shrink-0 mt-0.5 ${color}`} />
|
||||
<div className="min-w-0 flex-1">
|
||||
{n.title && <div className="text-sm font-semibold">{n.title}</div>}
|
||||
{n.title && <div className="text-sm font-semibold">{sayNotif(n.title, t)}</div>}
|
||||
<div className="text-sm wrap-break-word">
|
||||
{n.message}
|
||||
{sayNotif(n.message, t)}
|
||||
{n.repeat > 1 && (
|
||||
<span className="ml-1.5 align-middle text-2xs font-semibold text-muted tabular-nums">
|
||||
×{n.repeat}
|
||||
|
||||
Reference in New Issue
Block a user