From ee8fbbbab4691fd6eb92b463ae74a2de0c6386d3 Mon Sep 17 00:00:00 2001 From: MapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Wed, 29 Dec 2021 01:55:02 -0600 Subject: [PATCH] event info speedcode any% this is horrifying --- helpers/prune-null-values.ts | 15 +++++ library/core/component-event.ts | 59 ++++++++++++++++++- library/core/reacord-discord-js.ts | 91 +++++++++++++++++++++++++++++- library/core/reacord-tester.ts | 11 ++++ playground/main.tsx | 7 ++- todo.md | 10 ++-- 6 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 helpers/prune-null-values.ts diff --git a/helpers/prune-null-values.ts b/helpers/prune-null-values.ts new file mode 100644 index 0000000..5ce7dc3 --- /dev/null +++ b/helpers/prune-null-values.ts @@ -0,0 +1,15 @@ +export function pruneNullishValues( + object: T, +): PruneNullishValues { + const result: any = {} + for (const [key, value] of Object.entries(object)) { + if (value != undefined) { + result[key] = value + } + } + return result +} + +type PruneNullishValues = { + [Key in keyof T]: NonNullable +} diff --git a/library/core/component-event.ts b/library/core/component-event.ts index a248715..2b5873e 100644 --- a/library/core/component-event.ts +++ b/library/core/component-event.ts @@ -2,7 +2,64 @@ import type { ReactNode } from "react" import type { ReacordInstance } from "./instance" export type ComponentEvent = { - // todo: add more info, like user, channel, member, guild, etc. + message: MessageInfo + channel: ChannelInfo + user: UserInfo + guild?: GuildInfo reply(content?: ReactNode): ReacordInstance ephemeralReply(content?: ReactNode): ReacordInstance } + +export type ChannelInfo = { + id: string + name?: string + topic?: string + nsfw?: boolean + lastMessageId?: string + ownerId?: string + parentId?: string + rateLimitPerUser?: number +} + +export type MessageInfo = { + id: string + channelId: string + authorId: UserInfo + member?: GuildMemberInfo + content: string + timestamp: string + editedTimestamp?: string + tts: boolean + mentionEveryone: boolean + /** The IDs of mentioned users */ + mentions: string[] +} + +export type GuildInfo = { + id: string + name: string + member: GuildMemberInfo +} + +export type GuildMemberInfo = { + id: string + nick?: string + displayName: string + avatarUrl?: string + displayAvatarUrl: string + roles: string[] + color: number + joinedAt?: string + premiumSince?: string + pending?: boolean + communicationDisabledUntil?: string +} + +export type UserInfo = { + id: string + username: string + discriminator: string + tag: string + avatarUrl: string + accentColor?: number +} diff --git a/library/core/reacord-discord-js.ts b/library/core/reacord-discord-js.ts index ff57b94..d9fd19d 100644 --- a/library/core/reacord-discord-js.ts +++ b/library/core/reacord-discord-js.ts @@ -1,13 +1,22 @@ /* eslint-disable class-methods-use-this */ -import type * as Discord from "discord.js" +import * as Discord from "discord.js" import type { ReactNode } from "react" import type { Except } from "type-fest" +import { pick } from "../../helpers/pick" +import { pruneNullishValues } from "../../helpers/prune-null-values" import { raise } from "../../helpers/raise" import { toUpper } from "../../helpers/to-upper" import type { ComponentInteraction } from "../internal/interaction" import type { Message, MessageOptions } from "../internal/message" import { ChannelMessageRenderer } from "../internal/renderers/channel-message-renderer" import { InteractionReplyRenderer } from "../internal/renderers/interaction-reply-renderer" +import type { + ChannelInfo, + GuildInfo, + GuildMemberInfo, + MessageInfo, + UserInfo, +} from "./component-event" import type { ReacordInstance } from "./instance" import type { ReacordConfig } from "./reacord" import { Reacord } from "./reacord" @@ -126,6 +135,81 @@ export class ReacordDiscordJs extends Reacord { private createReacordComponentInteraction( interaction: Discord.MessageComponentInteraction, ): ComponentInteraction { + // todo please dear god clean this up + const channel: ChannelInfo = interaction.channel + ? { + ...pick(pruneNullishValues(interaction.channel), [ + "topic", + "nsfw", + "lastMessageId", + "ownerId", + "parentId", + "rateLimitPerUser", + ]), + id: interaction.channelId, + } + : raise("Non-channel interactions are not supported") + + const message: MessageInfo = + interaction.message instanceof Discord.Message + ? { + ...pick(interaction.message, [ + "id", + "channelId", + "authorId", + "content", + "tts", + "mentionEveryone", + ]), + timestamp: new Date( + interaction.message.createdTimestamp, + ).toISOString(), + editedTimestamp: interaction.message.editedTimestamp + ? new Date(interaction.message.editedTimestamp).toISOString() + : undefined, + mentions: interaction.message.mentions.users.map((u) => u.id), + } + : raise("Message not found") + + const member: GuildMemberInfo | undefined = + interaction.member instanceof Discord.GuildMember + ? { + ...pick(pruneNullishValues(interaction.member), [ + "id", + "nick", + "displayName", + "avatarUrl", + "displayAvatarUrl", + "color", + "pending", + ]), + displayName: interaction.member.displayName, + roles: [...interaction.member.roles.cache.map((role) => role.id)], + joinedAt: interaction.member.joinedAt?.toISOString(), + premiumSince: interaction.member.premiumSince?.toISOString(), + communicationDisabledUntil: + interaction.member.communicationDisabledUntil?.toISOString(), + } + : undefined + + const guild: GuildInfo | undefined = interaction.guild + ? { + ...pick(pruneNullishValues(interaction.guild), ["id", "name"]), + member: member ?? raise("unexpected: member is undefined"), + } + : undefined + + const user: UserInfo = { + ...pick(pruneNullishValues(interaction.user), [ + "id", + "username", + "discriminator", + "tag", + ]), + avatarUrl: interaction.user.avatarURL()!, + accentColor: interaction.user.accentColor ?? undefined, + } + const baseProps: Except = { id: interaction.id, customId: interaction.customId, @@ -151,6 +235,11 @@ export class ReacordDiscordJs extends Reacord { return createReacordMessage(message as Discord.Message) }, event: { + channel, + message, + user, + guild, + reply: (content?: ReactNode) => this.createInstance( this.createInteractionReplyRenderer(interaction), diff --git a/library/core/reacord-tester.ts b/library/core/reacord-tester.ts index ac56fa7..ab16400 100644 --- a/library/core/reacord-tester.ts +++ b/library/core/reacord-tester.ts @@ -22,6 +22,12 @@ import type { } from "../internal/message" import { ChannelMessageRenderer } from "../internal/renderers/channel-message-renderer" import { InteractionReplyRenderer } from "../internal/renderers/interaction-reply-renderer" +import type { + ChannelInfo, + GuildInfo, + MessageInfo, + UserInfo, +} from "./component-event" import type { ButtonClickEvent } from "./components/button" import type { SelectChangeEvent } from "./components/select" import type { ReacordInstance } from "./instance" @@ -250,6 +256,11 @@ class TestSelectInteraction class TestComponentEvent { constructor(private tester: ReacordTester) {} + message: MessageInfo = {} as any // todo + channel: ChannelInfo = {} as any // todo + user: UserInfo = {} as any // todo + guild: GuildInfo = {} as any // todo + reply(content?: ReactNode): ReacordInstance { return this.tester.reply() } diff --git a/playground/main.tsx b/playground/main.tsx index 7f4a4d2..fda4b4f 100644 --- a/playground/main.tsx +++ b/playground/main.tsx @@ -70,7 +70,12 @@ createCommandHandler(client, [ <>