More errors fixed
diff --git a/src/commands/mod/info.ts b/src/commands/mod/info.ts
index 61a01e2..6b5c81e 100644
--- a/src/commands/mod/info.ts
+++ b/src/commands/mod/info.ts
@@ -12,9 +12,8 @@
     ButtonStyle,
     StringSelectMenuInteraction,
     TextInputStyle,
-    APIMessageComponentEmoji
 } from "discord.js";
-import { SlashCommandSubcommandBuilder, StringSelectMenuOptionBuilder } from "@discordjs/builders";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import client from "../../utils/client.js";
@@ -158,26 +157,19 @@
         let components: (ActionRowBuilder<Discord.StringSelectMenuBuilder> | ActionRowBuilder<ButtonBuilder>)[] = []
         if (openFilterPane) components = components.concat([
             new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents(
-                new Discord.StringSelectMenuBuilder().setOptions(
-                    // ...Object.entries(types).map(([key, value]) => new StringSelectMenuOptionBuilder()
-                    //     .setLabel(value.text)
-                    //     .setValue(key)
-                    //     .setDefault(filteredTypes.includes(key))
-                    //     .setEmoji(client.emojis.resolve(getEmojiByName(value.emoji, "id"))! as APIMessageComponentEmoji)
-                    // )
-                    ...Object.entries(types).map(([key, value]) => ({
-                        label: value.text,
-                        value: key,
-                        default: filteredTypes.includes(key),
-                        emoji: client.emojis.resolve(getEmojiByName(value.emoji, "id"))! as APIMessageComponentEmoji
-                    }))
-                )
-                .setMinValues(1)
-                .setMaxValues(Object.keys(types).length)
-                .setCustomId("filter")
-                .setPlaceholder("Select events to show")
-            )
-        ])
+                new Discord.StringSelectMenuBuilder()
+                    .setMinValues(1)
+                    .setMaxValues(Object.keys(types).length)
+                    .setCustomId("filter")
+                    .setPlaceholder("Select events to show")
+                    .setOptions(...Object.entries(types).map(([key, value]) => new Discord.StringSelectMenuOptionBuilder()
+                        .setLabel(value.text)
+                        .setValue(key)
+                        .setDefault(filteredTypes.includes(key))
+                        // @ts-expect-error
+                        .setEmoji(getEmojiByName(value.emoji, "id"))  // FIXME: This gives a type error but is valid
+            )))
+        ]);
         components = components.concat([new ActionRowBuilder<Discord.ButtonBuilder>().addComponents([
             new ButtonBuilder()
                 .setCustomId("prevYear")
@@ -188,7 +180,10 @@
                 .setCustomId("prevPage")
                 .setLabel("Previous page")
                 .setStyle(ButtonStyle.Primary),
-            new ButtonBuilder().setCustomId("today").setLabel("Today").setStyle(ButtonStyle.Primary),
+            new ButtonBuilder()
+                .setCustomId("today")
+                .setLabel("Today")
+                .setStyle(ButtonStyle.Primary),
             new ButtonBuilder()
                 .setCustomId("nextPage")
                 .setLabel("Next page")
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 95c8c5a..05a9ec2 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -1,5 +1,5 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
-import Discord, { CommandInteraction, GuildMember, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
+import { LinkWarningFooter, LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import Discord, { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
@@ -48,15 +48,16 @@
                 .setRequired(false)
         );
 
+
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     if (!interaction.guild) return;
     const { log, NucleusColors, renderUser, entry, renderDelta } = client.logger;
-    const user = interaction.options.getMember("user") as GuildMember;
-    const time = {
-        days: interaction.options.getInteger("days") ?? 0,
-        hours: interaction.options.getInteger("hours") ?? 0,
-        minutes: interaction.options.getInteger("minutes") ?? 0,
-        seconds: interaction.options.getInteger("seconds") ?? 0
+    const member = interaction.options.getMember("user") as GuildMember;
+    const time: {days: number, hours: number, minutes: number, seconds: number} = {
+        days: (interaction.options.get("days")?.value as number | null) ?? 0,
+        hours: (interaction.options.get("hours")?.value as number | null) ?? 0,
+        minutes: (interaction.options.get("minutes")?.value as number | null) ?? 0,
+        seconds: (interaction.options.get("seconds")?.value as number | null) ?? 0
     };
     const config = await client.database.guilds.read(interaction.guild.id);
     let serverSettingsDescription = config.moderation.mute.timeout ? "given a timeout" : "";
@@ -66,28 +67,28 @@
 
     let muteTime = time.days * 24 * 60 * 60 + time.hours * 60 * 60 + time.minutes * 60 + time.seconds;
     if (muteTime === 0) {
-        const m = (await interaction.reply({
+        const m = await interaction.reply({
             embeds: [
                 new EmojiEmbed()
                     .setEmoji("PUNISH.MUTE.GREEN")
                     .setTitle("Mute")
-                    .setDescription("How long should the user be muted")
+                    .setDescription("How long should the user be muted for?")
                     .setStatus("Success")
             ],
             components: [
-                new ActionRowBuilder().addComponents([
+                new ActionRowBuilder<ButtonBuilder>().addComponents([
                     new Discord.ButtonBuilder().setCustomId("1m").setLabel("1 Minute").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("10m").setLabel("10 Minutes").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("30m").setLabel("30 Minutes").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("1h").setLabel("1 Hour").setStyle(ButtonStyle.Secondary)
                 ]),
-                new ActionRowBuilder().addComponents([
+                new ActionRowBuilder<ButtonBuilder>().addComponents([
                     new Discord.ButtonBuilder().setCustomId("6h").setLabel("6 Hours").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("12h").setLabel("12 Hours").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("1d").setLabel("1 Day").setStyle(ButtonStyle.Secondary),
                     new Discord.ButtonBuilder().setCustomId("1w").setLabel("1 Week").setStyle(ButtonStyle.Secondary)
                 ]),
-                new ActionRowBuilder().addComponents([
+                new ActionRowBuilder<ButtonBuilder>().addComponents([
                     new Discord.ButtonBuilder()
                         .setCustomId("cancel")
                         .setLabel("Cancel")
@@ -97,7 +98,7 @@
             ],
             ephemeral: true,
             fetchReply: true
-        })) as Message;
+        });
         let component;
         try {
             component = await m.awaitMessageComponent({
@@ -172,7 +173,7 @@
             .setTitle("Mute")
             .setDescription(
                 keyValueList({
-                    user: renderUser(user.user),
+                    user: renderUser(member.user),
                     time: `${humanizeDuration(muteTime * 1000, {
                         round: true
                     })}`,
@@ -180,17 +181,15 @@
                 }) +
                     "The user will be " +
                     serverSettingsDescription +
-                    "\n" +
-                    `The user **will${notify ? "" : " not"}** be notified\n\n` +
-                    `Are you sure you want to mute <@!${user.id}>?`
+                    "\n\n" +
+                    `Are you sure you want to mute <@!${member.id}>?`
             )
             .setColor("Danger")
             .addCustomBoolean(
                 "appeal",
                 "Create appeal ticket",
                 !(await areTicketsEnabled(interaction.guild.id)),
-                async () =>
-                    await create(interaction.guild, interaction.options.getUser("user")!, interaction.user, reason),
+                async () => await create(interaction.guild!, interaction.options.getUser("user")!, interaction.user, reason),
                 "An appeal ticket will be created when Confirm is clicked",
                 null,
                 "CONTROL.TICKET",
@@ -200,8 +199,8 @@
                 "notify",
                 "Notify user",
                 false,
-                undefined,
                 null,
+                "The user will be sent a DM",
                 null,
                 "ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
                 notify
@@ -210,146 +209,15 @@
             .send(true);
         reason = reason ?? "";
         if (confirmation.cancelled) timedOut = true;
-        if (confirmation.success) success = true;
-        if (confirmation.newReason) reason = confirmation.newReason;
-        if (confirmation.components) {
+        else if (confirmation.success) success = true;
+        else if (confirmation.newReason) reason = confirmation.newReason;
+        else if (confirmation.components) {
             notify = confirmation.components["notify"]!.active;
             createAppealTicket = confirmation.components["appeal"]!.active;
         }
     } while (!timedOut && !success)
     if (timedOut) return;
-    let dmd = false;
-    let dm;
-    if (confirmation.success) {
-        try {
-            if (notify) {
-                dm = await user.send({
-                    embeds: [
-                        new EmojiEmbed()
-                            .setEmoji("PUNISH.MUTE.RED")
-                            .setTitle("Muted")
-                            .setDescription(
-                                `You have been muted in ${interaction.guild.name}` +
-                                    (reason
-                                        ? ` for:\n> ${reason}`
-                                        : ".\n\n" +
-                                        `You will be unmuted at: <t:${
-                                            Math.round(new Date().getTime() / 1000) + muteTime
-                                        }:D> at <t:${Math.round(new Date().getTime() / 1000) + muteTime}:T> (<t:${
-                                            Math.round(new Date().getTime() / 1000) + muteTime
-                                        }:R>)`) +
-                                    (confirmation.components!["appeal"]!.response
-                                        ? `You can appeal this here: <#${confirmation.components!["appeal"]!.response}>`
-                                        : "")
-                            )
-                            .setStatus("Danger")
-                    ],
-                    components: [
-                        new ActionRowBuilder().addComponents(
-                            config.moderation.mute.text
-                                ? [
-                                    new ButtonBuilder()
-                                        .setStyle(ButtonStyle.Link)
-                                        .setLabel(config.moderation.mute.text)
-                                        .setURL(config.moderation.mute.link)
-                                ]
-                                : []
-                        )
-                    ]
-                });
-                dmd = true;
-            }
-        } catch {
-            dmd = false;
-        }
-        const member = user;
-        let errors = 0;
-        try {
-            if (config.moderation.mute.timeout) {
-                await member.timeout(muteTime * 1000, reason || "*No reason provided*");
-                if (config.moderation.mute.role !== null) {
-                    await member.roles.add(config.moderation.mute.role);
-                    await client.database.eventScheduler.schedule("naturalUnmute", new Date().getTime() + muteTime * 1000, {
-                        guild: interaction.guild.id,
-                        user: user.id,
-                        expires: new Date().getTime() + muteTime * 1000
-                    });
-                }
-            }
-        } catch {
-            errors++;
-        }
-        try {
-            if (config.moderation.mute.role !== null) {
-                await member.roles.add(config.moderation.mute.role);
-                await client.database.eventScheduler.schedule("unmuteRole", new Date().getTime() + muteTime * 1000, {
-                    guild: interaction.guild.id,
-                    user: user.id,
-                    role: config.moderation.mute.role
-                });
-            }
-        } catch (e) {
-            console.log(e);
-            errors++;
-        }
-        if (errors === 2) {
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setEmoji("PUNISH.MUTE.RED")
-                        .setTitle("Mute")
-                        .setDescription("Something went wrong and the user was not muted")
-                        .setStatus("Danger")
-                ],
-                components: []
-            }); // TODO: make this clearer
-            if (dmd && dm) await dm.delete();
-            return;
-        }
-        await client.database.history.create("mute", interaction.guild.id, member.user, interaction.user, reason);
-        const failed = !dmd && notify;
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
-                    .setTitle("Mute")
-                    .setDescription(
-                        "The member was muted" +
-                            (failed ? ", but could not be notified" : "") +
-                            (confirmation.components!["appeal"]!.response
-                                ? ` and an appeal ticket was opened in <#${confirmation.components!["appeal"]!.response}>`
-                                : "")
-                    )
-                    .setStatus(failed ? "Warning" : "Success")
-            ],
-            components: []
-        });
-        const data = {
-            meta: {
-                type: "memberMute",
-                displayName: "Member Muted",
-                calculateType: "guildMemberPunish",
-                color: NucleusColors.yellow,
-                emoji: "PUNISH.WARN.YELLOW",
-                timestamp: new Date().getTime()
-            },
-            list: {
-                memberId: entry(member.user.id, `\`${member.user.id}\``),
-                name: entry(member.user.id, renderUser(member.user)),
-                mutedUntil: entry(
-                    new Date().getTime() + muteTime * 1000,
-                    renderDelta(new Date().getTime() + muteTime * 1000)
-                ),
-                muted: entry(new Date().getTime(), renderDelta(new Date().getTime() - 1000)),
-                mutedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user)),
-                reason: entry(reason, reason ? reason : "*No reason provided*")
-            },
-            hidden: {
-                guild: interaction.guild.id
-            }
-        };
-        log(data);
-    } else {
+    if (!confirmation.success) {
         await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
@@ -360,13 +228,153 @@
             ],
             components: []
         });
+        return;
     }
+    const status: {timeout: boolean | null, role: boolean | null, dm: boolean | null} = {timeout: null, role: null, dm: null};
+    let dmMessage;
+    try {
+        if (notify) {
+            const messageData: {
+                embeds: EmojiEmbed[];
+                components: ActionRowBuilder<ButtonBuilder>[];
+            } = {
+                embeds: [
+                    new EmojiEmbed()
+                        .setEmoji("PUNISH.MUTE.RED")
+                        .setTitle("Muted")
+                        .setDescription(
+                            `You have been muted in ${interaction.guild.name}` +
+                                (reason ? ` for:\n> ${reason}` : ".\n*No reason was provided*") + "\n\n" +
+                            `You will be unmuted at: <t:${Math.round(new Date().getTime() / 1000) + muteTime}:D> at ` +
+                            `<t:${Math.round(new Date().getTime() / 1000) + muteTime}:T> (<t:${Math.round(new Date().getTime() / 1000) + muteTime
+                            }:R>)` + "\n\n" +
+                            (createAppealTicket
+                                ? `You can appeal this in the ticket created in <#${confirmation.components!["appeal"]!.response}>`
+                                : "")
+                        )
+                        .setStatus("Danger")
+                ],
+                components: []
+            }
+            if (config.moderation.mute.text && config.moderation.mute.link) {
+                messageData.embeds[0]!.setFooter(LinkWarningFooter);
+                messageData.components.push(new ActionRowBuilder<Discord.ButtonBuilder>()
+                    .addComponents(new ButtonBuilder()
+                        .setStyle(ButtonStyle.Link)
+                        .setLabel(config.moderation.mute.text)
+                        .setURL(config.moderation.mute.link)
+                    )
+                )
+            };
+            dmMessage = await member.send(messageData);
+            status.dm = true;
+        }
+    } catch {
+        status.dm = false;
+    }
+    try {
+        if (config.moderation.mute.timeout) {
+            await member.timeout(muteTime * 1000, reason || "*No reason provided*");
+            if (config.moderation.mute.role !== null) {
+                await member.roles.add(config.moderation.mute.role);
+                await client.database.eventScheduler.schedule("naturalUnmute", (new Date().getTime() + muteTime * 1000).toString(), {
+                    guild: interaction.guild.id,
+                    user: member.id,
+                    expires: new Date().getTime() + muteTime * 1000
+                });
+            }
+        } else {
+            status.timeout = true;
+        }
+    } catch {
+        status.timeout = false;
+    }
+    try {
+        if (config.moderation.mute.role !== null) {
+            await member.roles.add(config.moderation.mute.role);
+            await client.database.eventScheduler.schedule("unmuteRole", (new Date().getTime() + muteTime * 1000).toString(), {
+                guild: interaction.guild.id,
+                user: member.id,
+                role: config.moderation.mute.role
+            });
+        } else {
+            status.role = true;
+        }
+    } catch {
+        status.role = false;
+    }
+    const countTrue = (items: (boolean | null)[]) => items.filter(item => item === true).length;
+    const requiredPunishments = countTrue([config.moderation.mute.timeout, config.moderation.mute.role !== null]);
+    const actualPunishments = countTrue([status.timeout, status.role]);
+
+    await client.database.history.create("mute", interaction.guild.id, member.user, interaction.user, reason);
+    if (requiredPunishments !== actualPunishments) {
+        const messages = [];
+        if (config.moderation.mute.timeout) messages.push(`The member was ${status.timeout ? "" : "not "}timed out`);
+        if (config.moderation.mute.role !== null) messages.push(`The member was ${status.role ? "" : "not "}given the mute role`);
+        messages.push(`The member was not sent a DM`);
+        if (dmMessage && actualPunishments === 0) await dmMessage.delete();
+        await interaction.editReply({
+            embeds: [
+                new EmojiEmbed()
+                    .setEmoji("PUNISH.MUTE." + (actualPunishments > 0 ? "YELLOW" : "RED"))
+                    .setTitle("Mute")
+                    .setDescription(
+                        "Mute " + (actualPunishments > 0 ? "partially" : "failed") + ":\n" +
+                        messages.map(message => `> ${message}`).join("\n")
+                    )
+                    .setStatus(actualPunishments > 0 ? "Warning" : "Danger")
+            ],
+            components: []
+        });
+    }
+    const data = {
+        meta: {
+            type: "memberMute",
+            displayName: "Member Muted",
+            calculateType: "guildMemberPunish",
+            color: NucleusColors.yellow,
+            emoji: "PUNISH.WARN.YELLOW",
+            timestamp: new Date().getTime()
+        },
+        list: {
+            memberId: entry(member.user.id, `\`${member.user.id}\``),
+            name: entry(member.user.id, renderUser(member.user)),
+            mutedUntil: entry(
+                (new Date().getTime() + muteTime * 1000).toString(),
+                renderDelta(new Date().getTime() + muteTime * 1000)
+            ),
+            muted: entry(new Date().getTime.toString(), renderDelta(new Date().getTime() - 1000)),
+            mutedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
+            reason: entry(reason, reason ? reason : "*No reason provided*")
+        },
+        hidden: {
+            guild: interaction.guild.id
+        }
+    };
+    log(data);
+    const failed = !status.dm && notify;
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
+                .setTitle("Mute")
+                .setDescription(
+                    "The member was muted" + (failed ? ", but could not be notified" : "") +
+                    (createAppealTicket
+                        ? ` and an appeal ticket was opened in <#${confirmation.components!["appeal"]!.response}>`
+                        : "")
+                )
+                .setStatus(failed ? "Warning" : "Success")
+        ],
+        components: []
+    });
 };
 
 const check = (interaction: CommandInteraction) => {
     if (!interaction.guild) return;
     const member = interaction.member as GuildMember;
-    const me = interaction.guild.me!;
+    const me = interaction.guild.members.me!;
     const apply = interaction.options.getMember("user") as GuildMember;
     const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
     const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
@@ -376,13 +384,13 @@
     // Check if Nucleus can mute the member
     if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
     // Check if Nucleus has permission to mute
-    if (!me.permissions.has("MODERATE_MEMBERS")) throw new Error("I do not have the *Moderate Members* permission");
+    if (!me.permissions.has("ModerateMembers")) throw new Error("I do not have the *Moderate Members* permission");
     // Do not allow muting Nucleus
     if (member.id === me.id) throw new Error("I cannot mute myself");
     // Allow the owner to mute anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has moderate_members permission
-    if (!member.permissions.has("MODERATE_MEMBERS"))
+    if (!member.permissions.has("ModerateMembers"))
         throw new Error("You do not have the *Moderate Members* permission");
     // Check if the user is below on the role list
     if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member");
diff --git a/src/commands/ticket/close.ts b/src/commands/ticket/close.ts
index e2efcc3..d2ffaf9 100644
--- a/src/commands/ticket/close.ts
+++ b/src/commands/ticket/close.ts
@@ -1,5 +1,5 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import close from "../../actions/tickets/delete.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) => builder.setName("close").setDescription("Closes a ticket");
diff --git a/src/commands/ticket/create.ts b/src/commands/ticket/create.ts
index 3d0b5ce..91442b5 100644
--- a/src/commands/ticket/create.ts
+++ b/src/commands/ticket/create.ts
@@ -1,5 +1,5 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import create from "../../actions/tickets/create.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>