Skip to content

Commit

Permalink
Create buttons (#32)
Browse files Browse the repository at this point in the history
* feat: create buttons

Co-authored-by: Vijay M <vijaybalamahalingam@users.noreply.github.com>

* fix: handle images

* chore: remove id option

* chore: handle cancel button
Co-authored-by: Alvin Ben <alvinbengeorge@users.noreply.github.com>

* chore: enhance button function

Co-authored-by: Alvin Ben <alvinbengeorge@users.noreply.github.com>

* chore: remove ununsed imports

* chore: change default value

* chore: update empty images

* fix: fix image logic

---------

Co-authored-by: Vijay M <vijaybalamahalingam@users.noreply.github.com>
Co-authored-by: vijaybalamahalingam <vijaybala.mahalingam@gmail.com>
Co-authored-by: Alvin Ben <alvinbengeorge@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 25, 2024
1 parent 145af7f commit 88a3cd7
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 96 deletions.
49 changes: 0 additions & 49 deletions src/commands/announce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@ import {
SlashCommandChannelOption,
TextInputBuilder,
TextInputStyle,
EmbedBuilder,
ColorResolvable,
} from "discord.js";
import { Command } from "../interface";
import { COLOR, FOOTER_VALUE } from "../config/constant";
import db from "../utils/database";
import { ObjectId } from "mongodb";
import { TemplateSchemaType } from "../types";

export default {
data: new SlashCommandBuilder()
Expand All @@ -27,7 +21,6 @@ export default {
.setRequired(true)
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement);
})
.addStringOption(option => option.setName("id").setDescription("The template you want to use").setRequired(false))
.addStringOption(option =>
option.setName("mention").setDescription("Who to mention").setRequired(false),
) as SlashCommandBuilder,
Expand All @@ -36,50 +29,8 @@ export default {
if (!interaction.guild) return;

const channelId = (interaction.options.getChannel("channel")?.id || interaction.channelId) as string;
const templateId = interaction.options.getString("id");
const mention = interaction.options.getString("mention") || "none";

if (templateId) {
const data = await (await db())
.collection<TemplateSchemaType>("templates")
.findOne({ _id: new ObjectId(templateId), isDeleted: false });

if (!data) {
await interaction.reply({ content: "Did not find a template with that ID", ephemeral: true });
return;
}

const embed = new EmbedBuilder()
.setTitle(data.title)
.setDescription(data.description)
.setColor(COLOR.WHITE as ColorResolvable)
.setTimestamp()
.setFooter({ text: FOOTER_VALUE });

const channel = interaction.guild.channels.cache.get(channelId);

if (!channel) {
await interaction.reply({ content: "Target Channel Not Found", ephemeral: true });
return;
}

if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement) {
await interaction.reply({ content: "Invalid Channel Provided. Please Provide a text channel" });
return;
}

if (mention !== "none") {
await channel.send({ content: `📢 Announcement ${mention}`, embeds: [embed] });
await interaction.reply({ content: `Embed sent to <#${channel.id}>` });
return;
}

await channel.send({ embeds: [embed] });

await interaction.reply({ content: `Embed sent to <#${channel.id}>` });
return;
}

const modal = new ModalBuilder().setCustomId(`announce-${channelId}-${mention}`).setTitle("Announcements");
const Title = new TextInputBuilder()
.setCustomId("Title")
Expand Down
36 changes: 0 additions & 36 deletions src/commands/echo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import {
TextInputStyle,
} from "discord.js";
import { Command } from "../interface";
import db from "../utils/database";
import { ObjectId } from "mongodb";
import { TemplateSchemaType } from "../types";

export default {
data: new SlashCommandBuilder()
Expand All @@ -24,47 +21,14 @@ export default {
.setRequired(true)
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement);
})
.addStringOption(option => option.setName("id").setDescription("The template you want to use").setRequired(false))
.addStringOption(option =>
option.setName("mention").setDescription("Who to mention").setRequired(false),
) as SlashCommandBuilder,

