Add report room dialog button/dialog. (#29513)
* Add report room dialog button/dialog. * Update copy * fixup tests / lint * Fix title in test. * update snapshot * Add unit tests for dialog * lint
This commit is contained in:
95
src/components/views/dialogs/ReportRoomDialog.tsx
Normal file
95
src/components/views/dialogs/ReportRoomDialog.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ChangeEventHandler, useCallback, useState } from "react";
|
||||
import { Root, Field, Label, InlineSpinner, ErrorMessage } from "@vector-im/compound-web";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import Markdown from "../../../Markdown";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
interface IProps {
|
||||
roomId: string;
|
||||
onFinished(complete: boolean): void;
|
||||
}
|
||||
|
||||
/*
|
||||
* A dialog for reporting a room.
|
||||
*/
|
||||
|
||||
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 client = MatrixClientPeg.safeGet();
|
||||
|
||||
const onReasonChange = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => setReason(e.target.value), []);
|
||||
const onCancel = useCallback(() => onFinished(sent), [sent, onFinished]);
|
||||
const onSubmit = useCallback(async () => {
|
||||
setBusy(true);
|
||||
try {
|
||||
await client.reportRoom(roomId, reason);
|
||||
setSent(true);
|
||||
} catch (ex) {
|
||||
if (ex instanceof Error) {
|
||||
setErr(ex.message);
|
||||
} else {
|
||||
setErr("Unknown error");
|
||||
}
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}, [roomId, reason, client]);
|
||||
|
||||
const adminMessageMD = SdkConfig.getObject("report_event")?.get("admin_message_md", "adminMessageMD");
|
||||
let adminMessage: JSX.Element | undefined;
|
||||
if (adminMessageMD) {
|
||||
const html = new Markdown(adminMessageMD).toHTML({ externalLinks: true });
|
||||
adminMessage = <p dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
className="mx_ReportRoomDialog"
|
||||
onFinished={() => onFinished(sent)}
|
||||
title={_t("report_room|title")}
|
||||
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}
|
||||
disabled={busy}
|
||||
/>
|
||||
</Root>
|
||||
)}
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2024, 2025 New Vector Ltd.
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
@@ -77,6 +77,7 @@ import { isVideoRoom as calcIsVideoRoom } from "../../../utils/video-rooms";
|
||||
import { usePinnedEvents } from "../../../hooks/usePinnedEvents";
|
||||
import { ReleaseAnnouncement } from "../../structures/ReleaseAnnouncement.tsx";
|
||||
import { useScopedRoomContext } from "../../../contexts/ScopedRoomContext.tsx";
|
||||
import { ReportRoomDialog } from "../dialogs/ReportRoomDialog.tsx";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
@@ -231,6 +232,11 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
||||
room_id: room.roomId,
|
||||
});
|
||||
};
|
||||
const onReportRoomClick = (): void => {
|
||||
Modal.createDialog(ReportRoomDialog, {
|
||||
roomId: room.roomId,
|
||||
});
|
||||
};
|
||||
|
||||
const isRoomEncrypted = useIsEncrypted(cli, room);
|
||||
const roomContext = useScopedRoomContext("e2eStatus", "timelineRenderingType");
|
||||
@@ -439,14 +445,21 @@ const RoomSummaryCard: React.FC<IProps> = ({
|
||||
<MenuItem Icon={SettingsIcon} label={_t("common|settings")} onSelect={onRoomSettingsClick} />
|
||||
|
||||
<Separator />
|
||||
|
||||
<MenuItem
|
||||
className="mx_RoomSummaryCard_leave"
|
||||
Icon={LeaveIcon}
|
||||
kind="critical"
|
||||
label={_t("action|leave_room")}
|
||||
onSelect={onLeaveRoomClick}
|
||||
/>
|
||||
<div className="mx_RoomSummaryCard_bottomOptions">
|
||||
<MenuItem
|
||||
className="mx_RoomSummaryCard_leave"
|
||||
Icon={LeaveIcon}
|
||||
kind="critical"
|
||||
label={_t("action|leave_room")}
|
||||
onSelect={onLeaveRoomClick}
|
||||
/>
|
||||
<MenuItem
|
||||
Icon={ErrorIcon}
|
||||
kind="critical"
|
||||
label={_t("action|report_room")}
|
||||
onSelect={onReportRoomClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</BaseCard>
|
||||
);
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
"reply": "Reply",
|
||||
"reply_in_thread": "Reply in thread",
|
||||
"report_content": "Report Content",
|
||||
"report_room": "Report room",
|
||||
"resend": "Resend",
|
||||
"reset": "Reset",
|
||||
"resume": "Resume",
|
||||
@@ -1810,6 +1811,12 @@
|
||||
"spam_or_propaganda": "Spam or propaganda",
|
||||
"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"
|
||||
},
|
||||
"restore_key_backup_dialog": {
|
||||
"count_of_decryption_failures": "Failed to decrypt %(failedCount)s sessions!",
|
||||
"count_of_successfully_restored_keys": "Successfully restored %(sessionCount)s keys",
|
||||
|
||||
Reference in New Issue
Block a user