possibly finished current features

pull/11/head
TheCodedProf 3 years ago
parent 1f67504a24
commit 01cba76c6d

@ -3,7 +3,6 @@ import type { HistorySchema } from "../../utils/database.js";
import Discord, { import Discord, {
CommandInteraction, CommandInteraction,
GuildMember, GuildMember,
Interaction,
Message, Message,
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
@ -401,12 +400,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}); });
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user);
m,
(m: Interaction) =>
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
(m) => m.customId === "modify"
);
} catch (e) { } catch (e) {
timedOut = true; timedOut = true;
continue; continue;

@ -8,11 +8,8 @@ import { ActionRowBuilder,
ChannelSelectMenuBuilder, ChannelSelectMenuBuilder,
ChannelSelectMenuInteraction, ChannelSelectMenuInteraction,
CommandInteraction, CommandInteraction,
Interaction,
Message, Message,
MessageComponentInteraction,
ModalBuilder, ModalBuilder,
ModalSubmitInteraction,
RoleSelectMenuBuilder, RoleSelectMenuBuilder,
RoleSelectMenuInteraction, RoleSelectMenuInteraction,
StringSelectMenuBuilder, StringSelectMenuBuilder,
@ -317,12 +314,7 @@ const wordMenu = async (interaction: StringSelectMenuInteraction, m: Message, cu
await i.showModal(modal); await i.showModal(modal);
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user);
m,
(m: Interaction) =>
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
(m) => m.customId === "back"
);
} catch (e) { } catch (e) {
break; break;
} }
@ -612,12 +604,7 @@ const mentionMenu = async (interaction: StringSelectMenuInteraction, m: Message,
await i.showModal(modal); await i.showModal(modal);
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user);
m,
(m: Interaction) =>
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
(m) => m.customId === "back"
);
} catch (e) { } catch (e) {
break; break;
} }
@ -912,7 +899,8 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
} }
} }
} while(!closed) } while(!closed);
await interaction.deleteReply()
}; };

