Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(templates): add interaction handler templates #216

Merged
merged 16 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion templates/.sapphirerc.json.sapphire
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"arguments": "arguments",
"commands": "commands",
"listeners": "listeners",
"preconditions": "preconditions"
"preconditions": "preconditions",
"routes": "routes",
"interaction-handlers": "interaction-handlers"
},
"customFileTemplates": {
"enabled": false,
Expand Down
1 change: 1 addition & 0 deletions templates/.sapphirerc.yml.sapphire
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ locations:
listeners: listeners
preconditions: preconditions
routes: routes
interaction-handlers: interaction-handlers
customFileTemplates:
enabled: false
location: ""
52 changes: 52 additions & 0 deletions templates/components/autocompleteinteractionhandler.js.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"category": "interaction-handlers",
}
---
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');

class AutocompleteHandler extends InteractionHandler {
/**
* @param {InteractionHandler.Context} context
* @param {InteractionHandler.Options} options
*/
constructor(context, options) {
super(context, {
...options,
interactionHandlerType: InteractionHandlerTypes.Autocomplete
});
}

/**
* @param {import('discord.js').AutocompleteInteraction} interaction
* @param {import('discord.js').ApplicationCommandOptionChoiceData[]} result
*/
async run(interaction, result) {
return interaction.respond(result);
}

/**
* @param {import('discord.js').AutocompleteInteraction} interaction
*/
async parse(interaction) {
// Only run this interaction for the command with ID '1000802763292020737'
if (interaction.commandId !== '1000802763292020737') return this.none();
// Get the focussed (current) option
const focusedOption = interaction.options.getFocused(true);
// Ensure that the option name is one that can be autocompleted, or return none if not.
switch (focusedOption.name) {
case 'search': {
// Search your API or similar. This is example code!
const searchResult = await myApi.searchForSomething(focusedOption.value);
// Map the search results to the structure required for Autocomplete
return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
}
default:
return this.none();
}
}
}

module.exports = {
AutocompleteHandler
};
34 changes: 34 additions & 0 deletions templates/components/autocompleteinteractionhandler.ts.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"category": "interaction-handlers",
}
---
import { ApplyOptions } from '@sapphire/decorators';
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
import { ApplicationCommandOptionChoiceData, AutocompleteInteraction } from 'discord.js';

@ApplyOptions<InteractionHandler.Options>({
interactionHandlerType: InteractionHandlerTypes.Autocomplete
})
export class AutocompleteHandler extends InteractionHandler {
public override async run(interaction: AutocompleteInteraction, result: ApplicationCommandOptionChoiceData[]) {
return interaction.respond(result);
}

public override async parse(interaction: AutocompleteInteraction) {
// Only run this interaction for the command with ID '1000802763292020737'
if (interaction.commandId !== '1000802763292020737') return this.none();
// Get the focussed (current) option
const focusedOption = interaction.options.getFocused(true);
// Ensure that the option name is one that can be autocompleted, or return none if not.
switch (focusedOption.name) {
case 'search': {
// Search your API or similar. This is example code!
const searchResult = await myApi.searchForSomething(focusedOption.value);
// Map the search results to the structure required for Autocomplete
return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
}
default:
return this.none();
}
}
}
41 changes: 41 additions & 0 deletions templates/components/buttoninteractionhandler.js.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"category": "interaction-handlers"
}
---
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');

class ButtonHandler extends InteractionHandler {
/**
* @param {InteractionHandler.Context} context
* @param {InteractionHandler.Options} options
*/
constructor(context, options) {
super(context, {
...options,
interactionHandlerType: InteractionHandlerTypes.Button
});
}

/**
* @param {import('discord.js').ButtonInteraction} interaction
*/
async run(interaction) {
await interaction.reply({
content: 'Hello from a button interaction handler!',
// Let's make it so only the person who pressed the button can see this message!
ephemeral: true
});
}

/**
* @param {import('discord.js').ButtonInteraction} interaction
*/
parse(interaction) {
if (interaction.customId !== 'my-awesome-button') return this.none();
return this.some();
}
}

module.exports = {
ButtonHandler
};
26 changes: 26 additions & 0 deletions templates/components/buttoninteractionhandler.ts.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"category": "interaction-handlers"
}
---
import { ApplyOptions } from '@sapphire/decorators';
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
import type { ButtonInteraction } from 'discord.js';

