Tickets! and a lot of bug fixes
diff --git a/src/commands/mod/about.ts b/src/commands/mod/about.ts
index c69f4a9..130cdbc 100644
--- a/src/commands/mod/about.ts
+++ b/src/commands/mod/about.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from '../../utils/defaultEmbeds.js';
+import { LoadingEmbed } from '../../utils/defaults.js';
 import type { HistorySchema } from "../../utils/database.js";
 import Discord, {
     CommandInteraction,
@@ -251,7 +251,10 @@
         }
         let i: MessageComponentInteraction;
         try {
-            i = await m.awaitMessageComponent({ time: 300000 });
+            i = await m.awaitMessageComponent({
+                time: 300000,
+                filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+            });
         } catch (e) {
             interaction.editReply({
                 embeds: [
@@ -354,7 +357,10 @@
         })) as Message;
         let i: MessageComponentInteraction;
         try {
-            i = await m.awaitMessageComponent({ time: 300000 });
+            i = await m.awaitMessageComponent({
+                time: 300000,
+                filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+            });
         } catch (e) {
             timedOut = true;
             continue;
@@ -426,7 +432,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as GuildMember;
     if (!member.permissions.has("ModerateMembers"))
-        throw new Error("You do not have the *Moderate Members* permission");
+        return "You do not have the *Moderate Members* permission";
     return true;
 };
 
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 330edfd..18b6c7e 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -5,7 +5,7 @@
 import keyValueList from "../../utils/generateKeyValueList.js";
 import addPlurals from "../../utils/plurals.js";
 import client from "../../utils/client.js";
-import { LinkWarningFooter } from "../../utils/defaultEmbeds.js";
+import { LinkWarningFooter } from "../../utils/defaults.js";
 
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
@@ -84,7 +84,7 @@
                         .setEmoji("PUNISH.BAN.RED")
                         .setTitle("Banned")
                         .setDescription(
-                            `You have been banned in ${interaction.guild.name}` +
+                            `You have been banned from ${interaction.guild.name}` +
                                 (reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
                         )
                         .setStatus("Danger")
@@ -131,7 +131,7 @@
                 banned: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
                 bannedBy: entry(interaction.user.id, renderUser(interaction.user)),
                 reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
-                accountCreated: entry(member.user.createdAt.toString(), renderDelta(member.user.createdAt.getTime())),
+                accountCreated: entry(member.user.createdTimestamp, renderDelta(member.user.createdTimestamp)),
                 serverMemberCount: interaction.guild.memberCount
             },
             hidden: {
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index a4b9774..bdbb9ee 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -1,4 +1,4 @@
-import { LinkWarningFooter } from './../../utils/defaultEmbeds.js';
+import { LinkWarningFooter } from '../../utils/defaults.js';
 import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 // @ts-expect-error
 import humanizeDuration from "humanize-duration";
@@ -177,19 +177,19 @@
     const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
     const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
     // Do not allow kicking the owner
-    if (member.id === interaction.guild.ownerId) throw new Error("You cannot kick the owner of the server");
+    if (member.id === interaction.guild.ownerId) return "You cannot kick the owner of the server";
     // Check if Nucleus can kick the member
-    if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+    if (!(mePos > applyPos)) return "I do not have a role higher than that member";
     // Check if Nucleus has permission to kick
-    if (!me.permissions.has("KickMembers")) throw new Error("I do not have the *Kick Members* permission");
+    if (!me.permissions.has("KickMembers")) return "I do not have the *Kick Members* permission";
     // Do not allow kicking Nucleus
-    if (member.id === interaction.guild.members.me!.id) throw new Error("I cannot kick myself");
+    if (member.id === interaction.guild.members.me!.id) return "I cannot kick myself";
     // Allow the owner to kick anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has kick_members permission
-    if (!member.permissions.has("KickMembers")) throw new Error("You do not have the *Kick Members* permission");
+    if (!member.permissions.has("KickMembers")) return "You do not have the *Kick 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");
+    if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
     // Allow kick
     return true;
 };
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index b558e87..3270d37 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -1,4 +1,4 @@
-import { LinkWarningFooter, LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LinkWarningFooter, LoadingEmbed } from "../../utils/defaults.js";
 import Discord, { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -370,20 +370,20 @@
     const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
     const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
     // Do not allow muting the owner
-    if (member.id === interaction.guild.ownerId) throw new Error("You cannot mute the owner of the server");
+    if (member.id === interaction.guild.ownerId) return "You cannot mute the owner of the server";
     // Check if Nucleus can mute the member
-    if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+    if (!(mePos > applyPos)) return "I do not have a role higher than that member";
     // Check if Nucleus has permission to mute
-    if (!me.permissions.has("ModerateMembers")) throw new Error("I do not have the *Moderate Members* permission");
+    if (!me.permissions.has("ModerateMembers")) return "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");
+    if (member.id === me.id) return "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("ModerateMembers"))
-        throw new Error("You do not have the *Moderate Members* permission");
+        return "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");
+    if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
     // Allow mute
     return true;
 };
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index c5e45b6..1fbde64 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -176,20 +176,20 @@
     const applyPos = apply.roles.cache.size ? apply.roles.highest.position : 0;
     if (!interaction.guild) return false;
     // Do not allow any changing of the owner
-    if (member.id === interaction.guild.ownerId) throw new Error("You cannot change the owner's nickname");
+    if (member.id === interaction.guild.ownerId) return "You cannot change the owner's nickname";
     // Check if Nucleus can change the nickname
-    if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+    if (!(mePos > applyPos)) return "I do not have a role higher than that member";
     // Check if Nucleus has permission to change the nickname