@ -1,195 +1,105 @@
import { LoadingEmbed } from "../../../utils/defaults.js"; import { LoadingEmbed } from "../../../utils/defaults.js";
import { ChannelType } from "discord-api-types/v9"; import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelSelectMenuBuilder } from "discord.js";
import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonInteraction } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js"; import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
import confirmationMessage from "../../../utils/confirmationMessage.js";
import getEmojiByName from "../../../utils/getEmojiByName.js"; import getEmojiByName from "../../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js"; import client from "../../../utils/client.js";
import { getCommandMentionByName } from "../../../utils/getCommandDataByName.js";
const command = (builder: SlashCommandSubcommandBuilder) => const command = (builder: SlashCommandSubcommandBuilder) =>
builder builder
.setName("attachments") .setName("attachments")
.setDescription("Where attachments should be logged to (Premium only)") .setDescription("Where attachments should be logged to (Premium only)")
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to log attachments in")
.addChannelTypes(ChannelType.GuildText)
.setRequired(false)
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => { const callback = async (interaction: CommandInteraction): Promise<unknown> => {
const m = (await interaction.reply({ await interaction.reply({
embeds: LoadingEmbed, embeds: LoadingEmbed,
ephemeral: true, ephemeral: true,
fetchReply: true fetchReply: true
})) as Discord.Message; })
if (interaction.options.get("channel")?.channel) {
let channel; if(!client.database.premium.hasPremium(interaction.guild!.id)) return interaction.editReply({
try { embeds: [
channel = interaction.options.get("channel")?.channel; new EmojiEmbed()
} catch { .setTitle("Premium Required")
return await interaction.editReply({ .setDescription(`This feature is exclusive to ${getCommandMentionByName("nucleus/premium")} servers.`)
embeds: [ .setStatus("Danger")
new EmojiEmbed() .setEmoji("NUCLEUS.PREMIUM")
.setEmoji("CHANNEL.TEXT.DELETE") ]
.setTitle("Attachment Log Channel") });
.setDescription("The channel you provided is not a valid channel")
.setStatus("Danger") let data = await client.database.guilds.read(interaction.guild!.id);
] let channel = data.logging.staff.channel;
});
} let closed = false;
channel = channel as Discord.TextChannel; do {
if (channel.guild.id !== interaction.guild!.id) { const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
return interaction.editReply({ .addComponents(
embeds: [ new ChannelSelectMenuBuilder()
new EmojiEmbed() .setCustomId("channel")
.setTitle("Attachment Log Channel") .setPlaceholder("Select a channel")
.setDescription("You must choose a channel in this server") );
.setStatus("Danger") const buttons = new ActionRowBuilder<ButtonBuilder>()
.setEmoji("CHANNEL.TEXT.DELETE") .addComponents(
] new ButtonBuilder()
}); .setCustomId("clear")
} .setLabel("Clear")
const confirmation = await new confirmationMessage(interaction) .setStyle(ButtonStyle.Danger)
.setEmoji("CHANNEL.TEXT.EDIT") .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as Discord.APIMessageComponentEmoji)
.setTitle("Attachment Log Channel") .setDisabled(!channel),
new ButtonBuilder()
.setCustomId("save")
.setLabel("Save")
.setStyle(ButtonStyle.Success)
.setEmoji(getEmojiByName("ICONS.SAVE", "id") as Discord.APIMessageComponentEmoji)
.setDisabled(channel === data.logging.staff.channel)
);
const embed = new EmojiEmbed()
.setTitle("Attachments")
.setDescription( .setDescription(
"This will be the channel all attachments will be sent to.\n\n" + `The channel to send all attachments from the server, allowing you to check them if they are deleted` +
`Are you sure you want to set the attachment log channel to <#${channel.id}>?` `**Channel:** ${channel ? `<#${channel}>` : "*None*"}\n`
) )
.setColor("Warning") .setStatus("Success")
.setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE") .setEmoji("CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
await client.database.guilds.write(interaction.guild!.id, {
"logging.attachments.channel": channel.id
});
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
const data = {
meta: {
type: "attachmentChannelUpdate",
displayName: "Attachment Log Channel Updated",
calculateType: "nucleusSettingsUpdated",
color: NucleusColors.yellow,
emoji: "CHANNEL.TEXT.EDIT",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
channel: entry(channel.id, renderChannel(channel))
},
hidden: {
guild: interaction.guild!.id
}
};
log(data);
} catch (e) {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Attachment Log Channel")
.setDescription("Something went wrong and the attachment log channel could not be set")
.setStatus("Danger")
.setEmoji("CHANNEL.TEXT.DELETE")
],
components: []
});
}
} else {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Attachment Log Channel")
.setDescription("No changes were made")
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: []
});
}
}
let clicks = 0;
const data = await client.database.guilds.read(interaction.guild!.id);
let channel = data.logging.staff.channel;
let timedOut = false;
while (!timedOut) {
await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [embed],
new EmojiEmbed() components: [channelMenu, buttons]
.setTitle("Attachment Log Channel")
.setDescription(
channel
? `Your attachment log channel is currently set to <#${channel}>`
: "This server does not have an attachment log channel" +
(await client.database.premium.hasPremium(interaction.guild!.id)
? ""
: "\n\nThis server does not have premium, so this feature is disabled")
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel(clicks ? "Click again to confirm" : "Reset channel")
.setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Danger)
.setDisabled(!channel)
])
]
}); });
let i;
let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
try { try {
i = await m.awaitMessageComponent({ i = (await interaction.channel!.awaitMessageComponent({
time: 300000, filter: (i) => i.user.id === interaction.user.id,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } time: 300000
}); })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
} catch (e) { } catch (e) {
timedOut = true; closed = true;
continue; break;
} }
await i.deferUpdate(); await i.deferUpdate();
if ((i.component as unknown as ButtonInteraction).customId === "clear") { if(i.isButton()) {
clicks ++; switch (i.customId) {
if (clicks === 2) { case "clear": {
clicks = 0; channel = null;
await client.database.guilds.write(interaction.guild!.id, null, ["logging.announcements.channel"]); break;
channel = null; }
case "save": {
await client.database.guilds.write(interaction.guild!.id, {
"logging.attachments.channel": channel
});
data = await client.database.guilds.read(interaction.guild!.id);
break;
}
} }
} else {
channel = i.values[0]!;
} }
}
await interaction.editReply({ } while (!closed);
embeds: [ await interaction.deleteReply()
new EmojiEmbed()
.setTitle("Attachment Log Channel")
.setDescription(
channel
? `Your attachment log channel is currently set to <#${channel}>`
: "This server does not have an attachment log channel"
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
.setFooter({ text: "Message closed" })
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel("Clear")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Secondary)
.setDisabled(true)
])
]
});
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -1,9 +1,11 @@
import { LoadingEmbed } from "../../../utils/defaults.js"; import { LoadingEmbed } from "../../../utils/defaults.js";
import Discord, { CommandInteraction, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, EmbedBuilder } from "discord.js"; import Discord, { CommandInteraction, ActionRowBuilder, ChannelSelectMenuBuilder, ChannelType, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonInteraction, StringSelectMenuInteraction, ChannelSelectMenuInteraction, APIMessageComponentEmoji } from "discord.js";
import { SlashCommandSubcommandBuilder, StringSelectMenuOptionBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
import client from "../../../utils/client.js"; import client from "../../../utils/client.js";
import compare from "lodash";
import { toHexArray, toHexInteger } from "../../../utils/calculate.js"; import { toHexArray, toHexInteger } from "../../../utils/calculate.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../../utils/getEmojiByName.js";
const logs: Record<string, string> = { const logs: Record<string, string> = {
channelUpdate: "Channels created, deleted or modified", channelUpdate: "Channels created, deleted or modified",
@ -24,85 +26,135 @@ const logs: Record<string, string> = {
webhookUpdate: "Webhooks created or deleted", webhookUpdate: "Webhooks created or deleted",
guildMemberVerify: "Member runs verify", guildMemberVerify: "Member runs verify",
autoModeratorDeleted: "Messages auto deleted by Nucleus", autoModeratorDeleted: "Messages auto deleted by Nucleus",
nucleusSettingsUpdated: "Nucleus' settings updated by a moderator", ticketUpdate: "Tickets created or deleted",
ticketUpdate: "Tickets created or deleted" //nucleusSettingsUpdated: "Nucleus' settings updated by a moderator" // TODO
}; };
const command = (builder: SlashCommandSubcommandBuilder) => const command = (builder: SlashCommandSubcommandBuilder) =>
builder.setName("events").setDescription("Sets what events should be logged"); builder
.setName("events")
.setDescription("The general log channel for the server, and setting what events to show")
const callback = async (interaction: CommandInteraction): Promise<void> => { const callback = async (interaction: CommandInteraction): Promise<void> => {
await interaction.reply({ const m = (await interaction.reply({
embeds: LoadingEmbed, embeds: LoadingEmbed,
fetchReply: true, ephemeral: true,
ephemeral: true fetchReply: true
}); })) as Discord.Message;
let m: Message;
let timedOut = false; let config = await client.database.guilds.read(interaction.guild!.id);
let data = Object.assign({}, config.logging.logs);
let closed = false;
let show = false;
do { do {
const config = await client.database.guilds.read(interaction.guild!.id); const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
const converted = toHexArray(config.logging.logs.toLog); .addComponents(
const selectPane = new StringSelectMenuBuilder() new ChannelSelectMenuBuilder()
.setPlaceholder("Set events to log") .setCustomId("channel")
.setMaxValues(Object.keys(logs).length) .setPlaceholder("Select a channel")
.setCustomId("logs") .setChannelTypes(ChannelType.GuildText)
.setMinValues(0) )
Object.keys(logs).map((e, i) => { const buttons = new ActionRowBuilder<ButtonBuilder>()
selectPane.addOptions(new StringSelectMenuOptionBuilder() .addComponents(
.setLabel(logs[e]!) new ButtonBuilder()
.setValue(i.toString()) .setCustomId("switch")
.setDefault(converted.includes(e)) .setLabel(data.enabled ? "Enabled" : "Disabled")
.setStyle(data.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
.setEmoji(getEmojiByName((data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS"), "id") as APIMessageComponentEmoji),
new ButtonBuilder()
.setCustomId("remove")
.setLabel("Remove")
.setStyle(ButtonStyle.Danger)
.setDisabled(!data.channel),
new ButtonBuilder()
.setCustomId("show")
.setLabel("Manage Events")
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setCustomId("save")
.setLabel("Save")
.setStyle(ButtonStyle.Success)
.setDisabled(compare.isEqual(data, config.logging.logs))
)
const converted = toHexArray(data.toLog);
const toLogMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
.addComponents(
new StringSelectMenuBuilder()
.setPlaceholder("Set events to log")
.setMaxValues(Object.keys(logs).length)
.setCustomId("logs")
.setMinValues(0)
)
Object.keys(logs).map((e) => {
toLogMenu.components[0]!.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel(logs[e]!)
.setValue(e)
.setDefault(converted.includes(e))
) )
}); });
m = (await interaction.editReply({
embeds: [ const embed = new EmojiEmbed()
new EmojiEmbed() .setTitle("General Log Channel")
.setTitle("Logging Events") .setStatus("Success")
.setDescription( .setEmoji("CHANNEL.TEXT.CREATE")
"Below are the events being logged in the server. You can toggle them on and off in the dropdown" .setDescription(
) `This is the channel that all events you set to be logged will be stored\n` +
.setStatus("Success") `**Channel:** ${data.channel ? `<#${data.channel}>` : "None"}\n`
.setEmoji("CHANNEL.TEXT.CREATE") )
],
components: [ let components: ActionRowBuilder<ButtonBuilder | ChannelSelectMenuBuilder | StringSelectMenuBuilder>[] = [channelMenu, buttons];
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectPane), if(show) components.push(toLogMenu);
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder().setLabel("Select all").setStyle(ButtonStyle.Primary).setCustomId("all"), await interaction.editReply({
new ButtonBuilder().setLabel("Select none").setStyle(ButtonStyle.Danger).setCustomId("none") embeds: [embed],
]) components: components
] });
})) as Message;
let i; let i: ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
try { try {
i = await m.awaitMessageComponent({ i = await m.awaitMessageComponent({
time: 300000, filter: (i) => i.user.id === interaction.user.id,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } time: 300000
}); }) as ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
} catch (e) { } catch (e) {
timedOut = true; closed = true;
continue; break;
} }
await i.deferUpdate(); await i.deferUpdate();
if (i.isStringSelectMenu() && i.customId === "logs") {
const selected = i.values; if(i.isButton()) {
const newLogs = toHexInteger(selected.map((e: string) => Object.keys(logs)[parseInt(e)]!)); switch(i.customId) {
await client.database.guilds.write(interaction.guild!.id, { case "show": {
"logging.logs.toLog": newLogs show = !show;
}); break;
} else if (i.customId === "all") { }
const newLogs = toHexInteger(Object.keys(logs).map((e) => e)); case "switch": {
await client.database.guilds.write(interaction.guild!.id, { data.enabled = !data.enabled;
"logging.logs.toLog": newLogs break;
}); }
} else if (i.customId === "none") { case "save": {
await client.database.guilds.write(interaction.guild!.id, { await client.database.guilds.write(interaction.guild!.id, {"logging.logs": data});
"logging.logs.toLog": 0 config = await client.database.guilds.read(interaction.guild!.id);
}); data = Object.assign({}, config.logging.logs);
break;
}
case "remove": {
data.channel = null;
break;
}
}
} else if(i.isStringSelectMenu()) {
let hex = toHexInteger(i.values);
data.toLog = hex;
} else if(i.isChannelSelectMenu()) {
data.channel = i.values[0]!;
} }
} while (!timedOut);
await interaction.editReply({ embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })] }); } while (!closed);
return; await interaction.deleteReply()
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -1,197 +0,0 @@
import { LoadingEmbed } from "../../../utils/defaults.js";
import { ChannelType } from "discord-api-types/v9";
import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonInteraction, ButtonComponent } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
import confirmationMessage from "../../../utils/confirmationMessage.js";
import getEmojiByName from "../../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("general")
.setDescription("Sets or shows the log channel")
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to set the log channel to")
.addChannelTypes(ChannelType.GuildText)
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
const m = (await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
fetchReply: true
})) as Discord.Message;
if (interaction.options.get("channel")?.channel) {
let channel;
try {
channel = interaction.options.get("channel")?.channel;
} catch {
return await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.TEXT.DELETE")
.setTitle("Log Channel")
.setDescription("The channel you provided is not a valid channel")
.setStatus("Danger")
]
});
}
channel = channel as Discord.TextChannel;
if (channel.guild.id !== interaction.guild!.id) {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Log Channel")
.setDescription("You must choose a channel in this server")
.setStatus("Danger")
.setEmoji("CHANNEL.TEXT.DELETE")
]
});
}
const confirmation = await new confirmationMessage(interaction)
.setEmoji("CHANNEL.TEXT.EDIT")
.setTitle("Log Channel")
.setDescription(`Are you sure you want to set the log channel to <#${channel.id}>?`)
.setColor("Warning")
.setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
await client.database.guilds.write(interaction.guild!.id, {
"logging.logs.channel": channel.id
});
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
const data = {
meta: {
type: "logChannelUpdate",
displayName: "Log Channel Changed",
calculateType: "nucleusSettingsUpdated",
color: NucleusColors.yellow,
emoji: "CHANNEL.TEXT.EDIT",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
channel: entry(channel.id, renderChannel(channel))
},
hidden: {
guild: channel.guild.id
}
};
log(data);
} catch (e) {
console.log(e);
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Log Channel")
.setDescription("Something went wrong and the log channel could not be set")
.setStatus("Danger")
.setEmoji("CHANNEL.TEXT.DELETE")
],
components: []
});
}
} else {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Log Channel")
.setDescription("No changes were made")
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: []
});
}
}
let clicks = 0;
const data = await client.database.guilds.read(interaction.guild!.id);
let channel = data.logging.logs.channel;
let timedOut = false;
while (!timedOut) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Log channel")
.setDescription(
channel
? `Your log channel is currently set to <#${channel}>`
: "This server does not have a log channel"
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel(clicks ? "Click again to confirm" : "Reset channel")
.setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Danger)
.setDisabled(!channel)
])
]
});
let i: ButtonInteraction;
try {
i = await m.awaitMessageComponent({
time: 300000,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
}) as ButtonInteraction;
} catch (e) {
timedOut = true;
}
i = i!
await i.deferUpdate();
if ((i.component as ButtonComponent).customId === "clear") {
clicks ++;
if (clicks === 2) {
clicks = 0;
await client.database.guilds.write(interaction.guild!.id, null, ["logging.logs.channel"]);
channel = null;
}
}
}
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Log channel")
.setDescription(
channel
? `Your log channel is currently set to <#${channel}>`
: "This server does not have a log channel"
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
.setFooter({ text: "Message closed" })
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel("Clear")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Secondary)
.setDisabled(true)
])
]
});
};
const check = (interaction: CommandInteraction, _partial: boolean = false) => {
const member = interaction.member as Discord.GuildMember;
if (!member.permissions.has("ManageGuild"))
return "You must have the *Manage Server* permission to use this command";
return true;
};
export { command };
export { callback };
export { check };

