Update report room dialog to match designs (#29669)

* Rework for designs

* Update report room position

* lint

* Improve test coverage
This commit is contained in:
Will Hunt
2025-04-03 14:25:19 +01:00
committed by GitHub
parent 1f9db9fa1a
commit cb657d6848
11 changed files with 280 additions and 186 deletions

View File

@@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX, type ChangeEventHandler, useCallback, useState } from "react";
import { Root, Field, Label, InlineSpinner, ErrorMessage } from "@vector-im/compound-web";
import { Root, Field, Label, InlineSpinner, ErrorMessage, HelpMessage } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig";
@@ -14,10 +14,11 @@ import Markdown from "../../../Markdown";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
interface IProps {
roomId: string;
onFinished(complete: boolean): void;
onFinished(leave: boolean): void;
}
/*
@@ -27,27 +28,26 @@ interface IProps {
export const ReportRoomDialog: React.FC<IProps> = function ({ roomId, onFinished }) {
const [error, setErr] = useState<string>();
const [busy, setBusy] = useState(false);
const [sent, setSent] = useState(false);
const [reason, setReason] = useState("");
const [leaveRoom, setLeaveRoom] = useState(false);
const client = MatrixClientPeg.safeGet();
const onReasonChange = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => setReason(e.target.value), []);
const onCancel = useCallback(() => onFinished(sent), [sent, onFinished]);
const onCancel = useCallback(() => onFinished(false), [onFinished]);
const onSubmit = useCallback(async () => {
setBusy(true);
try {
await client.reportRoom(roomId, reason);
setSent(true);
onFinished(leaveRoom);
} catch (ex) {
setBusy(false);
if (ex instanceof Error) {
setErr(ex.message);
} else {
setErr("Unknown error");
}
} finally {
setBusy(false);
}
}, [roomId, reason, client]);
}, [roomId, reason, client, leaveRoom, onFinished]);
const adminMessageMD = SdkConfig.getObject("report_event")?.get("admin_message_md", "adminMessageMD");
let adminMessage: JSX.Element | undefined;
@@ -59,37 +59,39 @@ export const ReportRoomDialog: React.FC<IProps> = function ({ roomId, onFinished
return (
<BaseDialog
className="mx_ReportRoomDialog"
onFinished={() => onFinished(sent)}
title={_t("report_room|title")}
onFinished={onCancel}
title={_t("action|report_room")}
contentId="mx_ReportEventDialog"
>
{sent && <p>{_t("report_room|sent")}</p>}
{!sent && (
<Root id="mx_ReportEventDialog" onSubmit={onSubmit}>
<p>{_t("report_room|description")}</p>
{adminMessage}
<Field name="reason">
<Label htmlFor="mx_ReportRoomDialog_reason">{_t("room_settings|permissions|ban_reason")}</Label>
<textarea
id="mx_ReportRoomDialog_reason"
placeholder={_t("report_room|reason_placeholder")}
rows={5}
onChange={onReasonChange}
value={reason}
disabled={busy}
/>
{error ? <ErrorMessage>{error}</ErrorMessage> : null}
</Field>
{busy ? <InlineSpinner /> : null}
<DialogButtons
primaryButton={_t("action|send_report")}
onPrimaryButtonClick={onSubmit}
focus={true}
onCancel={onCancel}
<Root id="mx_ReportEventDialog" onSubmit={onSubmit}>
<Field name="reason">
<Label htmlFor="mx_ReportRoomDialog_reason">{_t("report_room|reason_label")}</Label>
<textarea
id="mx_ReportRoomDialog_reason"
rows={5}
onChange={onReasonChange}
value={reason}
disabled={busy}
/>
</Root>
)}
{error ? <ErrorMessage>{error}</ErrorMessage> : null}
<HelpMessage>{_t("report_room|description")}</HelpMessage>
</Field>
{adminMessage}
{busy ? <InlineSpinner /> : null}
<LabelledToggleSwitch
label={_t("room_list|more_options|leave_room")}
value={leaveRoom}
onChange={setLeaveRoom}
/>
<DialogButtons
primaryButton={_t("action|send_report")}
onPrimaryButtonClick={onSubmit}
focus={true}
onCancel={onCancel}
primaryButtonClass="danger"
primaryDisabled={busy || !reason}
/>
</Root>
</BaseDialog>
);
};

View File

@@ -233,10 +233,16 @@ const RoomSummaryCard: React.FC<IProps> = ({
room_id: room.roomId,
});
};
const onReportRoomClick = (): void => {
Modal.createDialog(ReportRoomDialog, {
const onReportRoomClick = async (): Promise<void> => {
const [leave] = await Modal.createDialog(ReportRoomDialog, {
roomId: room.roomId,
});
}).finished;
if (leave) {
defaultDispatcher.dispatch({
action: "leave_room",
room_id: room.roomId,
});
}
};
const isRoomEncrypted = useIsEncrypted(cli, room);
@@ -447,6 +453,12 @@ const RoomSummaryCard: React.FC<IProps> = ({
<Separator />
<div className="mx_RoomSummaryCard_bottomOptions">
<MenuItem
Icon={ErrorIcon}
kind="critical"
label={_t("action|report_room")}
onSelect={onReportRoomClick}
/>
<MenuItem
className="mx_RoomSummaryCard_leave"
Icon={LeaveIcon}
@@ -454,12 +466,6 @@ const RoomSummaryCard: React.FC<IProps> = ({
label={_t("action|leave_room")}
onSelect={onLeaveRoomClick}
/>
<MenuItem
Icon={ErrorIcon}
kind="critical"
label={_t("action|report_room")}
onSelect={onReportRoomClick}
/>
</div>
</div>
</BaseCard>

View File

@@ -1827,10 +1827,8 @@
"toxic_behaviour": "Toxic Behaviour"
},
"report_room": {
"description": "Report this room to your homeserver admin. This will send the room's unique ID, but if messages are encrypted, the administrator won't be able to read them or view shared files.",
"reason_placeholder": " Reason for reporting...",
"sent": "Your report was sent.",
"title": "Report Room"
"description": "Report this room to your account provider. If the messages are encrypted, your admin will not be able to read them.",
"reason_label": "Describe the reason"
},
"restore_key_backup_dialog": {
"count_of_decryption_failures": "Failed to decrypt %(failedCount)s sessions!",