From 00c97fb5dfaeffb22628d6475f2c419417902496 Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Sun, 12 Jan 2025 20:52:56 +0000 Subject: [PATCH] Add moderation actions to user panel --- web/src/icons/eject.svg | 1 - web/src/icons/gavel.svg | 1 + web/src/ui/rightpanel/RightPanel.css | 28 ++++ web/src/ui/rightpanel/UserInfo.tsx | 3 + web/src/ui/rightpanel/UserModeration.tsx | 142 ++++++++++++++++++ .../timeline/menu/ConfirmWithMessageModal.tsx | 6 +- 6 files changed, 177 insertions(+), 4 deletions(-) delete mode 100644 web/src/icons/eject.svg create mode 100644 web/src/icons/gavel.svg create mode 100644 web/src/ui/rightpanel/UserModeration.tsx diff --git a/web/src/icons/eject.svg b/web/src/icons/eject.svg deleted file mode 100644 index bdb3953..0000000 --- a/web/src/icons/eject.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/icons/gavel.svg b/web/src/icons/gavel.svg new file mode 100644 index 0000000..aa5406e --- /dev/null +++ b/web/src/icons/gavel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/ui/rightpanel/RightPanel.css b/web/src/ui/rightpanel/RightPanel.css index 50a3c44..f709361 100644 --- a/web/src/ui/rightpanel/RightPanel.css +++ b/web/src/ui/rightpanel/RightPanel.css @@ -192,6 +192,34 @@ div.right-panel-content.user { } } + div.user-moderation { + display: flex; + flex-direction: column; + gap: .5rem; + + div.moderation-actions { + .dangerous { + color: var(--error-color); + + svg { + fill: var(--error-color) + } + } + .invite { + color: var(--primary-color); + svg { + fill: var(--primary-color) + } + } + } + button { + padding: .25rem 0; + width: 100%; + gap: .25rem; + justify-content: left; + } + } + div.errors { display: flex; flex-direction: column; diff --git a/web/src/ui/rightpanel/UserInfo.tsx b/web/src/ui/rightpanel/UserInfo.tsx index 0181904..17823d1 100644 --- a/web/src/ui/rightpanel/UserInfo.tsx +++ b/web/src/ui/rightpanel/UserInfo.tsx @@ -26,6 +26,7 @@ import UserExtendedProfile from "./UserExtendedProfile.tsx" import DeviceList from "./UserInfoDeviceList.tsx" import UserInfoError from "./UserInfoError.tsx" import MutualRooms from "./UserInfoMutualRooms.tsx" +import UserModeration from "./UserModeration.tsx" interface UserInfoProps { userID: UserID @@ -77,6 +78,8 @@ const UserInfo = ({ userID }: UserInfoProps) => { }
+ +
{errors?.length ? <>
diff --git a/web/src/ui/rightpanel/UserModeration.tsx b/web/src/ui/rightpanel/UserModeration.tsx new file mode 100644 index 0000000..18968d2 --- /dev/null +++ b/web/src/ui/rightpanel/UserModeration.tsx @@ -0,0 +1,142 @@ +// gomuks - A Matrix client written in Go. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import { use, useState } from "react" +import Client from "@/api/client.ts" +import { RoomStateStore } from "@/api/statestore" +import { MemDBEvent, MemberEventContent, Membership } from "@/api/types" +import { ModalContext } from "@/ui/modal" +import { RoomContext } from "@/ui/roomview/roomcontext.ts" +import ConfirmWithMessageModal from "@/ui/timeline/menu/ConfirmWithMessageModal.tsx" +import Gavel from "@/icons/gavel.svg?react" +import PersonAdd from "@/icons/person-add.svg?react" +import PersonRemove from "@/icons/person-remove.svg?react" + +interface UserModerationProps { + userID: string; + client: Client; + room?: RoomStateStore; + member: MemDBEvent | null; +} + +const UserModeration = ({ userID, client, member }: UserModerationProps) => { + const [actionInProgress, setActionInProgress] = useState(false) + const roomCtx = use(RoomContext) + const openModal = use(ModalContext) + + const runAction = (mode: Membership) => { + const callback = (reason: string) => { + if (!roomCtx?.store.roomID) { + console.error("Cannot action user without a room") + return + } + const payload: MemberEventContent = { + membership: mode, + } + if (reason) { + payload["reason"] = reason + } + setActionInProgress(true) + client.rpc + .setState(roomCtx?.store.roomID, "m.room.member", userID, payload) + .then(() => { + console.debug("Actioned", userID) + setActionInProgress(false) + }) + .catch((e) => { + console.error("Failed to action", e) + setActionInProgress(false) + }) + } + return () => { + openModal({ + dimmed: true, + boxed: true, + innerBoxClass: "confirm-message-modal", + content: ( + + + + ), + }) + } + } + + const membership = member?.content.membership || "leave" + return ( +
+

Moderation

+
+ {(["knock", "leave"].includes(membership) || !member) && ( + + )} + {["knock", "invite"].includes(membership) && ( + + )} + {membership === "join" && ( + + )} + {membership !== "ban" && ( + + )} + {membership === "ban" && ( + + )} +
+
+ ) +} +export default UserModeration diff --git a/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx b/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx index 9028a32..adef703 100644 --- a/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx +++ b/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx @@ -20,7 +20,7 @@ import { ModalCloseContext } from "../../modal" import TimelineEvent from "../TimelineEvent.tsx" interface ConfirmWithMessageProps { - evt: MemDBEvent + evt?: MemDBEvent title: string description: string placeholder: string @@ -40,9 +40,9 @@ const ConfirmWithMessageModal = ({ } return

{title}

-
+ {evt &&
-
+
}
{description}