-    if (!me.permissions.has("ManageNicknames")) throw new Error("I do not have the *Manage Nicknames* permission");
+    if (!me.permissions.has("ManageNicknames")) return "I do not have the *Manage Nicknames* permission";
     // Allow the owner to change anyone's nickname
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has manage_nicknames permission
     if (!member.permissions.has("ManageNicknames"))
-        throw new Error("You do not have the *Manage Nicknames* permission");
+        return "You do not have the *Manage Nicknames* permission";
     // Allow changing your own nickname
     if (member === apply) return true;
     // 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");
+    if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
     // Allow change
     return true;
 };
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 5425714..e6b4670 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -1,3 +1,4 @@
+import { JSONTranscriptFromMessageArray, JSONTranscriptToHumanReadable } from '../../utils/logTranscripts.js';
 import Discord, { CommandInteraction, GuildChannel, GuildMember, TextChannel, ButtonStyle, ButtonBuilder } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -93,7 +94,7 @@
             let component;
             try {
                 component = m.awaitMessageComponent({
-                    filter: (m) => m.user.id === interaction.user.id,
+                    filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id,
                     time: 300000
                 });
             } catch (e) {
@@ -146,7 +147,7 @@
                 displayName: "Channel Purged",
                 calculateType: "messageDelete",
                 color: NucleusColors.red,
-                emoji: "PUNISH.BAN.RED",
+                emoji: "CHANNEL.PURGE.RED",
                 timestamp: new Date().getTime()
             },
             list: {
@@ -160,19 +161,9 @@
             }
         };
         log(data);
-        let out = "";
-        deleted.reverse().forEach((message) => {
-            out += `${message.author.username}#${message.author.discriminator} (${message.author.id}) [${new Date(
-                message.createdTimestamp
-            ).toISOString()}]\n`;
-            const lines = message.content.split("\n");
-            lines.forEach((line) => {
-                out += `> ${line}\n`;
-            });
-            out += "\n\n";
-        });
+        const transcript = JSONTranscriptToHumanReadable(JSONTranscriptFromMessageArray(deleted)!);
         const attachmentObject = {
-            attachment: Buffer.from(out),
+            attachment: Buffer.from(transcript),
             name: `purge-${channel.id}-${Date.now()}.txt`,
             description: "Purge log"
         };
@@ -197,7 +188,7 @@
         let component;
         try {
             component = await m.awaitMessageComponent({
-                filter: (m) => m.user.id === interaction.user.id,
+                filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id,
                 time: 300000
             });
         } catch {
@@ -304,7 +295,7 @@
                 displayName: "Channel Purged",
                 calculateType: "messageDelete",
                 color: NucleusColors.red,
-                emoji: "PUNISH.BAN.RED",
+                emoji: "CHANNEL.PURGE.RED",
                 timestamp: new Date().getTime()
             },
             list: {
@@ -367,7 +358,7 @@
         let component;
         try {
             component = await m.awaitMessageComponent({
-                filter: (m) => m.user.id === interaction.user.id,
+                filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id,
                 time: 300000
             });
         } catch {
@@ -405,11 +396,11 @@
     const member = interaction.member as GuildMember;
     const me = interaction.guild.members.me!;
     // Check if nucleus has the manage_messages permission
-    if (!me.permissions.has("ManageMessages")) throw new Error("I do not have the *Manage Messages* permission");
+    if (!me.permissions.has("ManageMessages")) return "I do not have the *Manage Messages* permission";
     // Allow the owner to purge
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has manage_messages permission
-    if (!member.permissions.has("ManageMessages")) throw new Error("You do not have the *Manage Messages* permission");
+    if (!member.permissions.has("ManageMessages")) return "You do not have the *Manage Messages* permission";
     // Allow purge
     return true;
 };
diff --git a/src/commands/mod/slowmode.ts b/src/commands/mod/slowmode.ts
index 9bd994d..9792827 100644
--- a/src/commands/mod/slowmode.ts
+++ b/src/commands/mod/slowmode.ts
@@ -79,9 +79,9 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as GuildMember;
     // Check if Nucleus can set the slowmode
-    if (!interaction.guild!.members.me!.permissions.has("ManageChannels")) throw new Error("I do not have the *Manage Channels* permission");
+    if (!interaction.guild!.members.me!.permissions.has("ManageChannels")) return "I do not have the *Manage Channels* permission";
     // Check if the user has manage_channel permission
-    if (!member.permissions.has("ManageChannels")) throw new Error("You do not have the *Manage Channels* permission");
+    if (!member.permissions.has("ManageChannels")) return "You do not have the *Manage Channels* permission";
     // Allow slowmode
     return true;
 };
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index 12bfc3e..35f275f 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -1,173 +1,201 @@
-import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
+import Discord, { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, User, ButtonStyle } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import confirmationMessage from "../../utils/confirmationMessage.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
+import addPlurals from "../../utils/plurals.js";
 import client from "../../utils/client.js";
-import addPlural from "../../utils/plurals.js";
+import { LinkWarningFooter } from "../../utils/defaults.js";
+
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
         .setName("softban")
         .setDescription("Kicks a user and deletes their messages")
         .addUserOption((option) => option.setName("user").setDescription("The user to softban").setRequired(true))
