diff --git a/packages/discord.js/src/structures/CommandInteraction.js b/packages/discord.js/src/structures/CommandInteraction.js index 69fa4558e..9400d6351 100644 --- a/packages/discord.js/src/structures/CommandInteraction.js +++ b/packages/discord.js/src/structures/CommandInteraction.js @@ -204,6 +204,7 @@ class CommandInteraction extends Interaction { deleteReply() {} followUp() {} showModal() {} + awaitModalSubmit() {} } InteractionResponses.applyToClass(CommandInteraction, ['deferUpdate', 'update']); diff --git a/packages/discord.js/src/structures/MessageComponentInteraction.js b/packages/discord.js/src/structures/MessageComponentInteraction.js index e9d9e4b21..4f16b2715 100644 --- a/packages/discord.js/src/structures/MessageComponentInteraction.js +++ b/packages/discord.js/src/structures/MessageComponentInteraction.js @@ -91,6 +91,7 @@ class MessageComponentInteraction extends Interaction { deferUpdate() {} update() {} showModal() {} + awaitModalSubmit() {} } InteractionResponses.applyToClass(MessageComponentInteraction); diff --git a/packages/discord.js/src/structures/interfaces/InteractionResponses.js b/packages/discord.js/src/structures/interfaces/InteractionResponses.js index 2a126e90b..f23d7bfe7 100644 --- a/packages/discord.js/src/structures/interfaces/InteractionResponses.js +++ b/packages/discord.js/src/structures/interfaces/InteractionResponses.js @@ -1,8 +1,9 @@ 'use strict'; const { isJSONEncodable } = require('@discordjs/builders'); -const { InteractionResponseType, MessageFlags, Routes } = require('discord-api-types/v10'); +const { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10'); const { Error } = require('../../errors'); +const InteractionCollector = require('../InteractionCollector'); const MessagePayload = require('../MessagePayload'); /** @@ -248,6 +249,38 @@ class InteractionResponses { this.replied = true; } + /** + * An object containing the same properties as {@link CollectorOptions}, but a few less: + * @typedef {Object} AwaitModalSubmitOptions + * @property {CollectorFilter} [filter] The filter applied to this collector + * @property {number} time Time to wait for an interaction before rejecting + */ + + /** + * Collects a single modal submit interaction that passes the filter. + * The Promise will reject if the time expires. + * @param {AwaitModalSubmitOptions} options Options to pass to the internal collector + * @returns {Promise} + * @example + * // Collect a modal submit interaction + * const filter = (interaction) => interaction.customId === 'modal'; + * interaction.awaitModalSubmit({ filter, time: 15_000 }) + * .then(interaction => console.log(`${interaction.customId} was submitted!`)) + * .catch(console.error); + */ + awaitModalSubmit(options) { + if (typeof options.time !== 'number') throw new Error('INVALID_TYPE', 'time', 'number'); + const _options = { ...options, max: 1, interactionType: InteractionType.ModalSubmit }; + return new Promise((resolve, reject) => { + const collector = new InteractionCollector(this.client, _options); + collector.once('end', (interactions, reason) => { + const interaction = interactions.first(); + if (interaction) resolve(interaction); + else reject(new Error('INTERACTION_COLLECTOR_ERROR', reason)); + }); + }); + } + static applyToClass(structure, ignore = []) { const props = [ 'deferReply', @@ -259,6 +292,7 @@ class InteractionResponses { 'deferUpdate', 'update', 'showModal', + 'awaitModalSubmit', ]; for (const prop of props) { diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index f31e0d0ec..494474b0c 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -379,6 +379,7 @@ export interface InteractionResponseFields showModal( modal: JSONEncodable | ModalData | APIModalInteractionResponseCallbackData, ): Promise; + awaitModalSubmit(options: AwaitModalSubmitOptions): Promise>; } export abstract class CommandInteraction extends Interaction { @@ -1744,6 +1745,7 @@ export class MessageComponentInteraction e public showModal( modal: JSONEncodable | ModalData | APIModalInteractionResponseCallbackData, ): Promise; + public awaitModalSubmit(options: AwaitModalSubmitOptions): Promise; } export class MessageContextMenuCommandInteraction< @@ -3563,6 +3565,18 @@ export type AwaitMessageComponentOptions 'max' | 'maxComponents' | 'maxUsers' >; +export type ModalSubmitInteractionCollectorOptions = Omit< + InteractionCollectorOptions, + 'channel' | 'message' | 'guild' | 'interactionType' +>; + +export type AwaitModalSubmitOptions = Omit< + ModalSubmitInteractionCollectorOptions, + 'max' | 'maxComponents' | 'maxUsers' +> & { + time: number; +}; + export interface AwaitMessagesOptions extends MessageCollectorOptions { errors?: string[]; }