- refactor

- add modal
This commit is contained in:
Enrico Bühler 2022-09-21 01:26:46 +02:00
parent b7cc57770c
commit c018d35e2a
8 changed files with 221 additions and 76 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
node_modules node_modules
# Keep environment variables out of version control # Keep environment variables out of version control
.env .env
prisma/dev.db

Binary file not shown.

View File

@ -0,0 +1,10 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
export default function getActionsComponent() {
return new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId("quoteModal")
.setLabel("Quote")
.setStyle(ButtonStyle.Primary)
);
}

View File

@ -0,0 +1,30 @@
import { SlashCommandBuilder } from "discord.js";
export default function getCommands() {
const commands = [
new SlashCommandBuilder()
.setName("quote")
.setDescription("Lets you post a qoute without showing your name")
.addStringOption((option) =>
option
.setName("content")
.setDescription("The content of the quote")
.setRequired(true)
),
new SlashCommandBuilder()
.setName("quotemodal")
.setDescription(
"Shows a model which lets you post a quote without showing your name"
),
new SlashCommandBuilder()
.setName("actions")
.setDescription("Handle actions on this server")
.addSubcommand((subcommand) =>
subcommand
.setName("send")
.setDescription("Sends bot actions in the current channel")
),
].map((command) => command.toJSON());
return commands;
}

View File

@ -0,0 +1,23 @@
import {
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle,
} from "discord.js";
export default function getQuoteModal() {
const modal = new ModalBuilder()
.setCustomId("quoteModal")
.setTitle("Submit a quote!");
const contentInput = new TextInputBuilder()
.setCustomId("contentInput")
.setLabel("Content")
.setStyle(TextInputStyle.Paragraph);
const firstActionRow = new ActionRowBuilder().addComponents(contentInput);
modal.addComponents(firstActionRow as any);
return modal;
}

View File