async execute(interaction) {
if (!interaction.guild) return;
const channelId = (interaction.options.getChannel("channel")?.id || interaction.channelId) as string;
const templateId = interaction.options.getString("id");
const mention = interaction.options.getString("mention") || "none";
if (templateId) {
const data = await (await db())
.collection<TemplateSchemaType>("templates")
.findOne({ _id: new ObjectId(templateId), isDeleted: false });

if (!data) {
await interaction.reply({ content: "Did not find a template with that ID", ephemeral: true });
return;
}
const channel = interaction.guild.channels.cache.get(channelId);

if (!channel) {
await interaction.reply({ content: "Target Channel Not Found", ephemeral: true });
return;
}

if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement) {
await interaction.reply({ content: "Invalid Channel Provided. Please Provide a text channel" });
return;
}

if (mention !== "none") {
await channel.send({ content: `📢 Announcement ${mention}\n# ${data.title}\n${data.description}` });
await interaction.reply({ content: `Message sent to <#${channel.id}>` });
return;
}

await channel.send({ content: `# ${data.title}\n${data.description}` });
await interaction.reply({ content: `Message sent to <#${channel.id}>` });
return;
}
const Title = new TextInputBuilder()
.setCustomId("Title")
.setLabel("Provide us with the Title")
Expand Down
28 changes: 24 additions & 4 deletions src/commands/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
ModalBuilder,
StringSelectMenuBuilder,
SlashCommandSubcommandBuilder,
ChannelType,
} from "discord.js";
import { Command } from "../interface";
import db from "../utils/database";

export default {
data: new SlashCommandBuilder()
.setName("template")
Expand All @@ -18,7 +20,16 @@ export default {
subcommand.setName("create").setDescription("Creates Templates"),
)
.addSubcommand((subcommand: SlashCommandSubcommandBuilder) =>
subcommand.setName("list").setDescription("Provides us with the list"),
subcommand
.setName("list")
.setDescription("Provides us with the list")
.addChannelOption(option =>
option
.setName("channel")
.setDescription("Channel to announce to")
.setRequired(true)
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement),
),
)
.addSubcommand((subcommand: SlashCommandSubcommandBuilder) =>
subcommand.setName("delete").setDescription("Deletes the Templates"),
Expand All @@ -42,10 +53,19 @@ export default {
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(1900);

const Image = new TextInputBuilder()
.setCustomId("image")
.setLabel("Provide us with the Image")
.setStyle(TextInputStyle.Paragraph)
.setMinLength(10)
.setMaxLength(4000)
.setRequired(false);

const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(Title);
const secondActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(Description);
const thirdActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(Image);

modal.addComponents(firstActionRow, secondActionRow);
modal.addComponents(firstActionRow, secondActionRow, thirdActionRow);
await interaction.showModal(modal);
} else if (subcommand === "delete") {
const data = await (await db())
Expand Down Expand Up @@ -92,11 +112,11 @@ export default {
});
return;
}

const channelId = (interaction.options.getChannel("channel")?.id || interaction.channelId) as string;
const templatesData = data.map(data => ({
label: data.title.slice(0, 50),
description: data.description.slice(0, 50),
value: data._id.toString(),
value: JSON.stringify({ templateId: data._id.toString(), channelId }),
}));

const selectMenu = new StringSelectMenuBuilder()
Expand Down
76 changes: 76 additions & 0 deletions src/events/handleButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Events, Interaction, EmbedBuilder, ColorResolvable, ChannelType } from "discord.js";
import db from "../utils/database";
import { ObjectId } from "mongodb";
import { COLOR, FOOTER_VALUE } from "../config/constant";