-        .addIntegerOption((option) =>
+        .addNumberOption((option) =>
             option
                 .setName("delete")
-                .setDescription("The days of messages to delete | Default: 0")
+                .setDescription("Delete this number of days of messages from the user | Default: 0")
                 .setMinValue(0)
                 .setMaxValue(7)
                 .setRequired(false)
         );
 
-const callback = async (interaction: CommandInteraction): Promise<unknown> => {
+
+const callback = async (interaction: CommandInteraction): Promise<void> => {
+    if (!interaction.guild) return;
     const { renderUser } = client.logger;
     // TODO:[Modals] Replace this with a modal
     let reason = null;
     let notify = true;
     let confirmation;
+    let chosen = false;
     let timedOut = false;
-    let success = false;
-    while (!timedOut && !success) {
-        const confirmation = await new confirmationMessage(interaction)
+    do {
+        confirmation = await new confirmationMessage(interaction)
             .setEmoji("PUNISH.BAN.RED")
             .setTitle("Softban")
             .setDescription(
                 keyValueList({
-                    user: renderUser(interaction.options.getUser("user")),
-                    reason: reason ? "\n> " + (reason ?? "").replaceAll("\n", "\n> ") : "*No reason provided*"
+                    user: renderUser(interaction.options.getUser("user")!),
+                    reason: reason ? "\n> " + (reason).replaceAll("\n", "\n> ") : "*No reason provided*"
                 }) +
                     `The user **will${notify ? "" : " not"}** be notified\n` +
-                    `${addPlural(
-                        interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0,
-                        "day"
-                    )} of messages will be deleted\n\n` +
+                    `${addPlurals(
+                        (interaction.options.get("delete")?.value as number | null) ?? 0, "day")
+                    } of messages will be deleted\n\n` +
                     `Are you sure you want to softban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`
             )
-            .setColor("Danger")
             .addCustomBoolean(
                 "notify",
                 "Notify user",
                 false,
-                null,
-                null,
+                undefined,
+                "The user will be sent a DM",
                 null,
                 "ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
                 notify
             )
+            .setColor("Danger")
             .addReasonButton(reason ?? "")
+            .setFailedMessage("No changes were made", "Success", "PUNISH.BAN.GREEN")
             .send(reason !== null);
         reason = reason ?? "";
         if (confirmation.cancelled) timedOut = true;
-        else if (confirmation.success) success = true;
+        else if (confirmation.success !== undefined) chosen = true;
         else if (confirmation.newReason) reason = confirmation.newReason;
-        else if (confirmation.components) {
-            notify = confirmation.components.notify.active;
-        }
-    }
-    if (timedOut) return;
-    if (confirmation.success) {
-        let dmd = false;
-        const config = await client.database.guilds.read(interaction.guild.id);
-        try {
-            if (notify) {
-                await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [
-                        new EmojiEmbed()
-                            .setEmoji("PUNISH.BAN.RED")
-                            .setTitle("Softbanned")
-                            .setDescription(
-                                `You have been softbanned from ${interaction.guild.name}` +
-                                    (reason ? ` for:\n> ${reason}` : ".")
-                            )
-                            .setStatus("Danger")
-                    ],
-                    components: [
-                        new ActionRowBuilder().addComponents(
-                            config.moderation.ban.text
-                                ? [
-                                      new ButtonBuilder()
-                                          .setStyle(ButtonStyle.Link)
-                                          .setLabel(config.moderation.ban.text)
-                                          .setURL(config.moderation.ban.link)
-                                  ]
-                                : []
-                        )
-                    ]
-                });
-                dmd = true;
-            }
-        } catch {
-            dmd = false;
-        }
-        const member = interaction.options.getMember("user") as GuildMember;
-        try {
-            await member.ban({
-                days: Number(interaction.options.getInteger("delete") ?? 0),
-                reason: reason
-            });
-            await interaction.guild.members.unban(member, "Softban");
-        } catch {
-            await interaction.editReply({
+        else if (confirmation.components) notify = confirmation.components["notify"]!.active;
+    } while (!timedOut && !chosen)
+    if (timedOut || !confirmation.success) return;
+    reason = reason.length ? reason : null
+    let dmSent = false;
+    let dmMessage;
+    const config = await client.database.guilds.read(interaction.guild.id);
+    try {
+        if (notify) {
+            if (reason) { reason = reason.split("\n").map((line) => "> " + line).join("\n") }
+            const messageData: {
+                embeds: EmojiEmbed[];
+                components: ActionRowBuilder<ButtonBuilder>[];
+            } = {
                 embeds: [
                     new EmojiEmbed()
                         .setEmoji("PUNISH.BAN.RED")
                         .setTitle("Softban")
-                        .setDescription("Something went wrong and the user was not softbanned")
+                        .setDescription(
+                            `You have been softbanned from ${interaction.guild.name}` +
+                                (reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
+                        )
                         .setStatus("Danger")
                 ],
                 components: []
-            });
+            };
+            if (config.moderation.softban.text && config.moderation.softban.link) {
+                messageData.embeds[0]!.setFooter(LinkWarningFooter)
+                messageData.components.push(new ActionRowBuilder<Discord.ButtonBuilder>()
+                        .addComponents(new ButtonBuilder()
+                            .setStyle(ButtonStyle.Link)
+                            .setLabel(config.moderation.softban.text)
+                            .setURL(config.moderation.softban.link)
+                        )
+                )
+            }
+            dmMessage = await (interaction.options.getMember("user") as GuildMember).send(messageData);
+            dmSent = true;
         }
-        await client.database.history.create("softban", interaction.guild.id, member.user, reason);
-        const failed = !dmd && notify;
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
-                    .setTitle("Softban")
-                    .setDescription("The member was softbanned" + (failed ? ", but could not be notified" : ""))
-                    .setStatus(failed ? "Warning" : "Success")
-            ],
-            components: []
-        });
-    } else {
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji("PUNISH.BAN.GREEN")
-                    .setTitle("Softban")
-                    .setDescription("No changes were made")
-                    .setStatus("Success")
-            ],
-            components: []
-        });
+    } catch {
+        dmSent = false;
     }