@ -1,8 +1,6 @@
import { LoadingEmbed } from "../../../utils/defaults.js"; import { LoadingEmbed } from "../../../utils/defaults.js";
import { ChannelType } from "discord-api-types/v9"; import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelSelectMenuBuilder } from "discord.js";
import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent } from "discord.js";
import EmojiEmbed from "../../../utils/generateEmojiEmbed.js"; import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
import confirmationMessage from "../../../utils/confirmationMessage.js";
import getEmojiByName from "../../../utils/getEmojiByName.js"; import getEmojiByName from "../../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../../utils/client.js"; import client from "../../../utils/client.js";
@ -11,182 +9,86 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
builder builder
.setName("warnings") .setName("warnings")
.setDescription("Settings for the staff notifications channel") .setDescription("Settings for the staff notifications channel")
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to set the staff notifications channel to")
.addChannelTypes(ChannelType.GuildText)
.setRequired(false)
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => { const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return; if (!interaction.guild) return;
const m = (await interaction.reply({ await interaction.reply({
embeds: LoadingEmbed, embeds: LoadingEmbed,
ephemeral: true, ephemeral: true,
fetchReply: true fetchReply: true
})) as Discord.Message; })
if (interaction.options.get("channel")?.channel) {
let channel; let data = await client.database.guilds.read(interaction.guild.id);
try { let channel = data.logging.staff.channel;
channel = interaction.options.get("channel")?.channel; let closed = false;
} catch { do {
return await interaction.editReply({ const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
embeds: [ .addComponents(
new EmojiEmbed() new ChannelSelectMenuBuilder()
.setEmoji("CHANNEL.TEXT.DELETE") .setCustomId("channel")
.setTitle("Staff Notifications Channel") .setPlaceholder("Select a channel")
.setDescription("The channel you provided is not a valid channel") );
.setStatus("Danger") const buttons = new ActionRowBuilder<ButtonBuilder>()
] .addComponents(
}); new ButtonBuilder()
} .setCustomId("clear")
channel = channel as Discord.TextChannel; .setLabel("Clear")
if (channel.guild.id !== interaction.guild.id) { .setStyle(ButtonStyle.Danger)
return interaction.editReply({ .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as Discord.APIMessageComponentEmoji)
embeds: [ .setDisabled(!channel),
new EmojiEmbed() new ButtonBuilder()
.setTitle("Staff Notifications Channel") .setCustomId("save")
.setDescription("You must choose a channel in this server") .setLabel("Save")
.setStatus("Danger") .setStyle(ButtonStyle.Success)
.setEmoji("CHANNEL.TEXT.DELETE") .setEmoji(getEmojiByName("ICONS.SAVE", "id") as Discord.APIMessageComponentEmoji)
] .setDisabled(channel === data.logging.staff.channel)
}); );
}
const confirmation = await new confirmationMessage(interaction) const embed = new EmojiEmbed()
.setEmoji("CHANNEL.TEXT.EDIT")
.setTitle("Staff Notifications Channel") .setTitle("Staff Notifications Channel")
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
.setDescription( .setDescription(
"This will be the channel all notifications, updates, user reports etc. will be sent to.\n\n" + `Logs which require an action from a moderator or administrator will be sent to this channel.\n` +
`Are you sure you want to set the staff notifications channel to <#${channel.id}>?` `**Channel:** ${channel ? `<#${channel}>` : "*None*"}\n`
) )
.setColor("Warning")
.setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
await client.database.guilds.write(interaction.guild.id, {
"logging.staff.channel": channel.id
});
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
const data = {
meta: {
type: "staffChannelUpdate",
displayName: "Staff Notifications Channel Updated",
calculateType: "nucleusSettingsUpdated",
color: NucleusColors.yellow,
emoji: "CHANNEL.TEXT.EDIT",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
channel: entry(channel.id, renderChannel(channel))
},
hidden: {
guild: interaction.guild.id
}
};
log(data);
} catch (e) {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Staff Notifications Channel")
.setDescription("Something went wrong and the staff notifications channel could not be set")
.setStatus("Danger")
.setEmoji("CHANNEL.TEXT.DELETE")
],
components: []
});
}
} else {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Staff Notifications Channel")
.setDescription("No changes were made")
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: []
});
}
}
let clicks = 0;
const data = await client.database.guilds.read(interaction.guild.id);
let channel = data.logging.staff.channel;
let timedOut = false;
while (!timedOut) {
await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [embed],
new EmojiEmbed() components: [channelMenu, buttons]
.setTitle("Staff Notifications channel")
.setDescription(
channel
? `Your staff notifications channel is currently set to <#${channel}>`
: "This server does not have a staff notifications channel"
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel(clicks ? "Click again to confirm" : "Reset channel")
.setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Danger)
.setDisabled(!channel)
])
]
}); });
let i;
let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
try { try {
i = await m.awaitMessageComponent({ i = (await interaction.channel!.awaitMessageComponent({
time: 300000, filter: (i) => i.user.id === interaction.user.id,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } time: 300000
}); })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
} catch (e) { } catch (e) {
timedOut = true; closed = true;
continue; break;
} }
await i.deferUpdate(); await i.deferUpdate();
if ((i.component as ButtonComponent).customId === "clear") { if(i.isButton()) {
clicks ++; switch (i.customId) {
if (clicks === 2) { case "clear": {
clicks = 0; channel = null;
await client.database.guilds.write(interaction.guild.id, null, ["logging.staff.channel"]); break;
channel = null; }
case "save": {
await client.database.guilds.write(interaction.guild!.id, {
"logging.warnings.channel": channel
});
data = await client.database.guilds.read(interaction.guild!.id);
break;
}
} }
} else {
channel = i.values[0]!;
} }
} } while (!closed);
await interaction.editReply({
embeds: [ await interaction.deleteReply()
new EmojiEmbed()
.setTitle("Staff Notifications channel")
.setDescription(
channel
? `Your staff notifications channel is currently set to <#${channel}>`
: "This server does not have a staff notifications channel"
)
.setStatus("Success")
.setEmoji("CHANNEL.TEXT.CREATE")
.setFooter({ text: "Message closed" })
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel("Clear")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Secondary)
.setDisabled(true)
])
]
});
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -1,5 +1,5 @@
import { LoadingEmbed } from "../../utils/defaults.js"; import { LoadingEmbed } from "../../utils/defaults.js";
import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent, TextInputBuilder, Message, RoleSelectMenuBuilder } from "discord.js"; import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, ButtonComponent, TextInputBuilder, RoleSelectMenuBuilder } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js"; import getEmojiByName from "../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
@ -12,17 +12,16 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.setDescription("Links and text shown to a user after a moderator action is performed") .setDescription("Links and text shown to a user after a moderator action is performed")
const callback = async (interaction: CommandInteraction): Promise<void> => { const callback = async (interaction: CommandInteraction): Promise<void> => {
await interaction.reply({ const m = await interaction.reply({
embeds: LoadingEmbed, embeds: LoadingEmbed,
ephemeral: true, ephemeral: true,
fetchReply: true fetchReply: true
}); });
let m: Message;
let timedOut = false; let timedOut = false;
while (!timedOut) { while (!timedOut) {
const config = await client.database.guilds.read(interaction.guild!.id); const config = await client.database.guilds.read(interaction.guild!.id);
const moderation = config.moderation; const moderation = config.moderation;
m = await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [
new EmojiEmbed() new EmojiEmbed()
.setTitle("Moderation Commands") .setTitle("Moderation Commands")
@ -152,11 +151,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
}); });
let out: Discord.ModalSubmitInteraction | null; let out: Discord.ModalSubmitInteraction | null;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
m,
(m) => m.channel!.id === interaction.channel!.id,
(_) => true
) as Discord.ModalSubmitInteraction | null;
} catch (e) { } catch (e) {
continue; continue;
} }
@ -175,6 +170,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
} }
} }
} }
await interaction.deleteReply()
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -144,11 +144,7 @@ const editNameDescription = async (i: ButtonInteraction, interaction: StringSele
let out: Discord.ModalSubmitInteraction | null; let out: Discord.ModalSubmitInteraction | null;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
m,
(m) => m.channel!.id === interaction.channel!.id,
(_) => true
) as Discord.ModalSubmitInteraction | null;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
out = null; out = null;
@ -472,7 +468,8 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
} }
} }
} while (!closed) } while (!closed);
await interaction.deleteReply()
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -74,7 +74,6 @@ const showModal = async (interaction: MessageComponentInteraction, current: { en
type ObjectSchema = Record<string, {name: string, enabled: boolean}> type ObjectSchema = Record<string, {name: string, enabled: boolean}>
const addStatsChannel = async (interaction: CommandInteraction, m: Message, currentObject: ObjectSchema): Promise<ObjectSchema> => { const addStatsChannel = async (interaction: CommandInteraction, m: Message, currentObject: ObjectSchema): Promise<ObjectSchema> => {
let closed = false; let closed = false;
let cancelled = false; let cancelled = false;
@ -172,11 +171,7 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr
}); });
showModal(i, {name: newChannelName, enabled: newChannelEnabled}) showModal(i, {name: newChannelName, enabled: newChannelEnabled})
const out: Discord.ModalSubmitInteraction | ButtonInteraction| null = await modalInteractionCollector( const out: Discord.ModalSubmitInteraction | ButtonInteraction| null = await modalInteractionCollector(m, interaction.user);
m,
(m) => m.channel!.id === interaction.channel!.id && m.user!.id === interaction.user!.id,
(i) => i.channel!.id === interaction.channel!.id && i.user!.id === interaction.user!.id && i.message!.id === m.id
);
if (!out) continue; if (!out) continue;
if (out.isButton()) continue; if (out.isButton()) continue;
newChannelName = out.fields.getTextInputValue("text"); newChannelName = out.fields.getTextInputValue("text");
@ -340,11 +335,7 @@ const callback = async (interaction: CommandInteraction) => {
}); });
let out: Discord.ModalSubmitInteraction | null; let out: Discord.ModalSubmitInteraction | null;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user) as Discord.ModalSubmitInteraction | null;
m,
(m) => m.channel!.id === interaction.channel!.id,
(_) => true
) as Discord.ModalSubmitInteraction | null;
} catch (e) { } catch (e) {
continue; continue;
} }
@ -396,6 +387,7 @@ const callback = async (interaction: CommandInteraction) => {
} }
} while (!closed); } while (!closed);
await interaction.deleteReply()
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -181,11 +181,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}); });
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user);
m,
(m) => m.user.id === interaction.user.id,
(m) => m.customId === "back"
);
} catch (e) { } catch (e) {
continue; continue;
} }
@ -207,6 +203,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
} }
} }
} }
await interaction.deleteReply()
}; };
@ -384,11 +381,7 @@ async function manageTypes(interaction: CommandInteraction, data: GuildConfig["t
}); });
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user);
m,
(m) => m.user.id === interaction.user.id,
(m) => m.customId === "back"
);
} catch (e) { } catch (e) {
continue; continue;
} }