export default {
name: Events.InteractionCreate,
once: false,

async execute(interaction: Interaction) {
if (interaction.isButton()) {
if (!interaction.guild) return;
const [button, templateId, channelId] = interaction.customId.split("-");
if (!templateId || !channelId) {
await interaction.reply({ content: "Invalid ChannelId", ephemeral: true });
return;
}
const channel = interaction.guild.channels.cache.get(channelId);
if (!channel) {
await interaction.reply({ content: "Target Channel Not Found", ephemeral: true });
return;
}

if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement) {
await interaction.reply({ content: "Invalid Channel Provided. Please Provide a text channel" });
return;
}
const template = await (await db())
.collection("templates")
.findOne({ _id: new ObjectId(templateId), isDeleted: false });
if (!template) {
return;
}
const title = template.title;
const description = template.description;
const images = template.images;

if (button === "announce") {
const embeds: EmbedBuilder[] = [];
const embed = new EmbedBuilder()
.setTitle(title)
.setDescription(description)
.setColor(COLOR.WHITE as ColorResolvable)
.setTimestamp()
.setFooter({ text: FOOTER_VALUE });
if (!images) {
await channel.send({ content: "📢 Announcement", embeds: [embed] });
await interaction.reply({ content: `Embeds sent to <#${channel.id}>` });
return;
}
if (images.length > 0) {
const firstImage = images.shift();

if (firstImage) {
embed.setImage(firstImage);
}

embeds.push(embed);

images.forEach((url: string) => {
const newEmbed = new EmbedBuilder().setImage(url).setColor(COLOR.WHITE as ColorResolvable);
embeds.push(newEmbed);
});
} else {
await channel.send({ content: "📢 Announcement", embeds: [embed] });
await interaction.reply({ content: `Embeds sent to <#${channel.id}>` });
}
await channel.send({ content: "📢 Announcement", embeds: embeds });
await interaction.reply({ content: `Embeds sent to <#${channel.id}>` });
} else if (button === "echo") {
await channel.send({ content: `📢 Announcement\n# ${title}\n${description}` });
await interaction.reply({ content: `Message sent to <#${channel.id}>` });
}
}
},
};
13 changes: 9 additions & 4 deletions src/events/handleModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ export default {
if (!interaction.isModalSubmit()) return;
const title = interaction.fields.getTextInputValue("Title");
const description = interaction.fields.getTextInputValue("Description");

const [action, channelId, mention] = interaction.customId.split("-");

if (action === "template") {
const image = interaction.fields.getTextInputValue("image") || "";
const images = image.split("\n");
const validImages = images.filter(url => isValidImageUrl(url));

const data = await (await db())
.collection("templates")
.find({ guildId: interaction.guildId, isDeleted: false })
Expand All @@ -56,6 +59,7 @@ export default {
title,
description,
guildId: interaction.guild.id,
images: validImages,
isDeleted: false,
});
await interaction.reply({ content: "Template added to database!" });
Expand All @@ -75,6 +79,10 @@ export default {
}

if (action === "announce") {
const image = interaction.fields.getTextInputValue("image") || "none";
const images = image.split("\n");
const validImages = images.filter(url => isValidImageUrl(url));

const embeds: EmbedBuilder[] = [];
const embed = new EmbedBuilder()
.setTitle(title)
Expand All @@ -83,7 +91,6 @@ export default {
.setTimestamp()
.setFooter({ text: FOOTER_VALUE });

const image = interaction.fields.getTextInputValue("image") || "none";
if (image === "none") {
if (mention === "none") {
await channel.send({ embeds: [embed] });
Expand All @@ -93,8 +100,6 @@ export default {
await interaction.reply({ content: `Embed sent to <#${channel.id}>` });
return;
}
const images = image.split("\n");
const validImages = images.filter(url => isValidImageUrl(url));

if (validImages.length > 0) {
const firstImage = validImages.shift();
Expand Down
17 changes: 14 additions & 3 deletions src/events/handleTemplates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Events, Interaction } from "discord.js";
import { Events, Interaction, ButtonBuilder, ButtonStyle, ActionRowBuilder } from "discord.js";
import db from "../utils/database";
import { ObjectId } from "mongodb";

Expand All @@ -18,9 +18,20 @@ export default {
await collection.updateOne(query, update);
await interaction.reply("Successfully Deleted");
} else if (interaction.customId === "chooseTemplate") {
const templateId = interaction.values[0];
const { templateId, channelId } = JSON.parse(interaction.values[0] || "{}");
const announce = new ButtonBuilder()
.setCustomId(`announce-${templateId}-${channelId}`)
.setLabel("Announce")
.setStyle(ButtonStyle.Primary);
const echo = new ButtonBuilder()
.setCustomId(`echo-${templateId}-${channelId}`)
.setLabel("Echo")
.setStyle(ButtonStyle.Success);
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(announce, echo);
await interaction.reply({
content: `Use \`/announce\` or \`/echo\` command and provide with this \`${templateId}\` to use this template directly`,
content: "Which action would you like to perform?",
components: [button],
ephemeral: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions src/types/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const templateSchema = z.object({
title: z.string(),
description: z.string(),
guildId: z.string(),
images: z.array(z.string()),
isDeleted: z.boolean(),
});

Expand Down

0 comments on commit 88a3cd7

Please sign in to comment.