diff --git a/external/lang b/external/lang index 5bf84e27..79d9b042 160000 --- a/external/lang +++ b/external/lang @@ -1 +1 @@ -Subproject commit 5bf84e27074daeab3055f299e54be955aae5042d +Subproject commit 79d9b042866d466f39e3f4d053833416137491f8 diff --git a/src/controllers/modals/ModalController.tsx b/src/controllers/modals/ModalController.tsx index cbcf9be0..cd97cf49 100644 --- a/src/controllers/modals/ModalController.tsx +++ b/src/controllers/modals/ModalController.tsx @@ -41,6 +41,7 @@ import MFARecovery from "./components/MFARecovery"; import ModifyAccount from "./components/ModifyAccount"; import OutOfDate from "./components/OutOfDate"; import PendingFriendRequests from "./components/PendingFriendRequests"; +import ReportContent from "./components/Report"; import ServerIdentity from "./components/ServerIdentity"; import ServerInfo from "./components/ServerInfo"; import ShowToken from "./components/ShowToken"; @@ -276,4 +277,5 @@ export const modalController = new ModalControllerExtended({ sign_out_sessions: SignOutSessions, user_picker: UserPicker, user_profile: UserProfile, + report: ReportContent, }); diff --git a/src/controllers/modals/components/Report.tsx b/src/controllers/modals/components/Report.tsx new file mode 100644 index 00000000..8474855c --- /dev/null +++ b/src/controllers/modals/components/Report.tsx @@ -0,0 +1,125 @@ +import { API, Message as MessageInterface, User } from "revolt.js"; + +import { Text } from "preact-i18n"; + +import { ModalForm, Row } from "@revoltchat/ui"; + +import Message from "../../../components/common/messaging/Message"; +import UserShort from "../../../components/common/user/UserShort"; +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; + +const CONTENT_REASONS: API.ContentReportReason[] = [ + "NoneSpecified", + "Illegal", + "PromotesHarm", + "SpamAbuse", + "Malware", + "Harassment", +]; + +const USER_REASONS: API.UserReportReason[] = [ + "NoneSpecified", + "SpamAbuse", + "InappropriateProfile", + "Impersonation", + "BanEvasion", + "Underage", +]; + +/** + * Report creation modal + */ +export default function ReportContent({ + target, + ...props +}: ModalProps<"report">) { + const client = useClient(); + + return ( + + ) : ( + + ) + } + schema={{ + selected: "custom", + reason: "combo", + additional_context: "text", + }} + data={{ + selected: { + element: + target instanceof MessageInterface ? ( + + ) : target instanceof User ? ( + + + + ) : ( + <> + ), + }, + reason: { + field: ( + + ) as React.ReactChild, + options: (target instanceof User + ? USER_REASONS + : CONTENT_REASONS + ).map((value) => ({ + name: ( + + ), + value, + })), + }, + additional_context: { + field: ( + + ) as React.ReactChild, + }, + }} + callback={async ({ reason, additional_context }) => { + await client.api.post("/safety/report", { + content: { + id: target._id, + type: + target instanceof MessageInterface + ? "Message" + : target instanceof User + ? "User" + : "Server", + report_reason: reason as any, + }, + additional_context, + }); + }} + submit={{ + children: , + }} + /> + ); +} diff --git a/src/controllers/modals/components/ServerInfo.tsx b/src/controllers/modals/components/ServerInfo.tsx index 786026ad..ea15df7c 100644 --- a/src/controllers/modals/components/ServerInfo.tsx +++ b/src/controllers/modals/components/ServerInfo.tsx @@ -28,16 +28,24 @@ export default function ServerInfo({ } actions={[ { - onClick: () => + onClick: () => { modalController.push({ type: "server_identity", member: server.member!, - }), + }); + return true; + }, children: "Edit Identity", palette: "primary", }, { - onClick: () => report(server), + onClick: () => { + modalController.push({ + type: "report", + target: server, + }); + return true; + }, children: , palette: "error", }, diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index 033776a6..e09736a2 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -179,6 +179,10 @@ export type Modal = { | { type: "import_theme"; } + | { + type: "report"; + target: Server | User | Message; + } ); export type ModalProps = Modal & { type: T } & { diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index 16dd239a..ab7a674e 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -111,7 +111,8 @@ type Action = action: "set_notification_state"; key: string; state?: NotificationState; - }; + } + | { action: "report"; target: User | Server | Message }; // ! FIXME: I dare someone to re-write this // Tip: This should just be split into separate context menus per logical area. @@ -449,6 +450,12 @@ export default function ContextMenus() { case "open_server_settings": history.push(`/server/${data.id}/settings`); break; + case "report": + modalController.push({ + type: "report", + target: data.target, + }); + break; } })().catch((err) => { modalController.push({ @@ -669,6 +676,19 @@ export default function ContextMenus() { } as unknown as Action); } } + + if (user._id !== userId) { + generateAction( + { + action: "report", + target: user, + }, + "report_user", + undefined, + undefined, + "var(--error)", + ); + } } if (contextualChannel) { @@ -795,14 +815,33 @@ export default function ContextMenus() { }); } + if (message.author_id !== userId) { + generateAction( + { + action: "report", + target: message, + }, + "report_message", + undefined, + undefined, + "var(--error)", + ); + } + if ( message.author_id === userId || channelPermissions & Permission.ManageMessages ) { - generateAction({ - action: "delete_message", - target: message, - }); + generateAction( + { + action: "delete_message", + target: message, + }, + undefined, + undefined, + undefined, + "var(--error)", + ); } if ( @@ -1035,6 +1074,17 @@ export default function ContextMenus() { "var(--error)", ); } else { + generateAction( + { + action: "report", + target: server, + }, + "report_server", + undefined, + undefined, + "var(--error)", + ); + generateAction( { action: "leave_server", target: server }, "leave_server",