+    try {
+        const member = interaction.options.getMember("user") as GuildMember;
+        const days: number = interaction.options.get("delete")?.value as number | null ?? 0;
+        member.ban({
+            deleteMessageSeconds: days * 24 * 60 * 60,
+            reason: reason ?? "*No reason provided*"
+        });
+        await interaction.guild.members.unban(member, "Softban");
+        await client.database.history.create("ban", interaction.guild.id, member.user, interaction.user, reason);
+        const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
+        const data = {
+            meta: {
+                type: "memberSoftban",
+                displayName: "Member Softbanned",
+                calculateType: "guildMemberPunish",
+                color: NucleusColors.yellow,
+                emoji: "PUNISH.BAN.YELLOW",
+                timestamp: new Date().getTime()
+            },
+            list: {
+                memberId: entry(member.user.id, `\`${member.user.id}\``),
+                name: entry(member.user.id, renderUser(member.user)),
+                softbanned: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
+                softbannedBy: entry(interaction.user.id, renderUser(interaction.user)),
+                reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
+                accountCreated: entry(member.user.createdTimestamp, renderDelta(member.user.createdTimestamp)),
+                serverMemberCount: interaction.guild.memberCount
+            },
+            hidden: {
+                guild: interaction.guild.id
+            }
+        };
+        log(data);
+    } catch {
+        await interaction.editReply({
+            embeds: [
+                new EmojiEmbed()
+                    .setEmoji("PUNISH.BAN.RED")
+                    .setTitle("Softban")
+                    .setDescription("Something went wrong and the user was not softbanned")
+                    .setStatus("Danger")
+            ],
+            components: []
+        });
+        if (dmSent && dmMessage) await dmMessage.delete();
+        return;
+    }
+    const failed = !dmSent && notify;
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
+                .setTitle("Softban")
+                .setDescription("The member was softbanned" + (failed ? ", but could not be notified" : ""))
+                .setStatus(failed ? "Warning" : "Success")
+        ],
+        components: []
+    });
 };
 
-const check = (interaction: CommandInteraction) => {
+const check = async (interaction: CommandInteraction) => {
+    if (!interaction.guild) return;
     const member = interaction.member as GuildMember;
-    const me = interaction.guild.me!;
-    const apply = interaction.options.getMember("user") as GuildMember;
-    if (member === null || me === null || apply === null) throw new Error("That member is not in the server");
+    const me = interaction.guild.members.me!;
+    let apply = interaction.options.getUser("user") as User | 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;
-    const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
-    // Do not allow softbanning the owner
+    let applyPos = 0
+    try {
+        apply = await interaction.guild.members.fetch(apply.id) as GuildMember
+        applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
+    } catch {
+        apply = apply as User
+    }
+    // Do not allow banning the owner
     if (member.id === interaction.guild.ownerId) throw new Error("You cannot softban the owner of the server");
     // Check if Nucleus can ban the member
     if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
     // Check if Nucleus has permission to ban
-    if (!me.permissions.has("BAN_MEMBERS")) throw new Error("I do not have the *Ban Members* permission");
-    // Do not allow softbanning Nucleus
+    if (!me.permissions.has("BanMembers")) throw new Error("I do not have the *Ban Members* permission");
+    // Do not allow banning Nucleus
     if (member.id === me.id) throw new Error("I cannot softban myself");
-    // Allow the owner to softban anyone
+    // Allow the owner to ban anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has ban_members permission
-    if (!member.permissions.has("BAN_MEMBERS")) throw new Error("You do not have the *Ban Members* permission");
+    if (!member.permissions.has("BanMembers")) throw new Error("You do not have the *Ban 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");
-    // Allow softban
+    // Allow ban
     return true;
 };
 
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index d34f303..37fee99 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -1,5 +1,5 @@
-import { CommandInteraction, GuildMember, User } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction, GuildMember, User } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -16,7 +16,7 @@
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     if (!interaction.guild) return;
     const bans = await interaction.guild.bans.fetch();
-    const user = interaction.options.getString("user");
+    const user = interaction.options.get("user")?.value as string;
     let resolved = bans.find((ban) => ban.user.id === user);
     if (!resolved) resolved = bans.find((ban) => ban.user.username.toLowerCase() === user.toLowerCase());
     if (!resolved) resolved = bans.find((ban) => ban.user.tag.toLowerCase() === user.toLowerCase());
@@ -48,7 +48,7 @@
         try {
             await interaction.guild.members.unban(resolved.user as User, "Unban");
             const member = resolved.user as User;
-            await client.database.history.create("unban", interaction.guild.id, member, interaction.user);
+            await client.database.history.create("unban", interaction.guild.id, member, interaction.user, "No reason provided");
             const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
             const data = {
                 meta: {
@@ -64,7 +64,7 @@
                     name: entry(member.id, renderUser(member)),
                     unbanned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                     unbannedBy: entry(interaction.user.id, renderUser(interaction.user)),
-                    accountCreated: entry(member.createdAt, renderDelta(member.createdAt))
+                    accountCreated: entry(member.createdTimestamp, renderDelta(member.createdTimestamp))
                 },
                 hidden: {
                     guild: interaction.guild.id
@@ -110,13 +110,13 @@
 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!;
     // Check if Nucleus can unban members
-    if (!me.permissions.has("BAN_MEMBERS")) throw new Error("I do not have the *Ban Members* permission");
+    if (!me.permissions.has("BanMembers")) return "I do not have the *Ban Members* permission";
     // Allow the owner to unban anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has ban_members permission
-    if (!member.permissions.has("BAN_MEMBERS")) throw new Error("You do not have the *Ban Members* permission");
+    if (!member.permissions.has("BanMembers")) return "You do not have the *Ban Members* permission";
     // Allow unban
     return true;
 };
diff --git a/src/commands/mod/unmute.ts b/src/commands/mod/unmute.ts
index c93f8cc..e2585e1 100644
--- a/src/commands/mod/unmute.ts
+++ b/src/commands/mod/unmute.ts
@@ -43,6 +43,7 @@
                 notify
             )
             .addReasonButton(reason ?? "")
+            .setFailedMessage("No changes were made", "Success", "PUNISH.MUTE.GREEN")
             .send(reason !== null);
         if (confirmation.cancelled) timedOut = true;
         else if (confirmation.success !== undefined) success = true;
@@ -51,96 +52,83 @@
             notify = confirmation.components!["notify"]!.active;
         }
     } while (!timedOut && !success);
