@remit/web-client 0.0.24 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, test } from "node:test";
3
+ import {
4
+ describeSearchScope,
5
+ escalatedStatusLabel,
6
+ escalationActionLabel,
7
+ } from "./escalation-label.js";
8
+
9
+ describe("describeSearchScope", () => {
10
+ test("free text query wins and is quoted", () => {
11
+ assert.equal(describeSearchScope({ query: "npm" }), 'matching "npm"');
12
+ });
13
+
14
+ test("falls back to a from: filter when there's no free text", () => {
15
+ assert.equal(
16
+ describeSearchScope({ from: "billing@example.com" }),
17
+ 'from "billing@example.com"',
18
+ );
19
+ });
20
+
21
+ test("free text wins over a from: filter when both are set", () => {
22
+ assert.equal(
23
+ describeSearchScope({ query: "npm", from: "noreply@npmjs.com" }),
24
+ 'matching "npm"',
25
+ );
26
+ });
27
+
28
+ test("neither present falls back to a generic scope rather than throwing", () => {
29
+ assert.equal(describeSearchScope({}), "matching your search");
30
+ });
31
+ });
32
+
33
+ describe("escalationActionLabel", () => {
34
+ test("names the scope, never a bare Select all", () => {
35
+ assert.equal(
36
+ escalationActionLabel({ query: "npm" }),
37
+ 'Select all matching "npm"',
38
+ );
39
+ });
40
+ });
41
+
42
+ describe("escalatedStatusLabel", () => {
43
+ test("thousands-separates the total and names the scope", () => {
44
+ assert.equal(
45
+ escalatedStatusLabel({ query: "npm" }, 3412),
46
+ 'All 3,412 matching "npm" selected',
47
+ );
48
+ });
49
+ });
@@ -0,0 +1,32 @@
1
+ import { formatNumber } from "./format";
2
+
3
+ /** The subset of the search predicate that names the scope in escalation copy. */
4
+ export interface EscalationScopeQuery {
5
+ query?: string;
6
+ from?: string;
7
+ }
8
+
9
+ /**
10
+ * Names what an escalated selection covers, for the notice text and the
11
+ * confirm dialog — never a bare "Select all" (issue #92 requirement 4). Free
12
+ * text wins when present since it's what the user actually typed; `from:`
13
+ * alone still names a scope. Neither present is unreachable in practice (the
14
+ * escalation control only ever renders for an active search), but the
15
+ * fallback keeps the label honest instead of throwing.
16
+ */
17
+ export const describeSearchScope = (query: EscalationScopeQuery): string => {
18
+ if (query.query) return `matching "${query.query}"`;
19
+ if (query.from) return `from "${query.from}"`;
20
+ return "matching your search";
21
+ };
22
+
23
+ /** "Select all matching "npm"" — the escalation notice's action label. */
24
+ export const escalationActionLabel = (query: EscalationScopeQuery): string =>
25
+ `Select all ${describeSearchScope(query)}`;
26
+
27
+ /** "All 3,412 matching "npm" selected" — the bar's status label once escalated. */
28
+ export const escalatedStatusLabel = (
29
+ query: EscalationScopeQuery,
30
+ total: number,
31
+ ): string =>
32
+ `All ${formatNumber(total)} ${describeSearchScope(query)} selected`;
@@ -112,4 +112,11 @@ describe("formatDeleteToTrashTitle", () => {
112
112
  "Move 0 messages to Trash?",
113
113
  );
114
114
  });
115
+
116
+ test("thousands-separates an escalated-selection-scale count", () => {
117
+ assert.strictEqual(
118
+ formatDeleteToTrashTitle(3412),
119
+ "Move 3,412 messages to Trash?",
120
+ );
121
+ });
115
122
  });
package/src/lib/format.ts CHANGED
@@ -193,6 +193,10 @@ export const formatList = (
193
193
  /**
194
194
  * Confirmation title for the move-to-Trash delete flow. Reflects that delete
195
195
  * moves messages to Trash (not a permanent delete) and pluralizes on count.
196
+ * Thousands-separated: at escalated-selection scale this is exactly the digit
197
+ * count someone checks against what they meant to select.
196
198
  */
197
199
  export const formatDeleteToTrashTitle = (count: number): string =>
198
- count === 1 ? "Move 1 message to Trash?" : `Move ${count} messages to Trash?`;
200
+ count === 1
201
+ ? "Move 1 message to Trash?"
202
+ : `Move ${formatNumber(count)} messages to Trash?`;