@ -1,24 +1,24 @@
import { import {
ButtonInteraction,
CacheType, CacheType,
ChatInputCommandInteraction, ChatInputCommandInteraction,
Interaction, Interaction,
ModalSubmitInteraction,
} from "discord.js"; } from "discord.js";
import config from "config";
import EventEmitter from "events"; import EventEmitter from "events";
import DiscordService from "Services/discord.service"; import DiscordService from "Services/discord/discord.service";
import PrismaService from "Services/prisma.service";
export default class DiscordController extends EventEmitter { export default class DiscordController extends EventEmitter {
private discordService!: DiscordService; private discordService!: DiscordService;
private prismaService: PrismaService;
constructor() { constructor() {
super(); super();
this.discordService = new DiscordService(); this.discordService = new DiscordService();
this.prismaService = new PrismaService(); // log when running
this.discordService.client.once("ready", () => { this.discordService.client.once("ready", () => {
console.log("Listening..."); console.log("Listening...");
}); });
// listen for interactions
this.discordService.client.on( this.discordService.client.on(
"interactionCreate", "interactionCreate",
this.handleInteraction.bind(this) this.handleInteraction.bind(this)
@ -30,42 +30,55 @@ export default class DiscordController extends EventEmitter {
} }
async handleInteraction(interaction: Interaction<CacheType>) { async handleInteraction(interaction: Interaction<CacheType>) {
if (!interaction.isChatInputCommand()) return; if (interaction.isModalSubmit()) {
await this.handleModalSubmit(interaction);
}
if (interaction.isChatInputCommand()) {
await this.handleChatInputCommand(interaction);
}
if (interaction.isButton()) {
await this.handleButton(interaction);
}
}
async handleButton(interaction: ButtonInteraction<CacheType>) {
const { customId } = interaction;
if (customId === "quoteModal") {
this.discordService.handleQuoteModal(interaction);
}
}
async handleChatInputCommand(
interaction: ChatInputCommandInteraction<CacheType>
) {
const { commandName } = interaction; const { commandName } = interaction;
switch (commandName) { switch (commandName) {
case "quote": case "quote":
await this.quote(interaction); await this.discordService.handleQuote(interaction);
case "quotemodal":
await this.discordService.handleQuoteModal(interaction);
case "actions":
await this.discordService.handleActions(interaction);
default: default:
break; break;
} }
} }
async quote(interaction: ChatInputCommandInteraction<CacheType>) { async handleModalSubmit(interaction: ModalSubmitInteraction<CacheType>) {
// find the channel with configured id const { customId } = interaction;
const channel = this.discordService.client.channels.cache.find(
(ch) => ch.id === config.discord.channelId
);
if (channel?.isTextBased()) { switch (customId) {
const content = interaction.options.getString("content") || ""; case "quoteModal":
await this.discordService.handleQuote(interaction);
// send quote content as message default:
await this.prismaService.client.message.create({ break;
data: {
content,
userName: interaction.user.username,
},
});
await channel.send(content);
await interaction.reply({
content: "Completed!",
ephemeral: true,
});
return;
} }
} }
async sendActions(interaction: ChatInputCommandInteraction<CacheType>) {}
} }

View File

@ -1,46 +0,0 @@
import {
Client,
IntentsBitField,
Routes,
SlashCommandBuilder,
} from "discord.js";
import { REST } from "@discordjs/rest";
import config from "config";
const COMMANDS = [
new SlashCommandBuilder()
.setName("quote")
.setDescription("Lets you post a qoute without showing your name")
.addStringOption((option) =>
option
.setName("content")
.setDescription("The content of the quote")
.setRequired(true)
),
].map((command) => command.toJSON());
export default class DiscordService {
rest: REST;
client: Client<boolean>;
constructor() {
this.rest = new REST({ version: "10" }).setToken(config.discord.token);
this.client = new Client({ intents: [IntentsBitField.Flags.Guilds] });
}
async init() {
try {
await this.rest.put(
Routes.applicationCommands(config.discord.applicationId),
{
body: COMMANDS,
}
);
console.log("Successfully added commands");
await this.client.login(config.discord.token);
} catch (e) {
console.error(e);
}
}
}

View File

@ -0,0 +1,114 @@
import {
CacheType,
ChatInputCommandInteraction,
Client,
IntentsBitField,
Interaction,
Routes,
SlashCommandBuilder,
} from "discord.js";
import { REST } from "@discordjs/rest";
import config from "config";
import PrismaService from "Services/prisma.service";
import getCommands from "Components/commands.component";
import getQuoteModal from "Components/quote-modal.component";
import getActionsComponent from "Components/actions.component";
export default class DiscordService {
rest: REST;
client: Client<boolean>;
private prismaService: PrismaService;
constructor() {
this.rest = new REST({ version: "10" }).setToken(config.discord.token);
this.prismaService = new PrismaService();
this.client = new Client({ intents: [IntentsBitField.Flags.Guilds] });
}
async init() {
try {
await this.rest.put(
Routes.applicationCommands(config.discord.applicationId),
{
body: getCommands(),
}
);
console.log("Successfully added commands");
await this.client.login(config.discord.token);
} catch (e) {
console.error(e);
}
}
async handleQuote(interaction: Interaction<CacheType>) {
let content: string | undefined = undefined;
if (interaction.isModalSubmit()) {
content = interaction.fields.getTextInputValue("contentInput");
} else if (interaction.isChatInputCommand()) {
content = interaction.options.getString("content") || "";
}
if (content) {
await this.createQuote({ content }, interaction);
}
}
async handleQuoteModal(interaction: Interaction<CacheType>) {
const modal = getQuoteModal();
if (interaction.isButton() || interaction.isChatInputCommand()) {
await interaction.showModal(modal);
}
}
async handleActions(interaction: Interaction<CacheType>) {
if (interaction.isChatInputCommand()) {
if (interaction.options.getSubcommand() === "send") {
const channel = interaction.channel;
if (channel?.isTextBased()) {
const actions = getActionsComponent();
await interaction.reply({
content: "Choose an action!",
components: [actions as any],
});
}
}
}
}
async createQuote(
{ content }: { content: string },
interaction: Interaction
) {
// find the channel with configured id
const channel = this.client.channels.cache.find(
(ch) => ch.id === config.discord.channelId
);
if (channel?.isTextBased()) {
// send quote content as message
await this.prismaService.client.message.create({
data: {
content,
userName: interaction.user.username,
},
});
await channel.send(content);
if (interaction.isChatInputCommand() || interaction.isModalSubmit()) {
await interaction.reply({
content: "Completed!",
ephemeral: true,
});
}
return;
}
}
}