diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 6dfd746..b950f24 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -35,7 +35,7 @@ function Avatar(props: Props) { contextMenu.open2(e, [ContextMenus.User(user)])} + onContextMenu={(e) => contextMenu.open2(e, [...ContextMenus.User(user)])} > diff --git a/src/components/messaging/Message.tsx b/src/components/messaging/Message.tsx index be05ba6..73912e0 100644 --- a/src/components/messaging/Message.tsx +++ b/src/components/messaging/Message.tsx @@ -1,6 +1,7 @@ import { observer } from "mobx-react-lite"; import React, { memo } from "react"; import { ContextMenuContext } from "../../contexts/ContextMenuContext"; +import { useAppStore } from "../../stores/AppStore"; import { MessageLike } from "../../stores/objects/Message"; import { QueuedMessageStatus } from "../../stores/objects/QueuedMessage"; import ContextMenus from "../../utils/ContextMenus"; @@ -19,8 +20,11 @@ interface Props { } function Message({ message, header }: Props) { + const app = useAppStore(); const contextMenu = React.useContext(ContextMenuContext); - const [contextMenuItems, setContextMenuItems] = React.useState([ContextMenus.Message(message)]); + const [contextMenuItems, setContextMenuItems] = React.useState([ + ...ContextMenus.Message(app, message, app.account), + ]); return ( contextMenu.open2(e, contextMenuItems)}> diff --git a/src/components/messaging/MessageAttachment.tsx b/src/components/messaging/MessageAttachment.tsx index 971762a..0ffae8a 100644 --- a/src/components/messaging/MessageAttachment.tsx +++ b/src/components/messaging/MessageAttachment.tsx @@ -64,7 +64,7 @@ export default function MessageAttachment({ attachment, contextMenuItems, maxWid withPointer={attachment.content_type?.startsWith("image")} key={attachment.id} onContextMenu={(e) => - contextMenu.open2(e, [...(contextMenuItems ?? []), ContextMenus.MessageAttachment(attachment)]) + contextMenu.open2(e, [...(contextMenuItems ?? []), ...ContextMenus.MessageAttachment(attachment)]) } onClick={() => { if (!attachment.content_type?.startsWith("image")) return; diff --git a/src/components/messaging/MessageAuthor.tsx b/src/components/messaging/MessageAuthor.tsx index 4cab019..5955385 100644 --- a/src/components/messaging/MessageAuthor.tsx +++ b/src/components/messaging/MessageAuthor.tsx @@ -46,7 +46,7 @@ function MessageAuthor({ message }: Props) { style={{ color, }} - onContextMenu={(e) => contextMenu.open2(e, [ContextMenus.User(message.author)])} + onContextMenu={(e) => contextMenu.open2(e, [...ContextMenus.User(message.author)])} > {message.author.username} diff --git a/src/stores/GuildMemberStore.ts b/src/stores/GuildMemberStore.ts index 4649104..3a6a648 100644 --- a/src/stores/GuildMemberStore.ts +++ b/src/stores/GuildMemberStore.ts @@ -1,6 +1,6 @@ import type { Snowflake } from "@spacebarchat/spacebar-api-types/globals"; import type { APIGuildMember } from "@spacebarchat/spacebar-api-types/v9"; -import { action, makeObservable, observable, ObservableMap } from "mobx"; +import { action, computed, makeObservable, observable, ObservableMap } from "mobx"; import AppStore from "./AppStore"; import Guild from "./objects/Guild"; import GuildMember from "./objects/GuildMember"; @@ -64,4 +64,11 @@ export default class GuildMemberStore { get size() { return this.members.size; } + + @computed + get me() { + const meId = this.app.account?.id; + if (!meId) return null; + return this.members.get(meId); + } } diff --git a/src/stores/objects/Message.ts b/src/stores/objects/Message.ts index 2cc6605..ad0eca3 100644 --- a/src/stores/objects/Message.ts +++ b/src/stores/objects/Message.ts @@ -1,22 +1,23 @@ -import type { - APIActionRowComponent, - APIApplication, - APIAttachment, - APIChannel, - APIChannelMention, - APIEmbed, - APIMessage, - APIMessageActionRowComponent, - APIMessageActivity, - APIMessageInteraction, - APIMessageReference, - APIReaction, - APIRole, - APISticker, - APIStickerItem, - APIUser, - MessageFlags, - Snowflake, +import { + Routes, + type APIActionRowComponent, + type APIApplication, + type APIAttachment, + type APIChannel, + type APIChannelMention, + type APIEmbed, + type APIMessage, + type APIMessageActionRowComponent, + type APIMessageActivity, + type APIMessageInteraction, + type APIMessageReference, + type APIReaction, + type APIRole, + type APISticker, + type APIStickerItem, + type APIUser, + type MessageFlags, + type Snowflake, } from "@spacebarchat/spacebar-api-types/v9"; import { action, makeObservable, observable } from "mobx"; import AppStore from "../AppStore"; @@ -247,4 +248,8 @@ export default class Message extends MessageBase { this.timestamp = new Date(message.timestamp); this.edited_timestamp = message.edited_timestamp ? new Date(message.edited_timestamp) : null; } + + async delete() { + await this.app.rest.delete(Routes.channelMessage(this.channel_id, this.id)); + } } diff --git a/src/stores/objects/MessageBase.ts b/src/stores/objects/MessageBase.ts index c96a681..5d26467 100644 --- a/src/stores/objects/MessageBase.ts +++ b/src/stores/objects/MessageBase.ts @@ -27,7 +27,7 @@ export default class MessageBase { type: MessageType; author: User; - constructor(private readonly app: AppStore, data: MessageLikeData) { + constructor(public readonly app: AppStore, data: MessageLikeData) { this.id = data.id; this.content = data.content; this.timestamp = new Date(data.timestamp); diff --git a/src/stores/objects/QueuedMessage.ts b/src/stores/objects/QueuedMessage.ts index 5ae3ac6..86b106c 100644 --- a/src/stores/objects/QueuedMessage.ts +++ b/src/stores/objects/QueuedMessage.ts @@ -60,4 +60,8 @@ export default class QueuedMessage extends MessageBase { this.error = error; this.status = QueuedMessageStatus.FAILED; } + + delete() { + // + } } diff --git a/src/utils/ContextMenus.ts b/src/utils/ContextMenus.ts index 6dcc7a2..b1ac990 100644 --- a/src/utils/ContextMenus.ts +++ b/src/utils/ContextMenus.ts @@ -1,41 +1,73 @@ import { APIAttachment } from "@spacebarchat/spacebar-api-types/v9"; import { IContextMenuItem } from "../components/ContextMenuItem"; import AccountStore from "../stores/AccountStore"; +import AppStore from "../stores/AppStore"; import { MessageLike } from "../stores/objects/Message"; import User from "../stores/objects/User"; +import { Permissions } from "./Permissions"; export default { - User: (user: User | AccountStore): IContextMenuItem => { - return { - label: "Copy User ID", - onClick: () => { - navigator.clipboard.writeText(user.id); + User: (user: User | AccountStore): IContextMenuItem[] => { + return [ + { + label: "Copy User ID", + onClick: () => { + navigator.clipboard.writeText(user.id); + }, + iconProps: { + icon: "mdiIdentifier", + }, }, - iconProps: { - icon: "mdiIdentifier", - }, - }; + ]; }, - Message: (message: MessageLike): IContextMenuItem => { - return { - label: "Copy Message ID", - onClick: () => { - navigator.clipboard.writeText(message.id); + Message: (app: AppStore, message: MessageLike, account: AccountStore | null): IContextMenuItem[] => { + const channel = app.channels.get(message.channel_id); + const permissions = Permissions.getPermission(account?.id, channel?.guild, channel); + const canDeleteMessage = permissions.has("MANAGE_MESSAGES") || message.author.id === account?.id; + + const items: IContextMenuItem[] = [ + { + label: "Copy Message ID", + onClick: () => { + navigator.clipboard.writeText(message.id); + }, + iconProps: { + icon: "mdiIdentifier", + }, }, - iconProps: { - icon: "mdiIdentifier", - }, - }; + ]; + + if (canDeleteMessage) { + items.push({ + label: "Delete Message", + onClick: () => { + message.delete(); + }, + iconProps: { + icon: "mdiTrashCanOutline", + color: "red", + }, + color: "red", + hover: { + backgroundColor: "red", + color: "white", + }, + }); + } + + return items; }, - MessageAttachment: (attachment: APIAttachment): IContextMenuItem => { - return { - label: "Copy Attachment URL", - onClick: () => { - navigator.clipboard.writeText(attachment.url); + MessageAttachment: (attachment: APIAttachment): IContextMenuItem[] => { + return [ + { + label: "Copy Attachment URL", + onClick: () => { + navigator.clipboard.writeText(attachment.url); + }, + iconProps: { + icon: "mdiLink", + }, }, - iconProps: { - icon: "mdiLink", - }, - }; + ]; }, }; diff --git a/src/utils/REST.ts b/src/utils/REST.ts index 41d0328..f76404b 100644 --- a/src/utils/REST.ts +++ b/src/utils/REST.ts @@ -1,7 +1,3 @@ -// import {Globals} from '../constants/Globals'; -// import useLogger from '../hooks/useLogger'; -// import {DomainStore} from '../stores/DomainStore'; - import AppStore from "../stores/AppStore"; import QueuedMessage from "../stores/objects/QueuedMessage"; import { Globals } from "./Globals"; @@ -190,7 +186,7 @@ export default class REST { ): Promise { return new Promise((resolve, reject) => { const url = REST.makeAPIUrl(path, queryParams); - // this.logger.debug(`DELETE ${url}`); + this.logger.debug(`DELETE ${url}`); return ( fetch(url, { method: "DELETE",