@chatwarden/player-react 0.1.2 → 0.1.3
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.
- package/README.md +48 -24
- package/dist/src/Dialog.d.ts.map +1 -1
- package/dist/src/Dialog.js +2 -13
- package/dist/src/Dialog.js.map +1 -1
- package/dist/src/ReportDialog.d.ts +30 -16
- package/dist/src/ReportDialog.d.ts.map +1 -1
- package/dist/src/ReportDialog.js +59 -70
- package/dist/src/ReportDialog.js.map +1 -1
- package/dist/src/i18n.d.ts +26 -2
- package/dist/src/i18n.d.ts.map +1 -1
- package/dist/src/i18n.js +26 -2
- package/dist/src/i18n.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +5 -5
- package/src/Dialog.tsx +2 -12
- package/src/ReportDialog.tsx +137 -122
- package/src/i18n.ts +26 -2
- package/src/index.ts +1 -1
- package/src/styles.css +45 -61
- package/dist/src/FollowUp.d.ts +0 -35
- package/dist/src/FollowUp.d.ts.map +0 -1
- package/dist/src/FollowUp.js +0 -69
- package/dist/src/FollowUp.js.map +0 -1
- package/dist/src/Picker.d.ts +0 -14
- package/dist/src/Picker.d.ts.map +0 -1
- package/dist/src/Picker.js +0 -14
- package/dist/src/Picker.js.map +0 -1
- package/src/FollowUp.tsx +0 -139
- package/src/Picker.tsx +0 -60
package/dist/src/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoEb,+DAA+D;;IAE/D,+DAA+D;;;IAG/D,+DAA+D;;;;;;;;;;IAU/D,+DAA+D;;;IAG/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;;;;;;;;IAS/D,+DAA+D;;;;;;;;;;;;;;;;;;CAkBvD,CAAC;AAEX,sFAAsF;AACtF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7D,KAAK,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AACpE,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAE9E,sGAAsG;AACtG,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAErE,oFAAoF;AACpF,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC;AAIzE;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAO,GAAG,OAAO,CAiCtE"}
|
package/dist/src/i18n.js
CHANGED
|
@@ -70,9 +70,12 @@ export const en = {
|
|
|
70
70
|
'player.restricted.filter.noEnd': 'Your chat is off. It does not end on its own. The automatic filter caught a message.',
|
|
71
71
|
'player.restricted.ended': 'Your chat is back on. The restriction ended {when}.',
|
|
72
72
|
'player.restricted.ref': 'Reference {code}',
|
|
73
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
73
74
|
'player.report.title': 'Report a player',
|
|
75
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
74
76
|
'player.report.titleNamed': 'Report {name}',
|
|
75
|
-
'player.report.intro': 'Tell us
|
|
77
|
+
'player.report.intro': 'Tell us why and a moderator will look at it.',
|
|
78
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
76
79
|
'player.report.legend': 'What happened?',
|
|
77
80
|
'player.report.titleOneTap': 'Report this message?',
|
|
78
81
|
'player.report.titleOneTapNamed': 'Report {name}?',
|
|
@@ -82,24 +85,45 @@ export const en = {
|
|
|
82
85
|
'player.report.oneTap.intro': 'We will pass it to the moderators. You do not need to say why.',
|
|
83
86
|
'player.report.oneTap.send': 'Report',
|
|
84
87
|
'player.report.quote': '“{line}”',
|
|
88
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
85
89
|
'player.report.skip': 'Skip and report',
|
|
86
90
|
'player.report.needReason': 'Choose a reason.',
|
|
91
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
87
92
|
'player.report.needReasonOrSkip': 'Choose what happened, or skip.',
|
|
93
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
88
94
|
'player.report.addReason': 'Add a reason',
|
|
95
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
89
96
|
'player.report.addReasonHint': 'This helps, but the moderators decide what it really is. You can add this for a few minutes after you report.',
|
|
97
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
90
98
|
'player.report.detail.legend': 'What was it about?',
|
|
99
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
91
100
|
'player.report.detail.send': 'Add to my report',
|
|
101
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
92
102
|
'player.report.detail.need': 'Choose a reason or write a note.',
|
|
103
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
93
104
|
'player.report.detail.added': 'Added. Thanks.',
|
|
105
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
94
106
|
'player.report.detail.failed': 'We could not add that.',
|
|
107
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
95
108
|
'player.report.detail.refused.off': 'Adding to a report is not available right now.',
|
|
109
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
96
110
|
'player.report.detail.refused.not_found': 'We cannot find that report any more.',
|
|
111
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
97
112
|
'player.report.detail.refused.not_reporter': 'Only the player who sent a report can add to it.',
|
|
113
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
98
114
|
'player.report.detail.refused.too_late': 'It is too late to add to this report. We still have the report.',
|
|
115
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
99
116
|
'player.report.detail.refused.already_added': 'You already added to this report.',
|
|
117
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
100
118
|
'player.report.detail.refused.reason_unknown': 'That reason is not available any more. Your report is still with us.',
|
|
101
|
-
'player.report.note': '
|
|
119
|
+
'player.report.note': 'Note (optional)',
|
|
120
|
+
'player.report.addNote': 'Add a note',
|
|
121
|
+
'player.report.why': 'Why? (optional)',
|
|
122
|
+
'player.report.whyRequired': 'Why?',
|
|
123
|
+
'player.report.choose': 'Choose a reason (optional)',
|
|
124
|
+
'player.report.chooseRequired': 'Choose a reason',
|
|
102
125
|
'player.report.noteHint': 'A moderator will read this. Up to {max} characters. Do not include passwords or personal details.',
|
|
126
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
103
127
|
'player.report.send': 'Send report',
|
|
104
128
|
'player.report.cancel': 'Cancel',
|
|
105
129
|
'player.report.close': 'Close',
|
package/dist/src/i18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,EAAE;AACF,wHAAwH;AACxH,2EAA2E;AAC3E,8HAA8H;AAC9H,mHAAmH;AACnH,0HAA0H;AAC1H,qCAAqC;AACrC,EAAE;AACF,kIAAkI;AAClI,yDAAyD;AAEzD,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,sBAAsB,EAAE,kEAAkE;IAC1F,2BAA2B,EAAE,oDAAoD;IACjF,wBAAwB,EAAE,8BAA8B;IACxD,uBAAuB,EAAE,0BAA0B;IACnD,0BAA0B,EAAE,2CAA2C;IACvE,oCAAoC,EAAE,iDAAiD;IACvF,sCAAsC,EAAE,kDAAkD;IAC1F,qBAAqB,EAAE,kDAAkD;IACzE,sBAAsB,EAAE,uBAAuB;IAE/C,oBAAoB,EAAE,WAAW;IAEjC,2BAA2B,EAAE,iCAAiC;IAE9D,6BAA6B,EAAE,oBAAoB;IACnD,0BAA0B,EAAE,yBAAyB;IACrD,0BAA0B,EAAE,8BAA8B;IAC1D,yBAAyB,EAAE,gBAAgB;IAC3C,oCAAoC,EAAE,wBAAwB;IAC9D,8BAA8B,EAAE,+BAA+B;IAC/D,4BAA4B,EAAE,+EAA+E;IAC7G,yBAAyB,EAAE,uDAAuD;IAClF,yBAAyB,EAAE,oGAAoG;IAC/H,wBAAwB,EAAE,sCAAsC;IAChE,mCAAmC,EAAE,mFAAmF;IACxH,6BAA6B,EAAE,4CAA4C;IAC3E,wBAAwB,EAAE,uBAAuB;IACjD,oBAAoB,EAAE,MAAM;IAC5B,qBAAqB,EAAE,OAAO;IAC9B,qBAAqB,EAAE,OAAO;IAC9B,qBAAqB,EAAE,OAAO;IAC9B,qBAAqB,EAAE,aAAa;IACpC,6BAA6B,EAAE,sBAAsB;IACrD,yBAAyB,EAAE,iBAAiB;IAC5C,mBAAmB,EAAE,WAAW;IAChC,uBAAuB,EAAE,oCAAoC;IAC7D,qBAAqB,EAAE,gCAAgC;IACvD,4BAA4B,EAAE,4CAA4C;IAC1E,2BAA2B,EAAE,aAAa;IAC1C,qBAAqB,EAAE,QAAQ;IAC/B,sBAAsB,EAAE,0BAA0B;IAClD,yBAAyB,EAAE,4BAA4B;IACvD,2BAA2B,EAAE,eAAe;IAE5C,qBAAqB,EAAE,aAAa;IACpC,uBAAuB,EAAE,qBAAqB;IAC9C,0BAA0B,EAAE,gCAAgC;IAC5D,qBAAqB,EAAE,sEAAsE;IAC7F,qBAAqB,EAAE,mDAAmD;IAC1E,4BAA4B,EAAE,SAAS;IACvC,yBAAyB,EAAE,kBAAkB;IAC7C,yBAAyB,EAAE,0BAA0B;IACrD,wBAAwB,EAAE,KAAK;IAC/B,6BAA6B,EAAE,QAAQ;IAEvC,oBAAoB,EAAE,iBAAiB;IACvC,sBAAsB,EAAE,mBAAmB;IAC3C,yBAAyB,EAAE,8BAA8B;IACzD,oBAAoB,EAAE,6BAA6B;IAEnD,mCAAmC,EAAE,yDAAyD;IAC9F,mCAAmC,EAAE,+DAA+D;IACpG,gCAAgC,EAAE,gFAAgF;IAClH,gCAAgC,EAAE,sFAAsF;IACxH,yBAAyB,EAAE,qDAAqD;IAChF,uBAAuB,EAAE,kBAAkB;IAE3C,qBAAqB,EAAE,iBAAiB;IACxC,0BAA0B,EAAE,eAAe;IAC3C,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatwarden/player-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Player-facing React components for Chatwarden: the notice dialog, My record, the rules page, a report dialog and a restricted-chat line, over the player HTTP routes.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"react-dom": "^18.3.0 || ^19.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@chatwarden/core": "0.1.
|
|
56
|
-
"@chatwarden/http": "0.1.
|
|
57
|
-
"@chatwarden/hub-react": "0.1.
|
|
58
|
-
"@chatwarden/store-memory": "0.1.
|
|
55
|
+
"@chatwarden/core": "0.1.3",
|
|
56
|
+
"@chatwarden/http": "0.1.3",
|
|
57
|
+
"@chatwarden/hub-react": "0.1.3",
|
|
58
|
+
"@chatwarden/store-memory": "0.1.3",
|
|
59
59
|
"@testing-library/dom": "^10.4.2",
|
|
60
60
|
"@testing-library/jest-dom": "^7.0.1",
|
|
61
61
|
"@testing-library/react": "^16.3.3",
|
package/src/Dialog.tsx
CHANGED
|
@@ -11,18 +11,8 @@ import type { KeyboardEvent, ReactNode, RefObject } from 'react';
|
|
|
11
11
|
|
|
12
12
|
const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
* browser moves between its radios with the arrow keys: counting every radio would make "the first control" the wrong one to wrap at.
|
|
17
|
-
*/
|
|
18
|
-
function tabStops(box: HTMLElement): HTMLElement[] {
|
|
19
|
-
const all = [...box.querySelectorAll<HTMLElement>(FOCUSABLE)];
|
|
20
|
-
return all.filter((el) => {
|
|
21
|
-
if (!(el instanceof HTMLInputElement) || el.type !== 'radio' || el.name === '') return true;
|
|
22
|
-
const group = all.filter((o): o is HTMLInputElement => o instanceof HTMLInputElement && o.type === 'radio' && o.name === el.name);
|
|
23
|
-
return el === (group.find((r) => r.checked) ?? group[0]);
|
|
24
|
-
});
|
|
25
|
-
}
|
|
14
|
+
/** The controls Tab visits, in order. */
|
|
15
|
+
const tabStops = (box: HTMLElement): HTMLElement[] => [...box.querySelectorAll<HTMLElement>(FOCUSABLE)];
|
|
26
16
|
|
|
27
17
|
export function Dialog({
|
|
28
18
|
labelledBy,
|
package/src/ReportDialog.tsx
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { useEffect, useId, useRef, useState } from 'react';
|
|
2
|
-
import type { FormEvent } from 'react';
|
|
3
|
-
import type { PlayerReporting, ReportDetailResult,
|
|
2
|
+
import type { FormEvent, ReactNode } from 'react';
|
|
3
|
+
import type { PlayerReporting, ReportDetailResult, ReportRefusal, ReportResult } from '@chatwarden/core';
|
|
4
4
|
import { NOTE_MAX } from './constants.js';
|
|
5
5
|
import { PlayerError } from './client.js';
|
|
6
6
|
import { Dialog } from './Dialog.js';
|
|
7
|
-
import { DETAIL_REFUSED_TEXT, FollowUp } from './FollowUp.js';
|
|
8
|
-
import type { FollowUpOutcome, ReportFollowUp } from './FollowUp.js';
|
|
9
|
-
import { Picker } from './Picker.js';
|
|
10
7
|
import type { PlayerText } from './i18n.js';
|
|
11
8
|
import { groupReasons, readReporting } from './reporting.js';
|
|
12
|
-
import type { ReasonItem } from './reporting.js';
|
|
13
9
|
import { errorText, Portal, Root, useUi } from './ui.js';
|
|
14
10
|
import type { DialogHostProps, PlayerUiProps } from './ui.js';
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* What the player filled in. Your server adds the room and the seats and calls `cw.reports.submit({ ...draft, roomId, reporterSeat,
|
|
18
|
-
* targetSeat })`. The dialog sends `reason` (an id from the studio's `reporting` list, or nothing
|
|
19
|
-
* hint: the moderators decide what a report really is.
|
|
14
|
+
* targetSeat })`. The dialog sends `reason` (an id from the studio's `reporting` list, or nothing) and `note` in the one report. A
|
|
15
|
+
* reason is only a hint: the moderators decide what a report really is.
|
|
20
16
|
*/
|
|
21
17
|
export interface ReportDraft {
|
|
22
18
|
/** The reason the player chose: an id from `reporting.reasons`. Left out when none was chosen. */
|
|
@@ -25,7 +21,14 @@ export interface ReportDraft {
|
|
|
25
21
|
note?: string;
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
/**
|
|
25
|
+
* A reason and a note added to a report after it was filed (`cw.reports.addDetail`). The dialog no longer has a follow-up step (the
|
|
26
|
+
* reason and the note go in the one report), so this is only the shape a follow-up of your own may take.
|
|
27
|
+
*/
|
|
28
|
+
export interface ReportFollowUp {
|
|
29
|
+
reason?: string;
|
|
30
|
+
note?: string;
|
|
31
|
+
}
|
|
29
32
|
|
|
30
33
|
export interface ReportDialogProps extends PlayerUiProps, DialogHostProps {
|
|
31
34
|
/**
|
|
@@ -34,22 +37,30 @@ export interface ReportDialogProps extends PlayerUiProps, DialogHostProps {
|
|
|
34
37
|
*/
|
|
35
38
|
onSubmit: (draft: ReportDraft) => Promise<ReportResult>;
|
|
36
39
|
/**
|
|
37
|
-
* The
|
|
38
|
-
*
|
|
40
|
+
* @deprecated The dialog is one step now: the reason and the note go in the single `onSubmit`, so this is accepted but never
|
|
41
|
+
* called. Remove it. (`cw.reports.addDetail` is still there for a follow-up of your own.)
|
|
39
42
|
*/
|
|
40
43
|
onAddDetail?: (reportId: string, detail: ReportFollowUp) => Promise<ReportDetailResult>;
|
|
41
44
|
/** Called on Escape, Cancel and Close. Unmount the dialog in answer. */
|
|
42
45
|
onClose: () => void;
|
|
43
46
|
/**
|
|
44
|
-
* How reporting works here: `(await createPlayerClient.rules()).reporting`, the `reporting` part of `GET /rules`. It
|
|
45
|
-
* (
|
|
46
|
-
* one
|
|
47
|
+
* How reporting works here: `(await createPlayerClient.rules()).reporting`, the `reporting` part of `GET /rules`. It gives the
|
|
48
|
+
* reasons (grouped, with hints), whether a reason is required, and the thank-you. Without it the dialog has no reasons to offer:
|
|
49
|
+
* one press files the report, with the dialog's own words, the same as when `GET /rules` cannot be loaded.
|
|
47
50
|
*/
|
|
48
51
|
reporting?: PlayerReporting;
|
|
49
52
|
/** Who is being reported, as the player knows them (a handle). Shown as text in the heading. */
|
|
50
53
|
targetName?: string;
|
|
51
54
|
/** The message being reported. Shown as quoted text (cut if very long) so the player sees what they are reporting. */
|
|
52
55
|
line?: string;
|
|
56
|
+
/**
|
|
57
|
+
* @experimental Your own controls, placed inside the form under the reason and the note and above Report and Cancel (for example
|
|
58
|
+
* an "Also mute this player" checkbox and a line about false reports). You own their state; the dialog only places them, adds no
|
|
59
|
+
* styling beyond the spacing, and keeps their focusable controls in its Tab order (reason, note, yours, Report, Cancel) and its
|
|
60
|
+
* focus trap. They are not shown once the report is sent. They sit inside the dialog's form, so give your buttons `type="button"`:
|
|
61
|
+
* a plain button, or Enter in a text field of yours, sends the report.
|
|
62
|
+
*/
|
|
63
|
+
extra?: ReactNode;
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
// One plain message for each refusal the kit has. Anything else (a refusal a newer kit adds) gets the last one.
|
|
@@ -79,78 +90,66 @@ const quoted = (line: string | undefined): string => {
|
|
|
79
90
|
return plain.length > LINE_MAX ? `${plain.slice(0, LINE_MAX).trimEnd()}…` : plain;
|
|
80
91
|
};
|
|
81
92
|
|
|
82
|
-
/** The screen to draw: the flow, the reasons as the dialog will list them, and the thank-you. */
|
|
83
|
-
interface Screen {
|
|
84
|
-
flow: ReportFlow;
|
|
85
|
-
reasons: ReasonItem[];
|
|
86
|
-
thanks: string;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
93
|
/**
|
|
90
|
-
* A dialog for reporting a message or a player
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* chooses to report, and unmount it in `onClose`.
|
|
94
|
+
* A dialog for reporting a message or a player, in one step: "Report this message?", the quoted line, an optional "Why?" (one
|
|
95
|
+
* select, the reasons in groups) and a Report button. A note is behind "Add a note", or shown when the chosen reason asks for one.
|
|
96
|
+
* Report sends the reason and the note together (`onSubmit`); the dialog then says "Report sent" and the thank-you. The studio's
|
|
97
|
+
* `reporting` setting decides whether the reason is required (`reason_required`: the select is required, and Report without a
|
|
98
|
+
* reason asks for one and sends nothing), what the reasons are, and the thank-you. The reason is only a hint for the moderators.
|
|
99
|
+
* Every refusal the kit can give has its own plain message. Render it when the player chooses to report, and unmount it in `onClose`.
|
|
97
100
|
*/
|
|
98
101
|
export function ReportDialog(props: ReportDialogProps) {
|
|
99
|
-
const { onSubmit,
|
|
102
|
+
const { onSubmit, onClose, targetName, line, theme, className, container, returnFocusTo, extra } = props;
|
|
100
103
|
const ui = useUi(props);
|
|
101
104
|
const { t } = ui;
|
|
102
105
|
const heading = useRef<HTMLHeadingElement>(null);
|
|
103
|
-
const
|
|
104
|
-
|
|
106
|
+
const select = useRef<HTMLSelectElement>(null);
|
|
107
|
+
const noteField = useRef<HTMLTextAreaElement>(null);
|
|
108
|
+
// One report on its way at a time: a second click, or a second Enter, does nothing.
|
|
105
109
|
const sending = useRef(false);
|
|
106
110
|
const titleId = useId();
|
|
107
|
-
const
|
|
111
|
+
const reasonId = useId();
|
|
108
112
|
const noteId = useId();
|
|
109
|
-
const
|
|
113
|
+
const noteHintId = useId();
|
|
114
|
+
const reasonHintId = useId();
|
|
110
115
|
const missingId = useId();
|
|
111
|
-
const [reason, setReason] = useState
|
|
116
|
+
const [reason, setReason] = useState('');
|
|
112
117
|
const [note, setNote] = useState('');
|
|
118
|
+
// The note is shown once it was asked for (the "Add a note" button, or a reason that asks for one) and then stays.
|
|
119
|
+
const [noteOpen, setNoteOpen] = useState(false);
|
|
120
|
+
const [focusNote, setFocusNote] = useState(false);
|
|
113
121
|
const [missing, setMissing] = useState(false);
|
|
114
122
|
const [busy, setBusy] = useState(false);
|
|
115
123
|
const [failure, setFailure] = useState<PlayerError | null>(null);
|
|
116
124
|
const [result, setResult] = useState<ReportResult | null>(null);
|
|
117
|
-
// How the follow-up after a one-tap report ended, and whether its time is up (the kit takes one until `detailUntil`).
|
|
118
|
-
const [dDone, setDDone] = useState<FollowUpOutcome | null>(null);
|
|
119
|
-
const [expired, setExpired] = useState(false);
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
// The
|
|
131
|
-
|
|
126
|
+
// No `reporting` (or something that is not the payload): no reasons to offer, as when `GET /rules` cannot be loaded.
|
|
127
|
+
const read = readReporting(props.reporting) ?? { flow: 'one_tap' as const, reasons: [], thanks: '' };
|
|
128
|
+
const thanks = read.thanks.trim();
|
|
129
|
+
const hasReasons = read.reasons.length > 0;
|
|
130
|
+
// A flow that asks for a reason has nothing to ask with when the list is empty.
|
|
131
|
+
const required = hasReasons && read.flow === 'reason_required';
|
|
132
|
+
const groups = groupReasons(read.reasons);
|
|
133
|
+
const named = groups.filter((g) => g.name !== '');
|
|
134
|
+
const bare = groups.filter((g) => g.name === '').flatMap((g) => g.items);
|
|
135
|
+
// The reason is read from the CURRENT list: if `reporting` changes while the dialog is open and the id the player chose is gone, the
|
|
136
|
+
// select shows the placeholder, and this is undefined, so nothing stale is sent (and a required reason is asked for again).
|
|
137
|
+
const chosen = read.reasons.find((r) => r.id === reason);
|
|
138
|
+
const reasonValue = chosen === undefined ? '' : chosen.id;
|
|
139
|
+
const hint = chosen !== undefined && chosen.hint !== '' ? chosen.hint : null;
|
|
140
|
+
const noteShown = hasReasons && noteOpen;
|
|
132
141
|
|
|
133
142
|
// The form is gone once there is an answer: focus goes back to the heading, so the answer is read and focus is not lost.
|
|
134
143
|
useEffect(() => {
|
|
135
144
|
if (result !== null) heading.current?.focus();
|
|
136
145
|
}, [result]);
|
|
146
|
+
// "Add a note" is replaced by the field: focus follows it.
|
|
137
147
|
useEffect(() => {
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (until === null) return undefined;
|
|
144
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
145
|
-
// Looks at the clock again when the time comes, so a clock that has not moved does not end the offer early.
|
|
146
|
-
const check = (): void => {
|
|
147
|
-
const left = until - ui.now();
|
|
148
|
-
if (left < 0) setExpired(true);
|
|
149
|
-
else timer = setTimeout(check, Math.min(Math.max(left + 1, 50), 2_000_000_000));
|
|
150
|
-
};
|
|
151
|
-
check();
|
|
152
|
-
return () => clearTimeout(timer);
|
|
153
|
-
}, [until]);
|
|
148
|
+
if (focusNote) {
|
|
149
|
+
noteField.current?.focus();
|
|
150
|
+
setFocusNote(false);
|
|
151
|
+
}
|
|
152
|
+
}, [focusNote]);
|
|
154
153
|
|
|
155
154
|
const send = async (draft: ReportDraft): Promise<void> => {
|
|
156
155
|
sending.current = true;
|
|
@@ -170,24 +169,19 @@ export function ReportDialog(props: ReportDialogProps) {
|
|
|
170
169
|
const submit = (e: FormEvent): void => {
|
|
171
170
|
e.preventDefault();
|
|
172
171
|
if (sending.current) return;
|
|
173
|
-
if (
|
|
172
|
+
if (required && reasonValue === '') {
|
|
174
173
|
setMissing(true);
|
|
175
|
-
|
|
174
|
+
select.current?.focus();
|
|
176
175
|
return;
|
|
177
176
|
}
|
|
178
|
-
const draft: ReportDraft =
|
|
179
|
-
if (
|
|
177
|
+
const draft: ReportDraft = {};
|
|
178
|
+
if (reasonValue !== '') draft.reason = reasonValue;
|
|
179
|
+
if (noteShown && trimmed !== '') draft.note = trimmed;
|
|
180
180
|
void send(draft);
|
|
181
181
|
};
|
|
182
|
-
const skip = (): void => {
|
|
183
|
-
if (sending.current) return;
|
|
184
|
-
void send(showNote && trimmed !== '' ? { note: trimmed } : {});
|
|
185
|
-
};
|
|
186
182
|
|
|
187
|
-
const reportId = result?.ok === true && typeof result.reportId === 'string' && result.reportId !== '' ? result.reportId : null;
|
|
188
183
|
const quote = quoted(line);
|
|
189
|
-
const
|
|
190
|
-
const title = flow === 'one_tap' ? oneTapTitle : targetName === undefined ? t('player.report.title') : t('player.report.titleNamed', { name: targetName });
|
|
184
|
+
const title = quote !== '' ? t('player.report.titleOneTap') : targetName === undefined ? t('player.report.titleOneTapPlayer') : t('player.report.titleOneTapNamed', { name: targetName });
|
|
191
185
|
const taken = result?.ok === true;
|
|
192
186
|
const refusal = result !== null && !taken ? result : null;
|
|
193
187
|
// After an answer the heading says what happened (a question would be stale), and focus is on it.
|
|
@@ -197,11 +191,12 @@ export function ReportDialog(props: ReportDialogProps) {
|
|
|
197
191
|
const refused = (r as { refused?: unknown }).refused;
|
|
198
192
|
return typeof refused === 'string' && Object.hasOwn(REFUSED_TEXT, refused) ? REFUSED_TEXT[refused as ReportRefusal] : 'player.report.refused.unknown';
|
|
199
193
|
};
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
194
|
+
const option = (r: { id: string; label: string }) => (
|
|
195
|
+
<option key={r.id} value={r.id}>
|
|
196
|
+
{r.label}
|
|
197
|
+
</option>
|
|
198
|
+
);
|
|
199
|
+
const describedBy = [hint === null ? '' : reasonHintId, missing ? missingId : ''].filter((id) => id !== '').join(' ');
|
|
205
200
|
|
|
206
201
|
return (
|
|
207
202
|
<Portal container={container}>
|
|
@@ -210,51 +205,84 @@ export function ReportDialog(props: ReportDialogProps) {
|
|
|
210
205
|
<h2 id={titleId} ref={heading} className="cw-title" tabIndex={-1}>
|
|
211
206
|
{shownTitle}
|
|
212
207
|
</h2>
|
|
213
|
-
{/* Always there, so what is written into it is announced: the thank-you
|
|
208
|
+
{/* Always there, so what is written into it is announced: the thank-you. */}
|
|
214
209
|
<div role="status" className="cw-live">
|
|
215
210
|
{taken && (
|
|
216
211
|
<p className="cw-result">
|
|
217
|
-
{
|
|
212
|
+
{thanks === '' ? t('player.report.thanks') : thanks}
|
|
218
213
|
{remaining !== null && ` ${t('player.report.remaining', { count: remaining })}`}
|
|
219
214
|
</p>
|
|
220
215
|
)}
|
|
221
|
-
{dDone?.ok === true && <p className="cw-result">{t('player.report.detail.added')}</p>}
|
|
222
216
|
</div>
|
|
223
217
|
{result === null ? (
|
|
224
218
|
<form onSubmit={submit} noValidate>
|
|
225
|
-
<p className="cw-body">{
|
|
219
|
+
<p className="cw-body">{required ? t('player.report.intro') : t('player.report.oneTap.intro')}</p>
|
|
226
220
|
{quote !== '' && <blockquote className="cw-quote">{t('player.report.quote', { line: quote })}</blockquote>}
|
|
227
|
-
{
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
221
|
+
{hasReasons && (
|
|
222
|
+
<div className="cw-field">
|
|
223
|
+
<label className="cw-label" htmlFor={reasonId}>
|
|
224
|
+
{required ? t('player.report.whyRequired') : t('player.report.why')}
|
|
225
|
+
</label>
|
|
226
|
+
<select
|
|
227
|
+
id={reasonId}
|
|
228
|
+
ref={select}
|
|
229
|
+
className="cw-select"
|
|
230
|
+
value={reasonValue}
|
|
231
|
+
required={required}
|
|
232
|
+
aria-invalid={missing || undefined}
|
|
233
|
+
aria-describedby={describedBy === '' ? undefined : describedBy}
|
|
234
|
+
onChange={(e) => {
|
|
235
|
+
const id = e.target.value;
|
|
236
|
+
setReason(id);
|
|
237
|
+
setMissing(false);
|
|
238
|
+
if (read.reasons.find((r) => r.id === id)?.asksNote === true) setNoteOpen(true);
|
|
239
|
+
}}
|
|
240
|
+
>
|
|
241
|
+
<option value="">{required ? t('player.report.chooseRequired') : t('player.report.choose')}</option>
|
|
242
|
+
{named.map((g) => (
|
|
243
|
+
<optgroup key={g.name} label={g.name}>
|
|
244
|
+
{g.items.map(option)}
|
|
245
|
+
</optgroup>
|
|
246
|
+
))}
|
|
247
|
+
{bare.map(option)}
|
|
248
|
+
</select>
|
|
249
|
+
{hint !== null && (
|
|
250
|
+
<p id={reasonHintId} className="cw-hint">
|
|
251
|
+
{hint}
|
|
252
|
+
</p>
|
|
253
|
+
)}
|
|
254
|
+
{missing && (
|
|
255
|
+
<p id={missingId} className="cw-field-error" role="alert">
|
|
256
|
+
{t('player.report.needReason')}
|
|
257
|
+
</p>
|
|
258
|
+
)}
|
|
259
|
+
</div>
|
|
246
260
|
)}
|
|
247
|
-
{
|
|
248
|
-
|
|
261
|
+
{noteShown && (
|
|
262
|
+
<div className="cw-field">
|
|
249
263
|
<label className="cw-label" htmlFor={noteId}>
|
|
250
264
|
{t('player.report.note')}
|
|
251
265
|
</label>
|
|
252
|
-
<textarea id={noteId} className="cw-textarea" rows={
|
|
253
|
-
<p id={
|
|
266
|
+
<textarea id={noteId} ref={noteField} className="cw-textarea" rows={3} maxLength={NOTE_MAX} value={note} aria-describedby={noteHintId} onChange={(e) => setNote(e.target.value)} />
|
|
267
|
+
<p id={noteHintId} className="cw-hint">
|
|
254
268
|
{t('player.report.noteHint', { max: NOTE_MAX })}
|
|
255
269
|
</p>
|
|
256
|
-
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
{hasReasons && !noteShown && (
|
|
273
|
+
// No aria-expanded: this is a one-way door. It is removed when pressed (the note takes its place) and focus moves to the note.
|
|
274
|
+
<button
|
|
275
|
+
type="button"
|
|
276
|
+
className="cw-linkbtn"
|
|
277
|
+
onClick={() => {
|
|
278
|
+
setNoteOpen(true);
|
|
279
|
+
setFocusNote(true);
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
{t('player.report.addNote')}
|
|
283
|
+
</button>
|
|
257
284
|
)}
|
|
285
|
+
{extra !== undefined && extra !== null && extra !== false && <div className="cw-extra">{extra}</div>}
|
|
258
286
|
{failure !== null && (
|
|
259
287
|
<p className="cw-error" role="alert">
|
|
260
288
|
{t('player.report.failed')} {errorText(t, failure)}
|
|
@@ -262,13 +290,8 @@ export function ReportDialog(props: ReportDialogProps) {
|
|
|
262
290
|
)}
|
|
263
291
|
<div className="cw-actions">
|
|
264
292
|
<button type="submit" className="cw-btn cw-btn--primary" aria-disabled={busy || undefined} aria-busy={busy || undefined}>
|
|
265
|
-
{
|
|
293
|
+
{t('player.report.oneTap.send')}
|
|
266
294
|
</button>
|
|
267
|
-
{flow === 'reason_first' && (
|
|
268
|
-
<button type="button" className="cw-btn" aria-disabled={busy || undefined} aria-busy={busy || undefined} onClick={skip}>
|
|
269
|
-
{t('player.report.skip')}
|
|
270
|
-
</button>
|
|
271
|
-
)}
|
|
272
295
|
{/* Closing while a report is on its way would lose the answer: busy, like Escape. */}
|
|
273
296
|
<button type="button" className="cw-btn" aria-disabled={busy || undefined} onClick={() => !sending.current && onClose()}>
|
|
274
297
|
{t('player.report.cancel')}
|
|
@@ -282,14 +305,6 @@ export function ReportDialog(props: ReportDialogProps) {
|
|
|
282
305
|
{t(refusedKey(refusal))}
|
|
283
306
|
</p>
|
|
284
307
|
)}
|
|
285
|
-
{canFollow && dDone === null && (
|
|
286
|
-
<FollowUp t={t} groups={groups} reportId={reportId} onAddDetail={onAddDetail} sending={sending} busy={busy} onBusy={setBusy} onDone={setDDone} />
|
|
287
|
-
)}
|
|
288
|
-
{dDone !== null && !dDone.ok && (
|
|
289
|
-
<p className="cw-error" role="alert">
|
|
290
|
-
{t(detailRefusedKey(dDone.refused))}
|
|
291
|
-
</p>
|
|
292
|
-
)}
|
|
293
308
|
<div className="cw-actions">
|
|
294
309
|
<button type="button" className="cw-btn cw-btn--primary" aria-disabled={busy || undefined} onClick={() => !sending.current && onClose()}>
|
|
295
310
|
{t('player.report.close')}
|
package/src/i18n.ts
CHANGED
|
@@ -78,9 +78,12 @@ export const en = {
|
|
|
78
78
|
'player.restricted.ended': 'Your chat is back on. The restriction ended {when}.',
|
|
79
79
|
'player.restricted.ref': 'Reference {code}',
|
|
80
80
|
|
|
81
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
81
82
|
'player.report.title': 'Report a player',
|
|
83
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
82
84
|
'player.report.titleNamed': 'Report {name}',
|
|
83
|
-
'player.report.intro': 'Tell us
|
|
85
|
+
'player.report.intro': 'Tell us why and a moderator will look at it.',
|
|
86
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
84
87
|
'player.report.legend': 'What happened?',
|
|
85
88
|
'player.report.titleOneTap': 'Report this message?',
|
|
86
89
|
'player.report.titleOneTapNamed': 'Report {name}?',
|
|
@@ -90,24 +93,45 @@ export const en = {
|
|
|
90
93
|
'player.report.oneTap.intro': 'We will pass it to the moderators. You do not need to say why.',
|
|
91
94
|
'player.report.oneTap.send': 'Report',
|
|
92
95
|
'player.report.quote': '“{line}”',
|
|
96
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
93
97
|
'player.report.skip': 'Skip and report',
|
|
94
98
|
'player.report.needReason': 'Choose a reason.',
|
|
99
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
95
100
|
'player.report.needReasonOrSkip': 'Choose what happened, or skip.',
|
|
101
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
96
102
|
'player.report.addReason': 'Add a reason',
|
|
103
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
97
104
|
'player.report.addReasonHint': 'This helps, but the moderators decide what it really is. You can add this for a few minutes after you report.',
|
|
105
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
98
106
|
'player.report.detail.legend': 'What was it about?',
|
|
107
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
99
108
|
'player.report.detail.send': 'Add to my report',
|
|
109
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
100
110
|
'player.report.detail.need': 'Choose a reason or write a note.',
|
|
111
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
101
112
|
'player.report.detail.added': 'Added. Thanks.',
|
|
113
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
102
114
|
'player.report.detail.failed': 'We could not add that.',
|
|
115
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
103
116
|
'player.report.detail.refused.off': 'Adding to a report is not available right now.',
|
|
117
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
104
118
|
'player.report.detail.refused.not_found': 'We cannot find that report any more.',
|
|
119
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
105
120
|
'player.report.detail.refused.not_reporter': 'Only the player who sent a report can add to it.',
|
|
121
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
106
122
|
'player.report.detail.refused.too_late': 'It is too late to add to this report. We still have the report.',
|
|
123
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
107
124
|
'player.report.detail.refused.already_added': 'You already added to this report.',
|
|
125
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
108
126
|
'player.report.detail.refused.reason_unknown': 'That reason is not available any more. Your report is still with us.',
|
|
109
|
-
'player.report.note': '
|
|
127
|
+
'player.report.note': 'Note (optional)',
|
|
128
|
+
'player.report.addNote': 'Add a note',
|
|
129
|
+
'player.report.why': 'Why? (optional)',
|
|
130
|
+
'player.report.whyRequired': 'Why?',
|
|
131
|
+
'player.report.choose': 'Choose a reason (optional)',
|
|
132
|
+
'player.report.chooseRequired': 'Choose a reason',
|
|
110
133
|
'player.report.noteHint': 'A moderator will read this. Up to {max} characters. Do not include passwords or personal details.',
|
|
134
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
111
135
|
'player.report.send': 'Send report',
|
|
112
136
|
'player.report.cancel': 'Cancel',
|
|
113
137
|
'player.report.close': 'Close',
|
package/src/index.ts
CHANGED