-    if (confirmation.cancelled) return;
-    if (confirmation.success) {
-        let dmSent = false;
-        let dmMessage;
-        try {
-            if (notify) {
-                dmMessage = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [
-                        new EmojiEmbed()
-                            .setEmoji("PUNISH.MUTE.GREEN")
-                            .setTitle("Unmuted")
-                            .setDescription(
-                                `You have been unmuted in ${interaction.guild.name}` +
-                                    (reason ? ` for:\n> ${reason}` : " with no reason provided.")
-                            )
-                            .setStatus("Success")
-                    ]
-                });
-                dmSent = true;
-            }
-        } catch {
-            dmSent = false;
-        }
-        const member = interaction.options.getMember("user") as GuildMember;
-        try {
-            member.timeout(0, reason ?? "*No reason provided*");
-        } catch {
-            await interaction.editReply({
+    if (confirmation.cancelled || !confirmation.success) return;
+    let dmSent = false;
+    let dmMessage;
+    try {
+        if (notify) {
+            dmMessage = await (interaction.options.getMember("user") as GuildMember).send({
                 embeds: [
                     new EmojiEmbed()
-                        .setEmoji("PUNISH.MUTE.RED")
-                        .setTitle("Unmute")
-                        .setDescription("Something went wrong and the user was not unmuted")
-                        .setStatus("Danger")
-                ],
-                components: []
+                        .setEmoji("PUNISH.MUTE.GREEN")
+                        .setTitle("Unmuted")
+                        .setDescription(
+                            `You have been unmuted in ${interaction.guild.name}` +
+                                (reason ? ` for:\n> ${reason}` : " with no reason provided.")
+                        )
+                        .setStatus("Success")
+                ]
             });
-            if (dmSent && dmMessage) await dmMessage.delete();
-            return;
+            dmSent = true;
         }
-        await client.database.history.create(
-            "unmute",
-            interaction.guild.id,
-            (interaction.options.getMember("user") as GuildMember).user,
-            interaction.user,
-            reason
-        );
-        const data = {
-            meta: {
-                type: "memberUnmute",
-                displayName: "Unmuted",
-                calculateType: "guildMemberPunish",
-                color: NucleusColors.green,
-                emoji: "PUNISH.MUTE.GREEN",
-                timestamp: new Date().getTime()
-            },
-            list: {
-                memberId: entry(member.user.id, `\`${member.user.id}\``),
-                name: entry(member.user.id, renderUser(member.user)),
-                unmuted: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
-                unmutedBy: entry(interaction.user.id, renderUser(interaction.user))
-            },
-            hidden: {
-                guild: interaction.guild.id
-            }
-        };
-        log(data);
-        const failed = !dmSent && notify;
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
-                    .setTitle("Unmute")
-                    .setDescription("The member was unmuted" + (failed ? ", but could not be notified" : ""))
-                    .setStatus(failed ? "Warning" : "Success")
-            ],
-            components: []
-        });
-    } else {
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji("PUNISH.MUTE.GREEN")
-                    .setTitle("Unmute")
-                    .setDescription("No changes were made")
-                    .setStatus("Success")
-            ],
-            components: []
-        });
+    } catch {
+        dmSent = false;
     }
+    const member = interaction.options.getMember("user") as GuildMember;
+    try {
+        member.timeout(0, reason ?? "*No reason provided*");
+    } catch {
+        await interaction.editReply({
+            embeds: [
+                new EmojiEmbed()
+                    .setEmoji("PUNISH.MUTE.RED")
+                    .setTitle("Unmute")
+                    .setDescription("Something went wrong and the user was not unmuted")
+                    .setStatus("Danger")
+            ],
+            components: []
+        });
+        if (dmSent && dmMessage) await dmMessage.delete();
+        return;
+    }
+    await client.database.history.create(
+        "unmute",
+        interaction.guild.id,
+        (interaction.options.getMember("user") as GuildMember).user,
+        interaction.user,
+        reason
+    );
+    const data = {
+        meta: {
+            type: "memberUnmute",
+            displayName: "Unmuted",
+            calculateType: "guildMemberPunish",
+            color: NucleusColors.green,
+            emoji: "PUNISH.MUTE.GREEN",
+            timestamp: new Date().getTime()
+        },
+        list: {
+            memberId: entry(member.user.id, `\`${member.user.id}\``),
+            name: entry(member.user.id, renderUser(member.user)),
+            unmuted: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
+            unmutedBy: entry(interaction.user.id, renderUser(interaction.user))
+        },
+        hidden: {
+            guild: interaction.guild.id
+        }
+    };
+    log(data);
+    const failed = !dmSent && notify;
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
+                .setTitle("Unmute")
+                .setDescription("The member was unmuted" + (failed ? ", but could not be notified" : ""))
+                .setStatus(failed ? "Warning" : "Success")
+        ],
+        components: []
+    });
 };
 
 const check = (interaction: CommandInteraction) => {
@@ -152,18 +140,18 @@
     const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
     const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
     // Do not allow unmuting the owner
-    if (member.id === interaction.guild.ownerId) throw new Error("You cannot unmute the owner of the server");
+    if (member.id === interaction.guild.ownerId) return "You cannot unmute the owner of the server";
     // Check if Nucleus can unmute the member
-    if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+    if (!(mePos > applyPos)) return "I do not have a role higher than that member";
     // Check if Nucleus has permission to unmute
-    if (!me.permissions.has("ModerateMembers")) throw new Error("I do not have the *Moderate Members* permission");
+    if (!me.permissions.has("ModerateMembers")) return "I do not have the *Moderate Members* permission";
     // Allow the owner to unmute anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has moderate_members permission
     if (!member.permissions.has("ModerateMembers"))
-        throw new Error("You do not have the *Moderate Members* permission");
+        return "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");
+    if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
     // Allow unmute
     return true;
 };