@ApplyOptions<InteractionHandler.Options>({
interactionHandlerType: InteractionHandlerTypes.Button
})
export class ButtonHandler extends InteractionHandler {
public async run(interaction: ButtonInteraction) {
await interaction.reply({
content: 'Hello from a button interaction handler!',
// Let's make it so only the person who pressed the button can see this message!
ephemeral: true
});
}

public override parse(interaction: ButtonInteraction) {
if (interaction.customId !== 'my-awesome-button') return this.none();

return this.some();
}
}
41 changes: 41 additions & 0 deletions templates/components/modalinteractionhandler.js.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"category": "interaction-handlers",
}
---
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');

class ModalHandler extends InteractionHandler {
/**
* @param {InteractionHandler.Context} context
* @param {InteractionHandler.Options} options
*/
constructor(context, options) {
super(context, {
...options,
interactionHandlerType: InteractionHandlerTypes.ModalSubmit
});
}

/**
* @param {import('discord.js').ModalSubmitInteraction} interaction
*/
async run(interaction) {
await interaction.reply({
content: 'Thank you for submitting the form!',
ephemeral: true
});
}

/**
* @param {import('discord.js').ModalSubmitInteraction} interaction
*/
parse(interaction) {
if (interaction.customId !== 'hello-popup') return this.none();

return this.some();
}
}

module.exports = {
ModalHandler
};
25 changes: 25 additions & 0 deletions templates/components/modalinteractionhandler.ts.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"category": "interaction-handlers"
}
---
import { ApplyOptions } from '@sapphire/decorators';
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
import type { ModalSubmitInteraction } from 'discord.js';

@ApplyOptions<InteractionHandler.Options>({
interactionHandlerType: InteractionHandlerTypes.ModalSubmit
})
export class ModalHandler extends InteractionHandler {
public async run(interaction: ModalSubmitInteraction) {
await interaction.reply({
content: 'Thank you for submitting the form!',
ephemeral: true
});
}

public override parse(interaction: ModalSubmitInteraction) {
if (interaction.customId !== 'hello-popup') return this.none();

return this.some();
}
}
1 change: 1 addition & 0 deletions templates/components/route.js.sapphire
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{ "category": "routes" }
---
const { methods, Route } = require('@sapphire/plugin-api');

class UserRoute extends Route {
/**
* @param {Route.Context} context
Expand Down
41 changes: 41 additions & 0 deletions templates/components/selectmenuinteractionhandler.js.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"category": "interaction-handlers"
}
---
const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');

class MenuHandler extends InteractionHandler {
/**
* @param {InteractionHandler.Context} context
* @param {InteractionHandler.Options} options
*/
constructor(context, options) {
super(context, {
...options,
interactionHandlerType: InteractionHandlerTypes.SelectMenu
});
}

/**
* @param {import('discord.js').StringSelectMenuInteraction} interaction
*/
async run(interaction) {
await interaction.reply({
// Remember how we can have multiple values? Let's get the first one!
content: `You selected: ${interaction.values[0]}`
});
}

/**
* @param {import('discord.js').StringSelectMenuInteraction} interaction
*/
parse(interaction) {
if (interaction.customId !== 'my-echo-select') return this.none();

return this.some();
}
}

module.exports = {
MenuHandler
};
25 changes: 25 additions & 0 deletions templates/components/selectmenuinteractionhandler.ts.sapphire
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"category": "interaction-handlers"
}
---
import { ApplyOptions } from '@sapphire/decorators';
import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
import type { StringSelectMenuInteraction } from 'discord.js';

@ApplyOptions<InteractionHandler.Options>({
interactionHandlerType: InteractionHandlerTypes.SelectMenu
})
export class MenuHandler extends InteractionHandler {
public override async run(interaction: StringSelectMenuInteraction) {
await interaction.reply({
// Remember how we can have multiple values? Let's get the first one!
content: `You selected: ${interaction.values[0]}`
});
}

public override parse(interaction: StringSelectMenuInteraction) {
if (interaction.customId !== 'my-echo-select') return this.none();

return this.some();
}
}
3 changes: 3 additions & 0 deletions templates/schemas/.sapphirerc.scheme.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
},
"routes": {
"type": "string"
},
"interaction-handlers": {
"type": "string"
}
},
"required": ["base", "arguments", "commands", "listeners", "preconditions"]
Expand Down