import { Guild, GuildBasedChannel, ActionRowBuilder, ButtonBuilder, EmbedBuilder, Role, ApplicationCommandOptionType, ChannelType, ButtonStyle, } from "discord.js"; import BreakSchema from "../../Schemas/BreakSchema"; import { Command } from "../../Structures/Command"; import { RunOptions as ExtendedInteraction } from "../../Typings/CommandTypes"; import ms from "ms"; import ConfigSchema, { ConfigTypes } from "../../Schemas/ConfigSchema"; import RetrieveGuildId from "../../Modules/RetrieveGuildId"; import EditReply from "../../Modules/EditReply"; import { HydratedDocument } from "mongoose"; export default new Command({ name: "requestbreak", description: "Take some time off doing your job!", options: [ { name: "time", description: "Length of your break, please put a space inbetween each time format (1w, 1d, 1h).", required: true, type: ApplicationCommandOptionType.String, }, { name: "reason", description: "Specify the reason for your break.", required: true, type: ApplicationCommandOptionType.String, }, ], category: "StaffSystems", run: async ({ interaction, client, args }: ExtendedInteraction) => { const { firstGuildID, secondGuildID } = await RetrieveGuildId( interaction.guildId ); const firstConfig: HydratedDocument = await ConfigSchema.findOne({ GuildID: firstGuildID }); const secondConfig: HydratedDocument = await ConfigSchema.findOne({ GuildID: secondGuildID, }); const staffRoleIDs1 = firstConfig.StaffRoleID.map( (r: string) => r.split("-")[1] ); const staffRoleIDs2 = secondConfig.StaffRoleID.map( (r: string) => r.split("-")[1] ); if (!staffRoleIDs1 || !staffRoleIDs2) { return EditReply(interaction, { content: "**Uh oh, this is awkward.** The Staff role has not been setup in config yet.", components: [], embeds: [], }); } const hasStaffRole = interaction.member.roles.cache.some( (role) => staffRoleIDs1.includes(role.id) || staffRoleIDs2.includes(role.id) ); if (!hasStaffRole) { return EditReply(interaction, { content: "You must have the Staff role to run this command.", components: [], embeds: [], }); } // continue with the rest of your code if (!firstConfig) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** This server's configuration hasn't been created yet.", }); if (!firstConfig.BreakAcceptOrDenyChannel) return EditReply(interaction, { content: "**Uh oh.** The Break Accept and Deny channel has not yet been setup in config.", components: [], embeds: [], }); const [cGuildId, channelId] = firstConfig.BreakAcceptOrDenyChannel?.split("-"); if (!firstConfig.BreakAcceptOrDenyChannel) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** The break request channel has not been setup in config yet.", }); let channel: GuildBasedChannel; if (cGuildId == interaction.channel.id) interaction.guild.channels.cache .filter((ch) => ch.type == ChannelType.GuildText) .find( (ch) => ch.id == firstConfig.BreakAcceptOrDenyChannel.split("-")[1] ); else if (cGuildId == firstGuildID) { const fGuild = client.guilds.cache.find((g) => g.id == firstGuildID); if (fGuild == null) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** The other linked guild has returned invalid.", }); channel = fGuild.channels.cache .filter((ch) => ch.type == ChannelType.GuildText) .find( (ch) => ch.id == firstConfig.BreakAcceptOrDenyChannel.split("-")[1] ); } else if (cGuildId == secondGuildID) { const sGuild = client.guilds.cache.find((g) => g.id == secondGuildID); if (sGuild == null) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** The other linked guild has returned invalid.", }); channel = sGuild.channels.cache .filter((ch) => ch.type == ChannelType.GuildText) .find( (ch) => ch.id == firstConfig.BreakAcceptOrDenyChannel.split("-")[1] ); } if (!channel) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** The Break Request channel has returned invalid.", }); const time = args.getInteger("days"); const date: Date = new Date(); date.setHours(new Date().getHours() + time * 24); const times: Array = args .getString("time") .split(" ") .map((v) => { return ms(v); }); const length = Math.round(date.getTime() / 1000); const FindBreak = await BreakSchema.findOne({ GuildID: firstGuildID, UserID: interaction.user.id, }); const reason = args.getString("reason"); if (reason.length >= 1024) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** Your specified break reason is too long.", }); if (FindBreak?.Accepted == false) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** You already have an outstanding break request.", }); if (FindBreak) return EditReply(interaction, { components: [], embeds: [], content: "**Uh oh, this is awkward.** It looks like you are already on break!", }); const roleArray = []; const firstGuild = client.guilds.cache.find((g) => g.id == firstGuildID); let secondGuild: Guild; if (firstGuildID !== secondGuildID) secondGuild = client.guilds.cache.find((g) => g.id == secondGuildID); else secondGuild = undefined; firstConfig.StaffRoleIDs?.forEach((rl: string) => { const firstGuildMember = firstGuild.members.cache.find( (m) => m.id == interaction.member.id ); if (firstGuildMember) { firstGuildMember.roles.cache.forEach((rl) => { let match = firstConfig.StaffRoleIDs.find( (i: string) => i.split("-")[0] == firstGuildID && i.split("-")[1] == rl.id ); if (match) { roleArray.push(`${firstGuildID}-${rl.id}`); } }); } if (secondGuild !== null && secondGuildID !== firstGuildID) { const secondGuildMember = secondGuild.members.cache.find( (m) => m.id == interaction.member.id ); if (!secondGuildMember) return; secondGuildMember.roles.cache.forEach((rl) => { let match = secondConfig.StaffRoleIDs.find( (i: string) => i.split("-")[0] == secondGuild.id && i.split("-")[1] == rl.id ); if (match) { roleArray.push(`${secondGuildID}-${rl.id}`); } }); } }); const breakSchema = await new BreakSchema({ GuildID: firstGuildID, UserID: interaction.member.id, Reason: reason, BreakLength: time, FinishesAt: date, Accepted: false, Roles: Array.from(new Set(roleArray)), }).save(); const embed = new EmbedBuilder(); embed.setTitle(interaction.member.user.username + "'s Break Request"); embed.addFields( { name: "Reason", value: reason, }, { name: "Finishes In:", value: ``, }, { name: "User ID", value: interaction.member.id, } ); embed.setFooter({ text: interaction.member.id }); const AcceptButton = new ButtonBuilder(); AcceptButton.setCustomId("AcceptBreakButton"); AcceptButton.setLabel("Accept Break"); AcceptButton.setStyle(ButtonStyle.Secondary); AcceptButton.setEmoji("<:yes:1040828166454911037>"); const DenyButton = new ButtonBuilder(); DenyButton.setCustomId("DenyBreakButton"); DenyButton.setLabel("Deny Break"); DenyButton.setStyle(ButtonStyle.Secondary); DenyButton.setEmoji("<:no:1040828151237988443>"); const row = new ActionRowBuilder().addComponents( AcceptButton, DenyButton ); if (!channel.isTextBased()) return; channel .send({ embeds: [embed], components: [row] }) .catch((r) => interaction.channel .send( "**Uh oh, this is awkward.** I was not able to notify the HR team of your break. I have deleted the break request, you will have to restart the process." ) .catch(() => {}) ); return EditReply(interaction, { components: [], embeds: [], content: "**Good news!** Your break request has been sent off to the Break Request channel!", }); }, });