diff --git a/src/commands/mod/viewas.ts b/src/commands/mod/viewas.ts
index 8b2864a..6216a37 100644
--- a/src/commands/mod/viewas.ts
+++ b/src/commands/mod/viewas.ts
@@ -1,10 +1,13 @@
+import { LoadingEmbed } from './../../utils/defaults.js';
 import Discord, {
     CommandInteraction,
     GuildMember,
     ActionRowBuilder,
     ButtonBuilder,
     ButtonStyle,
-    NonThreadGuildBasedChannel
+    NonThreadGuildBasedChannel,
+    StringSelectMenuOptionBuilder,
+    StringSelectMenuBuilder
 } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import type { GuildBasedChannel } from "discord.js";
@@ -26,183 +29,155 @@
             "null": channel[]
         }
     */
+    const m = await interaction.reply({embeds: LoadingEmbed, ephemeral: true, fetchReply: true})
 
-    const channels: Record<string, GuildBasedChannel[]> = {"": [] as GuildBasedChannel[]};
+    let channels: Record<string, GuildBasedChannel[]> = {"": []};
 
-    interaction.guild!.channels.fetch().then(channelCollection => {
-        channelCollection.forEach(channel => {
-            if (!channel) return; // if no channel
-            if (channel.type === Discord.ChannelType.GuildCategory) {
-                if(!channels[channel!.id]) channels[channel!.id] = [channel];
-            } else if (channel.parent) {
-                if (!channels[channel.parent.id]) channels[channel.parent.id] = [channel];
-                else (channels[channel.parent.id as string])!.push(channel);
-            } else {
-                channels[""]!.push(channel);
-            }
-        });
+    const channelCollection = await interaction.guild!.channels.fetch();
+
+    channelCollection.forEach(channel => {
+        if (!channel) return; // if no channel
+        if (channel.type === Discord.ChannelType.GuildCategory) {
+            if(!channels[channel!.id]) channels[channel!.id] = [];
+        } else if (channel.parent) {
+            if (!channels[channel.parent.id]) channels[channel.parent.id] = [channel];
+            else (channels[channel.parent.id as string])!.push(channel);
+        } else {
+            channels[""]!.push(channel);
+        }
     });
 
     const member = interaction.options.getMember("member") as Discord.GuildMember;
     const autoSortBelow = [Discord.ChannelType.GuildVoice, Discord.ChannelType.GuildStageVoice];
-    // for each category, sort its channels. This should be based on the order of the channels, with voice and stage channels sorted below text
-    channels = Object.values(channels).map((c) => {
-        return c.sort((a: GuildBasedChannel, b: GuildBasedChannel) => {
-            if (a.type === Discord.ChannelType.PrivateThread || b.type === Discord.ChannelType.PrivateThread)
-            if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position ?? 0 - b.position ;
+
+    for (const category in channels) {
+        channels[category] = channels[category]!.sort((a: GuildBasedChannel, b: GuildBasedChannel) => {
+            const disallowedTypes = [Discord.ChannelType.PublicThread, Discord.ChannelType.PrivateThread, Discord.ChannelType.AnnouncementThread];
+            if (disallowedTypes.includes(a.type) || disallowedTypes.includes(b.type)) return 0;
+            a = a as NonThreadGuildBasedChannel;
+            b = b as NonThreadGuildBasedChannel;
+            if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position - b.position;
             if (autoSortBelow.includes(a.type)) return 1;
             if (autoSortBelow.includes(b.type)) return -1;
-            return a - b;
+            return a.position - b.position;
         });
     }
-    
+    for (const category in channels) {
+        channels[category] = channels[category]!.filter((c) => {
+            return c.permissionsFor(member).has("ViewChannel");
+        });
+    }
+    for (const category in channels) {
+        channels[category] = channels[category]!.filter((c) => {
+            return !(c.type === Discord.ChannelType.PublicThread || c.type === Discord.ChannelType.PrivateThread || c.type === Discord.ChannelType.AnnouncementThread)
+        });
+    }
+    channels = Object.fromEntries(Object.entries(channels).filter(([_, v]) => v.length > 0));
+    let page = 0;
+    let closed = false;
+    const categoryIDs = Object.keys(channels);
+    const categoryNames = Object.values(channels).map((c) => {
+        return c[0]!.parent?.name ?? "Uncategorised";
+    });
+    // Split the category names into the first and last 25, ignoring the last 25 if there are 25 or less
+    const first25 = categoryNames.slice(0, 25);
+    const last25 = categoryNames.slice(25);
+    const categoryNames25: string[][] = [first25];
+    if (last25.length > 0) categoryNames25.push(last25);
 
-    //OLD CODE START
-    // const unprocessedChannels: GuildBasedChannel[] = [];
-    // let m;
-    // interaction.guild!.channels.cache.forEach((channel) => {
-    //     if (!channel.parent && channel.type !== Discord.ChannelType.GuildCategory) unprocessedChannels.push(channel);
-    // });
-    // let channels: GuildBasedChannel[][] = [unprocessedChannels];
-    // channels = channels.concat(
-    //     interaction.guild!.channels.cache
-    //         .filter((c) => c.type === Discord.ChannelType.GuildCategory)
-    //         .map((c) => (c as CategoryChannel).children.map((c) => c))
-    // );
-    // const autoSortBelow = ["GUILD_VOICE", "GUILD_STAGE_VOICE"];
-    // channels = channels.map((c) =>
-    //     c.sort((a, b) => {
-    //         if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position - b.position;
-    //         if (autoSortBelow.includes(a.type)) return 1;
-    //         if (autoSortBelow.includes(b.type)) return -1;
-    //         return a.position - b.position;
-    //     })
-    // );
-    // // Sort all arrays by the position of the first channels parent position
-    // channels = channels.sort((a, b) => {
-    //     if (!a[0].parent) return -1;
-    //     if (!b[0].parent) return 1;
-    //     return a[0].parent.position - b[0].parent.position;
-    // });
-    // const member = interaction.options.getMember("member") as Discord.GuildMember;
-    // m = await interaction.reply({
-    //     embeds: [
-    //         new EmojiEmbed()
-    //             .setEmoji("MEMBER.JOIN")
-    //             .setTitle("Viewing as " + member.displayName)
-    //             .setStatus("Success")
-    //     ],
-    //     ephemeral: true,
-    //     fetchReply: true
-    // });
-    // let page = 0;
-    // let timedOut = false;
-    // while (!timedOut) {
-    //     m = await interaction.editReply({
-    //         embeds: [
-    //             new EmojiEmbed()
-    //                 .setEmoji("MEMBER.JOIN")
-    //                 .setTitle("Viewing as " + member.displayName)
-    //                 .setStatus("Success")
-    //                 .setDescription(
-    //                     `**${channels[page][0].parent ? channels[page][0].parent.name : "Uncategorised"}**` +
-    //                         "\n" +
-    //                         channels[page]
-    //                             .map((c) => {
-    //                                 let channelType = c.type;
-    //                                 if (interaction.guild.rulesChannelId === c.id) channelType = "RULES";
-    //                                 else if ("nsfw" in c && c.nsfw) channelType += "_NSFW";
-    //                                 return c.permissionsFor(member).has("VIEW_CHANNEL")
-    //                                     ? `${getEmojiByName("ICONS.CHANNEL." + channelType)} ${c.name}\n` +
-    //                                           (() => {
-    //                                               if ("threads" in c && c.threads.cache.size > 0) {
-    //                                                   return (
-    //                                                       c.threads.cache
-    //                                                           .map(
-    //                                                               (t) =>
-    //                                                                   ` ${
-    //                                                                       getEmojiByName("ICONS.CHANNEL.THREAD_PIPE") +
-    //                                                                       " " +
-    //                                                                       getEmojiByName("ICONS.CHANNEL.THREAD_CHANNEL")
-    //                                                                   } ${t.name}`
-    //                                                           )
-    //                                                           .join("\n") + "\n"
-    //                                                   );
-    //                                               }
-    //                                               return "";
-    //                                           })()
-    //                                     : "";
-    //                             })
-    //                             .join("") +
-    //                         "\n" +
-    //                         pageIndicator(channels.length, page)
-    //                 )
-    //         ],
-    //         components: [
-    //             new ActionRowBuilder().addComponents([
-    //                 new SelectMenuBuilder()
-    //                     .setOptions(
-    //                         channels.map((c, index) => ({
-    //                             label: c[0].parent ? c[0].parent.name : "Uncategorised",
-    //                             value: index.toString(),
-    //                             default: page === index
-    //                         }))
-    //                     )
-    //                     .setCustomId("select")
-    //                     .setMaxValues(1)
-    //                     .setMinValues(1)
-    //                     .setPlaceholder("Select a category")
-    //             ]),
-    //             new ActionRowBuilder().addComponents([
-    //                 new ButtonBuilder()
-    //                     .setLabel(
-    //                         page === 0
-    //                             ? ""
-    //                             : channels[page - 1][0].parent
-    //                             ? channels[page - 1][0].parent.name
-    //                             : "Uncategorised"
-    //                     )
-    //                     .setDisabled(page === 0)
-    //                     .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
-    //                     .setStyle(ButtonStyle.Primary)
-    //                     .setCustomId("previous"),
-    //                 new ButtonBuilder()
-    //                     .setLabel(
-    //                         page === channels.length - 1
-    //                             ? ""
-    //                             : channels[page + 1][0].parent
-    //                             ? channels[page + 1][0].parent.name
-    //                             : "Uncategorised"
-    //                     )
-    //                     .setDisabled(page === channels.length - 1)
-    //                     .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
-    //                     .setStyle(ButtonStyle.Primary)
-    //                     .setCustomId("next")
-    //             ])
-    //         ]
-    //     });
-    //     let i;
-    //     try {
-    //         i = await m.awaitMessageComponent({ time: 300000 });
-    //     } catch (e) {
-    //         timedOut = true;
-    //         continue;
-    //     }
-    //     i.deferUpdate();
-    //     if (i.customId === "next") {
-    //         page++;
-    //     } else if (i.customId === "previous") {
-    //         page--;
-    //     } else if (i.customId === "select") {
-    //         page = parseInt(i.values[0]);
-    //     }
-    // }
-    
+    const channelTypeEmoji: Record<number, string> = {
+        0: "GUILD_TEXT",  // Text channel
+        2: "GUILD_VOICE",  // Voice channel
+        5: "GUILD_NEWS",  // Announcement channel
+        13: "GUILD_STAGE_VOICE",  // Stage channel
+        15: "FORUM",  // Forum channel
+        99: "RULES"  // Rules channel
+    };
+    const NSFWAvailable: number[] = [0, 2, 5, 13];
+    const rulesChannel = interaction.guild!.rulesChannel?.id;
+
+    async function nameFromChannel(channel: GuildBasedChannel): Promise<string> {
+        let channelType = channel.type;
+        if (channelType === Discord.ChannelType.GuildCategory) return "";
+        if (channel.id === rulesChannel) channelType = 99
+        let threads: Discord.ThreadChannel[] = [];
+        if ("threads" in channel) {
+            threads = channel.threads.cache.toJSON().map((t) => t as Discord.ThreadChannel);
+        }
+        const nsfw = ("nsfw" in channel ? channel.nsfw : false) && NSFWAvailable.includes(channelType)
+        const emojiName = channelTypeEmoji[channelType] + (nsfw ? "_NSFW" : "");
+        const emoji = getEmojiByName("ICONS.CHANNEL." + (threads.length ? "THREAD_CHANNEL" : emojiName));
+        let current = `${emoji} ${channel.name}`;
+        if (threads.length) {
+            for (const thread of threads) {
+                current += `\n${getEmojiByName("ICONS.CHANNEL.THREAD_PIPE")} ${thread.name}`;
+            }
+        }
+        return current;
+    }
+
+    while (!closed) {
+        const category = categoryIDs[page]!;
+        let description = "";
+        for (const channel of channels[category]!) {
+            description += `${await nameFromChannel(channel)}\n`;
+        }
+
+        const parsedCategorySelectMenu: ActionRowBuilder<StringSelectMenuBuilder | ButtonBuilder>[] = categoryNames25.map(
+            (categories, set) => { return new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(new StringSelectMenuBuilder()
+                .setCustomId("category")
+                .setMinValues(1)
+                .setMaxValues(1)
+                .setOptions(categories.map((c, i) => {
+                    return new StringSelectMenuOptionBuilder()
+                        .setLabel(c)
+                        .setValue((set * 25 + i).toString())
+                        // @ts-expect-error
+                        .setEmoji(getEmojiByName("ICONS.CHANNEL.CATEGORY", "id"))  // Again, this is valid but TS doesn't think so
+                        .setDefault((set * 25 + i) === page)
+                }))
+            )}
+        );
+
+        const components: ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] = parsedCategorySelectMenu
+        components.push(new ActionRowBuilder<ButtonBuilder>().addComponents(
+            new ButtonBuilder()
+                .setCustomId("back")
+                .setStyle(ButtonStyle.Secondary)
+                .setDisabled(page === 0)
+                .setEmoji(getEmojiByName("CONTROL.LEFT", "id")),
+            new ButtonBuilder()
+                .setCustomId("right")
+                .setStyle(ButtonStyle.Secondary)
+                .setDisabled(page === categoryIDs.length - 1)
+                .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
+        ));
+
+        await interaction.editReply({
+            embeds: [new EmojiEmbed()
+                .setEmoji("MEMBER.JOIN")
+                .setTitle("Viewing as " + member.displayName)
+                .setStatus("Success")
+                .setDescription(description + "\n" + pageIndicator(categoryIDs.length, page))
+            ], components: components
+        });
+        let i;
+        try {
+            i = await m.awaitMessageComponent({filter: (i) => i.user.id === interaction.user.id, time: 30000});
+        } catch (e) {
+            closed = true;
+            continue;
+        }
+        i.deferUpdate();
+        if (i.customId === "back") page--;
+        else if (i.customId === "right") page++;
+        else if (i.customId === "category" && i.isStringSelectMenu()) page = parseInt(i.values[0]!);
+    }
 };
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as GuildMember;
-    if (!member.permissions.has("MANAGE_ROLES")) throw new Error("You do not have the *Manage Roles* permission");
+    if (!member.permissions.has("ManageRoles")) return "You do not have the *Manage Roles* permission";
     return true;
 };
 
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index c4aa7c3..93241e1 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -5,7 +5,7 @@
 import keyValueList from "../../utils/generateKeyValueList.js";
 import { create, areTicketsEnabled } from "../../actions/createModActionTicket.js";
 import client from "../../utils/client.js";
-import { LinkWarningFooter } from "../../utils/defaultEmbeds.js";
+import { LinkWarningFooter } from "../../utils/defaults.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -186,7 +186,7 @@
         let component;
         try {
             component = await m.awaitMessageComponent({
-                filter: (m) => m.user.id === interaction.user.id,
+                filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id,
                 time: 300000
             });
         } catch (e) {
@@ -279,18 +279,18 @@
     if (!interaction.guild) return;
     const member = interaction.member as GuildMember;
     const apply = interaction.options.getMember("user") as GuildMember | null;
-    if (apply === null) throw new Error("That member is not in the server");
+    if (apply === null) return "That member is not in the server";
     const memberPos = member.roles.cache.size ? member.roles.highest.position : 0;
     const applyPos = apply.roles.cache.size ? apply.roles.highest.position : 0;
     // Do not allow warning bots
-    if (member.user.bot) throw new Error("I cannot warn bots");
+    if (member.user.bot) return "I cannot warn bots";
     // Allow the owner to warn anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has moderate_members permission
     if (!member.permissions.has("ModerateMembers"))
-        throw new Error("You do not have the *Moderate Members* permission");
+        return "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");
+    if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
     // Allow warn
     return true;
 };