@ -63,11 +63,7 @@ const editName = async (i: ButtonInteraction, interaction: StringSelectMenuInter
let out: ModalSubmitInteraction | null; let out: ModalSubmitInteraction | null;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, interaction.user) as ModalSubmitInteraction | null;
m,
(m) => m.channel!.id === interaction.channel!.id,
(_) => true
) as ModalSubmitInteraction | null;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
out = null; out = null;
@ -440,7 +436,8 @@ const callback = async (interaction: CommandInteraction) => {
} }
} }
} while (!closed) } while (!closed);
await interaction.deleteReply()
} }
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -1,33 +1,25 @@
import { LoadingEmbed } from "../../utils/defaults.js"; import { LoadingEmbed } from "../../utils/defaults.js";
import Discord, { import Discord, {
CommandInteraction, CommandInteraction,
Interaction,
Message, Message,
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
MessageComponentInteraction,
ModalSubmitInteraction,
Role,
ButtonStyle, ButtonStyle,
StringSelectMenuBuilder, RoleSelectMenuBuilder,
TextInputBuilder, APIMessageComponentEmoji
EmbedBuilder,
ButtonComponent
} from "discord.js"; } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import confirmationMessage from "../../utils/confirmationMessage.js";
import getEmojiByName from "../../utils/getEmojiByName.js"; import getEmojiByName from "../../utils/getEmojiByName.js";
import type { SlashCommandSubcommandBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
import client from "../../utils/client.js"; import client from "../../utils/client.js";
import { modalInteractionCollector } from "../../utils/dualCollector.js"; import { getCommandMentionByName } from "../../utils/getCommandDataByName.js";
const command = (builder: SlashCommandSubcommandBuilder) => const command = (builder: SlashCommandSubcommandBuilder) =>
builder builder
.setName("verify") .setName("verify")
.setDescription("Manage the role given after typing /verify") .setDescription("Manage the role given after a user runs /verify")
.addRoleOption((option) =>
option.setName("role").setDescription("The role to give after verifying").setRequired(false)
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => { const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return; if (!interaction.guild) return;
@ -36,153 +28,79 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
ephemeral: true, ephemeral: true,
fetchReply: true fetchReply: true
})) as Message; })) as Message;
if (interaction.options.get("role")?.role) {
let role: Role; let closed = false;
try { let config = await client.database.guilds.read(interaction.guild.id);
role = interaction.options.get("role")?.role as Role; let data = Object.assign({}, config.verify);
} catch { do {
return await interaction.editReply({ console.log(config.verify, data)
embeds: [ const selectMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
new EmojiEmbed() .addComponents(
.setEmoji("GUILD.ROLES.DELETE") new RoleSelectMenuBuilder()
.setTitle("Verify Role") .setCustomId("role")
.setDescription("The role you provided is not a valid role") .setPlaceholder("Select a role")
.setStatus("Danger") );
]
}); const buttons = new ActionRowBuilder<ButtonBuilder>()
} .addComponents(
role = role as Discord.Role; new ButtonBuilder()
if (role.guild.id !== interaction.guild.id) { .setCustomId("switch")
return interaction.editReply({ .setLabel(data.enabled ? "Disabled" : "Enabled")
embeds: [ .setStyle(data.enabled ? ButtonStyle.Danger : ButtonStyle.Success)
new EmojiEmbed() .setEmoji(getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji),
.setTitle("Verify Role") new ButtonBuilder()
.setDescription("You must choose a role in this server") .setCustomId("save")
.setStatus("Danger") .setLabel("Save")
.setEmoji("GUILD.ROLES.DELETE") .setStyle(ButtonStyle.Success)
] .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
}); .setDisabled(data.role === config.verify.role && data.enabled === config.verify.enabled)
} );
const confirmation = await new confirmationMessage(interaction)
.setEmoji("GUILD.ROLES.EDIT") const embed = new EmojiEmbed()
.setTitle("Verify Role") .setTitle("Verify Role")
.setDescription(`Are you sure you want to set the verify role to <@&${role.id}>?`) .setDescription(
.setColor("Warning") `Select a role to be given to users after they run ${getCommandMentionByName("verify")}` +
.setFailedMessage("No changes were made", "Warning", "GUILD.ROLES.DELETE") `\n\nCurrent role: ${config.verify.role ? `<@&${config.verify.role}>` : "None"}`
.setInverted(true) )
.send(true); .setStatus("Success")
if (confirmation.cancelled) return; .setEmoji("CHANNEL.TEXT.CREATE");
if (confirmation.success) {
try {
await client.database.guilds.write(interaction.guild.id, {
"verify.role": role.id,
"verify.enabled": true
});
const { log, NucleusColors, entry, renderUser, renderRole } = client.logger;
const data = {
meta: {
type: "verifyRoleChanged",
displayName: "Verify Role Changed",
calculateType: "nucleusSettingsUpdated",
color: NucleusColors.green,
emoji: "CONTROL.BLOCKTICK",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
changedBy: entry(interaction.user.id, renderUser(interaction.user)),
role: entry(role.id, renderRole(role))
},
hidden: {
guild: interaction.guild.id
}
};
log(data);
} catch (e) {
console.log(e);
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Verify Role")
.setDescription("Something went wrong while setting the verify role")
.setStatus("Danger")
.setEmoji("GUILD.ROLES.DELETE")
],
components: []
});
}
} else {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Verify Role")
.setDescription("No changes were made")
.setStatus("Success")
.setEmoji("GUILD.ROLES.CREATE")
],
components: []
});
}
}
let clicks = 0;
const data = await client.database.guilds.read(interaction.guild.id);
let role = data.verify.role;
let timedOut = false;
while (!timedOut) {
await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [embed],
new EmojiEmbed() components: [selectMenu, buttons]
.setTitle("Verify Role")
.setDescription(
role ? `Your verify role is currently set to <@&${role}>` : "You have not set a verify role"
)
.setStatus("Success")
.setEmoji("GUILD.ROLES.CREATE")
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setCustomId("clear")
.setLabel(clicks ? "Click again to confirm" : "Reset role")
.setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
.setStyle(ButtonStyle.Danger)
.setDisabled(!role),
new ButtonBuilder()
.setCustomId("send")
.setLabel("Add verify button")
.setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
.setStyle(ButtonStyle.Primary)
])
]
}); });
let i: MessageComponentInteraction;
let i;
try { try {
i = await m.awaitMessageComponent({ i = await m.awaitMessageComponent({
time: 300000, time: 300000,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } filter: (i) => { return i.user.id === interaction.user.id }
}); });
} catch (e) { } catch (e) {
timedOut = true; closed = true;
continue; continue;
} }
await i.deferUpdate(); await i.deferUpdate();
if ((i.component as ButtonComponent).customId === "clear") {
clicks ++; if(i.isButton()) {
if (clicks === 2) { switch (i.customId) {
clicks = 0; case "save": {
await client.database.guilds.write(interaction.guild.id, null, ["verify.role", "verify.enabled"]); client.database.guilds.write(interaction.guild.id, {"verify": data} )
role = null; config = await client.database.guilds.read(interaction.guild.id);
break
}
case "switch": {
data.enabled = !data.enabled;
break
}
} }
} else { } else {
await i.deferUpdate(); data.role = i.values[0]!;
break;
} }
} // TODO: On save, clear SEN
await interaction.editReply({ } while (!closed);
embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message closed" })], await interaction.deleteReply()
components: []
});
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -1,304 +1,260 @@
import { LoadingEmbed } from "../../utils/defaults.js"; import { LoadingEmbed } from "../../utils/defaults.js";
import Discord, { import Discord, {
Channel,
CommandInteraction, CommandInteraction,
Message, AutocompleteInteraction,
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
MessageComponentInteraction,
Role,
ButtonStyle, ButtonStyle,
AutocompleteInteraction, APIMessageComponentEmoji,
GuildChannel, ChannelSelectMenuBuilder,
EmbedBuilder RoleSelectMenuBuilder,
RoleSelectMenuInteraction,
ChannelSelectMenuInteraction,
ButtonInteraction,
ModalBuilder,
TextInputBuilder,
TextInputStyle,
ModalSubmitInteraction,
} from "discord.js"; } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js"; import client from "../../utils/client.js";
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateKeyValueList from "../../utils/generateKeyValueList.js";
import { ChannelType } from "discord-api-types/v9";
import getEmojiByName from "../../utils/getEmojiByName.js"; import getEmojiByName from "../../utils/getEmojiByName.js";
import convertCurlyBracketString from "../../utils/convertCurlyBracketString.js";
import { modalInteractionCollector } from "../../utils/dualCollector.js";
const command = (builder: SlashCommandSubcommandBuilder) => const command = (builder: SlashCommandSubcommandBuilder) =>
builder builder
.setName("welcome") .setName("welcome")
.setDescription("Messages and roles sent or given when someone joins the server") .setDescription("Messages and roles sent or given when someone joins the server")
.addStringOption((option) =>
option
.setName("message")
.setDescription("The message to send when someone joins the server")
.setAutocomplete(true)
)
.addRoleOption((option) =>
option.setName("role").setDescription("The role given when someone joins the server")
)
.addRoleOption((option) =>
option.setName("ping").setDescription("The role pinged when someone joins the server")
)
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel the welcome message should be sent to")
.addChannelTypes(ChannelType.GuildText)
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => { const callback = async (interaction: CommandInteraction): Promise<void> => {
const { renderRole, renderChannel, log, NucleusColors, entry, renderUser } = client.logger; const { renderChannel } = client.logger;
await interaction.reply({ const m = await interaction.reply({
embeds: LoadingEmbed, embeds: LoadingEmbed,
fetchReply: true, fetchReply: true,
ephemeral: true ephemeral: true
}); });
let m: Message; let closed = false;
if ( let config = await client.database.guilds.read(interaction.guild!.id);
interaction.options.get("role")?.role || let data = Object.assign({}, config.welcome);
interaction.options.get("channel")?.channel ||
interaction.options.get("message")?.value as string
) {
let role: Role | null;
let ping: Role | null;
let channel: Channel | null;
const message: string | null = interaction.options.get("message")?.value as string | null;
try {
role = interaction.options.get("role")?.role as Role | null;
ping = interaction.options.get("ping")?.role as Role | null;
} catch {
return await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("GUILD.ROLES.DELETE")
.setTitle("Welcome Events")
.setDescription("The role you provided is not a valid role")
.setStatus("Danger")
]
});
}
try {
channel = interaction.options.get("channel")?.channel as Channel | null;
} catch {
return await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("GUILD.ROLES.DELETE")
.setTitle("Welcome Events")
.setDescription("The channel you provided is not a valid channel")
.setStatus("Danger")
]
});
}
const options: {
role?: string;
ping?: string;
channel?: string;
message?: string;
} = {};
if (role) options.role = renderRole(role);
if (ping) options.ping = renderRole(ping);
if (channel) options.channel = renderChannel(channel as GuildChannel);
if (message) options.message = "\n> " + message;
const confirmation = await new confirmationMessage(interaction)
.setEmoji("GUILD.ROLES.EDIT")
.setTitle("Welcome Events")
.setDescription(generateKeyValueList(options))
.setColor("Warning")
.setFailedMessage("No changes were made", "Success", "GUILD.ROLES.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
const toChange: {
"welcome.role"?: string;
"welcome.ping"?: string;
"welcome.channel"?: string;
"welcome.message"?: string;
} = {};
if (role) toChange["welcome.role"] = role.id;
if (ping) toChange["welcome.ping"] = ping.id;
if (channel) toChange["welcome.channel"] = channel.id;
if (message) toChange["welcome.message"] = message;
await client.database.guilds.write(interaction.guild!.id, toChange);
const list: {
memberId: ReturnType<typeof entry>;
changedBy: ReturnType<typeof entry>;
role?: ReturnType<typeof entry>;
ping?: ReturnType<typeof entry>;
channel?: ReturnType<typeof entry>;
message?: ReturnType<typeof entry>;
} = {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
changedBy: entry(interaction.user.id, renderUser(interaction.user))
};
if (role) list.role = entry(role.id, renderRole(role));
if (ping) list.ping = entry(ping.id, renderRole(ping));
if (channel) list.channel = entry(channel.id, renderChannel(channel as GuildChannel));
if (message) list.message = entry(message, `\`${message}\``);
const data = {
meta: {
type: "welcomeSettingsUpdated",
displayName: "Welcome Settings Changed",
calculateType: "nucleusSettingsUpdated",
color: NucleusColors.green,
emoji: "CONTROL.BLOCKTICK",
timestamp: new Date().getTime()
},
list: list,
hidden: {
guild: interaction.guild!.id
}
};
log(data);
} catch (e) {
console.log(e);
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Welcome Events")
.setDescription("Something went wrong while updating welcome settings")
.setStatus("Danger")
.setEmoji("GUILD.ROLES.DELETE")
],
components: []
});
}
} else {
return interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Welcome Events")
.setDescription("No changes were made")
.setStatus("Success")
.setEmoji("GUILD.ROLES.CREATE")
],
components: []
});
}
}
let lastClicked = null;
let timedOut = false;
do { do {
const config = await client.database.guilds.read(interaction.guild!.id); const buttons = new ActionRowBuilder<ButtonBuilder>()
m = (await interaction.editReply({ .addComponents(
embeds: [ new ButtonBuilder()
new EmojiEmbed() .setCustomId("switch")
.setTitle("Welcome Events") .setLabel(data.enabled ? "Enabled" : "Disabled")
.setDescription( .setStyle(data.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
`**Message:** ${config.welcome.message ? `\n> ${config.welcome.message}` : "*None set*"}\n` + .setEmoji(getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS", "id") as APIMessageComponentEmoji),
`**Role:** ${ new ButtonBuilder()
config.welcome.role .setCustomId("message")
? renderRole((await interaction.guild!.roles.fetch(config.welcome.role))!) .setLabel((data.message ? "Change" : "Set") + "Message")
: "*None set*" .setStyle(ButtonStyle.Primary)
}\n` + .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
`**Ping:** ${ new ButtonBuilder()
config.welcome.ping .setCustomId("channelDM")
? renderRole((await interaction.guild!.roles.fetch(config.welcome.ping))!) .setLabel("Send in DMs")
: "*None set*" .setStyle(ButtonStyle.Primary)
}\n` + .setDisabled(data.channel === "dm"),
`**Channel:** ${ new ButtonBuilder()
config.welcome.channel .setCustomId("role")
? config.welcome.channel === "dm" .setLabel("Clear Role")
? "DM" .setStyle(ButtonStyle.Danger)
: renderChannel((await interaction.guild!.channels.fetch(config.welcome.channel))!) .setEmoji(getEmojiByName("CONTROL.CROSS", "id") as APIMessageComponentEmoji),
: "*None set*" new ButtonBuilder()
}` .setCustomId("save")
.setLabel("Save")
.setStyle(ButtonStyle.Success)
.setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
.setDisabled(
data.enabled === config.welcome.enabled &&
data.message === config.welcome.message &&
data.role === config.welcome.role &&
data.ping === config.welcome.ping &&
data.channel === config.welcome.channel
) )
.setStatus("Success") );
.setEmoji("CHANNEL.TEXT.CREATE")
], const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>()
components: [ .addComponents(
new ActionRowBuilder<ButtonBuilder>().addComponents([ new ChannelSelectMenuBuilder()
new ButtonBuilder() .setCustomId("channel")
.setLabel(lastClicked === "clear-message" ? "Click again to confirm" : "Clear Message") .setPlaceholder("Select a channel to send welcome messages to")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id")) );
.setCustomId("clear-message") const roleMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
.setDisabled(!config.welcome.message) .addComponents(
.setStyle(ButtonStyle.Danger), new RoleSelectMenuBuilder()
new ButtonBuilder() .setCustomId("roleToGive")
.setLabel(lastClicked === "clear-role" ? "Click again to confirm" : "Clear Role") .setPlaceholder("Select a role to give to the member when they join the server")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id")) );
.setCustomId("clear-role") const pingMenu = new ActionRowBuilder<RoleSelectMenuBuilder>()
.setDisabled(!config.welcome.role) .addComponents(
.setStyle(ButtonStyle.Danger), new RoleSelectMenuBuilder()
new ButtonBuilder() .setCustomId("roleToPing")
.setLabel(lastClicked === "clear-ping" ? "Click again to confirm" : "Clear Ping") .setPlaceholder("Select a role to ping when a member joins the server")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id")) );
.setCustomId("clear-ping")
.setDisabled(!config.welcome.ping) const embed = new EmojiEmbed()
.setStyle(ButtonStyle.Danger), .setTitle("Welcome Settings")
new ButtonBuilder() .setStatus("Success")
.setLabel(lastClicked === "clear-channel" ? "Click again to confirm" : "Clear Channel") .setDescription(
.setEmoji(getEmojiByName("CONTROL.CROSS", "id")) `${getEmojiByName(data.enabled ? "CONTROL.TICK" : "CONTROL.CROSS")} Welcome messages and roles are ${data.enabled ? "enabled" : "disabled"}\n` +
.setCustomId("clear-channel") `**Welcome message:** ${data.message ?
.setDisabled(!config.welcome.channel) `\n> ` +
.setStyle(ButtonStyle.Danger), await convertCurlyBracketString(
new ButtonBuilder() data.message,
.setLabel("Set Channel to DM") interaction.user.id,
.setCustomId("set-channel-dm") interaction.user.username,
.setDisabled(config.welcome.channel === "dm") interaction.guild!.name,
.setStyle(ButtonStyle.Secondary) interaction.guild!.members
]) )
] : "*None*"}\n` +
})) as Message; `**Send message in:** ` + (data.channel ? (data.channel == "dm" ? "DMs" : renderChannel(data.channel)) : `*None set*`) + `\n` +
let i: MessageComponentInteraction; `**Role to ping:** ` + (data.ping ? `<@&${data.ping}>` : `*None set*`) + `\n` +
`**Role given on join:** ` + (data.role ? `<@&${data.role}>` : `*None set*`)
)
await interaction.editReply({
embeds: [embed],
components: [buttons, channelMenu, roleMenu, pingMenu]
});
let i: RoleSelectMenuInteraction | ChannelSelectMenuInteraction | ButtonInteraction;
try { try {
i = await m.awaitMessageComponent({ i = await m.awaitMessageComponent({
time: 300000, filter: (interaction) => interaction.user.id === interaction.user.id,
filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } time: 300000
}); }) as RoleSelectMenuInteraction | ChannelSelectMenuInteraction | ButtonInteraction;
} catch (e) { } catch (e) {
timedOut = true; closed = true;
continue; continue;
} }
await i.deferUpdate();
if (i.customId === "clear-message") { if(i.isButton()) {
if (lastClicked === "clear-message") { switch(i.customId) {
await client.database.guilds.write(interaction.guild!.id, { case "switch": {
"welcome.message": null await i.deferUpdate();
}); data.enabled = !data.enabled;
lastClicked = null; break;
} else { }
lastClicked = "clear-message"; case "message": {
} const modal = new ModalBuilder()
} else if (i.customId === "clear-role") { .setCustomId("modal")
if (lastClicked === "clear-role") { .setTitle("Welcome Message")
await client.database.guilds.write(interaction.guild!.id, { .addComponents(
"welcome.role": null new ActionRowBuilder<TextInputBuilder>().addComponents(
}); new TextInputBuilder()
lastClicked = null; .setCustomId("ex1")
} else { .setLabel("Server Info (1/3)")
lastClicked = "clear-role"; .setPlaceholder(
} `{serverName} - This server's name\n\n` +
} else if (i.customId === "clear-ping") { `These placeholders will be replaced with the server's name, etc..`
if (lastClicked === "clear-ping") { )
await client.database.guilds.write(interaction.guild!.id, { .setMaxLength(1)
"welcome.ping": null .setRequired(false)
}); .setStyle(TextInputStyle.Paragraph)
lastClicked = null; ),
} else { new ActionRowBuilder<TextInputBuilder>().addComponents(
lastClicked = "clear-ping"; new TextInputBuilder()
.setCustomId("ex2")
.setLabel("Member Counts (2/3) - {MemberCount:...}")
.setPlaceholder(
`{:all} - Total member count\n` +
`{:humans} - Total non-bot users\n` +
`{:bots} - Number of bots\n`
)
.setMaxLength(1)
.setRequired(false)
.setStyle(TextInputStyle.Paragraph)
),
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId("ex3")
.setLabel("Member who joined (3/3) - {member:...}")
.setPlaceholder(
`{:name} - The members name\n`
)
.setMaxLength(1)
.setRequired(false)
.setStyle(TextInputStyle.Paragraph)
),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setCustomId("message")
.setPlaceholder("Enter a message to send when someone joins the server")
.setValue(data.message ?? "")
.setLabel("Message")
.setStyle(TextInputStyle.Paragraph)
)
)
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("back")
.setLabel("Back")
.setStyle(ButtonStyle.Secondary)
.setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
)
await i.showModal(modal)
await i.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Welcome Settings")
.setDescription("Modal opened. If you can't see it, click back and try again.")
.setStatus("Success")
],
components: [button]
});
let out: ModalSubmitInteraction | null;
try {
out = await modalInteractionCollector(m, interaction.user) as ModalSubmitInteraction | null;
} catch (e) {
console.error(e);
out = null;
}
if(!out) break;
data.message = out.fields.getTextInputValue("message") ?? null;
break;
}
case "save": {
await i.deferUpdate();
await client.database.guilds.write(interaction.guild!.id, {"welcome": data});
config = await client.database.guilds.read(interaction.guild!.id);
data = Object.assign({}, config.welcome);
break;
}
case "channelDM": {
await i.deferUpdate();
data.channel = "dm";
break;
}
case "role": {
await i.deferUpdate();
data.role = null;
break;
}
} }
} else if (i.customId === "clear-channel") { } else if (i.isRoleSelectMenu()) {
if (lastClicked === "clear-channel") { await i.deferUpdate();
await client.database.guilds.write(interaction.guild!.id, { switch(i.customId) {
"welcome.channel": null case "roleToGive": {
}); data.role = i.values[0]!;
lastClicked = null; break
} else { }
lastClicked = "clear-channel"; case "roleToPing": {
data.ping = i.values[0]!;
break
}
} }
} else if (i.customId === "set-channel-dm") { } else {
await client.database.guilds.write(interaction.guild!.id, { await i.deferUpdate();
"welcome.channel": "dm" data.channel = i.values[0]!;
});
lastClicked = null;
} }
} while (!timedOut);
await interaction.editReply({ } while (!closed);
embeds: [new EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })], await interaction.deleteReply()
components: []
});
}; };
const check = (interaction: CommandInteraction, _partial: boolean = false) => { const check = (interaction: CommandInteraction, _partial: boolean = false) => {

@ -33,7 +33,7 @@ export async function callback(_client: NucleusClient, member: GuildMember) {
try { try {
await channel.send({ await channel.send({
embeds: [new EmojiEmbed().setDescription(string).setStatus("Success")], embeds: [new EmojiEmbed().setDescription(string).setStatus("Success")],
content: (config.welcome.ping ? `<@${config.welcome.ping}>` : "") + `<@${member.id}>` content: (config.welcome.ping ? `<@&${config.welcome.ping}>` : "") + `<@${member.id}>`
}); });
} catch (err) { } catch (err) {
singleNotify( singleNotify(

@ -17,16 +17,14 @@ const logs = [
"webhookUpdate", "webhookUpdate",
"guildMemberVerify", "guildMemberVerify",
"autoModeratorDeleted", "autoModeratorDeleted",
"nucleusSettingsUpdated", "ticketUpdate",
"ticketUpdate" // "nucleusSettingsUpdated"
]; ];
const tickets = ["support", "report", "question", "issue", "suggestion", "other"]; const tickets = ["support", "report", "question", "issue", "suggestion", "other"];
const toHexInteger = (permissions: string[], array?: string[]): string => { const toHexInteger = (permissions: string[], array?: string[]): string => {
if (!array) { if (!array) { array = logs; }
array = logs;
}
let int = 0n; let int = 0n;
for (const perm of permissions) { for (const perm of permissions) {

@ -56,7 +56,7 @@ async function registerCommands() {
} }
} }
console.log(`${colours.green}Processed ${processed.length} commands`) console.log(`${colours.green}Processed ${processed.length} commands${colours.none}`)
return processed; return processed;
}; };

@ -1,11 +1,9 @@
import { TextInputBuilder } from "discord.js"; import { TextInputBuilder } from "discord.js";
import Discord, { import Discord, {
CommandInteraction, CommandInteraction,
Interaction,
Message, Message,
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
MessageComponentInteraction,
ModalSubmitInteraction, ModalSubmitInteraction,
ButtonStyle, ButtonStyle,
TextInputStyle TextInputStyle
@ -246,12 +244,7 @@ class confirmationMessage {
}); });
let out; let out;
try { try {
out = await modalInteractionCollector( out = await modalInteractionCollector(m, this.interaction.user) as Discord.ModalSubmitInteraction | null;
m,
(m: Interaction) =>
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId === this.interaction.channelId,
(m) => m.customId === "reason"
);
} catch (e) { } catch (e) {
cancelled = true; cancelled = true;
continue; continue;

@ -1,4 +1,4 @@
import { ButtonInteraction, Client, Interaction, InteractionCollector, Message, MessageComponentInteraction, ModalSubmitInteraction } from "discord.js"; import { ButtonInteraction, Client, User, Interaction, InteractionCollector, Message, MessageComponentInteraction, ModalSubmitInteraction } from "discord.js";
import client from "./client.js"; import client from "./client.js";
export default async function ( export default async function (
@ -45,17 +45,25 @@ export default async function (
return out; return out;
} }
function defaultInteractionFilter(i: MessageComponentInteraction, user: User, m: Message) {
return i.channel!.id === m.channel!.id && i.user.id === user.id
}
function defaultModalFilter(i: ModalSubmitInteraction, user: User, m: Message) {
return i.channel!.id === m.channel!.id && i.user.id === user.id
}
export async function modalInteractionCollector( export async function modalInteractionCollector(
m: Message, m: Message, user: User,
modalFilter: (i: Interaction) => boolean | Promise<boolean>, modalFilter?: (i: Interaction) => boolean | Promise<boolean>,
interactionFilter: (i: MessageComponentInteraction) => boolean | Promise<boolean> interactionFilter?: (i: MessageComponentInteraction) => boolean | Promise<boolean>
): Promise<null | ButtonInteraction | ModalSubmitInteraction> { ): Promise<null | ButtonInteraction | ModalSubmitInteraction> {
let out: ButtonInteraction | ModalSubmitInteraction; let out: ButtonInteraction | ModalSubmitInteraction;
try { try {
out = await new Promise((resolve, _reject) => { out = await new Promise((resolve, _reject) => {
const int = m const int = m
.createMessageComponentCollector({ .createMessageComponentCollector({
filter: (i: MessageComponentInteraction) => interactionFilter(i), filter: (i: MessageComponentInteraction) => (interactionFilter ? interactionFilter(i) : true) && defaultInteractionFilter(i, user, m),
time: 300000 time: 300000
}) })
.on("collect", async (i: ButtonInteraction) => { .on("collect", async (i: ButtonInteraction) => {
@ -65,7 +73,7 @@ export async function modalInteractionCollector(
resolve(i); resolve(i);
}); });
const mod = new InteractionCollector(client as Client, { const mod = new InteractionCollector(client as Client, {
filter: (i: Interaction) => modalFilter(i) && i.isModalSubmit(), filter: (i: Interaction) => (modalFilter ? modalFilter(i) : true) && i.isModalSubmit() && defaultModalFilter(i, user, m),
time: 300000 time: 300000
}).on("collect", async (i: ModalSubmitInteraction) => { }).on("collect", async (i: ModalSubmitInteraction) => {
int.stop(); int.stop();
@ -75,6 +83,7 @@ export async function modalInteractionCollector(
}); });
}); });
} catch (e) { } catch (e) {
console.log(e);
return null; return null;
} }
return out; return out;

Loading…
Cancel
Save